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