kword

KWDocument.cpp

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