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