kword

KWDocument.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
00003    Copyright (C) 2002-2006 David Faure <faure@kde.org>
00004    Copyright (C) 2005 Thomas Zander <zander@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "KWDocument.h"
00023 
00024 #include "KWordDocIface.h"
00025 #include "KWBgSpellCheck.h"
00026 #include "KoTextBookmark.h"
00027 #include "KWCanvas.h"
00028 #include "KWCommand.h"
00029 #include "KWFormulaFrameSet.h"
00030 #include "KWFrameLayout.h"
00031 #include "KWPictureFrameSet.h"
00032 #include "KWPartFrameSet.h"
00033 #include "KWTableFrameSet.h"
00034 #include "KWTableStyle.h"
00035 #include "KWTableTemplate.h"
00036 #include "KWTextImage.h"
00037 #include "KWVariable.h"
00038 #include "KWView.h"
00039 #include "KWViewMode.h"
00040 #include "KWMailMergeDataBase.h"
00041 #include "KWLoadingInfo.h"
00042 #include "KWCollectFramesetsVisitor.h"
00043 #include "KWOasisLoader.h"
00044 #include "KWOasisSaver.h"
00045 #include "KWFrameList.h"
00046 #include "KWPageManager.h"
00047 #include "KWPage.h"
00048 #include "KWFrameView.h"
00049 #include "KWFrameViewManager.h"
00050 #include "KWStartupWidget.h"
00051 
00052 #include <KoPictureCollection.h>
00053 #include <KoTemplateChooseDia.h>
00054 #include <KoMainWindow.h>
00055 #include <KoDocumentInfo.h>
00056 #include <KoGlobal.h>
00057 #include <KoParagCounter.h>
00058 #include <KoTextObject.h>
00059 #include <KoAutoFormat.h>
00060 #include <KoVariable.h>
00061 #include <kformuladocument.h>
00062 #include <KoApplication.h>
00063 #include <KoOasisContext.h>
00064 #include <KoCommandHistory.h>
00065 #include <KoGenStyles.h>
00066 #include <KoStore.h>
00067 #include <KoStoreDrag.h>
00068 #include <KoStoreDevice.h>
00069 #include <KoXmlWriter.h>
00070 #include <KoOasisStore.h>
00071 #include <KoOasisStyles.h>
00072 #include <KoXmlNS.h>
00073 #include <KoDom.h>
00074 
00075 #include <kcursor.h>
00076 #include <kdebug.h>
00077 #include <kglobalsettings.h>
00078 #include <klibloader.h>
00079 #include <kmultipledrag.h>
00080 #include <klocale.h>
00081 #include <kmessagebox.h>
00082 #include <kspell.h>
00083 #include <kstandarddirs.h>
00084 
00085 #include <kspell2/settings.h>
00086 
00087 #include <qfileinfo.h>
00088 #include <qregexp.h>
00089 #include <qtimer.h>
00090 #include <qbuffer.h>
00091 
00092 #include <unistd.h>
00093 #include <math.h>
00094 
00095 //#define DEBUG_PAGES
00096 //#define DEBUG_SPEED
00097 
00098 // Make sure an appropriate DTD is available in www/koffice/DTD if changing this value
00099 static const char * CURRENT_DTD_VERSION = "1.2";
00100 
00101 /******************************************************************/
00102 /* Class: KWCommandHistory                                        */
00103 /******************************************************************/
00104 class KWCommandHistory : public KoCommandHistory
00105 {
00106 public:
00107     KWCommandHistory( KWDocument * doc ) : KoCommandHistory( doc->actionCollection(),  true ), m_pDoc( doc ) {}
00108 public /*slots*/: // They are already slots in the parent. Running moc on the inherited class shouldn't be necessary AFAICS.
00109     virtual void undo();
00110     virtual void redo();
00111 private:
00112     KWDocument * m_pDoc;
00113 };
00114 
00115 void KWCommandHistory::undo()
00116 {
00117     m_pDoc->clearUndoRedoInfos();
00118     KoCommandHistory::undo();
00119 }
00120 
00121 void KWCommandHistory::redo()
00122 {
00123     m_pDoc->clearUndoRedoInfos();
00124     KoCommandHistory::redo();
00125 }
00126 
00127 /******************************************************************/
00128 /* Class: KWDocument                                              */
00129 /******************************************************************/
00130 void KWDocument::clearUndoRedoInfos()
00131 {
00132     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
00133     for ( ; fit.current() ; ++fit )
00134     {
00135         KWTextFrameSet *fs = dynamic_cast<KWTextFrameSet *>( fit.current() );
00136         if ( fs )
00137             fs->clearUndoRedoInfo();
00138     }
00139 }
00140 
00145 class KWDocument::InitialEditing {
00146 public:
00147     QString m_initialFrameSet;
00148     int m_initialCursorParag;
00149     int m_initialCursorIndex;
00150 };
00151 
00152 const int KWDocument::CURRENT_SYNTAX_VERSION = 3;
00153 
00154 KWDocument::KWDocument(QWidget *parentWidget, const char *widname, QObject* parent, const char* name, bool singleViewMode )
00155     : KoDocument( parentWidget, widname, parent, name, singleViewMode ),
00156       m_urlIntern()
00157 {
00158     KWStatisticVariable::setExtendedType(  true );
00159     dcop = 0;
00160     m_framesChangedHandler = 0;
00161     m_pageManager = new KWPageManager();
00162     m_pageManager->appendPage();
00163     m_loadingInfo = 0L;
00164     m_tabStop = MM_TO_POINT( 15.0 );
00165     m_processingType = WP;
00166 
00167 //    varFormats.setAutoDelete(true);
00168     m_lstFrameSet.setAutoDelete( true );
00169     // m_textImageRequests does not create or delete the KWTextImage classes
00170     m_textImageRequests.setAutoDelete(false);
00171 
00172     m_styleColl = new KoStyleCollection();
00173     m_frameStyleColl = new KWFrameStyleCollection();
00174     m_tableStyleColl = new KWTableStyleCollection();
00175     m_tableTemplateColl = new KWTableTemplateCollection();
00176     m_pictureCollection = new KoPictureCollection();
00177 
00178     m_personalExpressionPath = KWFactory::instance()->dirs()->resourceDirs("expression");
00179 
00180     m_bShowGrid = false;
00181     m_bSnapToGrid = false;
00182 
00183 
00184     setInstance( KWFactory::instance(), false );
00185     setTemplateType( "kword_template" );
00186 
00187     m_gridX = m_gridY = MM_TO_POINT(5.0 );
00188     m_indent = MM_TO_POINT( 10.0 );
00189 
00190     m_iNbPagePerRow = 4;
00191     m_maxRecentFiles = 10;
00192     m_bShowRuler = true;
00193 
00194     m_footNoteSeparatorLinePos=SLP_LEFT;
00195 
00196     m_iFootNoteSeparatorLineLength = 20; // 20%, i.e. 1/5th
00197     m_footNoteSeparatorLineWidth = 2.0;
00198     m_footNoteSeparatorLineType = SLT_SOLID;
00199 
00200     m_viewFormattingChars = false;
00201 
00202     m_viewFormattingEndParag = true;
00203     m_viewFormattingSpace = true;
00204     m_viewFormattingTabs = true;
00205     m_viewFormattingBreak = true;
00206 
00207     m_viewFrameBorders = true;
00208     m_repaintAllViewsPending = false;
00209     m_recalcFramesPending = -1;
00210     m_bShowDocStruct = true;
00211     m_bShowRuler = true;
00212     m_bShowStatusBar = true;
00213     m_bAllowAutoFormat = true;
00214     m_pgUpDownMovesCaret = true;
00215     m_bShowScrollBar = true;
00216     m_cursorInProtectectedArea = true;
00217     m_bHasEndNotes = false;
00218 
00219     m_bInsertDirectCursor=false;
00220     m_globalLanguage = KGlobal::locale()->language();
00221     m_bGlobalHyphenation = false;
00222     m_bGeneratingPreview = false;
00223     m_viewModeType="ModeNormal";
00224     m_layoutViewMode = 0;
00225 
00226     m_commandHistory = new KWCommandHistory( this );
00227     connect( m_commandHistory, SIGNAL( documentRestored() ), this, SLOT( slotDocumentRestored() ) );
00228     connect( m_commandHistory, SIGNAL( commandExecuted() ), this, SLOT( slotCommandExecuted() ) );
00229 
00230     //styleMask = U_FONT_FAMILY_ALL_SIZE | U_COLOR | U_BORDER | U_INDENT |
00231     //                     U_NUMBERING | U_ALIGN | U_TABS | U_SMART;
00232     m_headerVisible = false;
00233     m_footerVisible = false;
00234 
00235     m_pasteFramesetsMap = 0L;
00236     m_initialEditing = 0L;
00237     m_bufPixmap = 0L;
00238     m_varFormatCollection = new KoVariableFormatCollection;
00239     m_varColl = new KWVariableCollection( new KWVariableSettings(), m_varFormatCollection );
00240 
00241     m_autoFormat = new KoAutoFormat(this,m_varColl,m_varFormatCollection );
00242     m_bgSpellCheck = new KWBgSpellCheck(this);
00243     m_slDataBase = new KWMailMergeDataBase( this );
00244     m_bookmarkList = new KoTextBookmarkList;
00245     slRecordNum = -1;
00246 
00247     m_syntaxVersion = CURRENT_SYNTAX_VERSION;
00248 
00249     m_hasTOC=false;
00250 
00251     // It's important to call this to have the kformula actions
00252     // created. The real document is still to be created if needed.
00253     m_formulaDocumentWrapper =
00254         new KFormula::DocumentWrapper( instance()->config(),
00255                                        actionCollection(),
00256                                        m_commandHistory );
00257 
00258     setEmpty();
00259     setModified(false);
00260 
00261     initConfig();
00262 
00263     // Get default font from the KWord config file
00264     KConfig *config = KWFactory::instance()->config();
00265     config->setGroup("Document defaults" );
00266     QString defaultFontname=config->readEntry("DefaultFont");
00267     if ( !defaultFontname.isEmpty() )
00268         m_defaultFont.fromString( defaultFontname );
00269     // If not found, we automatically fallback to the application font (the one from KControl's font module)
00270 
00271     // Try to force a scalable font.
00272     m_defaultFont.setStyleStrategy( QFont::ForceOutline );
00273 
00274     int ptSize = m_defaultFont.pointSize();
00275     if ( ptSize == -1 ) // specified with a pixel size ?
00276         ptSize = QFontInfo(m_defaultFont).pointSize();
00277 
00278     //kdDebug() << "Default font: requested family: " << m_defaultFont.family() << endl;
00279     //kdDebug() << "Default font: real family: " << QFontInfo(m_defaultFont).family() << endl;
00280 
00281     if ( name )
00282         dcopObject();
00283 }
00284 
00285 DCOPObject* KWDocument::dcopObject()
00286 {
00287     if ( !dcop )
00288         dcop = new KWordDocIface( this );
00289     return dcop;
00290 }
00291 
00292 KWDocument::~KWDocument()
00293 {
00294     //don't save config when kword is embedded into konqueror
00295     if(isReadWrite())
00296         saveConfig();
00297     // formula frames have to be deleted before m_formulaDocumentWrapper
00298     m_lstFrameSet.clear();
00299     delete m_loadingInfo;
00300     delete m_autoFormat;
00301     delete m_formulaDocumentWrapper;
00302     delete m_commandHistory;
00303     delete m_varColl;
00304     delete m_varFormatCollection;
00305     delete m_slDataBase;
00306     delete dcop;
00307     delete m_bgSpellCheck;
00308     delete m_styleColl;
00309     delete m_frameStyleColl;
00310     delete m_tableStyleColl;
00311     delete m_tableTemplateColl;
00312     delete m_layoutViewMode;
00313     delete m_bufPixmap;
00314     delete m_pictureCollection;
00315     delete m_pageManager;
00316     delete m_bookmarkList;
00317 }
00318 
00319 void KWDocument::initConfig()
00320 {
00321   KConfig *config = KWFactory::instance()->config();
00322   if( config->hasGroup("KSpell kword" ) )
00323   {
00324       config->setGroup( "KSpell kword" );
00325 
00326       // Default is false for spellcheck, but the spell-check config dialog
00327       // should write out "true" when the user configures spell checking.
00328       if ( isReadWrite() )
00329           m_bgSpellCheck->setEnabled(config->readBoolEntry( "SpellCheck", false ));
00330       else
00331           m_bgSpellCheck->setEnabled( false );
00332   }
00333 
00334   if(config->hasGroup("Interface" ) )
00335   {
00336       config->setGroup( "Interface" );
00337       setGridY(QMAX( config->readDoubleNumEntry("GridY",MM_TO_POINT(5.0) ), 0.1));
00338       setGridX(QMAX( config->readDoubleNumEntry("GridX",MM_TO_POINT(5.0) ), 0.1));
00339       setCursorInProtectedArea( config->readBoolEntry( "cursorInProtectArea", true ));
00340       // Config-file value in mm, default 10 pt
00341       double indent = config->readDoubleNumEntry("Indent", MM_TO_POINT(10.0) ) ;
00342       setIndentValue(indent);
00343       setShowRuler(config->readBoolEntry("Rulers",true));
00344       int defaultAutoSave = KoDocument::defaultAutoSave()/60; // in minutes
00345       setAutoSave(config->readNumEntry("AutoSave",defaultAutoSave)*60); // read key in minutes, call setAutoSave(seconds)
00346       setBackupFile( config->readBoolEntry("BackupFile", true) );
00347 
00348       setNbPagePerRow(config->readNumEntry("nbPagePerRow",4));
00349       m_maxRecentFiles = config->readNumEntry( "NbRecentFile", 10 );
00350 
00351       m_viewFormattingChars = config->readBoolEntry( "ViewFormattingChars", false );
00352       m_viewFormattingBreak = config->readBoolEntry( "ViewFormattingBreaks", true );
00353       m_viewFormattingSpace = config->readBoolEntry( "ViewFormattingSpace", true );
00354       m_viewFormattingEndParag = config->readBoolEntry( "ViewFormattingEndParag", true );
00355       m_viewFormattingTabs = config->readBoolEntry( "ViewFormattingTabs", true );
00356 
00357       m_viewFrameBorders = config->readBoolEntry( "ViewFrameBorders", true );
00358 
00359       m_zoom = config->readNumEntry( "Zoom", 100 );
00360       m_zoomMode = static_cast<KoZoomMode::Mode> (
00361               config->readNumEntry( "ZoomMode", KoZoomMode::ZOOM_CONSTANT )
00362       );
00363 
00364       m_bShowDocStruct = config->readBoolEntry( "showDocStruct", true );
00365       m_viewModeType = config->readEntry( "viewmode", "ModeNormal" );
00366       setShowStatusBar( config->readBoolEntry( "ShowStatusBar" , true ) );
00367       setAllowAutoFormat( config->readBoolEntry( "AllowAutoFormat" , true ) );
00368       setShowScrollBar( config->readBoolEntry( "ShowScrollBar", true ) );
00369       if ( isEmbedded() )
00370           m_bShowDocStruct = false; // off by default for embedded docs, but still toggleable
00371       m_pgUpDownMovesCaret = config->readBoolEntry( "PgUpDownMovesCaret", true );
00372       m_bInsertDirectCursor= config->readBoolEntry( "InsertDirectCursor", false );
00373       m_globalLanguage=config->readEntry("language", KGlobal::locale()->language());
00374       m_bGlobalHyphenation=config->readBoolEntry("hyphenation", false);
00375 
00376       setShowGrid( config->readBoolEntry( "ShowGrid" , false ));
00377       setSnapToGrid( config->readBoolEntry( "SnapToGrid", false ));
00378       setGridX( config->readDoubleNumEntry( "ResolutionX", MM_TO_POINT( 5.0 ) ));
00379       setGridY( config->readDoubleNumEntry( "ResolutionY", MM_TO_POINT( 5.0 ) ));
00380   }
00381   else
00382   {
00383       m_zoom = 100;
00384       m_zoomMode = KoZoomMode::ZOOM_WIDTH;
00385   }
00386   int undo=30;
00387   if(config->hasGroup("Misc" ) )
00388   {
00389       config->setGroup( "Misc" );
00390       undo=config->readNumEntry("UndoRedo",-1);
00391 
00392       //load default unit setting - this is only used for new files (from templates) or empty files
00393       if ( config->hasKey( "Units" ) )
00394           setUnit( KoUnit::unit( config->readEntry("Units") ) );
00395       m_defaultColumnSpacing = config->readDoubleNumEntry( "ColumnSpacing", 3.0 );
00396   }
00397 
00398   if(undo!=-1)
00399       setUndoRedoLimit(undo);
00400 
00401   setZoomAndResolution( m_zoom, KoGlobal::dpiX(), KoGlobal::dpiY() );
00402 
00403   //text mode view is not a good default for a readonly document...
00404   if ( !isReadWrite() && m_viewModeType =="ModeText" )
00405       m_viewModeType= "ModeNormal";
00406 
00407   m_layoutViewMode = KWViewMode::create( m_viewModeType, this, 0 /*no canvas*/);
00408 
00409   if(config->hasGroup("Kword Path" ) )
00410   {
00411       config->setGroup( "Kword Path" );
00412       if ( config->hasKey( "expression path" ) )
00413           m_personalExpressionPath = config->readPathListEntry( "expression path" );
00414       setBackupPath(config->readPathEntry( "backup path" ));
00415   }
00416 
00417   // Load personal dict
00418   KConfigGroup group( KoGlobal::kofficeConfig(), "Spelling" );
00419   m_spellCheckPersonalDict = group.readListEntry( "PersonalDict" );
00420 }
00421 
00422 void KWDocument::saveConfig()
00423 {
00424     if ( !isReadWrite() )
00425         return;
00426     KConfigGroup group( KoGlobal::kofficeConfig(), "Spelling" );
00427     group.writeEntry( "PersonalDict", m_spellCheckPersonalDict );
00428 
00429     if ( !isEmbedded() )
00430     {
00431         // Only save the config that is manipulated by the UI directly.
00432         // The config from the config dialog is saved by the dialog itself.
00433         KConfig *config = KWFactory::instance()->config();
00434         config->setGroup( "Interface" );
00435         config->writeEntry( "ViewFormattingChars", m_viewFormattingChars );
00436         config->writeEntry( "ViewFormattingBreaks", m_viewFormattingBreak );
00437         config->writeEntry( "ViewFormattingEndParag", m_viewFormattingEndParag );
00438         config->writeEntry( "ViewFormattingTabs", m_viewFormattingTabs );
00439         config->writeEntry( "ViewFormattingSpace", m_viewFormattingSpace );
00440         config->writeEntry( "ViewFrameBorders", m_viewFrameBorders );
00441         config->writeEntry( "Zoom", m_zoom );
00442         config->writeEntry( "ZoomMode", m_zoomMode );
00443         config->writeEntry( "showDocStruct", m_bShowDocStruct );
00444         config->writeEntry( "Rulers", m_bShowRuler );
00445         config->writeEntry( "viewmode", m_viewModeType) ;
00446         config->writeEntry( "AllowAutoFormat", m_bAllowAutoFormat );
00447         config->writeEntry( "ShowGrid" , m_bShowGrid );
00448         config->writeEntry( "SnapToGrid" , m_bSnapToGrid );
00449         config->writeEntry( "ResolutionX", m_gridX );
00450         config->writeEntry( "ResolutionY", m_gridY );
00451     }
00452 }
00453 
00454 void KWDocument::setZoomAndResolution( int zoom, int dpiX, int dpiY )
00455 {
00456     KoTextZoomHandler::setZoomAndResolution( zoom, dpiX, dpiY );
00457     if ( KFormula::Document* formulaDocument = m_formulaDocumentWrapper->document() )
00458         formulaDocument->setZoomAndResolution( zoom, dpiX, dpiY );
00459 }
00460 
00461 KWTextFrameSet * KWDocument::textFrameSet ( unsigned int num ) const
00462 {
00463     unsigned int i=0;
00464     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
00465     for ( ; fit.current() ; ++fit )
00466     {
00467         if(fit.current()->isDeleted()) continue;
00468         if(fit.current()->type()==FT_TEXT)
00469         {
00470             if(i==num)
00471                 return static_cast<KWTextFrameSet*>(fit.current());
00472             i++;
00473         }
00474     }
00475     return static_cast<KWTextFrameSet*>(m_lstFrameSet.getFirst());
00476 }
00477 
00478 void KWDocument::newZoomAndResolution( bool updateViews, bool forPrint )
00479 {
00480     if ( KFormula::Document* formulaDocument = m_formulaDocumentWrapper->document() )
00481         formulaDocument->newZoomAndResolution( updateViews,forPrint );
00482 #if 0
00483     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
00484     for ( ; fit.current() ; ++fit )
00485         fit.current()->zoom( forPrint );
00486 #endif
00487 
00488     // First recalc all frames (including the kotextdocument width)
00489     updateAllFrames();
00490     // Then relayout the text inside the frames
00491     layout();
00492     if ( updateViews )
00493     {
00494         emit newContentsSize();
00495         repaintAllViews( true );
00496     }
00497 }
00498 
00499 bool KWDocument::initDoc(InitDocFlags flags, QWidget* parentWidget)
00500 {
00501     m_pageColumns.columns = 1;
00502     m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing;
00503 
00504     m_pageHeaderFooter.header = HF_SAME;
00505     m_pageHeaderFooter.footer = HF_SAME;
00506     m_pageHeaderFooter.ptHeaderBodySpacing = 10;
00507     m_pageHeaderFooter.ptFooterBodySpacing = 10;
00508     m_pageHeaderFooter.ptFootNoteBodySpacing = 10;
00509 
00510     bool ok = FALSE;
00511 
00512     if ( isEmbedded() )
00513     {
00514       QString fileName( locate( "kword_template", "Normal/.source/Embedded.kwt" , KWFactory::instance() ) );
00515       resetURL();
00516      ok = loadNativeFormat( fileName );
00517       if ( !ok )
00518         showLoadingErrorDialog();
00519       setEmpty();
00520       setModified( FALSE );
00521       return ok;
00522     }
00523     else if (flags==KoDocument::InitDocEmpty)
00524     {
00525         QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::instance() ) );
00526         resetURL();
00527         ok = loadNativeFormat( fileName );
00528         if ( !ok )
00529             showLoadingErrorDialog();
00530         setEmpty();
00531         setModified( FALSE );
00532         return ok;
00533     }
00534 
00535     KoTemplateChooseDia::DialogType dlgtype;
00536 
00537     if (flags != KoDocument::InitDocFileNew)
00538         dlgtype = KoTemplateChooseDia::Everything;
00539     else
00540         dlgtype = KoTemplateChooseDia::OnlyTemplates;
00541 
00542 
00543     QString file;
00544     KoTemplateChooseDia::ReturnType ret = KoTemplateChooseDia::choose(
00545         KWFactory::instance(), file,
00546         dlgtype, "kword_template", parentWidget );
00547     if ( ret == KoTemplateChooseDia::Template ) {
00548         resetURL();
00549         ok = loadNativeFormat( file );
00550         if ( !ok )
00551             showLoadingErrorDialog();
00552         setEmpty();
00553     } else if ( ret == KoTemplateChooseDia::File ) {
00554         KURL url( file );
00555         //kdDebug() << "KWDocument::initDoc opening URL " << url.prettyURL() << endl;
00556         ok = openURL( url );
00557     } else if ( ret == KoTemplateChooseDia::Empty ) {
00558         QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::instance() ) );
00559         resetURL();
00560         ok = loadNativeFormat( fileName );
00561         if ( !ok )
00562             showLoadingErrorDialog();
00563         setEmpty();
00564     }
00565     setModified( FALSE );
00566     return ok;
00567 }
00568 
00569 void KWDocument::openExistingFile( const QString& file )
00570 {
00571   m_pageColumns.columns = 1;
00572   m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing;
00573 
00574   m_pageHeaderFooter.header = HF_SAME;
00575   m_pageHeaderFooter.footer = HF_SAME;
00576   m_pageHeaderFooter.ptHeaderBodySpacing = 10;
00577   m_pageHeaderFooter.ptFooterBodySpacing = 10;
00578   m_pageHeaderFooter.ptFootNoteBodySpacing = 10;
00579 
00580   KoDocument::openExistingFile( file );
00581 }
00582 
00583 void KWDocument::openTemplate( const QString& file )
00584 {
00585   m_pageColumns.columns = 1;
00586   m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing;
00587 
00588   m_pageHeaderFooter.header = HF_SAME;
00589   m_pageHeaderFooter.footer = HF_SAME;
00590   m_pageHeaderFooter.ptHeaderBodySpacing = 10;
00591   m_pageHeaderFooter.ptFooterBodySpacing = 10;
00592   m_pageHeaderFooter.ptFootNoteBodySpacing = 10;
00593 
00594   KoDocument::openTemplate( file );
00595 }
00596 
00597 void KWDocument::initEmpty()
00598 {
00599     m_pageColumns.columns = 1;
00600     m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing;
00601 
00602     m_pageHeaderFooter.header = HF_SAME;
00603     m_pageHeaderFooter.footer = HF_SAME;
00604     m_pageHeaderFooter.ptHeaderBodySpacing = 10;
00605     m_pageHeaderFooter.ptFooterBodySpacing = 10;
00606     m_pageHeaderFooter.ptFootNoteBodySpacing = 10;
00607 
00608     QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::instance() ) );
00609     bool ok = loadNativeFormat( fileName );
00610     if ( !ok )
00611         showLoadingErrorDialog();
00612     resetURL();
00613     setModified( FALSE );
00614     setEmpty();
00615 }
00616 
00617 KoPageLayout KWDocument::pageLayout(int pageNumber /* = 0 */) const
00618 {
00619     if( pageNumber < startPage()) // impossible page..
00620         pageNumber = startPage();
00621     return pageManager()->pageLayout(pageNumber);
00622 }
00623 
00624 void KWDocument::setPageLayout( const KoPageLayout& layout, const KoColumns& cl, const KoKWHeaderFooter& hf, bool updateViews )
00625 {
00626     m_pageLayout = layout;
00627     if ( m_processingType == WP ) {
00628         m_pageColumns = cl;
00629     }
00630     if ( m_processingType == DTP || isEmbedded() ) {
00631         m_pageLayout.ptLeft = 0;
00632         m_pageLayout.ptRight = 0;
00633         m_pageLayout.ptTop = 0;
00634         m_pageLayout.ptBottom = 0;
00635     }
00636     pageManager()->setDefaultPage(m_pageLayout);
00637     m_pageHeaderFooter = hf;
00638 
00639     // pages have a different size -> update framesInPage
00640     // TODO: it would be better to move stuff so that text boxes remain in the same page...
00641     // (page-number preservation instead of Y preservation)
00642     updateAllFrames( KWFrameSet::UpdateFramesInPage );
00643 
00644     recalcFrames();
00645 
00646     updateAllFrames();
00647 
00648     if ( updateViews )
00649     {
00650         // Invalidate document layout, for proper repaint
00651         this->layout();
00652         emit pageLayoutChanged( m_pageLayout );
00653         updateContentsSize();
00654     }
00655 }
00656 
00657 
00658 double KWDocument::ptColumnWidth() const
00659 {
00660     KWPage *page = pageManager()->page(pageManager()->startPage());
00661     return ( page->width() - page->leftMargin() - page->rightMargin() -
00662              ptColumnSpacing() * ( m_pageColumns.columns - 1 ) )
00663         / m_pageColumns.columns;
00664 }
00665 
00666 class KWFootNoteFrameSetList : public QPtrList<KWFootNoteFrameSet>
00667 {
00668 public:
00669     KWFootNoteFrameSetList( bool reversed ) : m_reversed( reversed ) {}
00670 protected:
00671     // Compare the order of the associated variables
00672     virtual int compareItems(QPtrCollection::Item a, QPtrCollection::Item b)
00673     {
00674         KWFootNoteFrameSet* fsa = ((KWFootNoteFrameSet *)a);
00675         KWFootNoteFrameSet* fsb = ((KWFootNoteFrameSet *)b);
00676         Q_ASSERT( fsa->footNoteVariable() );
00677         Q_ASSERT( fsb->footNoteVariable() );
00678         if ( fsa->footNoteVariable() && fsb->footNoteVariable() )
00679         {
00680             int numa = fsa->footNoteVariable()->num();
00681             int numb = fsb->footNoteVariable()->num();
00682             if (numa == numb) return 0;
00683             if (numa > numb) return m_reversed ? -1 : 1;
00684             return m_reversed ? 1 : -1;
00685         }
00686         return -1; // whatever
00687     }
00688 private:
00689     bool m_reversed;
00690 };
00691 
00692 /* append headers and footers if needed, and create enough pages for all the existing frames */
00693 void KWDocument::recalcFrames( int fromPage, int toPage /*-1 for all*/, uint flags )
00694 {
00695     fromPage = QMAX(pageManager()->startPage(), fromPage);
00696     if ( m_lstFrameSet.isEmpty() )
00697         return;
00698     //printDebug();
00699     kdDebug(32002) << "KWDocument::recalcFrames from=" << fromPage << " to=" << toPage << endl;
00700 
00701     KWFrameSet *frameset = m_lstFrameSet.getFirst();
00702 
00703     if ( m_processingType == WP ) { // In WP mode the pages are created automatically. In DTP not...
00704 
00705         KWTextFrameSet *firstHeader = 0L, *evenHeader = 0L, *oddHeader = 0L;
00706         KWTextFrameSet *firstFooter = 0L, *evenFooter = 0L, *oddFooter = 0L;
00707         m_bHasEndNotes = false; // will be set to true if we find any endnote
00708 
00709         // Lookup the various header / footer framesets into the variables above
00710         // [Done in all cases, in order to hide unused framesets]
00711 
00712         KWFootNoteFrameSetList footnotesList( true ); // Reversed, we want footnotes from bottom to top
00713         KWFootNoteFrameSetList endnotesList( false ); // Endnotes are in top to bottom order
00714         QPtrListIterator<KWFrameSet> fit = framesetsIterator();
00715         for ( ; fit.current() ; ++fit )
00716         {
00717             KWFrameSet * fs = fit.current();
00718             switch ( fs->frameSetInfo() ) {
00719             case KWFrameSet::FI_FIRST_HEADER:
00720                 if ( isHeaderVisible() ) {
00721                     firstHeader = dynamic_cast<KWTextFrameSet*>( fs );
00722                 } else { fs->setVisible( false ); fs->deleteAllCopies(); }
00723                 break;
00724             case KWFrameSet::FI_ODD_HEADER:
00725                 if ( isHeaderVisible() ) {
00726                     oddHeader = dynamic_cast<KWTextFrameSet*>( fs );
00727                 } else { fs->setVisible( false ); fs->deleteAllCopies(); }
00728                 break;
00729             case KWFrameSet::FI_EVEN_HEADER:
00730                 if ( isHeaderVisible() ) {
00731                     evenHeader = dynamic_cast<KWTextFrameSet*>( fs );
00732                 } else { fs->setVisible( false ); fs->deleteAllCopies(); }
00733                 break;
00734             case KWFrameSet::FI_FIRST_FOOTER:
00735                 if ( isFooterVisible() ) {
00736                     firstFooter = dynamic_cast<KWTextFrameSet*>( fs );
00737                 } else { fs->setVisible( false ); fs->deleteAllCopies(); }
00738                 break;
00739             case KWFrameSet::FI_ODD_FOOTER:
00740                 if ( isFooterVisible() ) {
00741                     oddFooter = dynamic_cast<KWTextFrameSet*>( fs );
00742                 } else { fs->setVisible( false ); fs->deleteAllCopies(); }
00743                 break;
00744             case KWFrameSet::FI_EVEN_FOOTER:
00745                 if ( isFooterVisible() ) {
00746                     evenFooter = dynamic_cast<KWTextFrameSet*>( fs );
00747                 } else { fs->setVisible( false ); fs->deleteAllCopies(); }
00748             case KWFrameSet::FI_FOOTNOTE: {
00749                 KWFootNoteFrameSet* fnfs = dynamic_cast<KWFootNoteFrameSet *>(fs);
00750                 if ( fnfs && fnfs->isVisible() ) // not visible is when the footnote has been deleted
00751                 {
00752                     if ( fnfs->isFootNote() )
00753                         footnotesList.append( fnfs );
00754                     else if ( fnfs->isEndNote() ) {
00755                         endnotesList.append( fnfs );
00756                         m_bHasEndNotes = true;
00757                     }
00758                 }
00759             }
00760                 break;
00761             default: break;
00762             }
00763         }
00764 
00765         // This allocation each time might slow things down a bit.
00766         // TODO KWHeaderFooterFrameSet : public KWTextFrameSet, and store the HeaderFooterFrameset data into there.
00767         // ... hmm, and then KWFootNoteFrameSet needs to inherit KWHeaderFooterFrameSet
00768         QPtrList<KWFrameLayout::HeaderFooterFrameset> headerFooterList;
00769         headerFooterList.setAutoDelete( true );
00770         const int firstPageNum = startPage();
00771 
00772         // Now hide & forget the unused header/footer framesets (e.g. 'odd pages' if we are in 'all the same' mode etc.)
00773         if ( isHeaderVisible() ) {
00774             Q_ASSERT( firstHeader );
00775             Q_ASSERT( oddHeader );
00776             Q_ASSERT( evenHeader );
00777             switch ( headerType() ) {
00778             case HF_SAME:
00779                 oddHeader->setVisible( true );
00780                 evenHeader->setVisible( false );
00781                 evenHeader->deleteAllCopies();
00782                 firstHeader->setVisible( false );
00783                 firstHeader->deleteAllCopies();
00784 
00785                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00786                                              oddHeader, firstPageNum, -1, m_pageHeaderFooter.ptHeaderBodySpacing ) );
00787                 break;
00788             case HF_FIRST_EO_DIFF: // added for koffice-1.2-beta2
00789                 firstHeader->setVisible( true );
00790                 oddHeader->setVisible( true );
00791                 evenHeader->setVisible( true );
00792 
00793                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00794                                              firstHeader, firstPageNum, firstPageNum, m_pageHeaderFooter.ptHeaderBodySpacing ) );
00795                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00796                                              oddHeader, firstPageNum + 2, -1, m_pageHeaderFooter.ptHeaderBodySpacing,
00797                                              KWFrameLayout::HeaderFooterFrameset::Odd ) );
00798                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00799                                              evenHeader, firstPageNum + 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing,
00800                                              KWFrameLayout::HeaderFooterFrameset::Even ) );
00801                 break;
00802             case HF_FIRST_DIFF:
00803                 oddHeader->setVisible( true );
00804                 evenHeader->setVisible( false );
00805                 evenHeader->deleteAllCopies();
00806                 firstHeader->setVisible( true );
00807 
00808                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00809                                              firstHeader, firstPageNum, firstPageNum, m_pageHeaderFooter.ptHeaderBodySpacing ) );
00810                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00811                                              oddHeader, firstPageNum + 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing ) );
00812                 break;
00813             case HF_EO_DIFF:
00814                 oddHeader->setVisible( true );
00815                 evenHeader->setVisible( true );
00816                 firstHeader->setVisible( false );
00817                 firstHeader->deleteAllCopies();
00818 
00819                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00820                                              oddHeader, firstPageNum, -1, m_pageHeaderFooter.ptHeaderBodySpacing,
00821                                              KWFrameLayout::HeaderFooterFrameset::Odd ) );
00822                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00823                                              evenHeader, firstPageNum + 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing,
00824                                              KWFrameLayout::HeaderFooterFrameset::Even ) );
00825                 break;
00826             }
00827         }
00828         if ( isFooterVisible() ) {
00829             Q_ASSERT( firstFooter );
00830             Q_ASSERT( oddFooter );
00831             Q_ASSERT( evenFooter );
00832             switch ( footerType() ) {
00833             case HF_SAME:
00834                 oddFooter->setVisible( true );
00835                 evenFooter->setVisible( false );
00836                 evenFooter->deleteAllCopies();
00837                 firstFooter->setVisible( false );
00838                 firstFooter->deleteAllCopies();
00839 
00840                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00841                                              oddFooter, firstPageNum, -1, m_pageHeaderFooter.ptFooterBodySpacing ) );
00842                 break;
00843             case HF_FIRST_EO_DIFF: // added for koffice-1.2-beta2
00844                 firstFooter->setVisible( true );
00845                 oddFooter->setVisible( true );
00846                 evenFooter->setVisible( true );
00847 
00848                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00849                                              firstFooter, firstPageNum, firstPageNum, m_pageHeaderFooter.ptFooterBodySpacing ) );
00850                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00851                                              oddFooter, firstPageNum + 2, -1, m_pageHeaderFooter.ptFooterBodySpacing,
00852                                              KWFrameLayout::HeaderFooterFrameset::Odd ) );
00853                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00854                                              evenFooter, firstPageNum + 1, -1, m_pageHeaderFooter.ptFooterBodySpacing,
00855                                              KWFrameLayout::HeaderFooterFrameset::Even ) );
00856                 break;
00857             case HF_FIRST_DIFF:
00858                 oddFooter->setVisible( true );
00859                 evenFooter->setVisible( false );
00860                 evenFooter->deleteAllCopies();
00861                 firstFooter->setVisible( true );
00862 
00863                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00864                                              firstFooter, firstPageNum, firstPageNum, m_pageHeaderFooter.ptFooterBodySpacing ) );
00865                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00866                                              oddFooter, firstPageNum + 1, -1, m_pageHeaderFooter.ptFooterBodySpacing ) );
00867                 break;
00868             case HF_EO_DIFF:
00869                 oddFooter->setVisible( true );
00870                 evenFooter->setVisible( true );
00871                 firstFooter->setVisible( false );
00872                 firstFooter->deleteAllCopies();
00873 
00874                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00875                                              oddFooter, firstPageNum, -1, m_pageHeaderFooter.ptFooterBodySpacing,
00876                                              KWFrameLayout::HeaderFooterFrameset::Odd ) );
00877                 headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset(
00878                                              evenFooter, firstPageNum + 1, -1, m_pageHeaderFooter.ptFooterBodySpacing,
00879                                              KWFrameLayout::HeaderFooterFrameset::Even ) );
00880                 break;
00881             }
00882         }
00883 
00884         // The frameset order _on screen_ is:
00885         // Header
00886         // Main text frame (if WP)
00887         // Footnote_s_
00888         // Footer
00889         // In the list it will have to be from top and from bottom:
00890         // Header, Footer, Footnote from bottom to top
00891         QPtrList<KWFrameLayout::HeaderFooterFrameset> footnotesHFList;
00892         footnotesHFList.setAutoDelete( true );
00893 
00894         footnotesList.sort();
00895         QPtrListIterator<KWFootNoteFrameSet> fnfsIt( footnotesList );  // fnfs == "footnote frameset"
00896         for ( ; fnfsIt.current() ; ++fnfsIt )
00897         {
00898             KWFootNoteFrameSet* fnfs = fnfsIt.current();
00899             int pageNum = -42; //fnfs->footNoteVariable()->pageNumber(); // determined by KWFrameLayout
00900             KWFrameLayout::HeaderFooterFrameset* hff = new KWFrameLayout::HeaderFooterFrameset(
00901                 fnfs, pageNum, pageNum,
00902                 m_pageHeaderFooter.ptFootNoteBodySpacing,
00903                 KWFrameLayout::HeaderFooterFrameset::All );
00904 
00905             // With other kind of framesets, the height is simply frame->height.
00906             // But for footnotes, the height to pass to KWFrameLayout is the sum of the frame heights.
00907             hff->m_height = 0;
00908             for (QPtrListIterator<KWFrame> f = fnfs->frameIterator(); f.current() ; ++f )
00909                 hff->m_height += f.current()->height();
00910 
00911             footnotesHFList.append( hff );
00912         }
00913 
00914         // Endnotes, however are laid out from top to bottom.
00915         QPtrList<KWFrameLayout::HeaderFooterFrameset> endnotesHFList;
00916         endnotesHFList.setAutoDelete( true );
00917 
00918         endnotesList.sort();
00919         QPtrListIterator<KWFootNoteFrameSet> enfsIt( endnotesList );  // enfs == "endnote frameset"
00920         for ( ; enfsIt.current() ; ++enfsIt )
00921         {
00922             KWFootNoteFrameSet* enfs = enfsIt.current();
00923             KWFrameLayout::HeaderFooterFrameset* hff = new KWFrameLayout::HeaderFooterFrameset(
00924                 enfs, -42, -42, // determined by KWFrameLayout
00925                 m_pageHeaderFooter.ptFootNoteBodySpacing,
00926                 KWFrameLayout::HeaderFooterFrameset::All );
00927 
00928             // The height to pass to KWFrameLayout is the sum of the frame heights.
00929             hff->m_height = 0;
00930             for (QPtrListIterator<KWFrame> f = enfs->frameIterator(); f.current() ; ++f )
00931                 hff->m_height += f.current()->height();
00932 
00933             endnotesHFList.append( hff );
00934         }
00935 
00936         // append pages as needed.
00937         double maxBottom = 0;
00938         for (QPtrListIterator<KWFrameSet> fsit = framesetsIterator(); fsit.current() ; ++fsit ) {
00939             KWFrameSet *fs = fsit.current();
00940             if ( !fs->isVisible() || fs->isAHeader() || !fs->isAFooter() ||
00941                     !fs->isFloating() || !fs->isFootEndNote() )
00942                 continue;
00943             for (QPtrListIterator<KWFrame> fit = fs->frameIterator(); fit.current() ; ++fit )
00944                 maxBottom = QMAX(maxBottom, fit.current()->bottom());
00945         }
00946         KWPage *last = pageManager()->page(lastPage());
00947         double docHeight = last->offsetInDocument() + last->height();
00948         while(docHeight <= maxBottom) {
00949             last = pageManager()->appendPage();
00950             docHeight += last->height();
00951         }
00952         int oldPages = pageCount();
00953 
00954         if ( toPage == -1 )
00955             toPage = lastPage();
00956         if ( fromPage > toPage ) // this can happen with "endnotes only" pages :) // ### really?
00957             fromPage = toPage; // ie. start at the last real page
00958         KWFrameLayout frameLayout( this, headerFooterList, footnotesHFList, endnotesHFList );
00959         frameLayout.layout( frameset, m_pageColumns.columns, fromPage, toPage, flags );
00960 
00961         // If the number of pages changed, update views and variables etc.
00962         // (now that the frame layout has been done)
00963         if ( pageCount() != oldPages && !m_bGeneratingPreview )
00964         {
00965             // Very much like the end of appendPage, but we don't want to call recalcFrames ;)
00966             emit newContentsSize();
00967             emit numPagesChanged();
00968             recalcVariables( VT_PGNUM );
00969         }
00970 
00971     }
00972     else {
00973         // DTP mode: calculate the number of pages from the frames.
00974         double maxBottom=0;
00975         for (QPtrListIterator<KWFrameSet> fit = framesetsIterator(); fit.current() ; ++fit ) {
00976             if(fit.current()->isDeleted()) continue;
00977             if(fit.current()->frameSetInfo()==KWFrameSet::FI_BODY && !fit.current()->isFloating()) {
00978                 KWFrameSet * fs = fit.current();
00979                 for (QPtrListIterator<KWFrame> f = fs->frameIterator(); f.current() ; ++f )
00980                     maxBottom=QMAX(maxBottom, f.current()->bottom());
00981             }
00982         }
00983         KWPage *last = pageManager()->page(lastPage());
00984         double docHeight = last->offsetInDocument() + last->height();
00985         while(docHeight <= maxBottom) {
00986             last = pageManager()->appendPage();
00987             docHeight += last->height();
00988         }
00989         if ( toPage == -1 )
00990             toPage = pageCount() - 1;
00991         KWFrameList::recalcFrames(this, fromPage, toPage);
00992     }
00993     kdDebug(32002) << "            ~recalcFrames" << endl;
00994 }
00995 
00996 bool KWDocument::loadChildren( KoStore *store )
00997 {
00998     //kdDebug(32001) << "KWDocument::loadChildren" << endl;
00999     QPtrListIterator<KoDocumentChild> it( children() );
01000     for( ; it.current(); ++it ) {
01001         if ( !it.current()->loadDocument( store ) )
01002             return FALSE;
01003     }
01004 
01005     return TRUE;
01006 }
01007 
01008 void KWDocument::loadPictureMap ( QDomElement& domElement )
01009 {
01010     m_pictureMap.clear();
01011 
01012     // <PICTURES>
01013     QDomElement picturesElem = domElement.namedItem( "PICTURES" ).toElement();
01014     if ( !picturesElem.isNull() )
01015     {
01016        m_pictureCollection->readXML( picturesElem, m_pictureMap );
01017     }
01018 
01019     // <PIXMAPS>
01020     QDomElement pixmapsElem = domElement.namedItem( "PIXMAPS" ).toElement();
01021     if ( !pixmapsElem.isNull() )
01022     {
01023        m_pictureCollection->readXML( pixmapsElem, m_pictureMap );
01024     }
01025 
01026     // <CLIPARTS>
01027     QDomElement clipartsElem = domElement.namedItem( "CLIPARTS" ).toElement();
01028     if ( !clipartsElem.isNull() )
01029     {
01030        m_pictureCollection->readXML( pixmapsElem, m_pictureMap );
01031     }
01032 }
01033 
01034 
01035 bool KWDocument::loadOasis( const QDomDocument& doc, KoOasisStyles& oasisStyles, const QDomDocument& settings, KoStore* store )
01036 {
01037     QTime dt;
01038     dt.start();
01039     emit sigProgress( 0 );
01040     clear();
01041     kdDebug(32001) << "KWDocument::loadOasis" << endl;
01042 
01043     QDomElement content = doc.documentElement();
01044     QDomElement realBody ( KoDom::namedItemNS( content, KoXmlNS::office, "body" ) );
01045     if ( realBody.isNull() )
01046     {
01047         kdError(32001) << "No office:body found!" << endl;
01048         setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No office:body tag found." ) );
01049         return false;
01050     }
01051     QDomElement body = KoDom::namedItemNS( realBody, KoXmlNS::office, "text" );
01052     if ( body.isNull() )
01053     {
01054         kdError(32001) << "No office:text found!" << endl;
01055         QDomElement childElem;
01056         QString localName;
01057         forEachElement( childElem, realBody ) {
01058             localName = childElem.localName();
01059         }
01060         if ( localName.isEmpty() )
01061             setErrorMessage( i18n( "Invalid OASIS OpenDocument file. No tag found inside office:body." ) );
01062         else
01063             setErrorMessage( i18n( "This is not a word processing document, but %1. Please try opening it with the appropriate application." ).arg( KoDocument::tagNameToDocumentType( localName ) ) );
01064         return false;
01065     }
01066 
01067     // TODO check versions and mimetypes etc.
01068 
01069     KoOasisContext context( this, *m_varColl, oasisStyles, store );
01070 
01071     createLoadingInfo();
01072 
01073     // In theory the page format is the style:master-page-name of the first paragraph...
01074     // But, hmm, in a doc with only a table there was no reference to the master page at all...
01075     // So we load the standard page layout to start with, and in KWTextParag
01076     // we might overwrite it with another one.
01077     m_loadingInfo->m_currentMasterPage = "Standard";
01078     if ( !loadOasisPageLayout( m_loadingInfo->m_currentMasterPage, context ) )
01079         return false;
01080 
01081     KWOasisLoader oasisLoader( this );
01082 
01083     // <text:page-sequence> oasis extension for DTP (2003-10-27 post by Daniel)
01084     m_processingType = ( !KoDom::namedItemNS( body, KoXmlNS::text, "page-sequence" ).isNull() )
01085                        ? DTP : WP;
01086 
01087     m_hasTOC = false;
01088     m_tabStop = MM_TO_POINT(15);
01089     const QDomElement* defaultParagStyle = oasisStyles.defaultStyle( "paragraph" );
01090     if ( defaultParagStyle ) {
01091         KoStyleStack stack;
01092         stack.push( *defaultParagStyle );
01093         stack.setTypeProperties( "paragraph" );
01094         QString tabStopVal = stack.attributeNS( KoXmlNS::style, "tab-stop-distance" );
01095         if ( !tabStopVal.isEmpty() )
01096             m_tabStop = KoUnit::parseValue( tabStopVal );
01097     }
01098     m_initialEditing = 0;
01099 
01100     // TODO MAILMERGE
01101 
01102     // Variable settings
01103     // By default display real variable value
01104     if ( !isReadWrite())
01105         m_varColl->variableSetting()->setDisplayFieldCode(false);
01106 
01107     // Load all styles before the corresponding paragraphs try to use them!
01108     m_styleColl->loadOasisStyles( context );
01109     if ( m_frameStyleColl->loadOasisStyles( context ) == 0 ) {
01110          // no styles loaded -> load default styles
01111         loadDefaultFrameStyleTemplates();
01112     }
01113 
01114     if ( m_tableStyleColl->loadOasisStyles( context, *m_styleColl, *m_frameStyleColl ) == 0 ) {
01115         // no styles loaded -> load default styles
01116         loadDefaultTableStyleTemplates();
01117     }
01118 
01119     static_cast<KWVariableSettings *>( m_varColl->variableSetting() )
01120         ->loadNoteConfiguration( oasisStyles.officeStyle() );
01121 
01122     loadDefaultTableTemplates();
01123 
01124     if ( m_processingType == WP ) {
01125         // Create main frameset
01126         KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Main Text Frameset" ) );
01127         m_lstFrameSet.append( fs ); // don't use addFrameSet here. We'll call finalize() once and for all in completeLoading
01128         fs->loadOasisContent( body, context );
01129         KWFrame* frame = new KWFrame( fs, 29, 42, 566-29, 798-42 );
01130         frame->setFrameBehavior( KWFrame::AutoCreateNewFrame );
01131         frame->setNewFrameBehavior( KWFrame::Reconnect );
01132         fs->addFrame( frame );
01133 
01134         // load padding, background and borders for the main frame
01135         const QDomElement* masterPage = context.oasisStyles().masterPages()[ m_loadingInfo->m_currentMasterPage ];
01136         const QDomElement *masterPageStyle = masterPage ? context.oasisStyles().findStyle(masterPage->attributeNS( KoXmlNS::style, "page-layout-name", QString::null ) ) : 0;
01137         if ( masterPageStyle )
01138         {
01139           KoStyleStack styleStack;
01140           styleStack.push(  *masterPageStyle );
01141           styleStack.setTypeProperties( "page-layout" );
01142           frame->loadBorderProperties( styleStack );
01143         }
01144         fs->renumberFootNotes( false /*no repaint*/ );
01145 
01146     } else {
01147         // DTP mode: the items in the body are page-sequence and then frames
01148         QDomElement tag;
01149         forEachElement( tag, body )
01150         {
01151             context.styleStack().save();
01152             const QString localName = tag.localName();
01153             if ( localName == "page-sequence" && tag.namespaceURI() == KoXmlNS::text )
01154             {
01155                 // We don't have support for changing the page layout yet, so just take the
01156                 // number of pages
01157                 int pages=1;
01158                 QDomElement page;
01159                 forEachElement( page, tag )
01160                     ++pages;
01161                 kdDebug() << "DTP mode: found " << pages << "pages" << endl;
01162                 //setPageCount ( pages );
01163             }
01164             else if ( localName == "frame" && tag.namespaceURI() == KoXmlNS::draw )
01165                 oasisLoader.loadFrame( tag, context, KoPoint() );
01166             else
01167                 kdWarning(32001) << "Unsupported tag in DTP loading:" << tag.tagName() << endl;
01168         }
01169     }
01170 
01171     loadMasterPageStyle( m_loadingInfo->m_currentMasterPage, context );
01172 
01173     if ( context.cursorTextParagraph() ) {
01174         // Maybe, once 1.3-support is dropped, we can get rid of InitialEditing and fetch the
01175         // values from KoOasisContext? But well, it lives a bit longer.
01176         // At least we could store a KWFrameSet* and a KoTextParag* instead of a name and an id.
01177         m_initialEditing = new InitialEditing();
01178         KWTextFrameSet* fs = static_cast<KWTextDocument *>( context.cursorTextParagraph()->textDocument() )->textFrameSet();
01179         m_initialEditing->m_initialFrameSet = fs->name();
01180         m_initialEditing->m_initialCursorParag = context.cursorTextParagraph()->paragId();
01181         m_initialEditing->m_initialCursorIndex = context.cursorTextIndex();
01182     }
01183 
01184     if ( !settings.isNull() )
01185     {
01186         oasisLoader.loadOasisSettings( settings );
01187     }
01188 
01189     kdDebug(32001) << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
01190     endOfLoading();
01191 
01192     // This sets the columns and header/footer flags, and calls recalcFrames,
01193     // so it must be done last.
01194     setPageLayout( m_pageLayout, m_loadingInfo->columns, m_loadingInfo->hf, false );
01195 
01196     //printDebug();
01197     return true;
01198 }
01199 
01200 bool KWDocument::loadOasisPageLayout( const QString& masterPageName, KoOasisContext& context )
01201 {
01202     KoColumns& columns = m_loadingInfo->columns;
01203 
01204     const KoOasisStyles& oasisStyles = context.oasisStyles();
01205     const QDomElement* masterPage = oasisStyles.masterPages()[ masterPageName ];
01206     Q_ASSERT( masterPage );
01207     const QDomElement *masterPageStyle = masterPage ? oasisStyles.findStyle( masterPage->attributeNS( KoXmlNS::style, "page-layout-name", QString::null ) ) : 0;
01208     Q_ASSERT( masterPageStyle );
01209     if ( masterPageStyle )
01210     {
01211         m_pageLayout.loadOasis( *masterPageStyle );
01212         if ( m_pageLayout.ptWidth <= 1e-13 || m_pageLayout.ptHeight <= 1e-13 )
01213         {
01214             // Loading page layout failed, try to see why.
01215             QDomElement properties( KoDom::namedItemNS( *masterPageStyle, KoXmlNS::style, "page-layout-properties" ) );
01216             //if ( properties.isNull() )
01217             //    setErrorMessage( i18n( "Invalid document. No page layout properties were found. The application which produced this document isn't OASIS-compliant." ) );
01218             //else if ( properties.hasAttributeNS( KoXmlNS::fo, "page-width" ) )
01219             //    setErrorMessage( i18n( "Invalid document. Page layout has no page width. The application which produced this document isn't OASIS-compliant." ) );
01220             //else
01221             if ( properties.hasAttributeNS( "http://www.w3.org/1999/XSL/Format", "page-width" ) )
01222                 setErrorMessage( i18n( "Invalid document. 'fo' has the wrong namespace. The application which produced this document is not OASIS-compliant." ) );
01223             else
01224                 setErrorMessage( i18n( "Invalid document. Paper size: %1x%2" ).arg( m_pageLayout.ptWidth ).arg( m_pageLayout.ptHeight ) );
01225             return false;
01226         }
01227         pageManager()->setDefaultPage(m_pageLayout);
01228 
01229         const QDomElement properties( KoDom::namedItemNS( *masterPageStyle, KoXmlNS::style, "page-layout-properties" ) );
01230         const QDomElement footnoteSep = KoDom::namedItemNS( properties, KoXmlNS::style, "footnote-sep" );
01231         if ( !footnoteSep.isNull() ) {
01232             // style:width="0.018cm" style:distance-before-sep="0.101cm"
01233             // style:distance-after-sep="0.101cm" style:adjustment="left"
01234             // style:rel-width="25%" style:color="#000000"
01235             const QString width = footnoteSep.attributeNS( KoXmlNS::style, "width", QString::null );
01236             if ( !width.isEmpty() ) {
01237                 m_footNoteSeparatorLineWidth = KoUnit::parseValue( width );
01238             }
01239 
01240             QString pageWidth = footnoteSep.attributeNS( KoXmlNS::style, "rel-width", QString::null );
01241             if ( pageWidth.endsWith( "%" ) ) {
01242                 pageWidth.truncate( pageWidth.length() - 1 ); // remove '%'
01243                 m_iFootNoteSeparatorLineLength = qRound( pageWidth.toDouble() );
01244             }
01245             // Not in KWord: color, distance before and after separator
01246 
01247             const QString style = footnoteSep.attributeNS( KoXmlNS::style, "line-style", QString::null );
01248             if ( style == "solid" || style.isEmpty() )
01249                 m_footNoteSeparatorLineType = SLT_SOLID;
01250             else if ( style == "dash" )
01251                 m_footNoteSeparatorLineType = SLT_DASH;
01252             else if ( style == "dotted" )
01253                 m_footNoteSeparatorLineType = SLT_DOT;
01254             else if ( style == "dot-dash" )
01255                 m_footNoteSeparatorLineType = SLT_DASH_DOT;
01256             else if ( style == "dot-dot-dash" )
01257                 m_footNoteSeparatorLineType = SLT_DASH_DOT_DOT;
01258             else
01259                 kdDebug() << "Unknown value for m_footNoteSeparatorLineType: " << style << endl;
01260 
01261             const QString pos = footnoteSep.attributeNS( KoXmlNS::style, "adjustment", QString::null );
01262             if ( pos == "centered" )
01263                 m_footNoteSeparatorLinePos = SLP_CENTERED;
01264             else if ( pos == "right")
01265                 m_footNoteSeparatorLinePos = SLP_RIGHT;
01266             else // if ( pos == "left" )
01267                 m_footNoteSeparatorLinePos = SLP_LEFT;
01268         }
01269 
01270         const QDomElement columnsElem = KoDom::namedItemNS( properties, KoXmlNS::style, "columns" );
01271         if ( !columnsElem.isNull() )
01272         {
01273             columns.columns = columnsElem.attributeNS( KoXmlNS::fo, "column-count", QString::null ).toInt();
01274             if ( columns.columns == 0 )
01275                 columns.columns = 1;
01276             // TODO OASIS OpenDocument supports columns of different sizes, using <style:column style:rel-width="...">
01277             // (with fo:start-indent/fo:end-indent for per-column spacing)
01278             // But well, it also allows us to specify a single gap.
01279             if ( columnsElem.hasAttributeNS( KoXmlNS::fo, "column-gap" ) )
01280                 columns.ptColumnSpacing = KoUnit::parseValue( columnsElem.attributeNS( KoXmlNS::fo, "column-gap", QString::null ) );
01281             // It also supports drawing a vertical line as a separator...
01282         }
01283 
01284         m_headerVisible = false;
01285         m_footerVisible = false;
01286 
01287         // TODO spHeadBody (where is this in OOo?)
01288         // TODO spFootBody (where is this in OOo?)
01289         // Answer: margins of the <style:header-footer> element
01290     }
01291     else // this doesn't happen with normal documents, but it can happen if copying something,
01292          // pasting into konq as foo.odt, then opening that...
01293     {
01294         columns.columns = 1;
01295         columns.ptColumnSpacing = 2;
01296         m_headerVisible = false;
01297         m_footerVisible = false;
01298         m_pageLayout = KoPageLayout::standardLayout();
01299         pageManager()->setDefaultPage(m_pageLayout);
01300     }
01301     return true;
01302 }
01303 
01304 void KWDocument::loadMasterPageStyle( const QString& masterPageName, KoOasisContext& context )
01305 {
01306     const KoOasisStyles& oasisStyles = context.oasisStyles();
01307     const QDomElement* masterPage = oasisStyles.masterPages()[ masterPageName ];
01308     Q_ASSERT( masterPage );
01309     const QDomElement *masterPageStyle = masterPage ? oasisStyles.findStyle( masterPage->attributeNS( KoXmlNS::style, "page-layout-name", QString::null ) ) : 0;
01310     Q_ASSERT( masterPageStyle );
01311 
01312     KoKWHeaderFooter& hf = m_loadingInfo->hf;
01313 
01314     bool hasEvenOddHeader = false;
01315     bool hasEvenOddFooter = false;
01316     if ( masterPageStyle )
01317     {
01318         KWOasisLoader oasisLoader( this );
01319 
01320         QDomElement headerStyle = KoDom::namedItemNS( *masterPageStyle, KoXmlNS::style, "header-style" );
01321         QDomElement footerStyle = KoDom::namedItemNS( *masterPageStyle, KoXmlNS::style, "footer-style" );
01322         QDomElement headerLeftElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "header-left" );
01323         QDomElement headerFirstElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "header-first" ); // hack, not oasis compliant
01324         const bool hasFirstHeader = !headerFirstElem.isNull();
01325         if ( !headerLeftElem.isNull() )
01326         {
01327             hasEvenOddHeader = true;
01328             hf.header = hasFirstHeader ? HF_FIRST_EO_DIFF : HF_EO_DIFF;
01329             oasisLoader.loadOasisHeaderFooter( headerLeftElem, hasEvenOddHeader, headerStyle, context );
01330         }
01331         else
01332         {
01333             hf.header = hasFirstHeader ? HF_FIRST_DIFF : HF_SAME;
01334         }
01335         if ( hasFirstHeader )
01336         {
01337             oasisLoader.loadOasisHeaderFooter( headerFirstElem, hasEvenOddHeader, headerStyle, context );
01338         }
01339 
01340         QDomElement headerElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "header" );
01341         if ( !headerElem.isNull() )
01342         {
01343             oasisLoader.loadOasisHeaderFooter( headerElem, hasEvenOddHeader, headerStyle, context );
01344         }
01345 
01346         // -- and now footers
01347 
01348         QDomElement footerLeftElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "footer-left" );
01349         QDomElement footerFirstElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "footer-first" ); // hack, not oasis compliant
01350         const bool hasFirstFooter = !footerFirstElem.isNull();
01351         if ( !footerLeftElem.isNull() )
01352         {
01353             hasEvenOddFooter = true;
01354             hf.footer = hasFirstFooter ? HF_FIRST_EO_DIFF : HF_EO_DIFF;
01355             oasisLoader.loadOasisHeaderFooter( footerLeftElem, hasEvenOddFooter, footerStyle, context );
01356         }
01357         else
01358         {
01359             hf.footer = hasFirstFooter ? HF_FIRST_DIFF : HF_SAME;
01360         }
01361         if ( hasFirstFooter )
01362         {
01363             oasisLoader.loadOasisHeaderFooter( footerFirstElem, hasEvenOddFooter, footerStyle, context );
01364         }
01365         QDomElement footerElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "footer" );
01366         if ( !footerElem.isNull() )
01367         {
01368             oasisLoader.loadOasisHeaderFooter( footerElem, hasEvenOddFooter, footerStyle, context );
01369         }
01370 
01371         // The bottom margin of headers is what we call headerBodySpacing
01372         // (TODO support the 3 other margins)
01373         if ( !headerStyle.isNull() ) {
01374             context.styleStack().push( headerStyle );
01375             context.styleStack().setTypeProperties( "header-footer" );
01376             hf.ptHeaderBodySpacing = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-bottom" ) );
01377             context.styleStack().pop();
01378         }
01379         // The top margin of footers is what we call footerBodySpacing
01380         // (TODO support the 3 other margins)
01381         if ( !footerStyle.isNull() ) {
01382             context.styleStack().push( footerStyle );
01383             context.styleStack().setTypeProperties( "header-footer" );
01384             hf.ptFooterBodySpacing = KoUnit::parseValue( context.styleStack().attributeNS( KoXmlNS::fo, "margin-top" ) );
01385             context.styleStack().pop();
01386         }
01387         // TODO ptFootNoteBodySpacing
01388     }
01389 }
01390 
01391 // Called before loading
01392 // It's important to clear out anything that might be in the document already,
01393 // for things like using DCOP to load multiple documents into the same KWDocument,
01394 // or "reload" when kword is embedded into konqueror.
01395 void KWDocument::clear()
01396 {
01397     m_pictureMap.clear();
01398     m_textImageRequests.clear();
01399     m_pictureRequests.clear();
01400     m_anchorRequests.clear();
01401     m_footnoteVarRequests.clear();
01402     m_spellCheckIgnoreList.clear();
01403 
01404     m_pageHeaderFooter.header = HF_SAME;
01405     m_pageHeaderFooter.footer = HF_SAME;
01406     m_pageHeaderFooter.ptHeaderBodySpacing = 10;
01407     m_pageHeaderFooter.ptFooterBodySpacing = 10;
01408     m_pageHeaderFooter.ptFootNoteBodySpacing = 10;
01409     m_pageColumns.columns = 1;
01410     m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing;
01411     m_bHasEndNotes = false;
01412 
01413     m_lstFrameSet.clear();
01414 
01415     m_varColl->clear();
01416     m_pictureCollection->clear();
01417     m_varFormatCollection->clear();
01418 
01419     m_styleColl->clear();
01420     m_frameStyleColl->clear();
01421     m_tableStyleColl->clear();
01422     m_tableTemplateColl->clear();
01423 
01424     // Some simple import filters don't define any style,
01425     // so let's have a Standard style at least
01426     KoParagStyle * standardStyle = new KoParagStyle( "Standard" ); // This gets translated later on
01427     //kdDebug() << "KWDocument::KWDocument creating standardStyle " << standardStyle << endl;
01428     standardStyle->format().setFont( m_defaultFont );
01429     m_styleColl->addStyle( standardStyle );
01430 
01431     // And let's do the same for framestyles
01432     KWFrameStyle * standardFrameStyle = new KWFrameStyle( "Plain" );
01433     standardFrameStyle->setBackgroundColor(Qt::white);
01434     standardFrameStyle->setTopBorder(KoBorder(Qt::black,KoBorder::SOLID,0));
01435     standardFrameStyle->setRightBorder(KoBorder(Qt::black,KoBorder::SOLID,0));
01436     standardFrameStyle->setLeftBorder(KoBorder(Qt::black,KoBorder::SOLID,0));
01437     standardFrameStyle->setBottomBorder(KoBorder(Qt::black,KoBorder::SOLID,0));
01438     m_frameStyleColl->addStyle( standardFrameStyle );
01439 
01440     // And let's do the same for tablestyles
01441     KWTableStyle *standardTableStyle = new KWTableStyle( "Plain", standardStyle, standardFrameStyle );
01442     m_tableStyleColl->addStyle( standardTableStyle );
01443 }
01444 
01445 bool KWDocument::loadXML( QIODevice *, const QDomDocument & doc )
01446 {
01447     QTime dt;
01448     dt.start();
01449     emit sigProgress( 0 );
01450     kdDebug(32001) << "KWDocument::loadXML" << endl;
01451     clear();
01452 
01453     KoPageLayout pgLayout;
01454     KoColumns columns;
01455     columns.columns = 1;
01456     columns.ptColumnSpacing = m_defaultColumnSpacing;
01457     KoKWHeaderFooter hf;
01458     hf.header = HF_SAME;
01459     hf.footer = HF_SAME;
01460     hf.ptHeaderBodySpacing = 10.0;
01461     hf.ptFooterBodySpacing = 10.0;
01462     hf.ptFootNoteBodySpacing = 10.0;
01463 
01464     QString value;
01465     QDomElement word = doc.documentElement();
01466 
01467     value = KWDocument::getAttribute( word, "mime", QString::null );
01468     if ( value.isEmpty() )
01469     {
01470         kdError(32001) << "No mime type specified!" << endl;
01471         setErrorMessage( i18n( "Invalid document. No mimetype specified." ) );
01472         return false;
01473     }
01474     else if ( value != "application/x-kword" && value != "application/vnd.kde.kword" )
01475     {
01476         kdError(32001) << "Unknown mime type " << value << endl;
01477         setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-kword or application/vnd.kde.kword, got %1" ).arg( value ) );
01478         return false;
01479     }
01480     m_syntaxVersion = KWDocument::getAttribute( word, "syntaxVersion", 0 );
01481     if ( m_syntaxVersion > CURRENT_SYNTAX_VERSION )
01482     {
01483         int ret = KMessageBox::warningContinueCancel(
01484             0, i18n("This document was created with a newer version of KWord (syntax version: %1)\n"
01485                     "Opening it in this version of KWord will lose some information.").arg(m_syntaxVersion),
01486             i18n("File Format Mismatch"), KStdGuiItem::cont() );
01487         if ( ret == KMessageBox::Cancel )
01488         {
01489             setErrorMessage( "USER_CANCELED" );
01490             return false;
01491         }
01492     }
01493 
01494     createLoadingInfo();
01495 
01496     // Looks like support for the old way of naming images internally,
01497     // see completeLoading.
01498     value = KWDocument::getAttribute( word, "url", QString::null );
01499     if ( !value.isNull() )
01500     {
01501         m_urlIntern = KURL( value ).path();
01502     }
01503 
01504     emit sigProgress(5);
01505 
01506     // <PAPER>
01507     QDomElement paper = word.namedItem( "PAPER" ).toElement();
01508     if ( !paper.isNull() )
01509     {
01510         pgLayout.format = static_cast<KoFormat>( KWDocument::getAttribute( paper, "format", 0 ) );
01511         pgLayout.orientation = static_cast<KoOrientation>( KWDocument::getAttribute( paper, "orientation", 0 ) );
01512         pgLayout.ptWidth = getAttribute( paper, "width", 0.0 );
01513         pgLayout.ptHeight = getAttribute( paper, "height", 0.0 );
01514         kdDebug() << " ptWidth=" << pgLayout.ptWidth << endl;
01515         kdDebug() << " ptHeight=" << pgLayout.ptHeight << endl;
01516         if ( pgLayout.ptWidth <= 0 || pgLayout.ptHeight <= 0 )
01517         {
01518             // Old document?
01519             pgLayout.ptWidth = getAttribute( paper, "ptWidth", 0.0 );
01520             pgLayout.ptHeight = getAttribute( paper, "ptHeight", 0.0 );
01521             kdDebug() << " ptWidth=" << pgLayout.ptWidth << endl;
01522             kdDebug() << " ptHeight=" << pgLayout.ptHeight << endl;
01523 
01524             // Still wrong?
01525             if ( pgLayout.ptWidth <= 0 || pgLayout.ptHeight <= 0 )
01526             {
01527                 setErrorMessage( i18n( "Invalid document. Paper size: %1x%2" )
01528                     .arg( pgLayout.ptWidth ).arg( pgLayout.ptHeight ) );
01529                 return false;
01530             }
01531         }
01532 
01533         hf.header = static_cast<KoHFType>( KWDocument::getAttribute( paper, "hType", 0 ) );
01534         hf.footer = static_cast<KoHFType>( KWDocument::getAttribute( paper, "fType", 0 ) );
01535         hf.ptHeaderBodySpacing = getAttribute( paper, "spHeadBody", 0.0 );
01536         hf.ptFooterBodySpacing  = getAttribute( paper, "spFootBody", 0.0 );
01537         hf.ptFootNoteBodySpacing  = getAttribute( paper, "spFootNoteBody", 10.0 );
01538         m_iFootNoteSeparatorLineLength = getAttribute( paper, "slFootNoteLength", 20);
01539         m_footNoteSeparatorLineWidth = getAttribute( paper, "slFootNoteWidth",2.0);
01540         m_footNoteSeparatorLineType = static_cast<SeparatorLineLineType>(getAttribute( paper, "slFootNoteType",0));
01541 
01542         if ( paper.hasAttribute("slFootNotePosition"))
01543         {
01544             QString tmp =paper.attribute("slFootNotePosition");
01545             if ( tmp =="centered" )
01546                 m_footNoteSeparatorLinePos = SLP_CENTERED;
01547             else if ( tmp =="right")
01548                 m_footNoteSeparatorLinePos = SLP_RIGHT;
01549             else if ( tmp =="left" )
01550                 m_footNoteSeparatorLinePos = SLP_LEFT;
01551         }
01552         columns.columns = KWDocument::getAttribute( paper, "columns", 1 );
01553         columns.ptColumnSpacing = KWDocument::getAttribute( paper, "columnspacing", 0.0 );
01554         // Now part of the app config
01555         //m_zoom = KWDocument::getAttribute( paper, "zoom", 100 );
01556         //if(m_zoom!=100)
01557         //    setZoomAndResolution( m_zoom, KoGlobal::dpiX(), KoGlobal::dpiY(), false, false );
01558 
01559 
01560         // Support the undocumented syntax actually used by KDE 2.0 for some of the above (:-().
01561         // Do not add anything to this block!
01562         if ( pgLayout.ptWidth == 0.0 )
01563             pgLayout.ptWidth = getAttribute( paper, "ptWidth", 0.0 );
01564         if ( pgLayout.ptHeight == 0.0 )
01565             pgLayout.ptHeight = getAttribute( paper, "ptHeight", 0.0 );
01566         if ( hf.ptHeaderBodySpacing == 0.0 )
01567             hf.ptHeaderBodySpacing = getAttribute( paper, "ptHeadBody", 0.0 );
01568         if ( hf.ptFooterBodySpacing == 0.0 )
01569             hf.ptFooterBodySpacing = getAttribute( paper, "ptFootBody", 0.0 );
01570         if ( columns.ptColumnSpacing == 0.0 )
01571             columns.ptColumnSpacing = getAttribute( paper, "ptColumnspc", 0.0 );
01572 
01573         // <PAPERBORDERS>
01574         QDomElement paperborders = paper.namedItem( "PAPERBORDERS" ).toElement();
01575         if ( !paperborders.isNull() )
01576         {
01577             pgLayout.ptLeft = getAttribute( paperborders, "left", 0.0 );
01578             pgLayout.ptTop = getAttribute( paperborders, "top", 0.0 );
01579             pgLayout.ptRight = getAttribute( paperborders, "right", 0.0 );
01580             pgLayout.ptBottom = getAttribute( paperborders, "bottom", 0.0 );
01581 
01582             // Support the undocumented syntax actually used by KDE 2.0 for some of the above (:-().
01583             if ( pgLayout.ptLeft == 0.0 )
01584                 pgLayout.ptLeft = getAttribute( paperborders, "ptLeft", 0.0 );
01585             if ( pgLayout.ptTop == 0.0 )
01586                 pgLayout.ptTop = getAttribute( paperborders, "ptTop", 0.0 );
01587             if ( pgLayout.ptRight == 0.0 )
01588                 pgLayout.ptRight = getAttribute( paperborders, "ptRight", 0.0 );
01589             if ( pgLayout.ptBottom == 0.0 )
01590                 pgLayout.ptBottom = getAttribute( paperborders, "ptBottom", 0.0 );
01591         }
01592         else
01593             kdWarning() << "No <PAPERBORDERS> tag!" << endl;
01594     }
01595     else
01596         kdWarning() << "No <PAPER> tag! This is a mandatory tag! Expect weird page sizes..." << endl;
01597 
01598     // <ATTRIBUTES>
01599     QDomElement attributes = word.namedItem( "ATTRIBUTES" ).toElement();
01600     if ( !attributes.isNull() )
01601     {
01602         m_processingType = static_cast<ProcessingType>( KWDocument::getAttribute( attributes, "processing", 0 ) );
01603         //KWDocument::getAttribute( attributes, "standardpage", QString::null );
01604         m_headerVisible = static_cast<bool>( KWDocument::getAttribute( attributes, "hasHeader", 0 ) );
01605         m_footerVisible = static_cast<bool>( KWDocument::getAttribute( attributes, "hasFooter", 0 ) );
01606         if ( attributes.hasAttribute( "unit" ) )
01607             setUnit( KoUnit::unit( attributes.attribute( "unit" ) ) );
01608         m_hasTOC =  static_cast<bool>(KWDocument::getAttribute( attributes,"hasTOC", 0 ) );
01609         m_tabStop = KWDocument::getAttribute( attributes, "tabStopValue", MM_TO_POINT(15) );
01610         m_initialEditing = new InitialEditing();
01611         m_initialEditing->m_initialFrameSet = attributes.attribute( "activeFrameset" );
01612         m_initialEditing->m_initialCursorParag = attributes.attribute( "cursorParagraph" ).toInt();
01613         m_initialEditing->m_initialCursorIndex = attributes.attribute( "cursorIndex" ).toInt();
01614     } else {
01615         m_processingType = WP;
01616         m_headerVisible = false;
01617         m_footerVisible = false;
01618         m_hasTOC = false;
01619         m_tabStop = MM_TO_POINT(15);
01620         delete m_initialEditing;
01621         m_initialEditing = 0L;
01622     }
01623 
01624     setPageLayout( pgLayout, columns, hf, false );
01625 
01626     variableCollection()->variableSetting()->load(word );
01627     //by default display real variable value
01628     if ( !isReadWrite())
01629         variableCollection()->variableSetting()->setDisplayFieldCode(false);
01630 
01631     emit sigProgress(10);
01632 
01633     QDomElement mailmerge = word.namedItem( "MAILMERGE" ).toElement();
01634     if (mailmerge!=QDomElement())
01635     {
01636         m_slDataBase->load(mailmerge);
01637     }
01638 
01639     emit sigProgress(15);
01640 
01641     // Load all styles before the corresponding paragraphs try to use them!
01642     QDomElement stylesElem = word.namedItem( "STYLES" ).toElement();
01643     if ( !stylesElem.isNull() )
01644         loadStyleTemplates( stylesElem );
01645 
01646     emit sigProgress(17);
01647 
01648     QDomElement frameStylesElem = word.namedItem( "FRAMESTYLES" ).toElement();
01649     if ( !frameStylesElem.isNull() )
01650         loadFrameStyleTemplates( frameStylesElem );
01651     else // load default styles
01652         loadDefaultFrameStyleTemplates();
01653 
01654     emit sigProgress(18);
01655 
01656     QDomElement tableStylesElem = word.namedItem( "TABLESTYLES" ).toElement();
01657     if ( !tableStylesElem.isNull() )
01658         loadTableStyleTemplates( tableStylesElem );
01659     else // load default styles
01660         loadDefaultTableStyleTemplates();
01661 
01662     emit sigProgress(19);
01663 
01664     loadDefaultTableTemplates();
01665 
01666     emit sigProgress(20);
01667 
01668     QDomElement bookmark = word.namedItem( "BOOKMARKS" ).toElement();
01669     if( !bookmark.isNull() )
01670     {
01671         QDomElement bookmarkitem = word.namedItem("BOOKMARKS").toElement();
01672         bookmarkitem = bookmarkitem.firstChild().toElement();
01673 
01674         while ( !bookmarkitem.isNull() )
01675         {
01676             if ( bookmarkitem.tagName() == "BOOKMARKITEM" )
01677             {
01678                 KWLoadingInfo::BookMark bk;
01679                 bk.bookname=bookmarkitem.attribute("name");
01680                 bk.cursorStartIndex=bookmarkitem.attribute("cursorIndexStart").toInt();
01681                 bk.frameSetName=bookmarkitem.attribute("frameset");
01682                 bk.paragStartIndex = bookmarkitem.attribute("startparag").toInt();
01683                 bk.paragEndIndex = bookmarkitem.attribute("endparag").toInt();
01684                 bk.cursorEndIndex = bookmarkitem.attribute("cursorIndexEnd").toInt();
01685                 Q_ASSERT( m_loadingInfo );
01686                 m_loadingInfo->bookMarkList.append( bk );
01687             }
01688             bookmarkitem = bookmarkitem.nextSibling().toElement();
01689         }
01690     }
01691 
01692     QStringList lst;
01693     QDomElement spellCheckIgnore = word.namedItem( "SPELLCHECKIGNORELIST" ).toElement();
01694     if( !spellCheckIgnore.isNull() )
01695     {
01696         QDomElement spellWord=word.namedItem("SPELLCHECKIGNORELIST").toElement();
01697         spellWord=spellWord.firstChild().toElement();
01698         while ( !spellWord.isNull() )
01699         {
01700             if ( spellWord.tagName()=="SPELLCHECKIGNOREWORD" )
01701                 lst.append(spellWord.attribute("word"));
01702             spellWord=spellWord.nextSibling().toElement();
01703         }
01704     }
01705     setSpellCheckIgnoreList( lst );
01706 
01707     emit sigProgress(25);
01708 
01709 
01710     QDomElement framesets = word.namedItem( "FRAMESETS" ).toElement();
01711     if ( !framesets.isNull() )
01712         loadFrameSets( framesets );
01713 
01714     emit sigProgress(85);
01715 
01716     loadPictureMap( word );
01717 
01718     emit sigProgress(90);
01719 
01720     // <EMBEDDED>
01721     loadEmbeddedObjects( word );
01722 
01723     emit sigProgress(100); // the rest is only processing, not loading
01724 
01725     kdDebug(32001) << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
01726 
01727     endOfLoading();
01728     return true;
01729 }
01730 
01731 void KWDocument::endOfLoading() // called by both oasis and oldxml
01732 {
01733     // insert pages
01734     double maxBottom = 0;
01735     for (QPtrListIterator<KWFrameSet> fsit = framesetsIterator(); fsit.current() ; ++fsit ) {
01736         KWFrameSet *fs = fsit.current();
01737         for (QPtrListIterator<KWFrame> fit = fs->frameIterator(); fit.current() ; ++fit ) {
01738             KWFrame *frame = fit.current();
01739             maxBottom = QMAX(maxBottom, frame->bottom());
01740         }
01741     }
01742     KWPage *last = pageManager()->page(lastPage());
01743     double docHeight = last->offsetInDocument() + last->height();
01744     while(docHeight <= maxBottom) {
01745         kdDebug(32001) << "KWDocument::loadXML appends a page\n";
01746         last = pageManager()->appendPage();
01747         docHeight += last->height();
01748     }
01749 
01750     bool first_footer = false, even_footer = false, odd_footer = false;
01751     bool first_header = false, even_header = false, odd_header = false;
01752 
01753     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
01754     for ( ; fit.current() ; ++fit )
01755     {
01756         switch( fit.current()->frameSetInfo() ) {
01757         case KWFrameSet::FI_FIRST_HEADER: first_header = true; break;
01758         case KWFrameSet::FI_ODD_HEADER: odd_header = true; break;
01759         case KWFrameSet::FI_EVEN_HEADER: even_header = true; break;
01760         case KWFrameSet::FI_FIRST_FOOTER: first_footer = true; break;
01761         case KWFrameSet::FI_ODD_FOOTER: odd_footer = true; break;
01762         case KWFrameSet::FI_EVEN_FOOTER: even_footer = true; break;
01763         case KWFrameSet::FI_FOOTNOTE: break;
01764         default: break;
01765         }
01766     }
01767 
01768     // Create defaults if they were not in the input file.
01769 
01770     // Where to insert the new frames: not at the end, since that breaks oasis-kword.sh
01771     uint newFramesetsIndex = m_lstFrameSet.isEmpty() ? 0 : 1;
01772 
01773     if ( !first_header ) {
01774         KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "First Page Header" ) );
01775         //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl;
01776         fs->setFrameSetInfo( KWFrameSet::FI_FIRST_HEADER );
01777         KWPage *page = pageManager()->page(startPage());
01778         KWFrame *frame = new KWFrame(fs, page->leftMargin(), page->topMargin(),
01779                 page->width() - page->leftMargin() - page->rightMargin(), 20 );
01780         //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << frame << endl;
01781         frame->setFrameBehavior( KWFrame::AutoExtendFrame );
01782         frame->setNewFrameBehavior( KWFrame::Copy );
01783         fs->addFrame( frame );
01784         m_lstFrameSet.insert( newFramesetsIndex++, fs );
01785     }
01786 
01787     if ( !odd_header ) {
01788         KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Odd Pages Header" ) );
01789         //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl;
01790         fs->setFrameSetInfo( KWFrameSet::FI_ODD_HEADER );
01791         KWPage *page = pageManager()->page(QMIN(startPage()+2, lastPage()));
01792         KWFrame *frame = new KWFrame(fs, page->leftMargin(), page->topMargin(),
01793                 page->width() - page->leftMargin() - page->rightMargin(), 20 );
01794         //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << *frame << endl;
01795         frame->setFrameBehavior( KWFrame::AutoExtendFrame );
01796         frame->setNewFrameBehavior( KWFrame::Copy );
01797         fs->addFrame( frame );
01798         m_lstFrameSet.insert( newFramesetsIndex++, fs );
01799     }
01800 
01801     if ( !even_header ) {
01802         KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Even Pages Header" ) );
01803         //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl;
01804         fs->setFrameSetInfo( KWFrameSet::FI_EVEN_HEADER );
01805         KWPage *page = pageManager()->page(QMIN(startPage()+1, lastPage()));
01806         KWFrame *frame = new KWFrame(fs, page->leftMargin(), page->topMargin(), page->width() -
01807                 page->leftMargin() - page->rightMargin(), 20 );
01808         //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << *frame << endl;
01809         frame->setFrameBehavior( KWFrame::AutoExtendFrame );
01810         frame->setNewFrameBehavior( KWFrame::Copy );
01811         fs->addFrame( frame );
01812         m_lstFrameSet.insert( newFramesetsIndex++, fs );
01813     }
01814 
01815     if ( !first_footer ) {
01816         KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "First Page Footer" ) );
01817         //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl;
01818         fs->setFrameSetInfo( KWFrameSet::FI_FIRST_FOOTER );
01819         KWPage *page = pageManager()->page(pageManager()->startPage());
01820         KWFrame *frame = new KWFrame(fs, page->leftMargin(), page->height() - page->topMargin()- 20,
01821                 page->width() - page->leftMargin() - page->rightMargin(), 20 );
01822         //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << *frame << endl;
01823         frame->setFrameBehavior( KWFrame::AutoExtendFrame );
01824         frame->setNewFrameBehavior( KWFrame::Copy );
01825         fs->addFrame( frame );
01826         m_lstFrameSet.insert( newFramesetsIndex++, fs );
01827     }
01828 
01829     if ( !odd_footer ) {
01830         KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Odd Pages Footer" ) );
01831         //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl;
01832         fs->setFrameSetInfo( KWFrameSet::FI_ODD_FOOTER );
01833         KWPage *page = pageManager()->page(QMIN(startPage()+2, lastPage()));
01834         KWFrame *frame = new KWFrame(fs, page->leftMargin(), page->height()- page->topMargin() - 20,
01835                 page->width() - page->leftMargin() - page->rightMargin(), 20 );
01836         //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << *frame << endl;
01837         frame->setFrameBehavior( KWFrame::AutoExtendFrame );
01838         frame->setNewFrameBehavior( KWFrame::Copy );
01839         fs->addFrame( frame );
01840         m_lstFrameSet.insert( newFramesetsIndex++, fs );
01841     }
01842 
01843     if ( !even_footer ) {
01844         KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Even Pages Footer" ) );
01845         //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl;
01846         fs->setFrameSetInfo( KWFrameSet::FI_EVEN_FOOTER );
01847         KWPage *page = pageManager()->page(QMIN(startPage()+1, lastPage()));
01848         KWFrame *frame = new KWFrame(fs, page->leftMargin(), page->height() - page->topMargin()- 20,
01849                 page->width() - page->leftMargin() - page->rightMargin(), 20 );
01850         //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << *frame << endl;
01851         frame->setFrameBehavior( KWFrame::AutoExtendFrame );
01852         frame->setNewFrameBehavior( KWFrame::Copy );
01853         fs->addFrame( frame );
01854         m_lstFrameSet.insert( newFramesetsIndex++, fs );
01855     }
01856 
01857     // do some sanity checking on document.
01858     for (int i = frameSetCount()-1; i>-1; i--) {
01859         KWFrameSet *fs = frameSet(i);
01860         if(!fs) {
01861             kdWarning() << "frameset " << i << " is NULL!!" << endl;
01862             m_lstFrameSet.remove(i);
01863             continue;
01864         }
01865         if( fs->type()==FT_TABLE) {
01866             static_cast<KWTableFrameSet *>( fs )->validate();
01867         } else if (fs->type() == FT_TEXT) {
01868             for (int f=fs->frameCount()-1; f>=0; f--) {
01869                 KWFrame *frame = fs->frame(f);
01870                 if(frame->left() < 0) {
01871                     kdWarning() << fs->name() << " frame " << f << " pos.x is < 0, moving frame" << endl;
01872                     frame->moveBy( 0- frame->left(), 0);
01873                 }
01874                 if(frame->right() > m_pageLayout.ptWidth) {
01875                     kdWarning() << fs->name() << " frame " << f << " rightborder outside page ("
01876                         << frame->right() << ">" << m_pageLayout.ptWidth << "), shrinking" << endl;
01877                     frame->setRight(m_pageLayout.ptWidth);
01878                 }
01879                 if(fs->isProtectSize())
01880                     continue; // don't make frames bigger of a protected frameset.
01881                 if(frame->height() < s_minFrameHeight) {
01882                     kdWarning() << fs->name() << " frame " << f << " height is so small no text will fit, adjusting (was: "
01883                                 << frame->height() << " is: " << s_minFrameHeight << ")" << endl;
01884                     frame->setHeight(s_minFrameHeight);
01885                 }
01886                 if(frame->width() < s_minFrameWidth) {
01887                     kdWarning() << fs->name() << " frame " << f << " width is so small no text will fit, adjusting (was: "
01888                                 << frame->width() << " is: " << s_minFrameWidth  << ")" << endl;
01889                     frame->setWidth(s_minFrameWidth);
01890                 }
01891             }
01892             if(fs->frameCount() == 0) {
01893                 KWPage *page = pageManager()->page(startPage());
01894                 KWFrame *frame = new KWFrame(fs, page->leftMargin(), page->topMargin(),
01895                         page->width() - page->leftMargin() - page->rightMargin(),
01896                         page->height() - page->topMargin() - page->bottomMargin());
01897                 //kdDebug(32001) << "KWDocument::loadXML main-KWFrame created " << *frame << endl;
01898                 fs->addFrame( frame );
01899             }
01900         } else if(fs->frameCount() == 0) {
01901             kdWarning () << "frameset " << i << " " << fs->name() << " has no frames" << endl;
01902             removeFrameSet(fs);
01903             if ( fs->type() == FT_PART )
01904                 delete static_cast<KWPartFrameSet *>(fs)->getChild();
01905             delete fs;
01906             continue;
01907         }
01908         if(fs->frameCount() > 0) {
01909             KWFrame *frame = fs->frame(0);
01910             if(frame->isCopy()) {
01911                 kdWarning() << "First frame in a frameset[" << fs->name() << "] was set to be a copy; resetting\n";
01912                 frame->setCopy(false);
01913             }
01914         }
01915     }
01916 
01917     // Renumber footnotes
01918     KWTextFrameSet *frameset = dynamic_cast<KWTextFrameSet *>( m_lstFrameSet.getFirst() );
01919     if ( frameset  )
01920         frameset->renumberFootNotes( false /*no repaint*/ );
01921 
01922     emit sigProgress(-1);
01923 
01924     //kdDebug(32001) << "KWDocument::loadXML done" << endl;
01925 
01926     // Connect to notifications from main text-frameset
01927     if ( frameset ) {
01928         connect( frameset->textObject(), SIGNAL( chapterParagraphFormatted( KoTextParag * ) ),
01929                  SLOT( slotChapterParagraphFormatted( KoTextParag * ) ) );
01930         connect( frameset, SIGNAL( mainTextHeightChanged() ),
01931                  SIGNAL( mainTextHeightChanged() ) );
01932     }
01933 
01934     // Note that more stuff will happen in completeLoading
01935 }
01936 
01937 void KWDocument::startBackgroundSpellCheck()
01938 {
01939     if ( backgroundSpellCheckEnabled() && isReadWrite() )
01940     {
01941         m_bgSpellCheck->start();
01942     }
01943 }
01944 
01945 void KWDocument::loadEmbeddedObjects( QDomElement& word )
01946 {
01947     QDomNodeList listEmbedded = word.elementsByTagName ( "EMBEDDED" );
01948     for (unsigned int item = 0; item < listEmbedded.count(); item++)
01949     {
01950         QDomElement embedded = listEmbedded.item( item ).toElement();
01951         loadEmbedded( embedded );
01952     }
01953 }
01954 
01955 void KWDocument::loadEmbedded( const QDomElement &embedded )
01956 {
01957     QDomElement object = embedded.namedItem( "OBJECT" ).toElement();
01958     if ( !object.isNull() )
01959     {
01960         KWDocumentChild *ch = new KWDocumentChild( this );
01961         ch->load( object, true );
01962         insertChild( ch );
01963         QDomElement settings = embedded.namedItem( "SETTINGS" ).toElement();
01964         QString name;
01965         if ( !settings.isNull() )
01966             name = settings.attribute( "name" );
01967         KWPartFrameSet *fs = new KWPartFrameSet( this, ch, name );
01968         m_lstFrameSet.append( fs );
01969         if ( !settings.isNull() )
01970         {
01971             kdDebug(32001) << "KWDocument::loadXML loading embedded object" << endl;
01972             fs->load( settings );
01973         }
01974         else
01975             kdError(32001) << "No <SETTINGS> tag in EMBEDDED" << endl;
01976 
01977     } else
01978         kdError(32001) << "No <OBJECT> tag in EMBEDDED" << endl;
01979 }
01980 
01981 
01982 void KWDocument::loadStyleTemplates( const QDomElement &stylesElem )
01983 {
01984     QValueList<QString> followingStyles;
01985     QDomNodeList listStyles = stylesElem.elementsByTagName( "STYLE" );
01986     if( listStyles.count() > 0) { // we are going to import at least one style.
01987         KoParagStyle *s = m_styleColl->findStyle("Standard");
01988         //kdDebug(32001) << "KWDocument::loadStyleTemplates looking for Standard, to delete it. Found " << s << endl;
01989         if(s) // delete the standard style.
01990             m_styleColl->removeStyle(s);
01991     }
01992     for (unsigned int item = 0; item < listStyles.count(); item++) {
01993         QDomElement styleElem = listStyles.item( item ).toElement();
01994 
01995         KoParagStyle *sty = new KoParagStyle( QString::null );
01996         // Load the style from the <STYLE> element
01997         sty->loadStyle( styleElem, m_syntaxVersion );
01998 
01999         //kdDebug(32001) << "KoParagStyle created name=" << sty->name() << endl;
02000 
02001         if ( m_syntaxVersion < 3 )
02002         {
02003             // Convert old style (up to 1.2.x included)
02004             // "include in TOC if chapter numbering" to the new attribute
02005             if ( sty->paragLayout().counter && sty->paragLayout().counter->numbering() == KoParagCounter::NUM_CHAPTER )
02006                 sty->setOutline( true );
02007         }
02008 
02009         // the real value of followingStyle is set below after loading all styles
02010         sty->setFollowingStyle( sty );
02011 
02012         QDomElement formatElem = styleElem.namedItem( "FORMAT" ).toElement();
02013         if ( !formatElem.isNull() )
02014             sty->format() = KWTextParag::loadFormat( formatElem, 0L, defaultFont(), globalLanguage(), globalHyphenation() );
02015         else
02016             kdWarning(32001) << "No FORMAT tag in <STYLE>" << endl; // This leads to problems in applyStyle().
02017 
02018         // Style created, now let's try to add it
02019         sty = m_styleColl->addStyle( sty );
02020 
02021         if(m_styleColl->styleList().count() > followingStyles.count() )
02022         {
02023             QString following = styleElem.namedItem("FOLLOWING").toElement().attribute("name");
02024             followingStyles.append( following );
02025         }
02026         else
02027             kdWarning () << "Found duplicate style declaration, overwriting former " << sty->name() << endl;
02028     }
02029 
02030     Q_ASSERT( followingStyles.count() == m_styleColl->styleList().count() );
02031 
02032     unsigned int i=0;
02033     for( QValueList<QString>::Iterator it = followingStyles.begin(); it != followingStyles.end(); ++it ) {
02034         KoParagStyle * style = m_styleColl->findStyle(*it);
02035         m_styleColl->styleAt(i++)->setFollowingStyle( style );
02036     }
02037 
02038 }
02039 
02040 void KWDocument::loadFrameStyleTemplates( const QDomElement &stylesElem )
02041 {
02042     QDomNodeList listStyles = stylesElem.elementsByTagName( "FRAMESTYLE" );
02043     if( listStyles.count() > 0) { // we are going to import at least one style.
02044         KWFrameStyle *s = m_frameStyleColl->findStyle("Plain");
02045         if(s) // delete the standard style.
02046             m_frameStyleColl->removeStyle(s);
02047     }
02048     for (unsigned int item = 0; item < listStyles.count(); item++) {
02049         QDomElement styleElem = listStyles.item( item ).toElement();
02050 
02051         KWFrameStyle *sty = new KWFrameStyle( styleElem );
02052         m_frameStyleColl->addStyle( sty );
02053     }
02054 }
02055 
02056 void KWDocument::loadDefaultFrameStyleTemplates()
02057 {
02058     const QString fsfileName( locate("data", "kword/framestyles.xml") );
02059 
02060     kdDebug(30003) << "Data directory: " << KGlobal::dirs()->resourceDirs( "data" ) << endl;
02061     kdDebug(30003) << "Directory searched: " << KGlobal::dirs()->resourceDirs( "data" ) << endl;
02062     kdDebug(30003) << "File framestyles.xml searched at: " << fsfileName << endl;
02063 
02064     m_frameStyleColl->setDefault( true );
02065 
02066     if ( ! QFile::exists( fsfileName ) )
02067     {
02068         kdWarning(30003) << "Cannot find any framestyles.xml" << endl;
02069         if (!m_frameStyleColl->findStyle("Plain")) {
02070             KWFrameStyle * standardFrameStyle = new KWFrameStyle( "Plain" );
02071             standardFrameStyle->setBackgroundColor(QColor("white"));
02072             standardFrameStyle->setTopBorder(KoBorder(QColor("black"),KoBorder::SOLID,0));
02073             standardFrameStyle->setRightBorder(KoBorder(QColor("black"),KoBorder::SOLID,0));
02074             standardFrameStyle->setLeftBorder(KoBorder(QColor("black"),KoBorder::SOLID,0));
02075             standardFrameStyle->setBottomBorder(KoBorder(QColor("black"),KoBorder::SOLID,0));
02076             m_frameStyleColl->addStyle( standardFrameStyle );
02077         }
02078         return;
02079     }
02080 
02081     kdDebug(30003) << "File framestyles.xml found!" << endl;
02082 
02083     // Open file and parse it
02084     QFile in( fsfileName );
02085     if ( !in.open( IO_ReadOnly ) )
02086     {
02087         //i18n( "Couldn't open the file for reading (check read permissions)" );
02088         kdWarning(30003) << "Couldn't open the file for reading (check read permissions)" << endl;
02089         return;
02090     }
02091     QString errorMsg;
02092     int errorLine;
02093     int errorColumn;
02094     QDomDocument doc;
02095     if ( ! doc.setContent( &in , &errorMsg, &errorLine, &errorColumn ) )
02096     {
02097         kdError (30003) << "Parsing Error! Aborting! (in KWDocument::loadDefaultFrameStyleTemplates())" << endl
02098                         << "  Line: " << errorLine << " Column: " << errorColumn << endl
02099                         << "  Message: " << errorMsg << endl;
02100     }
02101     in.close();
02102 
02103     // Start adding framestyles
02104     QDomElement stylesElem = doc.documentElement();
02105 
02106     QDomNodeList listStyles = stylesElem.elementsByTagName( "FRAMESTYLE" );
02107     if( listStyles.count() > 0) { // we are going to import at least one style.
02108         KWFrameStyle *s = m_frameStyleColl->findStyle("Plain");
02109         if(s) // delete the standard style.
02110             m_frameStyleColl->removeStyle(s);
02111     }
02112     for (unsigned int item = 0; item < listStyles.count(); item++) {
02113         QDomElement styleElem = listStyles.item( item ).toElement();
02114 
02115         KWFrameStyle *sty = new KWFrameStyle( styleElem );
02116         m_frameStyleColl->addStyle( sty );
02117     }
02118 }
02119 
02120 void KWDocument::loadTableStyleTemplates( const QDomElement& stylesElem )
02121 {
02122     QDomNodeList listStyles = stylesElem.elementsByTagName( "TABLESTYLE" );
02123     if( listStyles.count() > 0) { // we are going to import at least one style.
02124         KWTableStyle *s = m_tableStyleColl->findStyle("Plain");
02125         if(s) // delete the standard style.
02126             m_tableStyleColl->removeStyle(s);
02127     }
02128     for (unsigned int item = 0; item < listStyles.count(); item++) {
02129         QDomElement styleElem = listStyles.item( item ).toElement();
02130 
02131         KWTableStyle *sty = new KWTableStyle( styleElem, this );
02132         m_tableStyleColl->addStyle( sty );
02133     }
02134 }
02135 
02136 void KWDocument::loadDefaultTableStyleTemplates()
02137 {
02138     KURL fsfile;
02139 
02140     m_tableStyleColl->setDefault( true );
02141 
02142     if ( ! QFile::exists(locate("data", "kword/tablestyles.xml")) )
02143     {
02144         if (!m_tableStyleColl->findStyle("Plain")) {
02145             m_tableStyleColl->addStyle( new KWTableStyle( "Plain", m_styleColl->styleAt(0), m_frameStyleColl->frameStyleAt(0) ) );
02146         }
02147         return;
02148     }
02149 
02150     fsfile.setPath( locate("data", "kword/tablestyles.xml") );
02151 
02152     // Open file and parse it
02153     QFile in( fsfile.path() );
02154     if ( !in.open( IO_ReadOnly ) )
02155     {
02156         //i18n( "Couldn't open the file for reading (check read permissions)" );
02157         return;
02158     }
02159     in.at(0);
02160     QString errorMsg;
02161     int errorLine;
02162     int errorColumn;
02163     QDomDocument doc;
02164     if ( doc.setContent( &in , &errorMsg, &errorLine, &errorColumn ) ) {
02165     }
02166     else
02167     {
02168         kdError (30003) << "Parsing Error! Aborting! (in KWDocument::loadDefaultTableStyleTemplates())" << endl
02169                         << "  Line: " << errorLine << " Column: " << errorColumn << endl
02170                         << "  Message: " << errorMsg << endl;
02171     }
02172     in.close();
02173 
02174     // Start adding tablestyles
02175     QDomElement stylesElem = doc.documentElement();
02176 
02177     QDomNodeList listStyles = stylesElem.elementsByTagName( "TABLESTYLE" );
02178     if( listStyles.count() > 0) { // we are going to import at least one style.
02179         KWTableStyle *s = m_tableStyleColl->findStyle("Plain");
02180         if(s) // delete the standard style.
02181             m_tableStyleColl->removeStyle(s);
02182     }
02183     for (unsigned int item = 0; item < listStyles.count(); item++) {
02184         QDomElement styleElem = listStyles.item( item ).toElement();
02185 
02186         KWTableStyle *sty = new KWTableStyle( styleElem, this );
02187         m_tableStyleColl->addStyle( sty );
02188     }
02189 }
02190 
02191 void KWDocument::loadDefaultTableTemplates()
02192 {
02193     KURL fsfile;
02194 
02195     if ( ! QFile::exists(locate("data", "kword/tabletemplates.xml")) )
02196     {
02197         if (!m_tableTemplateColl->findTableTemplate("Plain")) {
02198             KWTableTemplate * standardTableTemplate = new KWTableTemplate( "Plain" );
02199             KWTableStyle* defaultTableStyle = tableStyleCollection()->findStyle("Plain");
02200             standardTableTemplate->setFirstRow( defaultTableStyle );
02201             standardTableTemplate->setLastRow( defaultTableStyle );
02202             standardTableTemplate->setFirstCol( defaultTableStyle );
02203             standardTableTemplate->setLastCol( defaultTableStyle );
02204             standardTableTemplate->setBodyCell( defaultTableStyle );
02205             standardTableTemplate->setTopLeftCorner( defaultTableStyle );
02206             standardTableTemplate->setTopRightCorner( defaultTableStyle );
02207             standardTableTemplate->setBottomLeftCorner( defaultTableStyle );
02208             standardTableTemplate->setBottomRightCorner( defaultTableStyle );
02209             m_tableTemplateColl->addTableTemplate( standardTableTemplate );
02210         }
02211         return;
02212     }
02213 
02214     fsfile.setPath( locate("data", "kword/tabletemplates.xml") );
02215 
02216     // Open file and parse it
02217     QFile in( fsfile.path() );
02218     if ( !in.open( IO_ReadOnly ) )
02219     {
02220         //i18n( "Couldn't open the file for reading (check read permissions)" );
02221         return;
02222     }
02223     in.at(0);
02224     QString errorMsg;
02225     int errorLine;
02226     int errorColumn;
02227     QDomDocument doc;
02228     if ( doc.setContent( &in , &errorMsg, &errorLine, &errorColumn ) ) {
02229     }
02230     else
02231     {
02232         kdError (30003) << "Parsing Error! Aborting! (in KWDocument::readTableTemplates())" << endl
02233                         << "  Line: " << errorLine << " Column: " << errorColumn << endl
02234                         << "  Message: " << errorMsg << endl;
02235     }
02236     in.close();
02237 
02238     // Start adding framestyles
02239     QDomElement templatesElem = doc.documentElement();
02240 
02241     QDomNodeList listTemplates = templatesElem.elementsByTagName( "TABLETEMPLATE" );
02242     if( listTemplates.count() > 0) {
02243         KWTableTemplate *s = m_tableTemplateColl->findTableTemplate("Plain");
02244         if(s)
02245             m_tableTemplateColl->removeTableTemplate(s);
02246     }
02247     for (unsigned int item = 0; item < listTemplates.count(); item++) {
02248         QDomElement templateElem = listTemplates.item( item ).toElement();
02249 
02250         KWTableTemplate *temp = new KWTableTemplate( templateElem, this );
02251         m_tableTemplateColl->addTableTemplate( temp );
02252     }
02253 }
02254 
02255 void KWDocument::progressItemLoaded()
02256 {
02257     if ( !m_nrItemsToLoad ) // happens when pasting
02258         return;
02259     m_itemsLoaded++;
02260     // We progress from 20 to 85 -> 65-wide range, 20 offset.
02261     unsigned int perc = 65 * m_itemsLoaded / m_nrItemsToLoad;
02262     if ( perc != 65 * (m_itemsLoaded-1) / m_nrItemsToLoad ) // only emit if different from previous call
02263     {
02264         //kdDebug(32001) << m_itemsLoaded << " items loaded. %=" << perc + 20 << endl;
02265         emit sigProgress( perc + 20 );
02266     }
02267 }
02268 
02269 void KWDocument::loadFrameSets( const QDomElement &framesetsElem )
02270 {
02271     // <FRAMESET>
02272     // First prepare progress info
02273     m_nrItemsToLoad = 0; // total count of items (mostly paragraph and frames)
02274     QDomElement framesetElem = framesetsElem.firstChild().toElement();
02275     // Workaround the slowness of QDom's elementsByTagName
02276     QValueList<QDomElement> framesets;
02277     for ( ; !framesetElem.isNull() ; framesetElem = framesetElem.nextSibling().toElement() )
02278     {
02279         if ( framesetElem.tagName() == "FRAMESET" )
02280         {
02281             framesets.append( framesetElem );
02282             m_nrItemsToLoad += framesetElem.childNodes().count();
02283         }
02284     }
02285 
02286     m_itemsLoaded = 0;
02287 
02288     QValueList<QDomElement>::Iterator it = framesets.begin();
02289     QValueList<QDomElement>::Iterator end = framesets.end();
02290     for ( ; it != end ; ++it )
02291     {
02292         (void) loadFrameSet( *it );
02293     }
02294 }
02295 
02296 KWFrameSet * KWDocument::loadFrameSet( QDomElement framesetElem, bool loadFrames, bool loadFootnote )
02297 {
02298     FrameSetType frameSetType = static_cast<FrameSetType>( KWDocument::getAttribute( framesetElem, "frameType", FT_BASE ) );
02299     QString fsname = KWDocument::getAttribute( framesetElem, "name", "" );
02300 
02301     switch ( frameSetType ) {
02302     case FT_TEXT: {
02303         QString tableName = KWDocument::getAttribute( framesetElem, "grpMgr", "" );
02304         if ( !tableName.isEmpty() ) {
02305             // Text frameset belongs to a table -> find table by name
02306             KWTableFrameSet *table = 0L;
02307             QPtrListIterator<KWFrameSet> fit = framesetsIterator();
02308             for ( ; fit.current() ; ++fit ) {
02309                 KWFrameSet *f = fit.current();
02310                 if( f->type() == FT_TABLE &&
02311                     f->isVisible() &&
02312                     f->name() == tableName ) {
02313                     table = static_cast<KWTableFrameSet *> (f);
02314                     break;
02315                 }
02316             }
02317             // No such table yet -> create
02318             if ( !table ) {
02319                 table = new KWTableFrameSet( this, tableName );
02320                 addFrameSet(table, false);
02321             }
02322             // Load the cell
02323             return table->loadCell( framesetElem );
02324         }
02325         else
02326         {
02327             KWFrameSet::Info info = static_cast<KWFrameSet::Info>( framesetElem.attribute("frameInfo").toInt() );
02328             if ( info == KWFrameSet::FI_FOOTNOTE )
02329             {
02330                 if ( !loadFootnote )
02331                     return 0L;
02332                 // Footnote -> create a KWFootNoteFrameSet
02333                 KWFootNoteFrameSet *fs = new KWFootNoteFrameSet( this, fsname );
02334                 fs->load( framesetElem, loadFrames );
02335                 addFrameSet(fs, false);
02336                 return fs;
02337             }
02338             else // Normal text frame
02339             {
02340                 KWTextFrameSet *fs = new KWTextFrameSet( this, fsname );
02341                 fs->load( framesetElem, loadFrames );
02342                 addFrameSet(fs, false);
02343 
02344                 // Old file format had autoCreateNewFrame as a frameset attribute
02345                 if ( framesetElem.hasAttribute( "autoCreateNewFrame" ) )
02346                 {
02347                     KWFrame::FrameBehavior behav = static_cast<KWFrame::FrameBehavior>( framesetElem.attribute( "autoCreateNewFrame" ).toInt() );
02348                     QPtrListIterator<KWFrame> frameIt( fs->frameIterator() );
02349                     for ( ; frameIt.current() ; ++frameIt ) // Apply it to all frames
02350                         frameIt.current()->setFrameBehavior( behav );
02351                 }
02352                 return fs;
02353             }
02354         }
02355     } break;
02356     case FT_CLIPART:
02357     {
02358         kdError(32001) << "FT_CLIPART used! (in KWDocument::loadFrameSet)" << endl;
02359         // Do not break!
02360     }
02361     case FT_PICTURE:
02362     {
02363         KWPictureFrameSet *fs = new KWPictureFrameSet( this, fsname );
02364         fs->load( framesetElem, loadFrames );
02365         addFrameSet(fs, false);
02366         return fs;
02367     } break;
02368     case FT_FORMULA: {
02369         KWFormulaFrameSet *fs = new KWFormulaFrameSet( this, fsname );
02370         fs->load( framesetElem, loadFrames );
02371         addFrameSet(fs, false);
02372         return fs;
02373     } break;
02374     // Note that FT_PART cannot happen when loading from a file (part frames are saved into the SETTINGS tag)
02375     // and FT_TABLE can't happen either.
02376     case FT_PART:
02377         kdWarning(32001) << "loadFrameSet: FT_PART: impossible case" << endl;
02378         break;
02379     case FT_TABLE:
02380         kdWarning(32001) << "loadFrameSet: FT_TABLE: impossible case" << endl;
02381         break;
02382     case FT_BASE:
02383         kdWarning(32001) << "loadFrameSet: FT_BASE !?!?" << endl;
02384         break;
02385     }
02386     return 0L;
02387 }
02388 
02389 void KWDocument::loadImagesFromStore( KoStore *store )
02390 {
02391     if ( store && !m_pictureMap.isEmpty() ) {
02392         m_pictureCollection->readFromStore( store, m_pictureMap );
02393         m_pictureMap.clear(); // Release memory
02394     }
02395 }
02396 
02397 bool KWDocument::completeLoading( KoStore *store )
02398 {
02399     kdDebug() << k_funcinfo << endl;
02400     // Old-XML stuff. No-op when loading OASIS.
02401     loadImagesFromStore( store );
02402     processPictureRequests();
02403     processAnchorRequests();
02404     processFootNoteRequests();
02405 
02406     // Save memory
02407     m_urlIntern = QString::null;
02408 
02409     // The fields and dates just got loaded -> update vars
02410     recalcVariables( VT_FIELD );
02411     recalcVariables( VT_DATE );
02412     recalcVariables( VT_STATISTIC ); // e.g. number of words etc.
02413 
02414     // Finalize all the existing [non-inline] framesets
02415     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
02416     for ( ; fit.current() ; ++fit )
02417         fit.current()->finalize();
02418 
02419     // This computes the number of pages (from the frames)
02420     // for the first time (and adds footers/headers/footnotes etc.)
02421     // ## Note: with OASIS the frame loading appends pages as necessary,
02422     // so maybe we don't need to calculate the pages from the frames anymore.
02423     recalcFrames();
02424 
02425     // Fix z orders on older documents
02426     fixZOrders();
02427 
02428     emit newContentsSize();
02429     repaintAllViews( true );     // in case any view exists already
02430     reactivateBgSpellChecking();
02431     connect( documentInfo(), SIGNAL( sigDocumentInfoModifed()),this,SLOT(slotDocumentInfoModifed() ) );
02432 
02433     //desactivate bgspellchecking
02434     //attributes isReadWrite is not placed at the beginning !
02435     if ( !isReadWrite())
02436         enableBackgroundSpellCheck( false );
02437 
02438     // Load bookmarks
02439     initBookmarkList();
02440 
02441     deleteLoadingInfo();
02442 
02443     setModified( false );
02444 
02445     return true;
02446 }
02447 
02448 KWLoadingInfo* KWDocument::createLoadingInfo()
02449 {
02450     Q_ASSERT( !m_loadingInfo );
02451     m_loadingInfo = new KWLoadingInfo();
02452     m_loadingInfo->columns.ptColumnSpacing = m_defaultColumnSpacing;
02453     return m_loadingInfo;
02454 }
02455 
02456 void KWDocument::deleteLoadingInfo()
02457 {
02458     Q_ASSERT( m_loadingInfo );
02459     delete m_loadingInfo;
02460     m_loadingInfo = 0;
02461 }
02462 
02463 void KWDocument::processPictureRequests()
02464 {
02465     QPtrListIterator<KWTextImage> it2 ( m_textImageRequests );
02466     for ( ; it2.current() ; ++it2 )
02467     {
02468         it2.current()->setImage( *m_pictureCollection );
02469     }
02470     m_textImageRequests.clear();
02471 
02472     //kdDebug(32001) << m_pictureRequests.count() << " picture requests." << endl;
02473     QPtrListIterator<KWPictureFrameSet> it3( m_pictureRequests );
02474     for ( ; it3.current() ; ++it3 )
02475         it3.current()->setPicture( m_pictureCollection->findPicture( it3.current()->key() ) );
02476     m_pictureRequests.clear();
02477 }
02478 
02479 void KWDocument::processAnchorRequests()
02480 {
02481     QMapIterator<QString, KWAnchorPosition> itanch = m_anchorRequests.begin();
02482     for ( ; itanch != m_anchorRequests.end(); ++itanch )
02483     {
02484         QString fsname = itanch.key();
02485         if ( m_pasteFramesetsMap && m_pasteFramesetsMap->contains( fsname ) )
02486             fsname = (*m_pasteFramesetsMap)[ fsname ];
02487         kdDebug(32001) << "KWDocument::processAnchorRequests anchoring frameset " << fsname << endl;
02488         KWFrameSet * fs = frameSetByName( fsname );
02489         Q_ASSERT( fs );
02490         if ( fs )
02491             fs->setAnchored( itanch.data().textfs, itanch.data().paragId, itanch.data().index, true, false /*don't repaint yet*/ );
02492     }
02493     m_anchorRequests.clear();
02494 }
02495 
02496 bool KWDocument::processFootNoteRequests()
02497 {
02498     bool ret = false;
02499     QMapIterator<QString, KWFootNoteVariable *> itvar = m_footnoteVarRequests.begin();
02500     for ( ; itvar != m_footnoteVarRequests.end(); ++itvar )
02501     {
02502         QString fsname = itvar.key();
02503         if ( m_pasteFramesetsMap && m_pasteFramesetsMap->contains( fsname ) )
02504             fsname = (*m_pasteFramesetsMap)[ fsname ];
02505         //kdDebug(32001) << "KWDocument::processFootNoteRequests binding footnote var " << itvar.data() << " and frameset " << fsname << endl;
02506         KWFrameSet * fs = frameSetByName( fsname );
02507         Q_ASSERT( fs );
02508         if ( !fs ) // #104431
02509             continue;
02510         Q_ASSERT( fs->type() == FT_TEXT );
02511         Q_ASSERT( fs->frameSetInfo() == KWFrameSet::FI_FOOTNOTE );
02512         KWFootNoteFrameSet* fnfs = dynamic_cast<KWFootNoteFrameSet *>(fs);
02513         if ( fnfs )
02514         {
02515             fnfs->setFootNoteVariable( itvar.data() );
02516             itvar.data()->setFrameSet( fnfs );
02517             ret = true;
02518         }
02519     }
02520     m_footnoteVarRequests.clear();
02521     // Renumber footnotes
02522     if ( ret ) {
02523         KWFrameSet *frameset = m_lstFrameSet.getFirst();
02524         if ( frameset && frameset->type() == FT_TEXT )
02525             static_cast<KWTextFrameSet *>(frameset)->renumberFootNotes( false /*no repaint*/ );
02526     }
02527     return ret;
02528 }
02529 
02530 QString KWDocument::uniqueFramesetName( const QString& oldName )
02531 {
02532     QString newName = oldName;
02533     if (frameSetByName( oldName ))//rename it if name frameset exists
02534     {
02535         // make up a new name for the frameset, use Copy[digits]-[oldname] as template.
02536         // Fully translatable naturally :)
02537         QString searchString( "^(" + i18n("Copy%1-%2").arg("\\d*").arg("){0,1}") );
02538         searchString = searchString.replace(QRegExp("\\-"), "\\-"); // escape the '-'
02539         QRegExp searcher(searchString);
02540         int count=0;
02541         do {
02542             newName=oldName;
02543             newName.replace(searcher,i18n("Copy%1-%2").arg(count > 0? QString("%1").arg(count):"").arg(""));
02544             count++;
02545         } while ( frameSetByName( newName ) );
02546     }
02547     return newName;
02548 }
02549 
02550 void KWDocument::pasteFrames( QDomElement topElem, KMacroCommand * macroCmd, bool copyFootNote, bool loadFootNote, bool selectFrames )
02551 {
02552     m_pasteFramesetsMap = new QMap<QString, QString>();
02553     //QPtrList<KWFrameSet> frameSetsToFinalize;
02554     int ref=0;
02555     int nb = 0;
02556     QDomElement elem = topElem.firstChild().toElement();
02557     for ( ; !elem.isNull() ; elem = elem.nextSibling().toElement() )
02558     {
02559         //kdDebug() << "pasteFrames: elem=" << elem.tagName() << endl;
02560         QDomElement frameElem;
02561         KWFrameSet * fs = 0L;
02562         if ( elem.tagName() == "FRAME" )
02563         {
02564             QString frameSetName = frameElem.attribute( "parentFrameset" );
02565             fs = frameSetByName( frameSetName );
02566             if ( !fs )
02567             {
02568                 kdWarning(32001) << "pasteFrames: Frameset '" << frameSetName << "' not found" << endl;
02569                 continue;
02570             }
02571             frameElem = elem;
02572         }
02573         else if ( elem.tagName() == "FRAMESET" )
02574         {
02575             // Prepare a new name for the frameset
02576             QString oldName = elem.attribute( "name" );
02577             QString newName = uniqueFramesetName( oldName ); // make up a new name for the frameset
02578 
02579             m_pasteFramesetsMap->insert( oldName, newName ); // remember the name transformation
02580             if(oldName != newName)
02581                 kdDebug(32001) << "KWDocument::pasteFrames new frameset: " << oldName << "->" << newName << endl;
02582             FrameSetType frameSetType = static_cast<FrameSetType>( KWDocument::getAttribute( elem, "frameType", FT_BASE ) );
02583             switch ( frameSetType ) {
02584             case FT_TABLE: {
02585                 KWTableFrameSet *table = new KWTableFrameSet( this, newName );
02586                 table->fromXML( elem, true, false /*don't apply names*/ );
02587                 table->moveBy( 20.0, 20.0 );
02588                 m_lstFrameSet.append( table );
02589                 table->setZOrder();
02590                 if ( macroCmd )
02591                     macroCmd->addCommand( new KWCreateTableCommand( QString::null, table ) );
02592                 fs = table;
02593                 break;
02594             }
02595             case FT_PART:
02596             {
02597                 ref |= Embedded;
02598 #if 0
02599                 KWPartFrameSet *part = new KWPartFrameSet( this, newName );
02600                 part->fromXML( elem, true, false /*don't apply names*/ );
02601                 part->moveBy( 20.0, 20.0 );
02602                 m_lstFrameSet.append( part );
02603                 part->setZOrder();
02604                 fs = part;
02605 #endif
02606                 break;
02607             }
02608             default:
02609                 fs = loadFrameSet( elem, false, loadFootNote );
02610                 if ( fs )
02611                 {
02612                     kdDebug() << "KWDocument::pasteFrames created frameset: '" << newName << "'\n";
02613                     fs->setName( newName );
02614                     frameElem = elem.namedItem( "FRAME" ).toElement();
02615                 }
02616             }
02617             //when we paste a header/footer we transforme it in a body frame
02618             if(fs && (fs->isHeaderOrFooter() || ( !copyFootNote && fs->isFootEndNote())))
02619                 fs->setFrameSetInfo(KWFrameSet::FI_BODY);
02620         }
02621         // Test commented out since the toplevel element can contain "PARAGRAPH" now
02622         //else
02623         //kdWarning(32001) << "Unsupported toplevel-element in KWCanvas::pasteFrames : '" << elem.tagName() << "'" << endl;
02624 
02625         if ( fs )
02626         {
02627             //if ( frameSetsToFinalize.findRef( fs ) == -1 )
02628             //    frameSetsToFinalize.append( fs );
02629 
02630             // Load the frame
02631             if ( !frameElem.isNull() )
02632             {
02633                 double offs = 20.0;
02634                 KoRect rect;
02635                 rect.setLeft( KWDocument::getAttribute( frameElem, "left", 0.0 ) + offs );
02636                 rect.setTop( KWDocument::getAttribute( frameElem, "top", 0.0 ) + offs );
02637                 rect.setRight( KWDocument::getAttribute( frameElem, "right", 0.0 ) + offs );
02638                 rect.setBottom( KWDocument::getAttribute( frameElem, "bottom", 0.0 ) + offs );
02639                 KWFrame * frame = new KWFrame( fs, rect.x(), rect.y(), rect.width(), rect.height() );
02640                 frame->load( frameElem, fs, KWDocument::CURRENT_SYNTAX_VERSION );
02641                 frame->setZOrder( maxZOrder( frame->pageNumber(this) ) + 1 +nb ); // make sure it's on top
02642                 nb++;
02643                 fs->addFrame( frame, false );
02644                 if ( selectFrames ) {
02645                     for( QValueList<KWView *>::Iterator it = m_lstViews.begin();
02646                             it != m_lstViews.end(); ++it ) {
02647                         KWFrameView *fv = (*it)->frameViewManager()->view(frame);
02648                         if(fv)
02649                             fv->setSelected(true);
02650                     }
02651                 }
02652                 if ( macroCmd )
02653                 {
02654                     KWCreateFrameCommand *cmd = new KWCreateFrameCommand( QString::null, frame );
02655                     macroCmd->addCommand(cmd);
02656                 }
02657             }
02658             int type=0;
02659             // Please move this to some common method somewhere (e.g. in KWDocument) (David)
02660             switch(fs->type())
02661             {
02662             case FT_TEXT:
02663                 type=(int)TextFrames;
02664                 break;
02665             case FT_CLIPART:
02666             {
02667                 kdError(32001) << "FT_CLIPART used! (in KWDocument::loadFrameSet)" << endl;
02668                 // Do not break!
02669             }
02670             case FT_PICTURE:
02671                 type=(int)Pictures;
02672                 break;
02673             case FT_PART:
02674                 type=(int)Embedded;
02675                 break;
02676             case FT_FORMULA:
02677                 type=(int)FormulaFrames;
02678                 break;
02679             case FT_TABLE:
02680                 type=(int)Tables;
02681                 break;
02682             default:
02683                 type=(int)TextFrames;
02684             }
02685             ref|=type;
02686         }
02687     }
02688     refreshDocStructure(ref);
02689 }
02690 
02691 void KWDocument::completePasting()
02692 {
02693     processPictureRequests();
02694     processAnchorRequests();
02695     if ( processFootNoteRequests() )
02696     {
02697         // We pasted footnotes. Relayout frames.
02698         recalcFrames();
02699     }
02700 
02701     // Finalize afterwards - especially in case of inline frames, made them inline in processAnchorRequests
02702     //for ( QPtrListIterator<KWFrameSet> fit( frameSetsToFinalize ); fit.current(); ++fit )
02703 
02704     // Do it on all of them (we'd need to store frameSetsToFinalize as member var if this is really slow)
02705     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
02706     for ( ; fit.current() ; ++fit )
02707         fit.current()->finalize();
02708     repaintAllViews();
02709     delete m_pasteFramesetsMap;
02710     m_pasteFramesetsMap = 0L;
02711 }
02712 
02713 void KWDocument::completeOasisPasting()
02714 {
02715     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
02716     for ( ; fit.current() ; ++fit )
02717         fit.current()->finalize();
02718     repaintAllViews();
02719 }
02720 
02721 void KWDocument::insertEmbedded( KoStore *store, QDomElement topElem, KMacroCommand * macroCmd, double offset )
02722 {
02723     if ( !m_pasteFramesetsMap ) // may have been created by pasteFrames
02724         m_pasteFramesetsMap = new QMap<QString, QString>();
02725 
02726     QDomElement elem = topElem.firstChild().toElement();
02727     for ( ; !elem.isNull() ; elem = elem.nextSibling().toElement() )
02728     {
02729         if ( elem.tagName() == "EMBEDDED" )
02730         {
02731             kdDebug()<<"KWDocument::insertEmbedded() Embedded object"<<endl;
02732             QDomElement object = elem.namedItem( "OBJECT" ).toElement();
02733             QDomElement settings = elem.namedItem( "SETTINGS" ).toElement();
02734             if ( object.isNull() || settings.isNull() )
02735             {
02736                 kdError() << "No <OBJECT> or <SETTINGS> tag" << endl;
02737             }
02738             else
02739             {
02740                 KWDocumentChild *ch = new KWDocumentChild( this );
02741                 kdDebug()<<"KWDocument::insertEmbedded() loading document"<<endl;
02742                 if ( ch->load( object, true ) )
02743                 {
02744                     ch->loadDocument( store );
02745                     insertChild( ch );
02746                     QString oldName = settings.attribute( "name" );
02747                     QString newName = uniqueFramesetName( oldName );
02748                     m_pasteFramesetsMap->insert( oldName, newName ); // remember the name transformation
02749                     KWPartFrameSet *part = new KWPartFrameSet( this, ch, newName );
02750                     m_lstFrameSet.append( part );
02751                     kdDebug() << "KWDocument::insertEmbedded loading embedded object" << endl;
02752                     part->load( settings );
02753                     if ( offset != 0 ) {
02754                         QRect r = ch->geometry();
02755                         r.moveBy( (int)offset, (int)offset );
02756                         ch->setGeometry( r );
02757                     }
02758                     part->setZOrder();
02759                     if ( macroCmd )
02760                     {
02761                         QPtrListIterator<KWFrame> frameIt( part->frameIterator() );
02762                         for ( ; frameIt.current(); ++frameIt )
02763                         {
02764                             macroCmd->addCommand( new KWCreateFrameCommand( QString::null, frameIt.current() ) );
02765                         }
02766                     }
02767                 }
02768             }
02769         }
02770     }
02771     refreshDocStructure( (int)Embedded );
02772 }
02773 
02774 bool KWDocument::saveOasis( KoStore* store, KoXmlWriter* manifestWriter )
02775 {
02776     QValueList<KWFrameView*> noFrames;
02777     return saveOasisHelper( store, manifestWriter, SaveAll, noFrames);
02778 }
02779 
02780 // can't be const due to recalcVariables()
02781 bool KWDocument::saveOasisHelper( KoStore* store, KoXmlWriter* manifestWriter, SaveFlag saveFlag, const QValueList<KWFrameView*> &selectedFrames, QString* plainText, KoPicture* picture, KWTextFrameSet* fs) {
02782     m_pictureCollection->assignUniqueIds();
02783     fixZOrders();
02784 
02785     manifestWriter->addManifestEntry( "content.xml", "text/xml" );
02786     KoOasisStore oasisStore( store );
02787 
02788     KoXmlWriter* contentWriter = oasisStore.contentWriter();
02789     if ( !contentWriter )
02790         return false;
02791 
02792     QValueList<KoPictureKey> pictureList;
02793     if ( saveFlag == SaveAll )
02794         pictureList = savePictureList();
02795 
02796     m_varColl->variableSetting()->setModificationDate(QDateTime::currentDateTime());
02797     recalcVariables( VT_DATE );
02798     recalcVariables( VT_TIME ); // for "current time"
02799     recalcVariables( VT_STATISTIC );
02800     m_syntaxVersion = CURRENT_SYNTAX_VERSION; // ### clean this up once we remove the old format
02801 
02802     KoGenStyles mainStyles;
02803     KoSavingContext savingContext( mainStyles, m_varColl->variableSetting(), m_pageColumns.columns > 1, KoSavingContext::Store );
02804 
02805     // Save user styles as KoGenStyle objects
02806     m_styleColl->saveOasis( mainStyles, KoGenStyle::STYLE_USER, savingContext );
02807 
02808     QByteArray headerFooterContent;
02809     if ( saveFlag == SaveAll )
02810     {
02811         // Save visual info for the first view, such as the active frameset and cursor position
02812         // It looks like a hack, but reopening a document creates only one view anyway (David)
02813         KWView * view = static_cast<KWView*>(views().getFirst());
02814         if ( view ) // no view if embedded document
02815         {
02816             KWFrameSetEdit* edit = view->getGUI()->canvasWidget()->currentFrameSetEdit();
02817             if ( edit )
02818             {
02819                 KWTextFrameSetEdit* textedit = dynamic_cast<KWTextFrameSetEdit *>(edit);
02820                 if ( textedit && textedit->cursor() ) {
02821                     KoTextCursor* cursor = textedit->cursor();
02822                     savingContext.setCursorPosition( cursor->parag(),
02823                                                      cursor->index() );
02824                 }
02825             }
02826         }
02827 
02828         // Header and footers save their content into master-styles/master-page, and their
02829         // styles into the page-layout automatic-style.
02830         // However the paragraph styles used by header/footers need to be known before
02831         // hand, to promote them to styles.xml. So we collect them first, which means
02832         // storing the content into a buffer.
02833         QBuffer buffer( headerFooterContent );
02834         buffer.open( IO_WriteOnly );
02835         KoXmlWriter headerFooterTmpWriter( &buffer );  // TODO pass indentation level
02836         QPtrListIterator<KWFrameSet> fit = framesetsIterator();
02837         // ## This loop is duplicated in saveOasisDocumentStyles
02838         for ( ; fit.current() ; ++fit ) {
02839             const KWFrameSet* fs = fit.current();
02840             if ( fs->isVisible() && // HACK to avoid saving [hidden] headers/footers framesets for now
02841                  !fs->isFloating() &&
02842                  !fs->isDeleted() &&
02843                  fs->type() == FT_TEXT &&
02844                  fs->isHeaderOrFooter() )
02845             {
02846                 // Save content
02847                 headerFooterTmpWriter.startElement( fs->headerFooterTag() ); // e.g. style:header
02848                 static_cast<const KWTextFrameSet *>(fs)->saveOasisContent( headerFooterTmpWriter, savingContext );
02849                 headerFooterTmpWriter.endElement();
02850             }
02851         }
02852         // Add trailing '0'  (Qt4: remove)
02853         headerFooterContent.resize( headerFooterContent.size() + 1 );
02854         headerFooterContent[headerFooterContent.size()-1] = '\0';
02855 
02856         // Now mark all autostyles as "for styles.xml" since headers/footers need them
02857         QValueList<KoGenStyles::NamedStyle> autoStyles = mainStyles.styles( KoGenStyle::STYLE_AUTO );
02858         for ( QValueList<KoGenStyles::NamedStyle>::const_iterator it = autoStyles.begin();
02859               it != autoStyles.end(); ++it ) {
02860             mainStyles.markStyleForStylesXml( (*it).name );
02861         }
02862     }
02863 
02864     KoXmlWriter* bodyWriter = oasisStore.bodyWriter();
02865     bodyWriter->startElement( "office:body" );
02866     bodyWriter->startElement( "office:text" );
02867 
02868     if ( saveFlag == SaveAll )
02869     {
02870         // save the body into bodyWriter
02871         saveOasisBody( *bodyWriter, savingContext );
02872     }
02873     else // SaveSelected
02874     {
02875         // In theory we should pass a view to this method, in order to
02876         // copy what is currently selected in that view only. But selection
02877         // is currently part of the KoTextParag data, so it's shared between views.
02878         if ( fs ) {
02879             *plainText = fs->textDocument()->copySelection( *bodyWriter, savingContext, KoTextDocument::Standard );
02880             // Collect inline framesets for e.g. pictures
02881             KWCollectFramesetsVisitor visitor;
02882             fs->textDocument()->visitSelection( KoTextDocument::Standard, &visitor );
02883             const QValueList<KWFrameSet *>& frameset = visitor.frameSets();
02884             kdDebug(32001) << frameset.count() << " inline framesets" << endl;
02885             for ( QValueList<KWFrameSet *>::ConstIterator it = frameset.begin(); it != frameset.end(); ++it )
02886             {
02887                 switch ( (*it)->type() ) {
02888                 case FT_PICTURE:
02889                 {
02890                     const KoPictureKey key = static_cast<KWPictureFrameSet *>( *it )->key();
02891                     if ( !pictureList.contains( key ) )
02892                         pictureList.append( key );
02893                 }
02894                 break;
02895                 case FT_PART:
02896                     // TODO
02897                 default:
02898                     break;
02899                 }
02900             }
02901         }
02902 
02903         // write selected (non-inline) frames
02904         QString newText;
02905         saveSelectedFrames( *bodyWriter, savingContext, pictureList,
02906                             selectedFrames, &newText ); // output vars
02907         *plainText += newText;
02908         // Single image -> return it
02909         if ( picture && pictureList.count() == 1 )
02910         {
02911             *picture = m_pictureCollection->findPicture( pictureList.first() );
02912         }
02913     }
02914 
02915     bodyWriter->endElement(); // office:text
02916     bodyWriter->endElement(); // office:body
02917 
02918     savingContext.writeFontFaces( *contentWriter );
02919     contentWriter->startElement( "office:automatic-styles" );
02920     KWOasisSaver::writeAutomaticStyles( *contentWriter, mainStyles, false );
02921     contentWriter->endElement(); // office:automatic-styles
02922 
02923     oasisStore.closeContentWriter();
02924 
02925     // Done with content.xml
02926 
02927     if ( !store->open( "styles.xml" ) )
02928         return false;
02929     manifestWriter->addManifestEntry( "styles.xml", "text/xml" );
02930     saveOasisDocumentStyles( store, mainStyles, savingContext, saveFlag, headerFooterContent );
02931     if ( !store->close() ) // done with styles.xml
02932         return false;
02933 
02934     //kdDebug(32001) << "saveOasis: " << pictureList.count() << " pictures" << endl;
02935     m_pictureCollection->saveOasisToStore( store, pictureList, manifestWriter );
02936 
02937     if ( saveFlag == SaveSelected ) {
02938         // Save embedded objects - code inspired from KoDocument::saveChildrenOasis,
02939         // for the case where we're saving only some embedded objects, like with Ctrl+C.
02940 
02941         // IMPORTANT: This must be done *after* we're done with writing content.xml,
02942         // not while writing it (like in saveSelectedFrames).
02943         // We can't be writing to two files at the same time.
02944 
02945         QValueList<KoDocumentChild*> embeddedObjects;
02946         QValueListConstIterator<KWFrameView*> framesIterator = selectedFrames.begin();
02947         for(; framesIterator != selectedFrames.end(); ++framesIterator) {
02948             KWFrame *frame = (*framesIterator)->frame();
02949             KWFrameSet *fs = frame->frameSet();
02950             if ( fs->isVisible() && fs->type() == FT_PART) {
02951                 embeddedObjects.append( static_cast<KWPartFrameSet *>(fs)->getChild() );
02952             }
02953         }
02954 
02955         QValueList<KoDocumentChild *>::const_iterator chl = embeddedObjects.begin();
02956         for( ; chl != embeddedObjects.end(); ++chl ) {
02957             if ( !(*chl)->saveOasis( store, manifestWriter ) )
02958                 return false;
02959         }
02960     }
02961 
02962     if ( saveFlag == SaveAll )
02963     {
02964 
02965         if(!store->open("settings.xml"))
02966             return false;
02967 
02968         KoStoreDevice contentDev( store );
02969         KoXmlWriter* settingsWriter = createOasisXmlWriter(&contentDev, "office:document-settings");
02970         saveOasisSettings( *settingsWriter );
02971         delete settingsWriter;
02972 
02973         if(!store->close())
02974             return false;
02975 
02976         manifestWriter->addManifestEntry("settings.xml", "text/xml");
02977     }
02978     return true;
02979 }
02980 
02981 // can't be const due to recalcVariables()
02982 QDragObject* KWDocument::dragSelected( const QValueList<KWFrameView*> &selectedFrames) {
02983     return dragSelectedPrivate(0, selectedFrames, 0);
02984 }
02985 // can't be const due to recalcVariables()
02986 QDragObject* KWDocument::dragSelected( QWidget *parent, KWTextFrameSet* fs) {
02987     QValueList<KWFrameView*> noFrames;
02988     return dragSelectedPrivate(parent, noFrames, fs);
02989 }
02990 // can't be const due to recalcVariables()
02991 QDragObject* KWDocument::dragSelectedPrivate( QWidget *parent, const QValueList<KWFrameView*> &selectedFrames, KWTextFrameSet* fs)
02992 {
02993     // We'll create a store (ZIP format) in memory
02994     QBuffer buffer;
02995     QCString mimeType = KWOasisSaver::selectionMimeType();
02996     KoStore* store = KoStore::createStore( &buffer, KoStore::Write, mimeType );
02997     Q_ASSERT( store );
02998     Q_ASSERT( !store->bad() );
02999     KoOasisStore oasisStore( store );
03000 
03001     KoXmlWriter* manifestWriter = oasisStore.manifestWriter( mimeType );
03002 
03003     QString plainText;
03004     KoPicture picture;
03005     if ( !saveOasisHelper( store, manifestWriter, KWDocument::SaveSelected, selectedFrames, &plainText, &picture, fs )
03006          || !oasisStore.closeManifestWriter() )
03007     {
03008         delete store;
03009         return 0;
03010     }
03011 
03012     delete store;
03013 
03014     KMultipleDrag* multiDrag = new KMultipleDrag( parent );
03015     if ( !plainText.isEmpty() )
03016         multiDrag->addDragObject( new QTextDrag( plainText, 0 ) );
03017     if ( !picture.isNull() )
03018         multiDrag->addDragObject( picture.dragObject( 0 ) );
03019     KoStoreDrag* storeDrag = new KoStoreDrag( KWOasisSaver::selectionMimeType(), 0 );
03020     kdDebug() << k_funcinfo << "setting zip data: " << buffer.buffer().size() << " bytes." << endl;
03021     storeDrag->setEncodedData( buffer.buffer() );
03022     multiDrag->addDragObject( storeDrag );
03023     return multiDrag;
03024 }
03025 
03026 void KWDocument::saveSelectedFrames( KoXmlWriter& bodyWriter, KoSavingContext& savingContext, QValueList<KoPictureKey>& pictureList, const QValueList<KWFrameView*> &selectedFrames, QString* plainText ) const {
03027     QPtrList<KoDocumentChild> embeddedObjects;
03028     QValueListConstIterator<KWFrameView*> framesIterator = selectedFrames.begin();
03029     for(; framesIterator != selectedFrames.end(); ++framesIterator) {
03030         KWFrame *frame = (*framesIterator)->frame();
03031         KWFrameSet *fs = frame->frameSet();
03032         if ( fs->isVisible() && fs->type() == FT_PART) {
03033             embeddedObjects.append( static_cast<KWPartFrameSet *>(fs)->getChild() );
03034         }
03035         bool isTable = fs->type() == FT_TABLE;
03036 
03037         // Two cases to be distinguished here
03038         // If it's the first frame of a frameset, then copy the frameset contents and the frame itself
03039         // Otherwise copy only the frame information
03040         if ( frame == fs->frame(0) || isTable ) {
03041             fs->saveOasis( bodyWriter, savingContext, false );
03042             if ( plainText )
03043                 *plainText += fs->toPlainText();
03044         }
03045         else if ( !isTable ) {
03046 #if 0
03047             // Save the frame information
03048             QDomElement frameElem = parentElem.ownerDocument().createElement( "FRAME" );
03049             parentElem.appendChild( frameElem );
03050             frame->save( frameElem );
03051             if ( frame != firstFrame )
03052             {
03053                 // Frame saved alone -> remember which frameset it's part of
03054                 frameElem.setAttribute( "parentFrameset", fs->name() );
03055             }
03056 #endif
03057         }
03058         if ( fs->type() == FT_PICTURE ) {
03059             kdDebug(32001) << "found non-inline picture framesets" << endl;
03060 
03061             const KoPictureKey key = static_cast<KWPictureFrameSet *>( fs )->key();
03062             if ( !pictureList.contains( key ) )
03063                 pictureList.append( key );
03064         }
03065         if ( isTable ) // Copy tables only once, even if they have many cells selected
03066             break;
03067     }
03068 }
03069 
03070 void KWDocument::saveOasisSettings( KoXmlWriter& settingsWriter ) const
03071 {
03072     settingsWriter.startElement("office:settings");
03073     settingsWriter.startElement("config:config-item-set");
03074 
03075     settingsWriter.addAttribute("config:name", "view-settings");
03076 
03077     KoUnit::saveOasis(&settingsWriter, unit());
03078 
03079     settingsWriter.endElement(); // config:config-item-set
03080 
03081     settingsWriter.startElement("config:config-item-set");
03082     settingsWriter.addAttribute("config:name", "configuration-settings");
03083     settingsWriter.addConfigItem("SpellCheckerIgnoreList", m_spellCheckIgnoreList.join( "," ) );
03084     settingsWriter.endElement(); // config:config-item-set
03085 
03086     m_varColl->variableSetting()->saveOasis( settingsWriter );
03087 
03088     settingsWriter.endElement(); // office:settings
03089     settingsWriter.endElement(); // Root element
03090     settingsWriter.endDocument();
03091 }
03092 
03093 void KWDocument::saveOasisDocumentStyles( KoStore* store, KoGenStyles& mainStyles, KoSavingContext& savingContext, SaveFlag saveFlag, const QByteArray& headerFooterContent ) const
03094 {
03095     if ( saveFlag == SaveAll )
03096     {
03097         m_frameStyleColl->saveOasis( mainStyles, savingContext );
03098         m_tableStyleColl->saveOasis( mainStyles, savingContext );
03099     }
03100 
03101     KoStoreDevice stylesDev( store );
03102     KoXmlWriter* stylesWriter = createOasisXmlWriter( &stylesDev, "office:document-styles" );
03103 
03104     stylesWriter->startElement( "office:styles" );
03105 
03106     if ( saveFlag == SaveAll )
03107     {
03108         stylesWriter->startElement( "style:default-style" );
03109         stylesWriter->addAttribute( "style:family", "paragraph" );
03110         stylesWriter->startElement( "style:paragraph-properties" );
03111         stylesWriter->addAttributePt( "style:tab-stop-distance", m_tabStop );
03112         stylesWriter->endElement(); // paragraph-properties
03113         stylesWriter->endElement(); // default-style
03114     }
03115 
03116     QValueList<KoGenStyles::NamedStyle> styles = mainStyles.styles( KoGenStyle::STYLE_USER );
03117     QValueList<KoGenStyles::NamedStyle>::const_iterator it = styles.begin();
03118     for ( ; it != styles.end() ; ++it ) {
03119         (*it).style->writeStyle( stylesWriter, mainStyles, "style:style", (*it).name, "style:paragraph-properties" );
03120     }
03121     styles = mainStyles.styles( KWDocument::STYLE_FRAME_USER );
03122     it = styles.begin();
03123     for ( ; it != styles.end() ; ++it ) {
03124         (*it).style->writeStyle( stylesWriter, mainStyles, "style:style", (*it).name , "style:graphic-properties"  );
03125     }
03126     styles = mainStyles.styles( KWDocument::STYLE_TABLE_CELL_USER );
03127     it = styles.begin();
03128     for ( ; it != styles.end() ; ++it ) {
03129         (*it).style->writeStyle( stylesWriter, mainStyles, "style:style", (*it).name , "style:table-cell-properties"  );
03130     }
03131     styles = mainStyles.styles( KoGenStyle::STYLE_LIST );
03132     it = styles.begin();
03133     for ( ; it != styles.end() ; ++it ) {
03134         (*it).style->writeStyle( stylesWriter, mainStyles, "text:list-style", (*it).name, 0 );
03135     }
03136     m_styleColl->saveOasisOutlineStyles( *stylesWriter );
03137     if ( saveFlag == SaveAll )
03138         static_cast<KWVariableSettings *>( m_varColl->variableSetting() )->saveNoteConfiguration( *stylesWriter );
03139     stylesWriter->endElement(); // office:styles
03140 
03141     QString pageLayoutName;
03142     if ( saveFlag == SaveAll )
03143     {
03144         stylesWriter->startElement( "office:automatic-styles" );
03145 
03146         KoGenStyle pageLayout = m_pageLayout.saveOasis();
03147         pageLayout.addAttribute( "style:page-usage", "all" ); // needed?
03148         // This is for e.g. spreadsheets, not for word-processors.
03149         //pageLayout.addProperty( "style:first-page-number", m_varColl->variableSetting()->startingPage() );
03150 
03151         if ( m_processingType == WP )
03152         {
03153             KWTextFrameSet *frameset = dynamic_cast<KWTextFrameSet *>( m_lstFrameSet.getFirst() );
03154             if ( frameset ) {
03155                 frameset->frame(0)->saveBorderProperties( pageLayout );
03156             }
03157         }
03158 
03159         QBuffer buffer;
03160         buffer.open( IO_WriteOnly );
03161         KoXmlWriter footnoteSepTmpWriter( &buffer );  // TODO pass indentation level
03162         footnoteSepTmpWriter.startElement( "style:footnote-sep" );
03163         QString tmp;
03164         switch( m_footNoteSeparatorLinePos )
03165         {
03166         case SLP_CENTERED:
03167             tmp = "centered";
03168             break;
03169         case SLP_RIGHT:
03170             tmp = "right";
03171             break;
03172         case SLP_LEFT:
03173             tmp = "left";
03174             break;
03175         }
03176 
03177         footnoteSepTmpWriter.addAttribute( "style:adjustment", tmp );
03178         footnoteSepTmpWriter.addAttributePt( "style:width", m_footNoteSeparatorLineWidth );
03179         footnoteSepTmpWriter.addAttribute( "style:rel-width", QString::number( footNoteSeparatorLineLength() ) + "%" );
03180         switch( m_footNoteSeparatorLineType )
03181         {
03182         case SLT_SOLID:
03183             tmp = "solid";
03184             break;
03185         case SLT_DASH:
03186             tmp = "dash";
03187             break;
03188         case SLT_DOT:
03189             tmp = "dotted";
03190             break;
03191         case SLT_DASH_DOT:
03192             tmp = "dot-dash";
03193             break;
03194         case SLT_DASH_DOT_DOT:
03195             tmp = "dot-dot-dash";
03196             break;
03197         }
03198 
03199         footnoteSepTmpWriter.addAttribute( "style:line-style", tmp );
03200 
03201         footnoteSepTmpWriter.endElement();
03202         const QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
03203         pageLayout.addChildElement( "separator", elementContents );
03204         buffer.close();
03205 
03206         if ( m_pageColumns.columns > 1 ) {
03207             buffer.setBuffer( QByteArray() ); // clear data
03208             buffer.open( IO_WriteOnly );
03209             KoXmlWriter columnsTmpWriter( &buffer );  // TODO pass indentation level
03210             columnsTmpWriter.startElement( "style:columns" );
03211             columnsTmpWriter.addAttribute( "fo:column-count", m_pageColumns.columns );
03212             columnsTmpWriter.addAttributePt( "fo:column-gap", m_pageColumns.ptColumnSpacing );
03213             columnsTmpWriter.endElement(); // style:columns
03214             buffer.close();
03215             const QString elementContents = QString::fromUtf8( buffer.buffer(), buffer.buffer().size() );
03216             pageLayout.addChildElement( "columns", elementContents );
03217         }
03218 
03219         // This is a bit of a hack, which only works as long as we have only one page master
03220         // if there's more than one pagemaster we need to rethink all this
03221 
03222         pageLayoutName = mainStyles.lookup( pageLayout, "pm" );
03223         pageLayout.writeStyle( stylesWriter, mainStyles, "style:page-layout", pageLayoutName,
03224                                "style:page-layout-properties", false /*don't close*/ );
03225 
03226         // Ouch another problem: there is only one header style in oasis
03227         // ##### can't have different borders for even/odd headers...
03228         bool headerStyleSaved = false;
03229         bool footerStyleSaved = false;
03230         // ## This loop is duplicated in saveOasis
03231         QPtrListIterator<KWFrameSet> fit = framesetsIterator();
03232         for ( ; fit.current() ; ++fit ) {
03233             const KWFrameSet* fs = fit.current();
03234             if ( fs->isVisible() && // HACK to avoid saving [hidden] headers/footers framesets for now
03235                  !fs->isFloating() &&
03236                  !fs->isDeleted() &&
03237                  fs->type() == FT_TEXT &&
03238                  fs->isHeaderOrFooter() )
03239             {
03240                 // Save header/footer style
03241                 KWFrame* frame = fs->frame(0);
03242                 if ( fs->isAHeader() ) {
03243                     if ( headerStyleSaved )
03244                         continue;
03245                     headerStyleSaved = true;
03246                     stylesWriter->startElement( "style:header-style" );
03247                 } else {
03248                     if ( footerStyleSaved )
03249                         continue;
03250                     footerStyleSaved = true;
03251                     stylesWriter->startElement( "style:footer-style" );
03252                 }
03253 #if 0 // more code reuse, but harder to integrate
03254                 KoGenStyle hfStyle;
03255                 hfStyle.addPropertyPt( "fo:min-height", frame->minimumFrameHeight() );
03256                 frame->saveBorderProperties( hfStyle );
03257                 frame->saveMarginProperties( hfStyle );
03258                 ...
03259 #endif
03260                 stylesWriter->startElement( "style:header-footer-properties" );
03261                 stylesWriter->addAttributePt( "fo:min-height", frame->minimumFrameHeight() );
03262                 if ( fs->isAHeader() )
03263                     stylesWriter->addAttributePt( "fo:margin-bottom", m_pageHeaderFooter.ptHeaderBodySpacing );
03264                 else
03265                     stylesWriter->addAttributePt( "fo:margin-top", m_pageHeaderFooter.ptFooterBodySpacing );
03266                 // TODO frame->saveBorderAttributes( *stylesWriter );
03267                 // Interesting idea, but we can't set margins (runaround) on
03268                 //frame->saveMarginAttributes( *stylesWriter );
03269                 stylesWriter->endElement(); // header-footer-properties
03270                 stylesWriter->endElement(); // header-style
03271             }
03272         }
03273         stylesWriter->endElement(); // style:page-layout
03274 
03275         // Headers and footers might have created new automatic parag/text styles -> save those
03276         KWOasisSaver::writeAutomaticStyles( *stylesWriter, mainStyles, true );
03277 
03278         stylesWriter->endElement(); // office:automatic-styles
03279     }
03280 
03281 
03282     stylesWriter->startElement( "office:master-styles" );
03283     stylesWriter->startElement( "style:master-page" );
03284     stylesWriter->addAttribute( "style:name", "Standard" );
03285     stylesWriter->addAttribute( "style:page-layout-name", pageLayoutName );
03286 
03287     if ( isHeaderVisible() || isFooterVisible() ) { // ### TODO save them even when hidden (and not empty)?
03288         stylesWriter->addCompleteElement( headerFooterContent.data() );
03289     }
03290 
03291     stylesWriter->endElement();
03292     stylesWriter->endElement(); // office:master-styles
03293 
03294     stylesWriter->endElement(); // root element (office:document-styles)
03295     stylesWriter->endDocument();
03296     delete stylesWriter;
03297 }
03298 
03299 void KWDocument::saveOasisCustomFied( KoXmlWriter &writer )const
03300 {
03301     bool customVariableFound = false;
03302     QPtrListIterator<KoVariable> it( m_varColl->getVariables() );
03303     for ( ; it.current() ; ++it )
03304     {
03305         if ( it.current()->type() == VT_CUSTOM )
03306         {
03307             if ( !customVariableFound )
03308             {
03309                 writer.startElement( "text:user-field-decls" );
03310                 customVariableFound = true;
03311             }
03312             //<text:user-field-decl office:value-type="string" office:string-value="dfddd" text:name="cvbcbcbx"/>
03313             writer.startElement( "text:user-field-decl" );
03314             writer.addAttribute( "office:value-type", "string" );
03315             writer.addAttribute( "office:string-value", static_cast<KoCustomVariable *>( it.current() )->value() );
03316             writer.addAttribute( "text:name", static_cast<KoCustomVariable*>( it.current() )->name() );
03317             writer.endElement();
03318         }
03319     }
03320     if ( customVariableFound )
03321         writer.endElement();
03322 }
03323 
03324 void KWDocument::saveOasisBody( KoXmlWriter& writer, KoSavingContext& context ) const
03325 {
03326     saveOasisCustomFied( writer );
03327     if ( m_processingType == WP ) {
03328 
03329         // Write out the non-inline framesets first; OOo wants it that way...
03330         QPtrListIterator<KWFrameSet> fit = framesetsIterator();
03331         ++fit; // skip main text frameset
03332         for ( ; fit.current() ; ++fit ) {
03333             KWFrameSet* fs = fit.current();
03334             if ( !fs->isFloating() &&
03335                  !fs->isDeleted() &&
03336                 // footnotes already saved inline, header/footers elsewhere
03337                  fs->frameSetInfo() == KWFrameSet::FI_BODY )
03338             {
03339                 fs->saveOasis( writer, context, true );
03340             }
03341         }
03342 
03343         // Write out the main text frameset's contents
03344         KWTextFrameSet *frameset = dynamic_cast<KWTextFrameSet *>( m_lstFrameSet.getFirst() );
03345         if ( frameset ) {
03346             frameset->saveOasisContent( writer, context );
03347         }
03348 
03349     } else { // DTP mode: all framesets are equal
03350         // write text:page-sequence, one item per page.
03351         writer.startElement( "text:page-sequence" );
03352         for ( int page = 0; page < pageCount(); ++page )
03353         {
03354             writer.startElement( "text:page" );
03355             // "pm" is a hack, see mainStyles.lookup( pageLayout, "pm" ) in saveOasis
03356             // [which currently happens afterwards...]
03357             writer.addAttribute( "text:master-page-name", "pm" );
03358             writer.endElement(); // text:page
03359         }
03360         writer.endElement() ; // "text:page-sequence";
03361         // Now write the framesets
03362         QPtrListIterator<KWFrameSet> fit = framesetsIterator();
03363         for ( ; fit.current() ; ++fit ) {
03364             KWFrameSet* fs = fit.current();
03365             if ( !fs->isFloating() &&
03366                  !fs->isDeleted() &&
03367                  fs->frameSetInfo() == KWFrameSet::FI_BODY )
03368             {
03369                 fs->saveOasis( writer, context, true );
03370             }
03371         }
03372      }
03373 }
03374 
03375 QDomDocument KWDocument::saveXML()
03376 {
03377     m_varColl->variableSetting()->setModificationDate(QDateTime::currentDateTime());
03378     recalcVariables( VT_DATE );
03379     recalcVariables( VT_TIME ); // for "current time"
03380     recalcVariables( VT_STATISTIC );
03381     QDomDocument doc = createDomDocument( "DOC", CURRENT_DTD_VERSION );
03382     QDomElement kwdoc = doc.documentElement();
03383     kwdoc.setAttribute( "editor", "KWord" );
03384     kwdoc.setAttribute( "mime", "application/x-kword" );
03385     m_syntaxVersion = CURRENT_SYNTAX_VERSION;
03386     kwdoc.setAttribute( "syntaxVersion", m_syntaxVersion );
03387 
03388     QDomElement paper = doc.createElement( "PAPER" );
03389     kwdoc.appendChild( paper );
03390     paper.setAttribute( "format", static_cast<int>( m_pageLayout.format ) );
03391     paper.setAttribute( "pages", pageCount() );
03392     paper.setAttribute( "width", m_pageLayout.ptWidth );
03393     paper.setAttribute( "height", m_pageLayout.ptHeight );
03394     paper.setAttribute( "orientation", static_cast<int>( m_pageLayout.orientation ) );
03395     paper.setAttribute( "columns", m_pageColumns.columns );
03396     paper.setAttribute( "columnspacing", m_pageColumns.ptColumnSpacing );
03397     paper.setAttribute( "hType", static_cast<int>( m_pageHeaderFooter.header ) );
03398     paper.setAttribute( "fType", static_cast<int>( m_pageHeaderFooter.footer ) );
03399     paper.setAttribute( "spHeadBody", m_pageHeaderFooter.ptHeaderBodySpacing );
03400     paper.setAttribute( "spFootBody", m_pageHeaderFooter.ptFooterBodySpacing );
03401     paper.setAttribute( "spFootNoteBody", m_pageHeaderFooter.ptFootNoteBodySpacing );
03402     if ( m_footNoteSeparatorLinePos!=SLP_LEFT )
03403     {
03404         if (m_footNoteSeparatorLinePos==SLP_CENTERED )
03405             paper.setAttribute( "slFootNotePosition", "centered" );
03406         else if ( m_footNoteSeparatorLinePos==SLP_RIGHT )
03407             paper.setAttribute( "slFootNotePosition", "right" );
03408         else if ( m_footNoteSeparatorLinePos==SLP_LEFT ) //never !
03409             paper.setAttribute( "slFootNotePosition", "left" );
03410     }
03411     if ( m_footNoteSeparatorLineType != SLT_SOLID )
03412         paper.setAttribute( "slFootNoteType", static_cast<int>(m_footNoteSeparatorLineType) );
03413 
03414 
03415     paper.setAttribute("slFootNoteLength", m_iFootNoteSeparatorLineLength);
03416     paper.setAttribute("slFootNoteWidth", m_footNoteSeparatorLineWidth);
03417 
03418     // Now part of the app config
03419     //paper.setAttribute( "zoom",m_zoom );
03420 
03421     QDomElement borders = doc.createElement( "PAPERBORDERS" );
03422     paper.appendChild( borders );
03423     borders.setAttribute( "left", m_pageLayout.ptLeft );
03424     borders.setAttribute( "top", m_pageLayout.ptTop );
03425     borders.setAttribute( "right", m_pageLayout.ptRight );
03426     borders.setAttribute( "bottom", m_pageLayout.ptBottom );
03427 
03428     QDomElement docattrs = doc.createElement( "ATTRIBUTES" );
03429     kwdoc.appendChild( docattrs );
03430     docattrs.setAttribute( "processing", static_cast<int>( m_processingType ) );
03431     docattrs.setAttribute( "standardpage", 1 );
03432     docattrs.setAttribute( "hasHeader", static_cast<int>(isHeaderVisible()) );
03433     docattrs.setAttribute( "hasFooter", static_cast<int>(isFooterVisible()) );
03434     docattrs.setAttribute( "unit", KoUnit::unitName(unit()) );
03435     docattrs.setAttribute( "hasTOC", static_cast<int>(m_hasTOC));
03436     docattrs.setAttribute( "tabStopValue", m_tabStop );
03437 
03438     // Save visual info for the first view, such as the active frameset and cursor position
03439     // It looks like a hack, but reopening a document creates only one view anyway (David)
03440     KWView * view = static_cast<KWView*>(views().getFirst());
03441     if ( view ) // no view if embedded document
03442     {
03443         KWFrameSetEdit* edit = view->getGUI()->canvasWidget()->currentFrameSetEdit();
03444         if ( edit )
03445         {
03446             docattrs.setAttribute( "activeFrameset", edit->frameSet()->name() );
03447             KWTextFrameSetEdit* textedit = dynamic_cast<KWTextFrameSetEdit *>(edit);
03448             if ( textedit && textedit->cursor() ) {
03449                 KoTextCursor* cursor = textedit->cursor();
03450                 docattrs.setAttribute( "cursorParagraph", cursor->parag()->paragId() );
03451                 docattrs.setAttribute( "cursorIndex", cursor->index() );
03452             }
03453         }
03454     }
03455 
03456     if( !m_bookmarkList->isEmpty() )
03457     {
03458         QDomElement bookmark = doc.createElement( "BOOKMARKS" );
03459         kwdoc.appendChild( bookmark );
03460 
03461         for ( KoTextBookmarkList::const_iterator it = m_bookmarkList->begin();
03462               it != m_bookmarkList->end() ; ++it )
03463         {
03464             const KoTextBookmark& book = *it;
03465             KWTextFrameSet* fs = static_cast<KWTextDocument*>(book.textDocument())->textFrameSet();
03466             if ( book.startParag() &&
03467                  book.endParag() &&
03468                  fs && !fs->isDeleted() )
03469             {
03470                 QDomElement bookElem = doc.createElement( "BOOKMARKITEM" );
03471                 bookmark.appendChild( bookElem );
03472                 bookElem.setAttribute( "name", book.bookmarkName() );
03473                 bookElem.setAttribute( "frameset", fs->name() );
03474                 bookElem.setAttribute( "startparag", book.startParag()->paragId() );
03475                 bookElem.setAttribute( "endparag", book.endParag()->paragId() );
03476 
03477                 bookElem.setAttribute( "cursorIndexStart", book.bookmarkStartIndex() );
03478                 bookElem.setAttribute( "cursorIndexEnd", book.bookmarkEndIndex() );
03479             }
03480         }
03481     }
03482     variableCollection()->variableSetting()->save(kwdoc );
03483 
03484     QDomElement framesets = doc.createElement( "FRAMESETS" );
03485     kwdoc.appendChild( framesets );
03486 
03487     m_textImageRequests.clear(); // for KWTextImage
03488     QValueList<KoPictureKey> savePictures;
03489 
03490     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
03491     for ( ; fit.current() ; ++fit )
03492     {
03493         KWFrameSet *frameSet = fit.current();
03494         // Save non-part framesets ( part are saved further down )
03495         if ( frameSet->type() != FT_PART )
03496             frameSet->save( framesets );
03497 
03498         // If picture frameset, make a note of the image it needs.
03499         if ( !frameSet->isDeleted() && ( frameSet->type() == FT_PICTURE ) )
03500         {
03501             KoPictureKey key = static_cast<KWPictureFrameSet *>( frameSet )->key();
03502             if ( !savePictures.contains( key ) )
03503                 savePictures.append( key );
03504         }
03505     }
03506 
03507     // Process the data of the KWTextImage classes.
03508     QPtrListIterator<KWTextImage> textIt ( m_textImageRequests );
03509     for ( ; textIt.current() ; ++textIt )
03510     {
03511         KoPictureKey key = textIt.current()->getKey();
03512         kdDebug(32001) << "KWDocument::saveXML registering text image " << key.toString() << endl;
03513         if ( !savePictures.contains( key ) )
03514             savePictures.append( key );
03515     }
03516 
03517     QDomElement styles = doc.createElement( "STYLES" );
03518     kwdoc.appendChild( styles );
03519     QValueList<KoUserStyle *> styleList(m_styleColl->styleList());
03520     for ( QValueList<KoUserStyle *>::const_iterator it = styleList.begin(), end = styleList.end();
03521           it != end ; ++it )
03522         saveStyle( static_cast<KoParagStyle *>( *it ), styles );
03523 
03524     QDomElement frameStyles = doc.createElement( "FRAMESTYLES" );
03525     kwdoc.appendChild( frameStyles );
03526     QValueList<KoUserStyle *> frameStyleList(m_frameStyleColl->styleList());
03527     for ( QValueList<KoUserStyle *>::const_iterator it = frameStyleList.begin(), end = frameStyleList.end();
03528           it != end ; ++it )
03529         saveFrameStyle( static_cast<KWFrameStyle *>(*it), frameStyles );
03530 
03531     QDomElement tableStyles = doc.createElement( "TABLESTYLES" );
03532     kwdoc.appendChild( tableStyles );
03533     QValueList<KoUserStyle *> tableStyleList(m_tableStyleColl->styleList());
03534     for ( QValueList<KoUserStyle *>::const_iterator it = tableStyleList.begin(), end = tableStyleList.end();
03535           it != end ; ++it )
03536         saveTableStyle( static_cast<KWTableStyle *>(*it), tableStyles );
03537 
03538     QDomElement pictures = m_pictureCollection->saveXML( KoPictureCollection::CollectionPicture, doc, savePictures );
03539     kwdoc.appendChild( pictures );
03540 
03541     // Not needed anymore
03542 #if 0
03543     // Write out the list of parags (id) that form the table of contents, see KWContents::createContents
03544     if ( contents->hasContents() ) {
03545         QDomElement cParags = doc.createElement( "CPARAGS" );
03546         kwdoc.appendChild( cParags );
03547         QValueList<int>::Iterator it = contents->begin();
03548         for ( ; it != contents->end(); ++it )
03549         {
03550             QDomElement paragElem = doc.createElement( "PARAG" );
03551             cParags.appendChild( paragElem );
03552             paragElem.setAttribute( "name", QString::number( *it ) ); // write parag id
03553         }
03554     }
03555 #endif
03556 
03557     QDomElement mailMerge=m_slDataBase->save(doc);
03558     kwdoc.appendChild(mailMerge);
03559 
03560     if( !m_spellCheckIgnoreList.isEmpty() )
03561     {
03562         QDomElement spellCheckIgnore = doc.createElement( "SPELLCHECKIGNORELIST" );
03563         kwdoc.appendChild( spellCheckIgnore );
03564         for ( QStringList::ConstIterator it = m_spellCheckIgnoreList.begin(); it != m_spellCheckIgnoreList.end(); ++it )
03565         {
03566             QDomElement spellElem = doc.createElement( "SPELLCHECKIGNOREWORD" );
03567             spellCheckIgnore.appendChild( spellElem );
03568             spellElem.setAttribute( "word", *it );
03569         }
03570     }
03571 
03572     // Save embedded objects
03573     saveEmbeddedObjects( kwdoc, children() );
03574     return doc;
03575 }
03576 
03577 // KWord-1.3 format
03578 void KWDocument::saveEmbeddedObjects( QDomElement& parentElem, const QPtrList<KoDocumentChild>& childList )
03579 {
03580     // Write "OBJECT" tag for every child, appending "EMBEDDING" tags to the main XML
03581     QPtrListIterator<KoDocumentChild> chl( childList );
03582     QDomDocument doc = parentElem.ownerDocument();
03583     for( ; chl.current(); ++chl ) {
03584         KWDocumentChild* curr = static_cast<KWDocumentChild*>(chl.current());
03585         if ( !curr->isDeleted() )
03586         {
03587             QDomElement embeddedElem = doc.createElement( "EMBEDDED" );
03588             parentElem.appendChild( embeddedElem );
03589 
03590             QDomElement objectElem = curr->save( doc, true );
03591             embeddedElem.appendChild( objectElem );
03592 
03593             QDomElement settingsElem = doc.createElement( "SETTINGS" );
03594             embeddedElem.appendChild( settingsElem );
03595 
03596             curr->partFrameSet()->save( settingsElem );
03597         }
03598     }
03599 }
03600 
03601 // KWord-1.3 format
03602 void KWDocument::saveStyle( KoParagStyle *sty, QDomElement parentElem )
03603 {
03604     QDomDocument doc = parentElem.ownerDocument();
03605     QDomElement styleElem = doc.createElement( "STYLE" );
03606     parentElem.appendChild( styleElem );
03607 
03608     sty->saveStyle( styleElem );
03609 
03610     QDomElement formatElem = KWTextParag::saveFormat( doc, &sty->format(), 0L, 0, 0 );
03611     styleElem.appendChild( formatElem );
03612 }
03613 
03614 // KWord-1.3 format
03615 void KWDocument::saveFrameStyle( KWFrameStyle *sty, QDomElement parentElem )
03616 {
03617     QDomDocument doc = parentElem.ownerDocument();
03618     QDomElement frameStyleElem = doc.createElement( "FRAMESTYLE" );
03619     parentElem.appendChild( frameStyleElem );
03620 
03621     sty->saveFrameStyle( frameStyleElem );
03622 }
03623 
03624 // KWord-1.3 format
03625 void KWDocument::saveTableStyle( KWTableStyle *sty, QDomElement parentElem )
03626 {
03627     QDomDocument doc = parentElem.ownerDocument();
03628     QDomElement tableStyleElem = doc.createElement( "TABLESTYLE" );
03629     parentElem.appendChild( tableStyleElem );
03630 
03631     sty->saveTableStyle( tableStyleElem );
03632 }
03633 
03634 
03635 QValueList<KoPictureKey> KWDocument::savePictureList()
03636 {
03637     QValueList<KoPictureKey> savePictures;
03638 
03639     // At first, we must process the data of the KWTextImage classes.
03640     // Process the data of the KWTextImage classes.
03641     QPtrListIterator<KWTextImage> textIt ( m_textImageRequests );
03642     for ( ; textIt.current() ; ++textIt )
03643     {
03644         KoPictureKey key = textIt.current()->getKey();
03645         kdDebug(32001) << "KWDocument::saveXML registering text image " << key.toString() << endl;
03646         if ( !savePictures.contains( key ) )
03647             savePictures.append( key );
03648     }
03649     m_textImageRequests.clear(); // Save some memory!
03650 
03651     // Now do the images/cliparts in frames.
03652     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
03653     for ( ; fit.current() ; ++fit )
03654     {
03655         KWFrameSet *frameSet = fit.current();
03656         // If picture frameset, make a note of the image it needs.
03657         if ( !frameSet->isDeleted() && ( frameSet->type() == FT_PICTURE ) )
03658         {
03659             KoPictureKey key = static_cast<KWPictureFrameSet *>( frameSet )->key();
03660             if ( !savePictures.contains( key ) )
03661                 savePictures.append( key );
03662         }
03663     }
03664     return savePictures;
03665 }
03666 
03667 // KWord-1.3 format
03668 bool KWDocument::completeSaving( KoStore *store )
03669 {
03670     if ( !store )
03671         return TRUE;
03672 
03673     QString u = KURL( url() ).path();
03674 
03675     QValueList<KoPictureKey> savePictures( savePictureList() );
03676 
03677     return m_pictureCollection->saveToStore( KoPictureCollection::CollectionPicture, store, savePictures );
03678 }
03679 
03680 int KWDocument::supportedSpecialFormats() const
03681 {
03682     return KoDocument::supportedSpecialFormats();
03683 }
03684 
03685 void KWDocument::addView( KoView *view )
03686 {
03687     m_lstViews.append( (KWView*)view );
03688     KoDocument::addView( view );
03689     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it ) {
03690         (*it)->deselectAllFrames();
03691     }
03692 }
03693 
03694 void KWDocument::removeView( KoView *view )
03695 {
03696     m_lstViews.remove( static_cast<KWView*>(view) );
03697     KoDocument::removeView( view );
03698 }
03699 
03700 void KWDocument::addShell( KoMainWindow *shell )
03701 {
03702     connect( shell, SIGNAL( documentSaved() ), m_commandHistory, SLOT( documentSaved() ) );
03703     connect( shell, SIGNAL( saveDialogShown() ), this, SLOT( saveDialogShown() ) );
03704     KoDocument::addShell( shell );
03705 }
03706 
03707 KoView* KWDocument::createViewInstance( QWidget* parent, const char* name )
03708 {
03709     if ( isEmbedded() )
03710         return new KWView( "ModeEmbedded", parent, name, this );
03711     else
03712         return new KWView( m_viewModeType, parent, name, this );
03713 }
03714 
03715 // Paint this document when it's embedded
03716 // This is also used to paint the preview.png that goes into the ZIP file
03717 void KWDocument::paintContent( QPainter& painter, const QRect& rectangle, bool transparent, double zoomX, double zoomY )
03718 {
03719     //kdDebug(32001) << "KWDocument::paintContent m_zoom=" << m_zoom << " zoomX=" << zoomX << " zoomY=" << zoomY << " transparent=" << transparent << " rectangle=" << rectangle << endl;
03720     Q_ASSERT( zoomX != 0 );
03721     Q_ASSERT( zoomY != 0 );
03722 
03723     setZoom( 100 );
03724     m_zoomMode = KoZoomMode::ZOOM_CONSTANT;
03725 
03726     // The caller doesn't care about DPI, that's our own internal zooming done on top of it:
03727     zoomX *= POINT_TO_INCH( static_cast<double>( KoGlobal::dpiX() ) );
03728     zoomY *= POINT_TO_INCH( static_cast<double>( KoGlobal::dpiY() ) );
03729 
03730     if ( m_zoomedResolutionX != zoomX || m_zoomedResolutionY != zoomY )
03731     {
03732         //kdDebug(32001) << "m_zoomedResolutionX=" << m_zoomedResolutionX << " != " << zoomX << " -> calling setResolution(" << zoomX << ")" << endl;
03733         int zoomLevel = qRound( 100 * zoomY / m_zoomedResolutionY ); // ## ignores the case where the x and y scaling differs
03734         setZoom( zoomLevel );
03735         bool forPrint = painter.device() && painter.device()->devType() == QInternal::Printer;
03736         newZoomAndResolution( false, forPrint );
03737         if ( KFormula::Document* formulaDocument = m_formulaDocumentWrapper->document() )
03738             formulaDocument->setZoomAndResolution( zoomLevel, zoomX, zoomY, false, forPrint );
03739         // Note that this zoom and resolution are then used when activating the embedded object!
03740     }
03741 
03742     QRect rect( rectangle );
03743     painter.save();
03744     painter.translate( rect.x(), rect.y() );
03745     QRect clipRect( 0, 0, rect.width(), rect.height() );
03746 
03747     KWViewModeEmbedded * viewMode = new KWViewModeEmbedded( this, 0 /*no canvas*/ );
03748     viewMode->setDrawFrameBackground( !transparent );
03749     viewMode->setDrawSelections( false );
03750 
03751     QColorGroup cg = QApplication::palette().active();
03752 
03753     if (!transparent)
03754     {
03755         QRegion emptyRegion( rect );
03756         createEmptyRegion( rect, emptyRegion, viewMode );
03757         eraseEmptySpace( &painter, emptyRegion, cg.brush( QColorGroup::Base ) );
03758     }
03759 
03760     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
03761     for ( ; fit.current() ; ++fit )
03762     {
03763         KWFrameSet * frameset = fit.current();
03764         if ( frameset->isVisible( viewMode ) && !frameset->isFloating() )
03765             frameset->drawContents( &painter, clipRect, cg,
03766                                     false /*onlyChanged*/, true /*resetChanged*/,
03767                                     0L, viewMode, 0 );
03768     }
03769     delete viewMode;
03770 
03771     painter.restore();
03772 }
03773 
03774 QPixmap KWDocument::generatePreview( const QSize& size )
03775 {
03776     int oldZoom = m_zoom;
03777     double oldResolutionX = resolutionX();
03778     double oldResolutionY = resolutionY();
03779     double oldZoomX = zoomedResolutionX();
03780     double oldZoomY = zoomedResolutionY();
03781 
03782     // Sometimes (due to the different resolution?) the layout creates a new page
03783     // while saving the preview. If this happens, we don't want to repaint the real views
03784     // (due to KWCanvas::slotNewContentsSize)
03785     // ##### One day when we have real doc/view separation in kotextparag, we shouldn't mess with
03786     // the real view's resolution, we should instead create a fake view for the preview itself.
03787     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it ) {
03788         (*it)->getGUI()->canvasWidget()->setUpdatesEnabled( false );
03789     }
03790     Q_ASSERT( !m_bGeneratingPreview );
03791     m_bGeneratingPreview = true;
03792     QPixmap pix = KoDocument::generatePreview(size);
03793 
03794     // Restore everything as it was before
03795     setResolution( oldResolutionX, oldResolutionY );
03796     setZoom( oldZoom );
03797 
03798     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it ) {
03799         (*it)->getGUI()->canvasWidget()->setUpdatesEnabled( true );
03800     }
03801     newZoomAndResolution( true /*set contents size again*/, false );
03802     m_bGeneratingPreview = false;
03803     if ( KFormula::Document* formulaDocument = m_formulaDocumentWrapper->document() ) {
03804         formulaDocument->setZoomAndResolution( oldZoom, oldZoomX, oldZoomY );
03805     }
03806     return pix;
03807 }
03808 
03809 void KWDocument::createEmptyRegion( const QRect & crect, QRegion & emptyRegion, KWViewMode * viewMode )
03810 {
03811     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
03812     for ( ; fit.current() ; ++fit )
03813     {
03814         KWFrameSet *frameset = fit.current();
03815         if ( frameset->isVisible( viewMode ) )
03816             frameset->createEmptyRegion( crect, emptyRegion, viewMode );
03817     }
03818 }
03819 
03820 void KWDocument::eraseEmptySpace( QPainter * painter, const QRegion & emptySpaceRegion, const QBrush & brush )
03821 {
03822     painter->save();
03823     painter->setClipRegion( emptySpaceRegion, QPainter::CoordPainter );
03824     painter->setPen( Qt::NoPen );
03825 
03826     //kdDebug(32001) << "KWDocument::eraseEmptySpace emptySpaceRegion: " << emptySpaceRegion << endl;
03827     //kdDebug(32001) << "                            boundingRect: " << DEBUGRECT( emptySpaceRegion.boundingRect() ) << endl;
03828     painter->fillRect( emptySpaceRegion.boundingRect(), brush );
03829     painter->restore();
03830 }
03831 
03832 KWDocumentChild* KWDocument::createChildDoc( const KoRect& rect, KoDocument* childDoc )
03833 {
03834     KWDocumentChild* ch = new KWDocumentChild( this, rect.toQRect(), childDoc );
03835     insertChild( ch );
03836     return ch;
03837 }
03838 
03839 KWPartFrameSet* KWDocument::insertObject( const KoRect& rect, KoDocumentEntry& e, QWidget* parentWidget )
03840 {
03841     KoDocument* doc = e.createDoc( this );
03842     if ( !doc )
03843         return 0;
03844     if ( !doc->showEmbedInitDialog( parentWidget )  )
03845         return 0;
03846 
03847     KWDocumentChild* ch = createChildDoc( rect, doc );
03848     setModified( TRUE );
03849 
03850     KWPartFrameSet *frameset = new KWPartFrameSet( this, ch, QString::null );
03851     KWFrame *frame = new KWFrame(frameset, rect.x(), rect.y(), rect.width(), rect.height() );
03852     frame->setZOrder( maxZOrder( frame->pageNumber(this) ) + 1 ); // make sure it's on top
03853     frameset->addFrame( frame );
03854     addFrameSet( frameset );
03855 
03856     KWCreateFrameCommand *cmd = new KWCreateFrameCommand( i18n("Create Part Frame"), frame);
03857     addCommand(cmd);
03858 
03859     frameChanged( frame ); // repaint etc.
03860 
03861     return frameset;
03862 }
03863 
03864 
03865 void KWDocument::delayedRepaintAllViews() {
03866     if (!m_repaintAllViewsPending) {
03867         QTimer::singleShot( 0, this, SLOT( slotRepaintAllViews() ) );
03868         m_repaintAllViewsPending=true;
03869     }
03870 }
03871 
03872 void KWDocument::slotRepaintAllViews() {
03873     m_repaintAllViewsPending=false;
03874     repaintAllViews( false );
03875 }
03876 
03877 void KWDocument::delayedRecalcFrames( int fromPage ) {
03878     //kdDebug() << k_funcinfo << fromPage << endl;
03879     if ( m_recalcFramesPending == -1 || fromPage < m_recalcFramesPending )
03880     {
03881         m_recalcFramesPending = fromPage;
03882         QTimer::singleShot( 0, this, SLOT( slotRecalcFrames() ) );
03883     }
03884 }
03885 
03886 void KWDocument::slotRecalcFrames() {
03887     int from = m_recalcFramesPending;
03888     kdDebug() << k_funcinfo << "from=" << from << endl;
03889     m_recalcFramesPending = -1;
03890     if ( from != -1 )
03891         recalcFrames( from );
03892 }
03893 
03894 void KWDocument::repaintAllViewsExcept( KWView *view, bool erase )
03895 {
03896     //kdDebug(32001) << "KWDocument::repaintAllViewsExcept" << endl;
03897     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it ) {
03898         KWView* viewPtr = *it;
03899         if ( viewPtr != view /*&& viewPtr->getGUI() && viewPtr->getGUI()->canvasWidget()*/ ) {
03900             viewPtr->getGUI()->canvasWidget()->repaintAll( erase );
03901         }
03902     }
03903 }
03904 
03905 void KWDocument::updateAllStyleLists()
03906 {
03907     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
03908         (*it)->updateStyleList();
03909 }
03910 
03911 void KWDocument::updateStyleListOrder( const QStringList &list )
03912 {
03913     styleCollection()->updateStyleListOrder( list );
03914 }
03915 
03916 void KWDocument::applyStyleChange( KoStyleChangeDefMap changed )
03917 {
03918     QPtrList<KWTextFrameSet> textFramesets = allTextFramesets( true );
03919 
03920     KWTextFrameSet *frm;
03921     for ( frm=textFramesets.first(); frm != 0; frm=textFramesets.next() ){
03922         frm->applyStyleChange( changed );
03923     }
03924 }
03925 
03926 void KWDocument::updateAllFrameStyleLists()
03927 {
03928     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
03929         (*it)->updateFrameStyleList();
03930 }
03931 
03932 void KWDocument::updateAllTableStyleLists()
03933 {
03934     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
03935         (*it)->updateTableStyleList();
03936 }
03937 
03938 void KWDocument::repaintAllViews( bool erase )
03939 {
03940     //kdDebug(32001) << "KWDocument::repaintAllViews" << endl;
03941     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
03942         (*it)->getGUI()->canvasWidget()->repaintAll( erase );
03943 }
03944 
03945 QPtrList<KWFrame> KWDocument::framesToCopyOnNewPage( int afterPageNum ) const {
03946     // afterPageNum can be -1 for 'before page 1'
03947 
03948     // Look at frames on pages afterPageNum and afterPageNum-1 (for sheetside stuff)
03949     QPtrList<KWFrame> framesToLookAt;
03950     if ( afterPageNum >= startPage() )
03951         framesToLookAt = framesInPage( afterPageNum, false );
03952 
03953     if ( afterPageNum >= startPage() + 1 )
03954     {
03955         QPtrList<KWFrame> framesToAlsoLookAt = framesInPage( afterPageNum-1, false ); // order doesn't matter
03956 
03957         // Merge into single list. Other alternative, two loops, code inside moved to another method.
03958         QPtrListIterator<KWFrame> frameAlsoIt( framesToAlsoLookAt );
03959         for ( ; frameAlsoIt.current(); ++frameAlsoIt )
03960             framesToLookAt.append( frameAlsoIt.current() );
03961     }
03962 
03963     QPtrList<KWFrame> framesToCopy; // the result
03964 
03965     QPtrListIterator<KWFrame> frameIt( framesToLookAt );
03966     for ( ; frameIt.current(); ++frameIt )
03967     {
03968         KWFrame * frame = frameIt.current();
03969         KWFrameSet* frameSet = frame->frameSet();
03970 
03971         // don't add tables! A table cell ( frameset ) _must_ not have cells auto-added to them!
03972         if ( frameSet->type() == FT_TABLE ) continue;
03973 
03974         // NewFrameBehavior == Copy is handled here except for headers/footers, which
03975         // are created in recalcFrames()
03976         if(frameSet->isAHeader() || frameSet->isAFooter()) continue;
03977 
03978 #ifdef DEBUG_PAGES
03979         kdDebug(32002) << "KWDocument::framesToCopyOnNewPage looking at frame " << frame << ", pageNum=" << frame->pageNumber() << " from " << frameSet->name() << endl;
03980         static const char * newFrameBh[] = { "Reconnect", "NoFollowup", "Copy" };
03981         kdDebug(32002) << "   frame->newFrameBehavior()==" << newFrameBh[frame->newFrameBehavior()] << endl;
03982 #endif
03983         const int frameIsOnPage = frame->pageNumber();
03984         if (frame->newFrameBehavior() == KWFrame::Copy &&
03985                 (frameIsOnPage == afterPageNum && frame->sheetSide() == KWFrame::AnySide ||
03986                  frameIsOnPage == afterPageNum -1 && frame->sheetSide() != KWFrame::AnySide))
03987             framesToCopy.append( frame );
03988     }
03989     return framesToCopy;
03990 }
03991 
03992 KWPage* KWDocument::insertPage( int afterPageNum ) // can be -1 for 'before page 0'
03993 {
03994 #ifdef DEBUG_PAGES
03995     kdDebug(32002) << "insertPage: afterPageNum=" << afterPageNum << endl;
03996 #endif
03997     if ( processingType() == WP )
03998         Q_ASSERT( afterPageNum == lastPage() ); // WP mode: can only append.
03999 
04000     double pageHeight = pageManager()->page( afterPageNum )->height();
04001     // If not appending, move down everything after 'afterPageNum', to make room.
04002     for ( int pg = pageCount () -1 ; pg > afterPageNum ; --pg )
04003     {
04004         // pg is the 'src' page. Its contents must be moved to the page pg+1
04005         QPtrList<KWFrame> frames = framesInPage( pg, false );
04006 #ifdef DEBUG_PAGES
04007         kdDebug(32002) << "insertPage: moving " << frames.count() << " frames down, from page " << pg << endl;
04008 #endif
04009         QPtrListIterator<KWFrame> frameIt( frames );
04010         for ( ; frameIt.current(); ++frameIt )
04011             frameIt.current()->moveBy( 0, pageHeight );
04012     }
04013 
04014     KWPage *page = pageManager()->insertPage(afterPageNum+1);
04015 
04016     // Fill in the new page
04017     QPtrList<KWFrame> framesToCopy = framesToCopyOnNewPage( afterPageNum );
04018     QPtrListIterator<KWFrame> frameIt( framesToCopy );
04019     for ( ; frameIt.current(); ++frameIt )
04020     {
04021         KWFrame * frame = frameIt.current();
04022 
04023         KWFrame *newFrame = frame->getCopy();
04024         newFrame->moveBy( 0, pageHeight );
04025         frame->frameSet()->addFrame( newFrame );
04026 
04027         if ( frame->newFrameBehavior()==KWFrame::Copy )
04028             newFrame->setCopy( true );
04029         //kdDebug(32002) << "   => created frame " << newFrame << " " << *newFrame << endl;
04030     }
04031     return page;
04032 }
04033 
04034 KWPage* KWDocument::appendPage()
04035 {
04036 #ifdef DEBUG_PAGES
04037     kdDebug(32002) << "KWDocument::appendPage pageCount()=" << pageCount() << " -> insertPage(" << lastPage() << ")" << endl;
04038 #endif
04039     return insertPage( lastPage() );
04040 }
04041 
04042 void KWDocument::afterInsertPage( int pageNum )
04043 {
04044 #ifdef DEBUG_PAGES
04045     kdDebug(32002) << "KWDocument::afterInsertPage " << pageNum << endl;
04046 #endif
04047     if ( !m_bGeneratingPreview )
04048         emit newContentsSize();
04049 
04050     // Get headers and footers on the new page
04051     // This shouldn't delete the newly created page because it's still empty though
04052     recalcFrames( pageNum, -1, KWFrameLayout::DontRemovePages );
04053     // Take into account the frames on the new page, and run updateFramesOnTopOrBelow (#73819)
04054     updateAllFrames();
04055 
04056     recalcVariables( VT_PGNUM );
04057     emit numPagesChanged();
04058     if ( m_viewModeType == "ModePreview" )
04059         repaintAllViews();
04060 }
04061 
04062 bool KWDocument::canRemovePage( int num )
04063 {
04064 kdDebug() << "KWDocument::canRemovePage " << num<< endl;
04065     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
04066     for ( ; fit.current() ; ++fit )
04067     {
04068         KWFrameSet * frameSet = fit.current();
04069         if ( frameSet->isHeaderOrFooter() ) // don't look at headers/footers, but look at footnotes/endnotes
04070             continue;
04071         if ( frameSet->isVisible() && !frameSet->canRemovePage( num ) )
04072             return false;
04073     }
04074 #ifdef DEBUG_PAGES
04075     kdDebug(32002) << "KWDocument::canRemovePage " << num << "-> TRUE" << endl;
04076 #endif
04077     return true;
04078 }
04079 
04080 void KWDocument::removePage( int pageNum )
04081 {
04082     if ( processingType() == WP )
04083         Q_ASSERT( pageNum == lastPage() ); // WP mode: can only remove last page.
04084     Q_ASSERT( pageCount() > 1 );
04085     if ( pageCount() == 1 )
04086         return;
04087 
04088     // ## This assumes that framesInPage is up-to-date.
04089     QPtrList<KWFrame> framesToDelete = framesInPage( pageNum, false );
04090 #ifdef DEBUG_PAGES
04091     kdDebug(32002) << "KWDocument::removePage " << pageNum << ", " << framesToDelete.count() << " frames to delete" << endl;
04092 #endif
04093     QPtrListIterator<KWFrame> frameIt( framesToDelete );
04094     for ( ; frameIt.current(); ++frameIt )
04095     {
04096         KWFrame * frame = frameIt.current();
04097         KWFrameSet * frameSet = frame->frameSet();
04098         if ( frameSet->frameSetInfo() != KWFrameSet::FI_BODY )
04099             continue;
04100         frameSet->deleteFrame( frame, true );
04101     }
04102 
04103     // If not removing the last one, move up everything after the one we removed.
04104     for ( int pg = pageNum+1 ; pg < pageCount() ; ++pg )
04105     {
04106         // pg is the 'src' page. Its contents must be moved to the page pg-1
04107         QPtrList<KWFrame> frames = framesInPage( pg, false );
04108 #ifdef DEBUG_PAGES
04109         kdDebug(32002) << "removePage: moving " << frames.count() << " frames up, from page " << pg << endl;
04110 #endif
04111         QPtrListIterator<KWFrame> frameIt( frames );
04112         for ( ; frameIt.current(); ++frameIt )
04113             frameIt.current()->moveBy( 0, pageManager()->page(0)->height() );
04114     }
04115 
04116     pageManager()->removePage(pageNum);
04117 #ifdef DEBUG_PAGES
04118     kdDebug(32002) << "KWDocument::removePage -- -> " << pageCount() << endl;
04119 #endif
04120     // Emitting this one for each page being removed helps giving the user some feedback
04121     emit numPagesChanged();
04122 }
04123 
04124 void KWDocument::afterRemovePages()
04125 {
04126     //### IMHO recalcFrames should take care of updateAllFrames (it already does it partially).
04127     recalcFrames();
04128     // Do this before recalcVariables (which repaints). The removed frames must be removed from the frame caches.
04129     // We don't call updateAllFrames() directly, because it still calls
04130     // updateFramesOnTopOrBelow, which is useless (and slow) here.
04131     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
04132     for ( ; fit.current() ; ++fit )
04133         fit.current()->updateFrames();
04134 
04135     recalcVariables( VT_PGNUM );
04136     if ( !m_bGeneratingPreview )
04137         emit newContentsSize();
04138     if ( m_viewModeType == "ModePreview" )
04139         repaintAllViews();
04140 }
04141 
04142 bool KWDocument::tryRemovingPages()
04143 {
04144     int last = lastPage();
04145     bool removed = false;
04146     // Last frame is empty -> try removing last page, and more if necessary
04147     while ( last > startPage() && canRemovePage( last ) )
04148     {
04149         removePage( last ); // this modifies pageCount
04150         if ( last <= lastPage() )
04151         {
04152             kdWarning() << "Didn't manage to remove page " << last << " (still having " << pageCount() << " pages ). Aborting" << endl;
04153             break;
04154         }
04155         removed = true;
04156         last = lastPage();
04157     }
04158     // Don't call afterRemovePages or recalcFrames from here, since this method is
04159     // itself called from KWFrameLayout (#95047)
04160     return removed;
04161 }
04162 
04163 
04164 KWFrameSet * KWDocument::frameSetByName( const QString & name )
04165 {
04166     // Note: this isn't recursive, so it won't find table cells.
04167     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
04168     for ( ; fit.current() ; ++fit )
04169         if ( fit.current()->name() == name )
04170             return fit.current();
04171     return 0L;
04172 }
04173 
04174 //#define DEBUG_FRAMESELECT
04175 
04176 QString KWDocument::generateFramesetName( const QString & templateName )
04177 {
04178     QString name;
04179     int num = 1;
04180     bool exists;
04181     do {
04182         name = templateName.arg( num );
04183         exists = frameSetByName( name );
04184         ++num;
04185     } while ( exists );
04186     return name;
04187 }
04188 
04189 void KWDocument::fixZOrders() {
04190     //KWFrame *frameFixed = 0;
04191     for (int pgnum = startPage() ; pgnum <= lastPage() ; pgnum++) {
04192         QPtrList<KWFrame> frames = framesInPage(pgnum);
04193         // scan this page to see if we need to fixup:
04194         // fix up if two frames have the same zOrder,
04195         // or if a zOrder is negative (not allowed by OASIS)
04196         bool need_fixup = false;
04197         KWFrame *f = frames.last();
04198         if ( !f )
04199             continue;
04200         int lastZOrder = f->zOrder();
04201         f = frames.prev();
04202         for ( ; f ; f=frames.prev() ) {
04203             if ( !f->frameSet()->isFloating() &&
04204                  ( f->zOrder() == lastZOrder || f->zOrder() < 0 ) ) {
04205                 need_fixup = true;
04206                 break;
04207             }
04208             lastZOrder = f->zOrder();
04209         }
04210         if ( need_fixup ) {
04211             int current_zorder=0;
04212             kdDebug() << "fixing page " << pgnum << " z-orders " << endl;
04213             for (KWFrame *fr = frames.first();fr;fr=frames.next()) {
04214                 // only consider non-inline framesets.
04215                 if (fr->frameSet()->isFloating())
04216                     continue;
04217                 current_zorder++;
04218                 fr->setZOrder(current_zorder);
04219                 //frameFixed = f;
04220             }
04221         }
04222 
04223         if ( m_processingType == KWDocument::WP )
04224         {
04225             // In all cases, ensure the main frames are below the rest.
04226             // (This could not be the case after e.g. an import filter does it wrong)
04227             lowerMainFrames( pgnum );
04228         }
04229     }
04230     //if ( frameFixed )
04231     //    frameFixed->frameStack()->recalcAllFrames();
04232     KWFrameList::recalcAllFrames(this);
04233 }
04234 
04235 void KWDocument::lowerMainFrames( int pageNum )
04236 {
04237     QPtrList<KWFrame> framesInPage = this->framesInPage(pageNum);
04238     int lowestZOrder=10000;
04239     for ( QPtrListIterator<KWFrame> frameIt( framesInPage ); frameIt.current(); ++frameIt )
04240         lowestZOrder=QMIN(lowestZOrder, frameIt.current()->zOrder());
04241     lowerMainFrames( pageNum, lowestZOrder );
04242 }
04243 
04244 // separated from the above one for KWView (which knows lowestZOrder already)
04245 void KWDocument::lowerMainFrames( int pageNum, int lowestZOrder )
04246 {
04247     // Get the main frameset and see if we have to lower its frame(s).
04248     QPtrList<KWFrame> framesInPage = this->framesInPage(pageNum);
04249     for ( QPtrListIterator<KWFrame> frameIt( framesInPage ); frameIt.current(); ++frameIt ) {
04250         if(frameIt.current()->frameSet()->isMainFrameset()) {
04251             if(lowestZOrder <= frameIt.current()->zOrder())
04252                 frameIt.current()->setZOrder(lowestZOrder-1);
04253             // keep going, in case of multiple columns
04254         }
04255     }
04256 }
04257 
04258 QPtrList<KWFrame> KWDocument::framesInPage( int pageNum, bool sorted ) const {
04259 
04260     ZOrderedFrameList frames;
04261     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
04262     for ( ; fit.current() ; ++fit )
04263     {
04264         KWFrameSet *frameSet = fit.current();
04265         if ( !frameSet->isVisible() )
04266             continue;
04267         // Append all frames from frameSet in page pageNum
04268         QPtrListIterator<KWFrame> it( frameSet->framesInPage( pageNum ) );
04269         for ( ; it.current() ; ++it )
04270             frames.append( it.current() );
04271     }
04272     if (sorted) frames.sort();
04273     return frames;
04274 }
04275 
04276 void KWDocument::updateAllFrames( int flags )
04277 {
04278 #ifdef DEBUG_SPEED
04279     QTime dt;
04280     dt.start();
04281 #endif
04282     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
04283     for ( ; fit.current() ; ++fit )
04284         fit.current()->updateFrames( flags );
04285 
04286 #ifdef DEBUG_SPEED
04287     kdDebug(32001) << "updateAllFrames(" << flags << ") took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
04288 #endif
04289 
04290     // TODO: check all calls to updateAllFrames, and fix them.
04291     // E.g., if one frame moved, updateAllFrames isn't necessary,
04292     // only fs->updateFrames() and doc->updateFramesOnTopOrBelow() are necessary.
04293 
04294     // Update frames ontop and below _afterwards_,
04295     // it needs the 'frames in page' array (in other framesets)
04296     KWFrameList::recalcAllFrames(this);
04297 }
04298 
04299 // Tell this method when a frame is moved / resized / created / deleted
04300 // and everything will be update / repainted accordingly
04301 void KWDocument::frameChanged( KWFrame * frame )
04302 {
04303     if(! m_framesChangedHandler) {
04304         m_framesChangedHandler = new FramesChangedHandler(this);
04305         QTimer::singleShot( 0, this, SLOT( updateFramesChanged() ) );
04306     }
04307     m_framesChangedHandler->addFrame(frame);
04308 }
04309 
04310 void KWDocument::framesChanged( const QPtrList<KWFrame> & frames, KWView * view )
04311 {
04312     Q_UNUSED( view ); // DF: seems my idea of excluding one view got thrown away
04313     QPtrListIterator<KWFrame> it( frames );
04314     for ( ; it.current() ; ++it )
04315         frameChanged(it.current());
04316 }
04317 
04318 void KWDocument::updateFramesChanged() { // slot called from frameChanged()
04319     if(!m_framesChangedHandler) return;
04320     m_framesChangedHandler->execute();
04321     delete m_framesChangedHandler;
04322     m_framesChangedHandler = 0;
04323 }
04324 
04325 void KWDocument::framesChanged( const QValueList<KWFrame*> &frames) {
04326     QValueListConstIterator<KWFrame*> framesIterator = frames.begin();
04327     for(;framesIterator != frames.end(); ++framesIterator)
04328         frameChanged(*framesIterator);
04329 }
04330 
04331 void KWDocument::setHeaderVisible( bool h )
04332 {
04333     m_headerVisible = h;
04334     recalcFrames();
04335     updateAllFrames();
04336     layout();
04337     setModified(true);
04338     repaintAllViews( true );
04339 }
04340 
04341 void KWDocument::setFooterVisible( bool f )
04342 {
04343     m_footerVisible = f;
04344     recalcFrames();
04345     updateAllFrames();
04346     layout();
04347     setModified(true);
04348     repaintAllViews( true );
04349 }
04350 
04351 bool KWDocument::hasEndNotes() const
04352 {
04353     return m_bHasEndNotes;
04354 }
04355 
04356 void KWDocument::updateHeaderButton()
04357 {
04358     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04359     {
04360         (*it)->updateHeaderFooterButton();
04361         (*it)->updateHeader();
04362     }
04363 }
04364 
04365 void KWDocument::updateFooterButton()
04366 {
04367     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04368     {
04369         (*it)->updateHeaderFooterButton();
04370         (*it)->updateFooter();
04371     }
04372 }
04373 
04374 void KWDocument::addTextImageRequest( KWTextImage *img )
04375 {
04376     m_textImageRequests.append( img );
04377 }
04378 
04379 void KWDocument::addPictureRequest( KWPictureFrameSet *fs )
04380 {
04381     m_pictureRequests.append( fs );
04382 }
04383 
04384 void KWDocument::addAnchorRequest( const QString &framesetName, const KWAnchorPosition &anchorPos )
04385 {
04386     m_anchorRequests.insert( framesetName, anchorPos );
04387 }
04388 
04389 void KWDocument::addFootNoteRequest( const QString &framesetName, KWFootNoteVariable* var )
04390 {
04391     if ( var->noteType() == EndNote )
04392         m_bHasEndNotes = true;
04393     m_footnoteVarRequests.insert( framesetName, var );
04394 }
04395 
04396 void KWDocument::refreshMenuCustomVariable()
04397 {
04398    emit sig_refreshMenuCustomVariable();
04399 }
04400 
04401 void KWDocument::recalcVariables( int type )
04402 {
04403     const QValueList<KoVariable *> modifiedVariables = m_varColl->recalcVariables(type);
04404     if ( m_bGeneratingPreview )
04405         return;
04406 
04407     QMap<KoTextDocument *, bool> modifiedTextDocuments; // Qt4: QSet
04408     for ( QValueList<KoVariable *>::const_iterator it = modifiedVariables.begin(), end = modifiedVariables.end() ; it != end ; ++it ) {
04409         KoTextDocument* textdoc = (*it)->textDocument();
04410         if ( modifiedTextDocuments.find( textdoc ) != modifiedTextDocuments.end() ) // Qt4: !contains
04411         {
04412             modifiedTextDocuments.insert( textdoc, true );
04413             KWTextFrameSet * textfs = static_cast<KWTextDocument *>(textdoc)->textFrameSet();
04414             slotRepaintChanged( textfs );
04415         }
04416     }
04417 }
04418 
04419 int KWDocument::mailMergeRecord() const
04420 {
04421     return slRecordNum;
04422 }
04423 
04424 void KWDocument::setMailMergeRecord( int r )
04425 {
04426     slRecordNum = r;
04427 }
04428 
04429 void KWDocument::getPageLayout( KoPageLayout& layout, KoColumns& cl, KoKWHeaderFooter& hf )
04430 {
04431     layout = m_pageLayout;
04432     cl = m_pageColumns;
04433     hf = m_pageHeaderFooter;
04434 }
04435 
04436 void KWDocument::addFrameSet( KWFrameSet *f, bool finalize /*= true*/ )
04437 {
04438     if(m_lstFrameSet.contains(f) > 0) {
04439         kdWarning(32001) << "Frameset " << f << " " << f->name() << " already in list!" << endl;
04440         return;
04441     }
04442     m_lstFrameSet.append(f);
04443 
04444     KWFrameList::createFrameList(f, this);
04445 
04446     if ( finalize )
04447         f->finalize();
04448     setModified( true );
04449     emit sigFrameSetAdded(f);
04450 }
04451 
04452 void KWDocument::removeFrameSet( KWFrameSet *f )
04453 {
04454     emit sig_terminateEditing( f );
04455     m_lstFrameSet.take( m_lstFrameSet.find(f) );
04456     setModified( true );
04457     emit sigFrameSetRemoved(f);
04458 }
04459 
04460 void KWDocument::addCommand( KCommand * cmd )
04461 {
04462     Q_ASSERT( cmd );
04463     //kdDebug(32001) << "KWDocument::addCommand " << cmd->name() << endl;
04464     m_commandHistory->addCommand( cmd, false );
04465     setModified( true );
04466 }
04467 
04468 void KWDocument::slotDocumentRestored()
04469 {
04470     setModified( false );
04471 }
04472 
04473 void KWDocument::slotCommandExecuted()
04474 {
04475     setModified( true );
04476 }
04477 
04478 #ifndef NDEBUG
04479 void KWDocument::printStyleDebug()
04480 {
04481     kdDebug() << "----------------------------------------"<<endl;
04482     m_styleColl->printDebug();
04483     kdDebug() << m_frameStyleColl->count() << " frame styles" << endl;
04484     kdDebug() << m_tableStyleColl->count() << " table-cell styles" << endl;
04485 }
04486 
04487 void KWDocument::printDebug()
04488 {
04489     kdDebug() << "----------------------------------------"<<endl;
04490     kdDebug() << "                 Debug info"<<endl;
04491     kdDebug() << "Document:" << this <<endl;
04492     kdDebug() << "Type of document: (0=WP, 1=DTP) " << processingType() <<endl;
04493     kdDebug() << "Header visible: " << isHeaderVisible() << endl;
04494     kdDebug() << "Footer visible: " << isFooterVisible() << endl;
04495     kdDebug() << "Units: " << unit() <<endl;
04496     kdDebug() << "# Framesets: " << frameSetCount() <<endl;
04497     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
04498     for ( unsigned int iFrameset = 0; fit.current() ; ++fit, iFrameset++ )
04499     {
04500         KWFrameSet * frameset = fit.current();
04501         kdDebug() << "Frameset " << iFrameset << ": '" <<
04502             frameset->name() << "' (" << frameset << ")" << (frameset->isDeleted()?" Deleted":"")<<endl;
04503         if ( frameset->isVisible())
04504             frameset->printDebug();
04505         else
04506             kdDebug() << "  [hidden] #" << frameset->frameCount() << " frames" << endl;
04507     }
04508 
04509     for ( uint pgNum = 0 ; pgNum < m_sectionTitles.size() ; ++pgNum ) {
04510         kdDebug() << "Page " << pgNum << "  Section: '" << m_sectionTitles[ pgNum ] << "'"<< endl;
04511     }
04512     /*
04513     kdDebug() << "# Images: " << getImageCollection()->iterator().count() <<endl;
04514     QDictIterator<KWImage> it( getImageCollection()->iterator() );
04515     while ( it.current() ) {
04516         kdDebug() << " + " << it.current()->getFilename() << ": "<<it.current()->refCount() <<endl;
04517         ++it;
04518     }
04519     */
04520 
04521     kdDebug() << "PageManager holds "<< pageCount() << " pages in the range: " << startPage() <<
04522         "-" << lastPage() << endl;
04523     for (int pgnum = startPage() ; pgnum <= lastPage() ; pgnum++) {
04524         KWPage *page = pageManager()->page(pgnum);
04525         kdDebug() << "Page " << pgnum << " width=" << page->width() << " height=" << page->height() << endl;
04526     }
04527     kdDebug() << "  The height of the doc (in pt) is: " << pageManager()->
04528         bottomOfPage(lastPage()) << endl;
04529 }
04530 #endif
04531 
04532 void KWDocument::layout()
04533 {
04534     QPtrListIterator<KWFrameSet> it = framesetsIterator();
04535     for (; it.current(); ++it )
04536         if ( it.current()->isVisible() )
04537             it.current()->layout();
04538 }
04539 
04540 void KWDocument::invalidate(const KWFrameSet *skipThisFrameSet)
04541 {
04542     QPtrListIterator<KWFrameSet> it = framesetsIterator();
04543     for (; it.current(); ++it )
04544         if(it.current()!=skipThisFrameSet)
04545             it.current()->invalidate();
04546 }
04547 
04548 KFormula::Document* KWDocument::formulaDocument( bool init )
04549 {
04550     KFormula::Document* formulaDocument = m_formulaDocumentWrapper->document();
04551     if (!formulaDocument) {
04552         kdDebug() << k_funcinfo << endl;
04553         formulaDocument = new KFormula::Document;
04554         m_formulaDocumentWrapper->document( formulaDocument, init );
04555         if ( formulaDocument != 0 ) {
04556             // re-calculate dpiX and dpiY
04557             formulaDocument->setZoomAndResolution( m_zoom,
04558                                                    qRound(INCH_TO_POINT( m_resolutionX )),
04559                                                    qRound(INCH_TO_POINT( m_resolutionY )) );
04560             formulaDocument->newZoomAndResolution(false,false);
04561         }
04562     }
04563     return formulaDocument;
04564 }
04565 
04566 
04567 void KWDocument::slotRepaintChanged( KWFrameSet * frameset )
04568 {
04569     // This has to be a loop instead of a signal, so that we can
04570     // send "true" for the last view (see KWFrameSet::drawContents)
04571     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it ) {
04572         (*it)->getGUI()->canvasWidget()->repaintChanged( frameset, it == m_lstViews.fromLast() );
04573     }
04574 }
04575 
04576 void KWDocument::deleteTable( KWTableFrameSet *table )
04577 {
04578     if ( !table )
04579         return;
04580     if ( table->isFloating() )
04581     {
04582         emit sig_terminateEditing( table ); // to unselect its cells, especially
04583         KWAnchor * anchor = table->findAnchor( 0 );
04584         addCommand( table->anchorFrameset()->deleteAnchoredFrame( anchor ) );
04585     }
04586     else
04587     {
04588         KWDeleteTableCommand *cmd = new KWDeleteTableCommand( i18n("Delete Table"), table );
04589         addCommand( cmd );
04590         cmd->execute();
04591     }
04592 }
04593 
04594 void KWDocument::deleteFrame( KWFrame * frame )
04595 {
04596     KWFrameSet * fs = frame->frameSet();
04597     kdDebug(32002) << "KWDocument::deleteFrame frame=" << frame << " fs=" << fs << endl;
04598     QString cmdName;
04599     TypeStructDocItem docItem = (TypeStructDocItem) 0;
04600     switch (fs->type() ) {
04601     case FT_TEXT:
04602         cmdName=i18n("Delete Text Frame");
04603         docItem=TextFrames;
04604         break;
04605     case FT_FORMULA:
04606         cmdName=i18n("Delete Formula Frame");
04607         docItem=FormulaFrames;
04608         break;
04609     case FT_CLIPART:
04610         kdError(32001) << "FT_CLIPART used! (in KWDocument::deleteFrame)" << endl;
04611     case FT_PICTURE:
04612         cmdName=i18n("Delete Picture Frame");
04613         docItem=Pictures;
04614         break;
04615     case FT_PART:
04616         cmdName=i18n("Delete Object Frame");
04617         docItem=Embedded;
04618         break;
04619     case FT_TABLE:
04620     case FT_BASE:
04621         Q_ASSERT( 0 );
04622         break;
04623     }
04624     if ( fs->isFloating() )
04625     {
04626         KWAnchor * anchor = fs->findAnchor( 0 );
04627         addCommand( fs->anchorFrameset()->deleteAnchoredFrame( anchor ) );
04628     }
04629     else
04630     {
04631         KWDeleteFrameCommand *cmd = new KWDeleteFrameCommand( cmdName, frame );
04632         addCommand( cmd );
04633         cmd->execute();
04634     }
04635     emit docStructureChanged(docItem);
04636 }
04637 
04638 void KWDocument::reorganizeGUI()
04639 {
04640     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04641         (*it)->getGUI()->reorganize();
04642 }
04643 
04644 void KWDocument::slotDocumentInfoModifed()
04645 {
04646     if (!variableCollection()->variableSetting()->displayFieldCode())
04647         recalcVariables( VT_FIELD );
04648 }
04649 
04650 void KWDocument::refreshDocStructure(int type)
04651 {
04652      emit docStructureChanged(type);
04653 }
04654 
04655 int KWDocument::typeItemDocStructure(FrameSetType type)
04656 {
04657     int typeItem;
04658     switch(type)
04659     {
04660         case FT_TEXT:
04661             typeItem=(int)TextFrames;
04662             break;
04663         case FT_PICTURE:
04664             typeItem=(int)Pictures;
04665             break;
04666         case FT_PART:
04667             typeItem=(int)Embedded;
04668             break;
04669         case FT_FORMULA:
04670             typeItem=(int)FormulaFrames;
04671             break;
04672         case FT_TABLE:
04673             typeItem=(int)Tables;
04674             break;
04675         default:
04676             typeItem=(int)TextFrames;
04677     }
04678     return typeItem;
04679 }
04680 
04681 void KWDocument::refreshDocStructure(FrameSetType type)
04682 {
04683     emit docStructureChanged(typeItemDocStructure(type));
04684 }
04685 
04686 QBrush KWDocument::resolveBgBrush( const QBrush & brush, QPainter * painter )
04687 {
04688     if ( brush.color().isValid() )
04689         return brush;
04690     QBrush ret( brush );
04691     ret.setColor( defaultBgColor( painter ) );
04692     return ret;
04693 }
04694 
04695 QColor KWDocument::resolveBgColor( const QColor & col, QPainter * painter )
04696 {
04697     if (col.isValid())
04698         return col;
04699 
04700     return defaultBgColor( painter );
04701 }
04702 
04703 QColor KWDocument::defaultBgColor( QPainter * painter )
04704 {
04705     if ( painter && painter->device()->devType() == QInternal::Printer )
04706         return Qt::white;
04707     return QApplication::palette().color( QPalette::Active, QColorGroup::Base );
04708 }
04709 
04710 
04711 void KWDocument::setTocPresent(bool hasToc)
04712 {
04713     m_hasTOC=hasToc;
04714     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04715         (*it)->updateTocActionText(hasToc);
04716 }
04717 
04718 void KWDocument::refreshMenuExpression()
04719 {
04720     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04721         (*it)->refreshMenuExpression();
04722 }
04723 
04724 void KWDocument::updateZoomRuler()
04725 {
04726     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it ) {
04727         (*it)->getGUI()->getHorzRuler()->setZoom( zoomedResolutionX() );
04728         (*it)->getGUI()->getVertRuler()->setZoom( zoomedResolutionY() );
04729         (*it)->slotUpdateRuler();
04730     }
04731 }
04732 
04733 void KWDocument::updateRulerFrameStartEnd()
04734 {
04735     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04736         (*it)->slotUpdateRuler();
04737 }
04738 
04739 int KWDocument::undoRedoLimit() const
04740 {
04741     return m_commandHistory->undoLimit();
04742 }
04743 
04744 void KWDocument::setUndoRedoLimit(int val)
04745 {
04746     m_commandHistory->setUndoLimit(val);
04747     m_commandHistory->setRedoLimit(val);
04748 }
04749 
04750 void KWDocument::setGridX(double gridx) {
04751     m_gridX = gridx;
04752     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04753         (*it)->getGUI()->getHorzRuler()->setGridSize(gridx);
04754 }
04755 
04756 QValueList<KoTextObject *> KWDocument::visibleTextObjects(KWViewMode *viewmode) const
04757 {
04758     QValueList<KoTextObject *> lst;
04759     QPtrList<KWTextFrameSet> textFramesets = allTextFramesets( true );
04760 
04761     KWTextFrameSet *frm;
04762     for ( frm=textFramesets.first(); frm != 0; frm=textFramesets.next() ) {
04763         if ( frm && frm->isVisible(viewmode) && !frm->textObject()->protectContent() )
04764         {
04765             lst.append( frm->textObject() );
04766         }
04767     }
04768 
04769     return lst;
04770 }
04771 
04772 void KWDocument::refreshGUIButton()
04773 {
04774     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04775         (*it)->initGUIButton();
04776 }
04777 
04778 void KWDocument::enableBackgroundSpellCheck( bool b )
04779 {
04780     m_bgSpellCheck->setEnabled(b);
04781     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04782         (*it)->updateBgSpellCheckingState();
04783 }
04784 
04785 bool KWDocument::backgroundSpellCheckEnabled() const
04786 {
04787     return m_bgSpellCheck->enabled();
04788 }
04789 
04790 void KWDocument::reactivateBgSpellChecking()
04791 {
04792     QPtrList<KWTextFrameSet> textFramesets = allTextFramesets( true );
04793 
04794     KWTextFrameSet *frm;
04795     for ( frm=textFramesets.first(); frm != 0; frm=textFramesets.next() ){
04796         frm->textObject()->setNeedSpellCheck(true);
04797     }
04798     repaintAllViews();
04799     startBackgroundSpellCheck();
04800 }
04801 
04802 void KWDocument::slotChapterParagraphFormatted( KoTextParag* /*parag*/ )
04803 {
04804     // Attempt at invalidating from the parag's page only
04805     // But that's not good enough - if a header gets moved down,
04806     // we also need to invalidate the previous page, from where the paragraph disappeared.
04807     /*
04808       KoPoint p;
04809     KWFrame* frame = internalToDocument( parag->rect().topLeft(), p );
04810     Q_ASSERT( frame );
04811     if ( frame )
04812         // Remove any information from this page and further pages.
04813         m_sectionTitles.resize( frame->pageNumber() );
04814     */
04815 
04816     m_sectionTitles.resize( 0 ); // clear up the entire cache
04817 
04818     // Don't store info from parag into m_sectionTitles here.
04819     // It breaks when having two headings in the same page
04820     // (or if it keeps existing info then it can't update properly)
04821 }
04822 
04823 QString KWDocument::checkSectionTitleInParag( KoTextParag* parag, KWTextFrameSet* frameset, int pageNum ) const
04824 {
04825     if ( parag->counter() && parag->counter()->numbering() == KoParagCounter::NUM_CHAPTER
04826          && parag->counter()->depth() == 0 )
04827     {
04828         QString txt = parag->string()->toString();
04829         txt = txt.left( txt.length() - 1 ); // remove trailing space
04830 #ifndef NDEBUG // not needed, just checking
04831         KoPoint p;
04832         KWFrame* frame = frameset->internalToDocument( parag->rect().topLeft(), p );
04833         Q_ASSERT( frame );
04834         if ( frame ) {
04835             int pgNum = frame->pageNumber();
04836             if( pgNum != pageNum )
04837                 kdWarning() << "sectionTitle: was looking for pageNum " << pageNum << ", got frame " << frame << " page " << pgNum << endl;
04838         }
04839         kdDebug(32001) << "KWDocument::sectionTitle for " << pageNum << ":" << txt << endl;
04840 #endif
04841         // Ensure array is big enough
04842         if ( pageNum > (int)m_sectionTitles.size()-1 )
04843             const_cast<KWDocument*>(this)->m_sectionTitles.resize( pageNum + 1 );
04844         const_cast<KWDocument*>(this)->m_sectionTitles[ pageNum ] = txt;
04845         return txt;
04846     }
04847     return QString::null;
04848 }
04849 
04850 QString KWDocument::sectionTitle( int pageNum ) const
04851 {
04852     //kdDebug(32001) << "KWDocument::sectionTitle(pageNum=" << pageNum << ") m_sectionTitles.size()=" << m_sectionTitles.size() << endl;
04853     // First look in the cache. If info is present, it's uptodate (see slotChapterParagraphFormatted)
04854     if ( (int)m_sectionTitles.size() > pageNum )
04855     {
04856         // Look whether this page has a section title, and if not, go back pages, one by one
04857         for ( int i = pageNum; i >= 0 ; --i )
04858         {
04859             const QString& s = m_sectionTitles[i];
04860             if ( !s.isEmpty() )
04861             {
04862                 // Update cache, to make this faster next time
04863                 if ( pageNum > (int)m_sectionTitles.size()-1 )
04864                     const_cast<KWDocument*>(this)->m_sectionTitles.resize( pageNum + 1 );
04865                 const_cast<KWDocument*>(this)->m_sectionTitles[ pageNum ] = s;
04866                 return s;
04867             }
04868         }
04869     }
04870 
04871     // If not in the cache, determine from the paragraphs in the page.
04872 
04873     if ( m_lstFrameSet.isEmpty() )
04874         return QString::null;
04875     // We use the "main" frameset to determine section titles.
04876     KWTextFrameSet *frameset = dynamic_cast<KWTextFrameSet *>( m_lstFrameSet.getFirst() );
04877     if ( !frameset )
04878         return QString::null;
04879 
04880     int topLUpix, bottomLUpix;
04881     if ( !frameset->minMaxInternalOnPage( pageNum, topLUpix, bottomLUpix ) )
04882         return QString::null;
04883 
04884     KoTextParag* parag = frameset->textDocument()->firstParag();
04885     //kdDebug(32001) << "KWDocument::sectionTitle " << pageNum
04886     //          << " topLUpix=" << topLUpix << " bottomLUpix=" << bottomLUpix << endl;
04887 
04888     KoTextParag* lastParagOfPageAbove = parag;
04889     for ( ; parag ; parag = parag->next() )
04890     {
04891         if ( parag->rect().bottom() < topLUpix ) // too early
04892         {
04893             lastParagOfPageAbove = parag;
04894             continue;
04895         }
04896         if ( parag->rect().top() > bottomLUpix ) // done
04897             break;
04898         QString txt = checkSectionTitleInParag( parag, frameset, pageNum );
04899         if ( !txt.isEmpty() )
04900             return txt;
04901     }
04902 
04903     // No heading found in page.
04904     // Go back up until the first section parag
04905     parag = lastParagOfPageAbove;
04906     for (  ; parag ; parag = parag->prev() )
04907     {
04908         QString txt = checkSectionTitleInParag( parag, frameset, pageNum );
04909         if ( !txt.isEmpty() )
04910             return txt;
04911     }
04912 
04913     // First page, no heading found
04914     return QString::null;
04915 }
04916 
04917 
04918 void KWDocument::setSpellCheckIgnoreList( const QStringList& lst )
04919 {
04920     m_spellCheckIgnoreList = lst;
04921     m_bgSpellCheck->settings()->setCurrentIgnoreList( m_spellCheckIgnoreList + m_spellCheckPersonalDict );
04922     setModified( true );
04923 }
04924 
04925 void KWDocument::addSpellCheckIgnoreWord( const QString & word )
04926 {
04927     // ### missing: undo/redo support
04928     if( m_spellCheckIgnoreList.findIndex( word ) == -1 )
04929         m_spellCheckIgnoreList.append( word );
04930     setSpellCheckIgnoreList( m_spellCheckIgnoreList );
04931     if ( backgroundSpellCheckEnabled() )
04932         // Re-check everything to make this word normal again
04933         reactivateBgSpellChecking();
04934 }
04935 
04936 int KWDocument::maxZOrder( int pageNum) const
04937 {
04938     bool first = true;
04939     int maxZOrder = 0; //this value is only used if there's no frame on the page
04940     QPtrList<KWFrame> frames = framesInPage( pageNum );
04941     QPtrListIterator<KWFrame> frameIt( frames );
04942     for ( ; frameIt.current(); ++frameIt ) {
04943         if ( first || frameIt.current()->zOrder() > maxZOrder ) {
04944             maxZOrder = frameIt.current()->zOrder();
04945             first = false;
04946         }
04947     }
04948     return maxZOrder;
04949 }
04950 
04951 QPtrList<KWTextFrameSet> KWDocument::allTextFramesets(bool onlyReadWrite) const
04952 {
04953     QPtrList<KWTextFrameSet> textFramesets;
04954     QPtrListIterator<KWFrameSet> fit = framesetsIterator();
04955     for ( ; fit.current() ; ++fit ) {
04956         if(fit.current()->isDeleted()) continue;
04957         fit.current()->addTextFrameSets(textFramesets, onlyReadWrite);
04958     }
04959     return textFramesets;
04960 }
04961 
04962 QValueList<KoTextDocument *> KWDocument::allTextDocuments() const
04963 {
04964     QValueList<KoTextDocument *> lst;
04965     const QPtrList<KWTextFrameSet> textFramesets = allTextFramesets(false);
04966     QPtrListIterator<KWTextFrameSet> fit( textFramesets );
04967     for ( ; fit.current() ; ++fit ) {
04968         lst.append( fit.current()->textObject()->textDocument() );
04969     }
04970     return lst;
04971 }
04972 
04973 int KWDocument::numberOfTextFrameSet( KWFrameSet* fs, bool onlyReadWrite )
04974 {
04975     QPtrList<KWTextFrameSet> textFramesets = allTextFramesets( onlyReadWrite );
04976     return textFramesets.findRef( static_cast<KWTextFrameSet*>(fs) );
04977 }
04978 
04979 KWFrameSet * KWDocument::textFrameSetFromIndex( unsigned int num, bool onlyReadWrite )
04980 {
04981     return allTextFramesets( onlyReadWrite ).at( num );
04982 }
04983 
04984 void KWDocument::updateTextFrameSetEdit()
04985 {
04986     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
04987         (*it)->slotFrameSetEditChanged();
04988 
04989 }
04990 
04991 void KWDocument::displayFootNoteFieldCode()
04992 {
04993     QPtrListIterator<KoVariable> it( m_varColl->getVariables() );
04994     for ( ; it.current() ; ++it )
04995     {
04996         if ( it.current()->type() == VT_FOOTNOTE )
04997         {
04998             static_cast<KWFootNoteVariable *>(it.current())->resize();
04999             static_cast<KWFootNoteVariable *>(it.current())->frameSet()->setCounterText( static_cast<KWFootNoteVariable *>(it.current())->text() );
05000 
05001             KoTextParag * parag = it.current()->paragraph();
05002             if ( parag )
05003             {
05004                 parag->invalidate( 0 );
05005                 parag->setChanged( true );
05006             }
05007         }
05008     }
05009 }
05010 
05011 void KWDocument::changeFootNoteConfig()
05012 {
05013     QMap<KoTextDocument *, bool> modifiedTextDocuments; // Qt4: QSet
05014     QPtrListIterator<KoVariable> it( m_varColl->getVariables() );
05015     for ( ; it.current() ; ++it )
05016     {
05017         if ( it.current()->type() == VT_FOOTNOTE )
05018         {
05019             KWFootNoteVariable* footNoteVar = static_cast<KWFootNoteVariable *>(it.current());
05020             footNoteVar->formatedNote();
05021             footNoteVar->resize();
05022             footNoteVar->frameSet()->setCounterText( footNoteVar->text() );
05023 
05024             KoTextParag * parag = footNoteVar->paragraph();
05025             if ( parag )
05026             {
05027                 parag->invalidate( 0 );
05028                 parag->setChanged( true );
05029             }
05030             KoTextDocument* textdoc = parag->textDocument();
05031             if ( modifiedTextDocuments.find( textdoc ) != modifiedTextDocuments.end() ) // Qt4: !contains
05032                 modifiedTextDocuments.insert( textdoc, true );
05033         }
05034     }
05035     for( QMap<KoTextDocument *,bool>::const_iterator it = modifiedTextDocuments.begin();
05036          it != modifiedTextDocuments.end(); ++it ) {
05037         KoTextDocument* textdoc = it.key();
05038         KWTextFrameSet * textfs = static_cast<KWTextDocument *>(textdoc)->textFrameSet();
05039         slotRepaintChanged( textfs );
05040     }
05041 }
05042 
05043 
05044 void KWDocument::setTabStopValue ( double tabStop )
05045 {
05046     m_tabStop = tabStop;
05047     QPtrList<KWTextFrameSet> textFramesets = allTextFramesets( true );
05048 
05049     KWTextFrameSet *frm;
05050     for ( frm=textFramesets.first(); frm != 0; frm=textFramesets.next() ){
05051         frm->textDocument()->setTabStops( ptToLayoutUnitPixX( tabStop ));
05052         frm->layout();
05053     }
05054     repaintAllViews();
05055 }
05056 
05057 void KWDocument::setGlobalHyphenation( bool hyphen )
05058 {
05059     m_bGlobalHyphenation = hyphen;
05060     // This is only used as a default setting for the default format in new documents;
05061     // In existing documents the hyphenation comes from the existing formats.
05062 }
05063 
05064 void KWDocument::setViewFrameBorders( bool b )
05065 {
05066     m_viewFrameBorders = b;
05067     m_layoutViewMode->setDrawFrameBorders( b );
05068     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
05069         (*it)->getGUI()->canvasWidget()->viewMode()->setDrawFrameBorders( b );
05070 }
05071 
05072 void KWDocument::switchViewMode( const QString& newViewModeType )
05073 {
05074     // Don't compare m_viewModeType and newViewMode here, it would break
05075     // changing the number of pages per row for the preview mode, in kwconfig.
05076     m_viewModeType = newViewModeType;
05077     delete m_layoutViewMode;
05078     m_layoutViewMode = KWViewMode::create( m_viewModeType, this, 0 /*no canvas */ );
05079 
05080     //necessary to switchmode view in all canvas in first.
05081     //otherwise with more than one view kword crashes !
05082     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
05083         (*it)->getGUI()->canvasWidget()->switchViewMode( m_viewModeType );
05084 
05085     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
05086         (*it)->switchModeView();
05087     emit newContentsSize();
05088 
05089     // Since the text layout depends on the view mode, we need to redo it
05090     // But after telling the canvas about the new viewmode, otherwise stuff like
05091     // slotNewContentsSize will crash.
05092     updateAllFrames();
05093     layout();
05094 
05095     repaintAllViews( true );
05096     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
05097         (*it)->getGUI()->canvasWidget()->ensureCursorVisible();
05098 }
05099 
05100 void KWDocument::changeBgSpellCheckingState( bool b )
05101 {
05102     enableBackgroundSpellCheck( b );
05103     reactivateBgSpellChecking();
05104     KConfig *config = KWFactory::instance()->config();
05105     config->setGroup("KSpell kword" );
05106     config->writeEntry( "SpellCheck", (int)b );
05107 }
05108 
05109 QString KWDocument::initialFrameSet() const
05110 {
05111     return m_initialEditing ? m_initialEditing->m_initialFrameSet : QString::null;
05112 }
05113 
05114 int KWDocument::initialCursorParag() const
05115 {
05116     return m_initialEditing ? m_initialEditing->m_initialCursorParag : 0;
05117 }
05118 
05119 int KWDocument::initialCursorIndex() const
05120 {
05121     return m_initialEditing ? m_initialEditing->m_initialCursorIndex : 0;
05122 }
05123 
05124 void KWDocument::deleteInitialEditingInfo()
05125 {
05126     delete m_initialEditing;
05127     m_initialEditing = 0L;
05128 }
05129 
05130 bool KWDocument::cursorInProtectedArea()const
05131 {
05132     return m_cursorInProtectectedArea;
05133 }
05134 
05135 void KWDocument::setCursorInProtectedArea( bool b )
05136 {
05137     m_cursorInProtectectedArea=b;
05138     testAndCloseAllFrameSetProtectedContent();
05139 }
05140 
05141 
05142 void KWDocument::testAndCloseAllFrameSetProtectedContent()
05143 {
05144     if ( !m_cursorInProtectectedArea )
05145     {
05146         for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
05147             (*it)->testAndCloseAllFrameSetProtectedContent();
05148     }
05149 }
05150 
05151 void KWDocument::updateRulerInProtectContentMode()
05152 {
05153     for( QValueList<KWView *>::const_iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
05154         (*it)->updateRulerInProtectContentMode();
05155 }
05156 
05157 
05158 void KWDocument::insertBookmark( const QString &name, KoTextParag *startparag, KoTextParag *endparag, int start, int end )
05159 {
05160     m_bookmarkList->append( KoTextBookmark( name, startparag, endparag, start, end ) );
05161 }
05162 
05163 void KWDocument::deleteBookmark( const QString &name )
05164 {
05165     if ( m_bookmarkList->removeByName( name ) )
05166         setModified(true);
05167 }
05168 
05169 void KWDocument::renameBookmark( const QString &oldName, const QString &newName )
05170 {
05171     if ( oldName == newName )
05172         return;
05173 
05174     KoTextBookmarkList::iterator it = m_bookmarkList->findByName( oldName );
05175     if ( it != m_bookmarkList->end() )
05176     {
05177         (*it).setBookmarkName( newName );
05178         setModified(true);
05179     }
05180 }
05181 
05182 const KoTextBookmark * KWDocument::bookmarkByName( const QString & name ) const
05183 {
05184     KoTextBookmarkList::const_iterator it = m_bookmarkList->findByName( name );
05185     if ( it != m_bookmarkList->end() )
05186         return &(*it);
05187     return 0;
05188 }
05189 
05190 QStringList KWDocument::listOfBookmarkName( KWViewMode * viewMode ) const
05191 {
05192     QStringList list;
05193     KoTextBookmarkList::const_iterator it = m_bookmarkList->begin();
05194     const KoTextBookmarkList::const_iterator end = m_bookmarkList->end();
05195     for ( ; it != end ; ++it )
05196     {
05197         const KoTextBookmark& book = *it;
05198         KWFrameSet* fs = static_cast<KWTextDocument *>(book.textDocument())->textFrameSet();
05199         if ( fs->isVisible( viewMode ) && !fs->isDeleted() )
05200             list.append( book.bookmarkName() );
05201     }
05202     return list;
05203 }
05204 
05205 void KWDocument::paragraphModified(KoTextParag* /*parag*/, int /*KoTextParag::ParagModifyType*/ /*type*/, int /*start*/, int /*length*/)
05206 {
05207     //kdDebug()<<" parag :"<<parag<<" start :"<<start<<" length :"<<length<<endl;
05208     emit docStructureChanged( Tables | TextFrames );
05209 }
05210 
05211 
05212 void KWDocument::paragraphDeleted( KoTextParag *parag, KWFrameSet *frm )
05213 {
05214     KWTextFrameSet* textfs = dynamic_cast<KWTextFrameSet *>( frm );
05215     if ( textfs )
05216     {
05217         // For speed KoTextBookmarkList should probably be a per-paragraph map.
05218         // The problem is that a bookmark is associated with TWO paragraphs...
05219 
05220         KoTextBookmarkList::iterator it = m_bookmarkList->begin();
05221         const KoTextBookmarkList::iterator end = m_bookmarkList->end();
05222         for ( ; it != end ; ++it )
05223         {
05224             KoTextBookmark& book = *it;
05225 
05226             // Adjust bookmark to point to a valid paragraph, below or above the deleted one.
05227             // The old implementation turned the bookmark into a useless one. OOo simply deletes the bookmark...
05228             if ( book.startParag() == parag )
05229                 book.setStartParag( parag->next() ? parag->next() : parag->prev() );
05230             if ( book.endParag() == parag )
05231                 book.setEndParag( parag->next() ? parag->next() : parag->prev() );
05232         }
05233     }
05234 }
05235 
05236 void KWDocument::initBookmarkList()
05237 {
05238     Q_ASSERT( m_loadingInfo );
05239     if ( !m_loadingInfo )
05240         return;
05241     KWLoadingInfo::BookMarkList::Iterator it = m_loadingInfo->bookMarkList.begin();
05242     KWLoadingInfo::BookMarkList::Iterator end = m_loadingInfo->bookMarkList.end();
05243     for( ; it != end; ++it )
05244     {
05245         KWFrameSet * fs = 0L;
05246         QString fsName = (*it).frameSetName;
05247         if ( !fsName.isEmpty() )
05248             fs = frameSetByName( fsName );
05249         if ( fs )
05250         {
05251             KWTextFrameSet *frm = dynamic_cast<KWTextFrameSet *>(fs);
05252             if ( frm )
05253             {
05254                 KoTextDocument* textdoc = frm->textDocument();
05255                 KoTextParag* startparag = textdoc->paragAt( (*it).paragStartIndex );
05256                 KoTextParag* endparag = textdoc->paragAt( (*it).paragEndIndex );
05257                 if ( startparag && endparag )
05258                 {
05259                     m_bookmarkList->append( KoTextBookmark( (*it).bookname,
05260                                                             startparag, endparag,
05261                                                             (*it).cursorStartIndex, (*it).cursorEndIndex ) );
05262                 }
05263             }
05264         }
05265     }
05266 }
05267 
05268 QPixmap* KWDocument::doubleBufferPixmap( const QSize& s )
05269 {
05270     if ( !m_bufPixmap ) {
05271         int w = QABS( s.width() );
05272         int h = QABS( s.height() );
05273         m_bufPixmap = new QPixmap( w, h );
05274     } else {
05275         if ( m_bufPixmap->width() < s.width() ||
05276                 m_bufPixmap->height() < s.height() ) {
05277             m_bufPixmap->resize( QMAX( s.width(), m_bufPixmap->width() ),
05278                     QMAX( s.height(), m_bufPixmap->height() ) );
05279         }
05280     }
05281 
05282     return m_bufPixmap;
05283 }
05284 
05285 void KWDocument::maybeDeleteDoubleBufferPixmap()
05286 {
05287     if ( m_bufPixmap && m_bufPixmap->height() * m_bufPixmap->width() > 400*400 )
05288     {
05289         delete m_bufPixmap;
05290         m_bufPixmap = 0L;
05291     }
05292 }
05293 
05294 void KWDocument::setPersonalExpressionPath( const QStringList & lst)
05295 {
05296     m_personalExpressionPath = lst;
05297     refreshMenuExpression();
05298 }
05299 
05300 void KWDocument::updateDirectCursorButton()
05301 {
05302     for( QValueList<KWView *>::Iterator it = m_lstViews.begin(); it != m_lstViews.end(); ++it )
05303         (*it)->updateDirectCursorButton();
05304 }
05305 
05306 void KWDocument::setInsertDirectCursor(bool b)
05307 {
05308     m_bInsertDirectCursor=b;
05309     KConfig *config = KWFactory::instance()->config();
05310     config->setGroup( "Interface" );
05311     config->writeEntry( "InsertDirectCursor", b );
05312     updateDirectCursorButton();
05313 }
05314 
05315 void KWDocument::saveDialogShown()
05316 {
05317     if ( !textFrameSet(0) )
05318         return;
05319     // Grab first 50 chars from the main frameset's document
05320     // ### This is a somewhat slow method, if the document is huge - better iterate
05321     // over the first few parags until 50 chars have been collected.
05322     QString first_row = textFrameSet(0)->textDocument()->plainText().left(50);
05323     bool truncate = false;
05324     QChar ch;
05325     for (int i=0; i < (int)first_row.length(); i++)
05326     {
05327         ch = first_row.at(i);
05328         if (!truncate)
05329             if (ch.isPunct() || ch.isSpace() || ch == '.' )
05330             {
05331                 first_row.remove(i,1);
05332                 --i;
05333             }
05334             else
05335                 truncate = true;
05336         else if ( truncate && (ch.isPunct() || ch == '.' || ch == '\n' ) )
05337         {
05338             first_row.truncate(i);
05339             break;
05340         }
05341     }
05342     first_row = first_row.stripWhiteSpace();
05343     kdDebug() << "Suggested filename:" << first_row << endl;
05344     setURL(first_row);
05345 }
05346 
05347 void KWDocument::addWordToDictionary( const QString& word )
05348 {
05349     if ( m_bgSpellCheck )
05350     {
05351         if( m_spellCheckPersonalDict.findIndex( word ) == -1 )
05352             m_spellCheckPersonalDict.append( word );
05353         m_bgSpellCheck->settings()->setCurrentIgnoreList( m_spellCheckIgnoreList + m_spellCheckPersonalDict );
05354         if ( backgroundSpellCheckEnabled() )
05355             // Re-check everything to make this word normal again
05356             reactivateBgSpellChecking();
05357     }
05358 }
05359 
05360 void KWDocument::setEmpty()
05361 {
05362     KoDocument::setEmpty();
05363     // Whether loaded from template or from empty doc: this is a new one -> set creation date
05364     m_varColl->variableSetting()->setCreationDate(QDateTime::currentDateTime());
05365     recalcVariables( VT_DATE ); // , VST_CREATION_DATE ...
05366     // If we then load a document, it will override that date.
05367 }
05368 
05369 void KWDocument::updateGridButton()
05370 {
05371   QPtrListIterator<KoView> it( views() );
05372   for (; it.current(); ++it )
05373     ((KWView*)it.current())->updateGridButton();
05374 
05375 }
05376 
05377 unsigned int KWDocument::paperHeight(int pageNum) const {
05378     return static_cast<unsigned int>(zoomItY( pageManager()->pageLayout(pageNum).ptHeight ));
05379 }
05380 
05381 unsigned int KWDocument::paperWidth(int pageNum) const {
05382     return static_cast<unsigned int>(zoomItX( pageManager()->pageLayout(pageNum).ptWidth ));
05383 }
05384 
05385 unsigned int KWDocument::pageTop( int pgNum ) const {
05386     return zoomItY( pageManager()->topOfPage( pgNum ) );
05387 }
05388 
05389 int KWDocument::pageCount() const {
05390     return pageManager()->pageCount();
05391 }
05392 
05393 int KWDocument::startPage() const {
05394     return pageManager()->startPage();
05395 }
05396 int KWDocument::lastPage() const {
05397     return pageManager()->lastPageNumber();
05398 }
05399 
05400 QWidget* KWDocument::createCustomDocumentWidget(QWidget *parent) {
05401     KoColumns columns;
05402     columns.columns = 1;
05403     columns.ptColumnSpacing = m_defaultColumnSpacing;
05404     return new KWStartupWidget(parent, this, columns);
05405 }
05406 
05407 KWDocument::FramesChangedHandler::FramesChangedHandler(KWDocument *parent) {
05408     m_parent = parent;
05409     m_needLayout = false;
05410 }
05411 
05412 void KWDocument::FramesChangedHandler::addFrame(KWFrame *frame) {
05413     if(frame == 0) return;
05414     if(m_frameSets.contains(frame->frameSet())) return;
05415     m_frameSets.append(frame->frameSet());
05416     if( frame->runAround() != KWFrame::RA_NO )
05417         m_needLayout = true;
05418 }
05419 
05420 void KWDocument::FramesChangedHandler::addFrameSet(KWFrameSet *fs) {
05421     if(m_frameSets.contains(fs)) return;
05422     m_frameSets.append(fs);
05423     m_needLayout = true;
05424 }
05425 
05426 void KWDocument::FramesChangedHandler::execute() {
05427     if(m_frameSets.count() == 0)
05428         m_parent->updateAllFrames();
05429     else {
05430         QValueListIterator<KWFrameSet*> iter = m_frameSets.begin();
05431         for(;iter != m_frameSets.end(); ++iter) {
05432             KWFrameSet *fs = *iter;
05433             fs->updateFrames();
05434             if(!m_needLayout)
05435                 fs->layout();
05436         }
05437 
05438         KWFrameList::recalcAllFrames(m_parent);
05439     }
05440 
05441     // If frame with text flowing around it -> re-layout all frames
05442     if ( m_needLayout)
05443         m_parent->layout();
05444     //m_parent->repaintAllViewsExcept( 0 );
05445     m_parent->repaintAllViews();
05446     m_parent->updateRulerFrameStartEnd();
05447 }
05448 
05449 #include "KWDocument.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys