diff --git a/kword/kwdoc.cc b/kword/kwdoc.cc index 40501afb35..68bb4a5c27 100644 --- a/kword/kwdoc.cc +++ b/kword/kwdoc.cc @@ -1,5447 +1,5443 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Reginald Stadlbauer Copyright (C) 2002-2004 David Faure This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "kwdoc.h" #include "KWordDocIface.h" #include "kwbgspellcheck.h" #include "kwbookmark.h" #include "kwcanvas.h" #include "kwcommand.h" #include "kwformulaframe.h" #include "kwframelayout.h" #include "kwpartframeset.h" #include "kwtableframeset.h" #include "kwtablestyle.h" #include "kwtabletemplate.h" #include "kwtextimage.h" #include "kwvariable.h" #include "kwview.h" #include "kwviewmode.h" #include "mailmerge.h" #include "kwloadinginfo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_PAGES //#define DEBUG_SPEED // Make sure an appropriate DTD is available in www/koffice/DTD if changing this value static const char * CURRENT_DTD_VERSION = "1.2"; /******************************************************************/ /* Class: KWCommandHistory */ /******************************************************************/ class KWCommandHistory : public KoCommandHistory { public: KWCommandHistory( KWDocument * doc ) : KoCommandHistory( doc->actionCollection(), true ), m_pDoc( doc ) {} public /*slots*/: // They are already slots in the parent. Running moc on the inherited class shouldn't be necessary AFAICS. virtual void undo(); virtual void redo(); private: KWDocument * m_pDoc; }; void KWCommandHistory::undo() { m_pDoc->clearUndoRedoInfos(); KoCommandHistory::undo(); } void KWCommandHistory::redo() { m_pDoc->clearUndoRedoInfos(); KoCommandHistory::redo(); } void KWDocument::clearUndoRedoInfos() { QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWTextFrameSet *fs = dynamic_cast( fit.current() ); if ( fs ) fs->clearUndoRedoInfo(); } } /** * Temporary storage for the initial edition info * (activeFrameset, cursorParagraph and cursorIndex attributes of the XML) */ class KWDocument::InitialEditing { public: QString m_initialFrameSet; int m_initialCursorParag; int m_initialCursorIndex; }; /******************************************************************/ /* Class: KWDocument */ /******************************************************************/ const int KWDocument::CURRENT_SYNTAX_VERSION = 3; KWDocument::KWDocument(QWidget *parentWidget, const char *widgetName, QObject* parent, const char* name, bool singleViewMode ) : KoDocument( parentWidget, widgetName, parent, name, singleViewMode ), m_urlIntern() { KWStatisticVariable::setExtendedType( true ); dcop = 0; if (KGlobal::locale()->measureSystem() == KLocale::Imperial) { m_unit = KoUnit::U_INCH; } else { m_unit = KoUnit::U_CM; } m_pages = 1; m_loadingInfo = 0L; m_tabStop = MM_TO_POINT( 15.0 ); m_processingType = WP; m_lstViews.setAutoDelete( false ); m_lstChildren.setAutoDelete( true ); // varFormats.setAutoDelete(true); m_lstFrameSet.setAutoDelete( true ); // m_textImageRequests does not create or delete the KWTextImage classes m_textImageRequests.setAutoDelete(false); m_bookmarkList.setAutoDelete( true ); m_styleColl=new KoStyleCollection(); m_frameStyleColl = new KWFrameStyleCollection(); m_tableStyleColl = new KWTableStyleCollection(); m_tableTemplateColl = new KWTableTemplateCollection(); m_pictureCollection = new KoPictureCollection(); m_personalExpressionPath = KWFactory::global()->dirs()->resourceDirs("expression"); m_picturePath= KGlobalSettings::documentPath(); #if 0 // KWORD_HORIZONTAL_LINE m_horizontalLinePath = KWFactory::global()->dirs()->resourceDirs("horizontalLine"); #endif setInstance( KWFactory::global(), false ); m_gridX = m_gridY = 10.0; m_indent = MM_TO_POINT( 10.0 ); m_iNbPagePerRow = 4; m_maxRecentFiles = 10; m_defaultColumnSpacing=3; m_bShowRuler = true; m_footNoteSeparatorLinePos=SLP_LEFT; //by default it's 1/5 m_iFootNoteSeparatorLineLength = 20; m_footNoteSeparatorLineWidth = 2.0; m_footNoteSeparatorLineType = SLT_SOLID; m_viewFormattingChars = false; m_viewFormattingEndParag = true; m_viewFormattingSpace = true; m_viewFormattingTabs = true; m_viewFormattingBreak = true; m_viewFrameBorders = true; m_repaintAllViewsPending = false; m_recalcFramesPending = -1; m_bShowDocStruct = true; m_bShowRuler = true; m_bShowStatusBar = true; m_bAllowAutoFormat = true; m_pgUpDownMovesCaret = true; m_bShowScrollBar = true; m_cursorInProtectectedArea = true; m_bHasEndNotes = false; m_bInsertDirectCursor=false; m_globalLanguage = KGlobal::locale()->language(); m_bGlobalHyphenation = false; m_bGeneratingPreview = false; m_lastViewMode="ModeNormal"; m_viewMode = 0; m_commandHistory = new KWCommandHistory( this ); connect( m_commandHistory, SIGNAL( documentRestored() ), this, SLOT( slotDocumentRestored() ) ); connect( m_commandHistory, SIGNAL( commandExecuted() ), this, SLOT( slotCommandExecuted() ) ); //styleMask = U_FONT_FAMILY_ALL_SIZE | U_COLOR | U_BORDER | U_INDENT | // U_NUMBERING | U_ALIGN | U_TABS | U_SMART; m_headerVisible = false; m_footerVisible = false; m_pasteFramesetsMap = 0L; m_initialEditing = 0L; m_bufPixmap = 0L; m_varFormatCollection = new KoVariableFormatCollection; m_varColl = new KWVariableCollection( new KWVariableSettings(), m_varFormatCollection ); m_autoFormat = new KoAutoFormat(this,m_varColl,m_varFormatCollection ); #ifdef HAVE_LIBKSPELL2 m_bgSpellCheck = new KWBgSpellCheck(this); #endif m_slDataBase = new KWMailMergeDataBase( this ); slRecordNum = -1; m_syntaxVersion = CURRENT_SYNTAX_VERSION; m_hasTOC=false; // It's important to call this to have the kformula actions // created. The real document is still to be created if needed. m_formulaDocumentWrapper = new KFormula::DocumentWrapper( instance()->config(), actionCollection(), m_commandHistory ); setEmpty(); setModified(false); initConfig(); // Get default font from the KWord config file KConfig *config = KWFactory::global()->config(); config->setGroup("Document defaults" ); QString defaultFontname=config->readEntry("DefaultFont"); if ( !defaultFontname.isEmpty() ) m_defaultFont.fromString( defaultFontname ); // If not found, we automatically fallback to the application font (the one from KControl's font module) // Try to force a scalable font. m_defaultFont.setStyleStrategy( QFont::ForceOutline ); int ptSize = m_defaultFont.pointSize(); if ( ptSize == -1 ) // specified with a pixel size ? ptSize = QFontInfo(m_defaultFont).pointSize(); //kdDebug() << "Default font: requested family: " << m_defaultFont.family() << endl; //kdDebug() << "Default font: real family: " << QFontInfo(m_defaultFont).family() << endl; - // Some simple import filters don't define any style, - // so let's have a Standard style at least - KoParagStyle * standardStyle = new KoParagStyle( "Standard" ); // This gets translated later on - //kdDebug() << "KWDocument::KWDocument creating standardStyle " << standardStyle << endl; - standardStyle->format().setFont( m_defaultFont ); - m_styleColl->addStyleTemplate( standardStyle ); - - // And let's do the same for framestyles - KWFrameStyle * standardFrameStyle = new KWFrameStyle( "Plain" ); - standardFrameStyle->setBackgroundColor(Qt::white); - standardFrameStyle->setTopBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); - standardFrameStyle->setRightBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); - standardFrameStyle->setLeftBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); - standardFrameStyle->setBottomBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); - m_frameStyleColl->addFrameStyleTemplate( standardFrameStyle ); - - // And let's do the same for tablestyles - KWTableStyle *standardTableStyle = new KWTableStyle( "Plain", standardStyle, standardFrameStyle ); - m_tableStyleColl->addTableStyleTemplate( standardTableStyle ); - if ( name ) dcopObject(); connect(m_varColl,SIGNAL(repaintVariable()),this,SLOT(slotRepaintVariable())); } /*==============================================================*/ DCOPObject* KWDocument::dcopObject() { if ( !dcop ) dcop = new KWordDocIface( this ); return dcop; } KWDocument::~KWDocument() { //don't save config when kword is embedded into konqueror if(isReadWrite()) saveConfig(); // formula frames have to be deleted before m_formulaDocumentWrapper m_lstFrameSet.clear(); m_bookmarkList.clear(); delete m_loadingInfo; delete m_autoFormat; delete m_formulaDocumentWrapper; delete m_commandHistory; delete m_varColl; delete m_varFormatCollection; delete m_slDataBase; delete dcop; #ifdef HAVE_LIBKSPELL2 delete m_bgSpellCheck; #endif delete m_styleColl; delete m_frameStyleColl; delete m_tableStyleColl; delete m_tableTemplateColl; delete m_viewMode; delete m_bufPixmap; delete m_pictureCollection; } void KWDocument::initConfig() { KConfig *config = KWFactory::global()->config(); if( config->hasGroup("KSpell kword" ) ) { config->setGroup( "KSpell kword" ); // Default is false for spellcheck, but the spell-check config dialog // should write out "true" when the user configures spell checking. #ifdef HAVE_LIBKSPELL2 if ( isReadWrite() ) m_bgSpellCheck->setEnabled(config->readBoolEntry( "SpellCheck", false )); else m_bgSpellCheck->setEnabled( false ); #endif } if(config->hasGroup("Interface" ) ) { config->setGroup( "Interface" ); setGridY(QMAX( config->readDoubleNumEntry("GridY",10.0), 0.1)); setGridX(QMAX( config->readDoubleNumEntry("GridX",10.0), 0.1)); setCursorInProtectedArea( config->readBoolEntry( "cursorInProtectArea", true )); // Config-file value in mm, default 10 pt double indent = config->readDoubleNumEntry("Indent", MM_TO_POINT(10.0) ) ; setIndentValue(indent); setShowRuler(config->readBoolEntry("Rulers",true)); int defaultAutoSave = KoDocument::defaultAutoSave()/60; // in minutes setAutoSave(config->readNumEntry("AutoSave",defaultAutoSave)*60); // read key in minutes, call setAutoSave(seconds) setBackupFile( config->readBoolEntry("BackupFile", true) ); setNbPagePerRow(config->readNumEntry("nbPagePerRow",4)); m_maxRecentFiles = config->readNumEntry( "NbRecentFile", 10 ); m_viewFormattingChars = config->readBoolEntry( "ViewFormattingChars", false ); m_viewFormattingBreak = config->readBoolEntry( "ViewFormattingBreaks", true ); m_viewFormattingSpace = config->readBoolEntry( "ViewFormattingSpace", true ); m_viewFormattingEndParag = config->readBoolEntry( "ViewFormattingEndParag", true ); m_viewFormattingTabs = config->readBoolEntry( "ViewFormattingTabs", true ); m_viewFrameBorders = config->readBoolEntry( "ViewFrameBorders", true ); m_zoom = config->readNumEntry( "Zoom", 100 ); m_bShowDocStruct = config->readBoolEntry( "showDocStruct", true ); m_lastViewMode = config->readEntry( "viewmode", "ModeNormal" ); setShowStatusBar( config->readBoolEntry( "ShowStatusBar" , true ) ); setAllowAutoFormat( config->readBoolEntry( "AllowAutoFormat" , true ) ); setShowScrollBar( config->readBoolEntry( "ShowScrollBar", true ) ); if ( isEmbedded() ) m_bShowDocStruct = false; // off by default for embedded docs, but still toggleable m_pgUpDownMovesCaret = config->readBoolEntry( "PgUpDownMovesCaret", true ); m_bInsertDirectCursor= config->readBoolEntry( "InsertDirectCursor", false ); m_globalLanguage=config->readEntry("language", KGlobal::locale()->language()); m_bGlobalHyphenation=config->readBoolEntry("hyphenation", false); } else m_zoom = 100; int undo=30; if(config->hasGroup("Misc" ) ) { config->setGroup( "Misc" ); undo=config->readNumEntry("UndoRedo",-1); } if(undo!=-1) setUndoRedoLimit(undo); setZoomAndResolution( m_zoom, KoGlobal::dpiX(), KoGlobal::dpiY() ); //text mode view is not a good default for a readonly document... if ( !isReadWrite() && m_lastViewMode =="ModeText" ) m_lastViewMode= "ModeNormal"; m_viewMode = KWViewMode::create( m_lastViewMode, this ); if(config->hasGroup("Kword Path" ) ) { config->setGroup( "Kword Path" ); if ( config->hasKey( "expression path" ) ) m_personalExpressionPath = config->readPathListEntry( "expression path" ); #if 0 // KWORD_HORIZONTAL_LINE if ( config->hasKey( "horizontal line path" ) ) m_horizontalLinePath = config->readPathListEntry( "horizontal line path" ); #endif if ( config->hasKey( "picture path" ) ) m_picturePath = config->readPathEntry( "picture path" ); setBackupPath(config->readPathEntry( "backup path" )); } } void KWDocument::saveConfig() { if ( isEmbedded() || !isReadWrite() ) return; // Only save the config that is manipulated by the UI directly. // The config from the config dialog is saved by the dialog itself. KConfig *config = KWFactory::global()->config(); config->setGroup( "Interface" ); config->writeEntry( "ViewFormattingChars", m_viewFormattingChars ); config->writeEntry( "ViewFormattingBreaks", m_viewFormattingBreak ); config->writeEntry( "ViewFormattingEndParag", m_viewFormattingEndParag ); config->writeEntry( "ViewFormattingTabs", m_viewFormattingTabs ); config->writeEntry( "ViewFormattingSpace", m_viewFormattingSpace ); config->writeEntry( "ViewFrameBorders", m_viewFrameBorders ); config->writeEntry( "Zoom", m_zoom ); config->writeEntry( "showDocStruct", m_bShowDocStruct); config->writeEntry( "Rulers", m_bShowRuler); config->writeEntry( "viewmode", m_lastViewMode); config->writeEntry( "AllowAutoFormat", m_bAllowAutoFormat ); } void KWDocument::setZoomAndResolution( int zoom, int dpiX, int dpiY ) { KoZoomHandler::setZoomAndResolution( zoom, dpiX, dpiY ); if ( KFormula::Document* formulaDocument = m_formulaDocumentWrapper->document() ) formulaDocument->setZoomAndResolution( zoom, dpiX, dpiY ); } KWTextFrameSet * KWDocument::textFrameSet ( unsigned int _num ) const { unsigned int i=0; QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { if(fit.current()->isDeleted()) continue; if(fit.current()->type()==FT_TEXT) { if(i==_num) return static_cast(fit.current()); i++; } } return static_cast(m_lstFrameSet.getFirst()); } void KWDocument::newZoomAndResolution( bool updateViews, bool forPrint ) { if ( KFormula::Document* formulaDocument = m_formulaDocumentWrapper->document() ) formulaDocument->newZoomAndResolution( updateViews,forPrint ); #if 0 QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) fit.current()->zoom( forPrint ); #endif // First recalc all frames (including the kotextdocument width) updateAllFrames(); // Then relayout the text inside the frames layout(); if ( updateViews ) { emit newContentsSize(); repaintAllViews( true ); } } bool KWDocument::initDoc(InitDocFlags flags, QWidget* parentWidget) { m_pages = 1; m_pageColumns.columns = 1; m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; m_pageHeaderFooter.header = HF_SAME; m_pageHeaderFooter.footer = HF_SAME; m_pageHeaderFooter.ptHeaderBodySpacing = 10; m_pageHeaderFooter.ptFooterBodySpacing = 10; m_pageHeaderFooter.ptFootNoteBodySpacing = 10; QString _template; bool ok = FALSE; if (flags==KoDocument::InitDocEmpty) { QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::global() ) ); resetURL(); initUnit(); ok = loadNativeFormat( fileName ); setEmpty(); setModified( FALSE ); return ok; } KoTemplateChooseDia::DialogType dlgtype; if (flags != KoDocument::InitDocFileNew) dlgtype = KoTemplateChooseDia::Everything; else dlgtype = KoTemplateChooseDia::OnlyTemplates; KoTemplateChooseDia::ReturnType ret = KoTemplateChooseDia::choose( KWFactory::global(), _template, dlgtype, "kword_template", parentWidget ); if ( ret == KoTemplateChooseDia::Template ) { QFileInfo fileInfo( _template ); QString fileName( fileInfo.dirPath( TRUE ) + "/" + fileInfo.baseName() + ".kwt" ); resetURL(); ok = loadNativeFormat( fileName ); initUnit(); setEmpty(); } else if ( ret == KoTemplateChooseDia::File ) { KURL url( _template); //kdDebug() << "KWDocument::initDoc opening URL " << url.prettyURL() << endl; ok = openURL( url ); } else if ( ret == KoTemplateChooseDia::Empty ) { QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::global() ) ); resetURL(); initUnit(); ok = loadNativeFormat( fileName ); setEmpty(); } setModified( FALSE ); return ok; } void KWDocument::initUnit() { //load default unit setting - this is only used for new files (from templates) or empty files KConfig *config = KWFactory::global()->config(); if (KGlobal::locale()->measureSystem() == KLocale::Imperial) { m_unit = KoUnit::U_INCH; } else { m_unit = KoUnit::U_CM; } if(config->hasGroup("Misc") ) { config->setGroup( "Misc" ); if ( config->hasKey( "Units" ) ) setUnit( KoUnit::unit( config->readEntry("Units") ) ); setDefaultColumnSpacing( config->readDoubleNumEntry("ColumnSpacing", 3.0) ); } m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; } void KWDocument::initEmpty() { m_pages = 1; m_pageColumns.columns = 1; m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; m_pageHeaderFooter.header = HF_SAME; m_pageHeaderFooter.footer = HF_SAME; m_pageHeaderFooter.ptHeaderBodySpacing = 10; m_pageHeaderFooter.ptFooterBodySpacing = 10; m_pageHeaderFooter.ptFootNoteBodySpacing = 10; QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::global() ) ); /*bool ok = */loadNativeFormat( fileName ); resetURL(); setModified( FALSE ); setEmpty(); } KoPageLayout KWDocument::pageLayout() const { return m_pageLayout; } void KWDocument::setPageLayout( const KoPageLayout& _layout, const KoColumns& _cl, const KoKWHeaderFooter& _hf, bool updateViews ) { if ( m_processingType == WP ) { int numPages = m_pages; //kdDebug() << "KWDocument::setPageLayout WP" << endl; m_pageLayout = _layout; m_pageColumns = _cl; m_pageHeaderFooter = _hf; if ( updateViews ) { // Fix things up, when we change the orientation we might accidentally change the number of pages // (and frames of the main textframeset might just remain un-moved...) KWFrameSet *frameset = m_lstFrameSet.getFirst(); KWFrame* lastFrame = frameset->frame( frameset->getNumFrames() - 1 ); if ( lastFrame && lastFrame->pageNum() + 1 < numPages ) { kdDebug(32002) << "KWDocument::setPageLayout ensuring that recalcFrames will consider " << numPages << " pages." << endl; // All that matters is that it's on numPages so that all pages will be recalc-ed. // If the text layout then wants to remove some pages, no problem. lastFrame->setY( numPages * ptPaperHeight() + ptTopBorder() ); } } } else { //kdDebug() << "KWDocument::setPageLayout NON-WP" << endl; m_pageLayout = _layout; m_pageLayout.ptLeft = 0; m_pageLayout.ptRight = 0; m_pageLayout.ptTop = 0; m_pageLayout.ptBottom = 0; m_pageHeaderFooter = _hf; } recalcFrames(); updateAllFrames(); if ( updateViews ) { // Invalidate document layout, for proper repaint layout(); emit pageLayoutChanged( m_pageLayout ); updateResizeHandles(); updateContentsSize(); } } double KWDocument::ptColumnWidth() const { return ( ptPaperWidth() - ptLeftBorder() - ptRightBorder() - ptColumnSpacing() * ( m_pageColumns.columns - 1 ) ) / m_pageColumns.columns; } class KWFootNoteFrameSetList : public QPtrList { public: KWFootNoteFrameSetList( bool reversed ) : m_reversed( reversed ) {} protected: // Compare the order of the associated variables virtual int compareItems(QPtrCollection::Item a, QPtrCollection::Item b) { KWFootNoteFrameSet* fsa = ((KWFootNoteFrameSet *)a); KWFootNoteFrameSet* fsb = ((KWFootNoteFrameSet *)b); Q_ASSERT( fsa->footNoteVariable() ); Q_ASSERT( fsb->footNoteVariable() ); if ( fsa->footNoteVariable() && fsb->footNoteVariable() ) { int numa = fsa->footNoteVariable()->num(); int numb = fsb->footNoteVariable()->num(); if (numa == numb) return 0; if (numa > numb) return m_reversed ? -1 : 1; return m_reversed ? 1 : -1; } return -1; // whatever } private: bool m_reversed; }; /* append headers and footers if needed, and create enough pages for all the existing frames */ void KWDocument::recalcFrames( int fromPage, int toPage /*-1 for all*/, uint flags ) { if ( m_lstFrameSet.isEmpty() ) return; //printDebug(); kdDebug(32002) << "KWDocument::recalcFrames from=" << fromPage << " to=" << toPage << endl; KWFrameSet *frameset = m_lstFrameSet.getFirst(); if ( m_processingType == WP ) { // In WP mode the pages are created automatically. In DTP not... KWTextFrameSet *firstHeader = 0L, *evenHeader = 0L, *oddHeader = 0L; KWTextFrameSet *firstFooter = 0L, *evenFooter = 0L, *oddFooter = 0L; m_bHasEndNotes = false; // will be set to true if we find any endnote // Lookup the various header / footer framesets into the variables above // [Done in all cases, in order to hide unused framesets] KWFootNoteFrameSetList footnotesList( true ); // Reversed, we want footnotes from bottom to top KWFootNoteFrameSetList endnotesList( false ); // Endnotes are in top to bottom order QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWFrameSet * fs = fit.current(); switch ( fs->frameSetInfo() ) { case KWFrameSet::FI_FIRST_HEADER: if ( isHeaderVisible() ) { firstHeader = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_ODD_HEADER: if ( isHeaderVisible() ) { oddHeader = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_EVEN_HEADER: if ( isHeaderVisible() ) { evenHeader = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_FIRST_FOOTER: if ( isFooterVisible() ) { firstFooter = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_ODD_FOOTER: if ( isFooterVisible() ) { oddFooter = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_EVEN_FOOTER: if ( isFooterVisible() ) { evenFooter = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } case KWFrameSet::FI_FOOTNOTE: { KWFootNoteFrameSet* fnfs = dynamic_cast(fs); if ( fnfs && fnfs->isVisible() ) // not visible is when the footnote has been deleted { if ( fnfs->isFootNote() ) footnotesList.append( fnfs ); else if ( fnfs->isEndNote() ) { endnotesList.append( fnfs ); m_bHasEndNotes = true; } } } break; default: break; } } // This allocation each time might slow things down a bit. // TODO KWHeaderFooterFrameSet : public KWTextFrameSet, and store the HeaderFooterFrameset data into there. // ... hmm, and then KWFootNoteFrameSet needs to inherit KWHeaderFooterFrameSet QPtrList headerFooterList; headerFooterList.setAutoDelete( true ); // Now hide & forget the unused header/footer framesets (e.g. 'odd pages' if we are in 'all the same' mode etc.) if ( isHeaderVisible() ) { Q_ASSERT( firstHeader ); Q_ASSERT( oddHeader ); Q_ASSERT( evenHeader ); switch ( getHeaderType() ) { case HF_SAME: oddHeader->setVisible( true ); evenHeader->setVisible( false ); evenHeader->deleteAllCopies(); firstHeader->setVisible( false ); firstHeader->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 0, -1, m_pageHeaderFooter.ptHeaderBodySpacing ) ); break; case HF_FIRST_EO_DIFF: // added for koffice-1.2-beta2 firstHeader->setVisible( true ); oddHeader->setVisible( true ); evenHeader->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstHeader, 0, 0, m_pageHeaderFooter.ptHeaderBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 2, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenHeader, 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; case HF_FIRST_DIFF: oddHeader->setVisible( true ); evenHeader->setVisible( false ); evenHeader->deleteAllCopies(); firstHeader->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstHeader, 0, 0, m_pageHeaderFooter.ptHeaderBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing ) ); break; case HF_EO_DIFF: oddHeader->setVisible( true ); evenHeader->setVisible( true ); firstHeader->setVisible( false ); firstHeader->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 0, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenHeader, 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; } } if ( isFooterVisible() ) { Q_ASSERT( firstFooter ); Q_ASSERT( oddFooter ); Q_ASSERT( evenFooter ); switch ( getFooterType() ) { case HF_SAME: oddFooter->setVisible( true ); evenFooter->setVisible( false ); evenFooter->deleteAllCopies(); firstFooter->setVisible( false ); firstFooter->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 0, -1, m_pageHeaderFooter.ptFooterBodySpacing ) ); break; case HF_FIRST_EO_DIFF: // added for koffice-1.2-beta2 firstFooter->setVisible( true ); oddFooter->setVisible( true ); evenFooter->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstFooter, 0, 0, m_pageHeaderFooter.ptFooterBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 2, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenFooter, 1, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; case HF_FIRST_DIFF: oddFooter->setVisible( true ); evenFooter->setVisible( false ); evenFooter->deleteAllCopies(); firstFooter->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstFooter, 0, 0, m_pageHeaderFooter.ptFooterBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 1, -1, m_pageHeaderFooter.ptFooterBodySpacing ) ); break; case HF_EO_DIFF: oddFooter->setVisible( true ); evenFooter->setVisible( true ); firstFooter->setVisible( false ); firstFooter->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 0, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenFooter, 1, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; } } // The frameset order _on screen_ is: // Header // Main text frame (if WP) // Footnote_s_ // Footer // In the list it will have to be from top and from bottom: // Header, Footer, Footnote from bottom to top QPtrList footnotesHFList; footnotesHFList.setAutoDelete( true ); footnotesList.sort(); QPtrListIterator fnfsIt( footnotesList ); // fnfs == "footnote frameset" for ( ; fnfsIt.current() ; ++fnfsIt ) { KWFootNoteFrameSet* fnfs = fnfsIt.current(); int pageNum = -42; //fnfs->footNoteVariable()->pageNum(); // determined by KWFrameLayout KWFrameLayout::HeaderFooterFrameset* hff = new KWFrameLayout::HeaderFooterFrameset( fnfs, pageNum, pageNum, m_pageHeaderFooter.ptFootNoteBodySpacing, KWFrameLayout::HeaderFooterFrameset::All ); // With other kind of framesets, the height is simply frame->height. // But for footnotes, the height to pass to KWFrameLayout is the sum of the frame heights. hff->m_height = 0; for (QPtrListIterator f = fnfs->frameIterator(); f.current() ; ++f ) hff->m_height += f.current()->height(); footnotesHFList.append( hff ); } // Endnotes, however are laid out from top to bottom. QPtrList endnotesHFList; endnotesHFList.setAutoDelete( true ); endnotesList.sort(); QPtrListIterator enfsIt( endnotesList ); // enfs == "endnote frameset" for ( ; enfsIt.current() ; ++enfsIt ) { KWFootNoteFrameSet* enfs = enfsIt.current(); KWFrameLayout::HeaderFooterFrameset* hff = new KWFrameLayout::HeaderFooterFrameset( enfs, -42, -42, // determined by KWFrameLayout m_pageHeaderFooter.ptFootNoteBodySpacing, KWFrameLayout::HeaderFooterFrameset::All ); // The height to pass to KWFrameLayout is the sum of the frame heights. hff->m_height = 0; for (QPtrListIterator f = enfs->frameIterator(); f.current() ; ++f ) hff->m_height += f.current()->height(); endnotesHFList.append( hff ); } int oldPages = m_pages; unsigned int frms = frameset->getNumFrames(); // Determine number of pages - first from the text frames // - BUT NOT from the number of frames. Some people manage to end up with // multiple frames of textframeset1 on the same page(!) //m_pages = static_cast( ceil( static_cast( frms ) / static_cast( m_pageColumns.columns ) ) ); #ifdef DEBUG_PAGES //kdDebug(32002) << "KWDocument::recalcFrames frms(" << frms << ") / columns(" << m_pageColumns.columns << ") = " << m_pages << endl; #endif m_pages = frameset->frame( frms - 1 )->pageNum() + 1; // Then from the other frames ( framesetNum > 0 ) double maxBottom = 0; for (int m = numFrameSets() - 1; m > 0; m-- ) { KWFrameSet *fs=frameSet(m); if ( fs->isVisible() && !fs->isAHeader() && !fs->isAFooter() && !fs->isFloating() && !fs->isFootEndNote() ) { for (int n = fs->getNumFrames()-1; n >= 0 ; n--) { //if ( n == fs->getNumFrames()-1 ) #ifdef DEBUG_PAGES kdDebug(32002) << "KWDocument::recalcFrames frameset number " << m << " '" << fs->getName() << "' frame " << n << " bottom=" << fs->frame(n)->bottom() << endl; #endif maxBottom = QMAX(maxBottom, fs->frame(n)->bottom()); } } } int pages2 = static_cast( ceil( maxBottom / ptPaperHeight() ) ); #ifdef DEBUG_PAGES kdDebug(32002) << "KWDocument::recalcFrames, WP, m_pages=" << m_pages << " pages2=" << pages2 << " (coming from maxBottom=" << maxBottom << " and ptPaperHeight=" << ptPaperHeight() << ")" << endl; #endif m_pages = QMAX( pages2, m_pages ); if ( toPage == -1 ) toPage = m_pages - 1; if ( fromPage > toPage ) // this can happen with "endnotes only" pages :) fromPage = toPage; // ie. start at the last real page KWFrameLayout frameLayout( this, headerFooterList, footnotesHFList, endnotesHFList ); frameLayout.layout( frameset, m_pageColumns.columns, fromPage, toPage, flags ); // If the number of pages changed, update views and variables etc. // (now that the frame layout has been done) if ( m_pages != oldPages && !m_bGeneratingPreview ) { // Very much like the end of appendPage, but we don't want to call recalcFrames ;) emit newContentsSize(); emit pageNumChanged(); recalcVariables( VT_PGNUM ); } } else { // DTP mode: calculate the number of pages from the frames. double maxBottom=0; for (QPtrListIterator fit = framesetsIterator(); fit.current() ; ++fit ) { if(fit.current()->isDeleted()) continue; if(fit.current()->frameSetInfo()==KWFrameSet::FI_BODY && !fit.current()->isFloating()) { KWFrameSet * fs = fit.current(); for (QPtrListIterator f = fs->frameIterator(); f.current() ; ++f ) { #ifdef DEBUG_PAGES kdDebug(32002) << " fs=" << fs->getName() << " bottom=" << f.current()->bottom() << endl; #endif maxBottom=QMAX(maxBottom, f.current()->bottom()); } } } m_pages = static_cast( ceil( maxBottom / ptPaperHeight() ) ); #ifdef DEBUG_PAGES kdDebug(32002) << "DTP mode: pages = maxBottom("< it( children() ); for( ; it.current(); ++it ) { if ( !it.current()->loadDocument( _store ) ) return FALSE; } return TRUE; } void KWDocument::loadPictureMap ( QDomElement& domElement ) { m_pictureMap.clear(); // QDomElement picturesElem = domElement.namedItem( "PICTURES" ).toElement(); if ( !picturesElem.isNull() ) { m_pictureCollection->readXML( picturesElem, m_pictureMap ); } // QDomElement pixmapsElem = domElement.namedItem( "PIXMAPS" ).toElement(); if ( !pixmapsElem.isNull() ) { m_pictureCollection->readXML( pixmapsElem, m_pictureMap ); } // QDomElement clipartsElem = domElement.namedItem( "CLIPARTS" ).toElement(); if ( !clipartsElem.isNull() ) { m_pictureCollection->readXML( pixmapsElem, m_pictureMap ); } } bool KWDocument::loadOasis( const QDomDocument& doc, KoOasisStyles& oasisStyles, const QDomDocument& settings, KoStore* store ) { QTime dt; dt.start(); emit sigProgress( 0 ); + clear(); kdDebug(32001) << "KWDocument::loadOasis" << endl; - m_pictureMap.clear(); - m_textImageRequests.clear(); - m_pictureRequests.clear(); - m_anchorRequests.clear(); - m_footnoteVarRequests.clear(); - m_spellListIgnoreAll.clear(); - - m_pageColumns.columns = 1; - m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; - - m_pageHeaderFooter.header = HF_SAME; - m_pageHeaderFooter.footer = HF_SAME; - m_pageHeaderFooter.ptHeaderBodySpacing = 10; - m_pageHeaderFooter.ptFooterBodySpacing = 10; - m_pageHeaderFooter.ptFootNoteBodySpacing = 10; - m_varFormatCollection->clear(); - - m_pages = 1; - m_bHasEndNotes = false; KoColumns __columns; __columns.columns = 1; __columns.ptColumnSpacing = m_defaultColumnSpacing; KoKWHeaderFooter __hf; __hf.header = HF_SAME; __hf.footer = HF_SAME; __hf.ptHeaderBodySpacing = 10.0; __hf.ptFooterBodySpacing = 10.0; __hf.ptFootNoteBodySpacing = 10.0; QDomElement content = doc.documentElement(); QDomElement body ( KoDom::namedItemNS( content, KoXmlNS::office, "body" ) ); if ( body.isNull() ) { kdError(30518) << "No office:body found!" << endl; setErrorMessage( i18n( "Invalid OASIS document. No office:body tag found." ) ); return false; } body = KoDom::namedItemNS( body, KoXmlNS::office, "text" ); if ( body.isNull() ) { kdError(30518) << "No office:text found!" << endl; // ## TODO: print the actual tag that was found, it might help finding the right app to use :) setErrorMessage( i18n( "Invalid KWord document. No office:text tag found." ) ); return false; } // TODO check versions and mimetypes etc. QString masterPageName = "Standard"; // use default layout as fallback // In theory the page format is the style:master-page-name of the first paragraph... // But, hmm, in a doc with only a table there was no reference to the master page at all... QDomElement* masterPage = oasisStyles.masterPages()[ masterPageName ]; Q_ASSERT( masterPage ); QDomElement *masterPageStyle = masterPage ? oasisStyles.styles()[masterPage->attributeNS( KoXmlNS::style, "page-layout-name", QString::null )] : 0; Q_ASSERT( masterPageStyle ); if ( masterPageStyle ) { m_pageLayout.loadOasis( *masterPageStyle ); if ( m_pageLayout.ptWidth <= 1e-13 || m_pageLayout.ptHeight <= 1e-13 ) { setErrorMessage( i18n( "Invalid document. Paper size: %1x%2" ).arg( m_pageLayout.ptWidth ).arg( m_pageLayout.ptHeight ) ); return false; } //__hf.ptHeaderBodySpacing = getAttribute( paper, "spHeadBody", 0.0 ); //__hf.ptFooterBodySpacing = getAttribute( paper, "spFootBody", 0.0 ); //__hf.ptFootNoteBodySpacing = getAttribute( paper, "spFootNoteBody", 10.0 ); QDomElement properties( KoDom::namedItemNS( *masterPageStyle, KoXmlNS::style, "page-layout-properties" ) ); QDomElement footnoteSep = KoDom::namedItemNS( properties, KoXmlNS::style, "footnote-sep" ); if ( !footnoteSep.isNull() ) { // style:width="0.018cm" style:distance-before-sep="0.101cm" // style:distance-after-sep="0.101cm" style:adjustment="left" // style:rel-width="25%" style:color="#000000" QString width = footnoteSep.attributeNS( KoXmlNS::style, "width", QString::null ); m_footNoteSeparatorLineWidth = KoUnit::parseValue( width ); QString pageWidth = footnoteSep.attributeNS( KoXmlNS::style, "rel-width", QString::null ); if ( pageWidth.endsWith( "%" ) ) { pageWidth.truncate( pageWidth.length() - 1 ); // remove '%' m_iFootNoteSeparatorLineLength = qRound( pageWidth.toDouble() ); } // Not in KWord: color, distance before and after separator // Not in OOo, but in OASIS now: line type of separator (solid, dot, dash etc.) // m_footNoteSeparatorLineType = ... // TODO style:line-style, added in OASIS QString pos = footnoteSep.attributeNS( KoXmlNS::style, "adjustment", QString::null ); if ( pos =="centered" ) m_footNoteSeparatorLinePos = SLP_CENTERED; else if ( pos =="right") m_footNoteSeparatorLinePos = SLP_RIGHT; else if ( pos =="left" ) m_footNoteSeparatorLinePos = SLP_LEFT; } // TODO columns (style:columns, attribute fo:column-count) __columns.columns = 1; // TODO // TODO columnspacing (style:column-sep ?) __columns.ptColumnSpacing = 2; // TODO m_headerVisible = false; m_footerVisible = false; // TODO spHeadBody (where is this in OOo?) // TODO spFootBody (where is this in OOo?) // Answer: margins of the element } m_loadingInfo = new KWLoadingInfo; // oasis extension for DTP (2003-10-27 post by Daniel) m_processingType = ( !KoDom::namedItemNS( body, KoXmlNS::text, "page-sequence" ).isNull() ) ? DTP : WP; // TODO settings (m_unit, spellcheck settings) m_hasTOC = false; m_tabStop = MM_TO_POINT(15); // TODO // TODO m_initialEditing // TODO variable settings // By default display real variable value if ( !isReadWrite()) getVariableCollection()->variableSetting()->setDisplayFieldCode(false); // TODO MAILMERGE KoOasisContext context( this, *m_varColl, oasisStyles, store ); Q_ASSERT( !oasisStyles.officeStyle().isNull() ); // Load all styles before the corresponding paragraphs try to use them! m_styleColl->loadOasisStyleTemplates( context ); // TODO framestyles and tablestyles loadDefaultTableTemplates(); if ( m_processingType == WP ) { // Create main frameset KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Main Text Frameset" ) ); m_lstFrameSet.append( fs ); // don't use addFrameSet here. We'll call finalize() once and for all in completeLoading fs->loadOasisContent( body, context ); KWFrame* frame = new KWFrame( fs, 29, 42, 798-29, 566-42 ); frame->setFrameBehavior( KWFrame::AutoCreateNewFrame ); frame->setNewFrameBehavior( KWFrame::Reconnect ); fs->addFrame( frame ); } // Header/Footer // TODO support for first-page bool hasEvenOddHeader = false; bool hasEvenOddFooter = false; QDomElement headerStyle = KoDom::namedItemNS( *masterPageStyle, KoXmlNS::style, "header-style" ); QDomElement footerStyle = KoDom::namedItemNS( *masterPageStyle, KoXmlNS::style, "footer-style" ); QDomElement headerLeftElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "header-left" ); if ( !headerLeftElem.isNull() ) { kdDebug() << "Found header-left" << endl; hasEvenOddHeader = true; __hf.header = HF_EO_DIFF; // ### loadOasisHeaderFooter( headerLeftElem, hasEvenOddHeader, headerStyle, context ); } QDomElement headerElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "header" ); if ( !headerElem.isNull() ) { kdDebug() << "Found header" << endl; loadOasisHeaderFooter( headerElem, hasEvenOddHeader, headerStyle, context ); } QDomElement footerLeftElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "footer-left" ); if ( !footerLeftElem.isNull() ) { kdDebug() << "Found footer-left" << endl; hasEvenOddFooter = true; __hf.footer = HF_EO_DIFF; // ### loadOasisHeaderFooter( footerLeftElem, hasEvenOddFooter, footerStyle, context ); } QDomElement footerElem = KoDom::namedItemNS( *masterPage, KoXmlNS::style, "footer" ); if ( !footerElem.isNull() ) { kdDebug() << "Found footer" << endl; loadOasisHeaderFooter( footerElem, hasEvenOddFooter, footerStyle, context ); } // TODO embedded objects kdDebug(32001) << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl; endOfLoading(); // This sets the columns and header/footer flags, and calls recalcFrames, // so it must be done last. setPageLayout( m_pageLayout, __columns, __hf, false ); if ( !settings.isNull() ) { loadOasisSettings( settings ); } //printDebug(); return true; } void KWDocument::loadOasisSettings( const QDomDocument&settingsDoc ) { KoOasisSettings settings( settingsDoc ); KoOasisSettings::Items viewSettings = settings.itemSet( "view-settings" ); if ( !viewSettings.isNull() ) { setUnit(KoUnit::unit(viewSettings.parseConfigItemString("unit"))); } loadOasisIgnoreList( settings ); } static QString headerTypeToFramesetName( const QString& tagName, bool hasEvenOdd ) { if ( tagName == "style:header" ) return hasEvenOdd ? i18n("Odd Pages Header") : i18n( "Header" ); if ( tagName == "style:header-left" ) return i18n("Even Pages Header"); if ( tagName == "style:footer" ) return hasEvenOdd ? i18n("Odd Pages Footer") : i18n( "Footer" ); if ( tagName == "style:footer-left" ) return i18n("Even Pages Footer"); kdWarning(30518) << "Unknown tag in headerTypeToFramesetName: " << tagName << endl; // ###### //return i18n("First Page Header"); //return i18n("First Page Footer"); return QString::null; } static KWFrameSet::Info headerTypeToFrameInfo( const QString& tagName, bool /*hasEvenOdd*/ ) { if ( tagName == "style:header" ) return KWFrameSet::FI_ODD_HEADER; if ( tagName == "style:header-left" ) return KWFrameSet::FI_EVEN_HEADER; if ( tagName == "style:footer" ) return KWFrameSet::FI_ODD_FOOTER; if ( tagName == "style:footer-left" ) return KWFrameSet::FI_EVEN_FOOTER; // ### return KWFrameSet::FI_FIRST_HEADER; TODO // ### return KWFrameSet::FI_FIRST_FOOTER; TODO return KWFrameSet::FI_BODY; } void KWDocument::loadOasisHeaderFooter( const QDomElement& headerFooter, bool hasEvenOdd, QDomElement& style, KoOasisContext& context ) { const QString tagName = headerFooter.tagName(); bool isHeader = tagName.startsWith( "style:header" ); KWTextFrameSet *fs = new KWTextFrameSet( this, headerTypeToFramesetName( tagName, hasEvenOdd ) ); fs->setFrameSetInfo( headerTypeToFrameInfo( tagName, hasEvenOdd ) ); m_lstFrameSet.append( fs ); // don't use addFrameSet here. We'll call finalize() once and for all in completeLoading if ( !style.isNull() ) context.styleStack().push( style ); KWFrame* frame = new KWFrame( fs, 29, isHeader?0:567, 798-29, 41 ); frame->loadCommonOasisProperties( context, fs ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); if ( !style.isNull() ) context.styleStack().pop(); // don't let it be active when parsing the text fs->loadOasisContent( headerFooter, context ); if ( isHeader ) m_headerVisible = true; else m_footerVisible = true; } -bool KWDocument::loadXML( QIODevice *, const QDomDocument & doc ) +// called before loading +void KWDocument::clear() { - QTime dt; - dt.start(); - emit sigProgress( 0 ); - kdDebug(32001) << "KWDocument::loadXML" << endl; m_pictureMap.clear(); m_textImageRequests.clear(); m_pictureRequests.clear(); m_anchorRequests.clear(); m_footnoteVarRequests.clear(); m_spellListIgnoreAll.clear(); - m_pageColumns.columns = 1; m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; m_pageHeaderFooter.header = HF_SAME; m_pageHeaderFooter.footer = HF_SAME; m_pageHeaderFooter.ptHeaderBodySpacing = 10; m_pageHeaderFooter.ptFooterBodySpacing = 10; m_pageHeaderFooter.ptFootNoteBodySpacing = 10; - m_varFormatCollection->clear(); - + m_pageColumns.columns = 1; + m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; m_pages = 1; m_bHasEndNotes = false; + m_varColl->clear(); + m_pictureCollection->clear(); + m_varFormatCollection->clear(); + + m_styleColl->clear(); + m_frameStyleColl->clear(); + m_tableStyleColl->clear(); + m_tableTemplateColl->clear(); + + // Some simple import filters don't define any style, + // so let's have a Standard style at least + KoParagStyle * standardStyle = new KoParagStyle( "Standard" ); // This gets translated later on + //kdDebug() << "KWDocument::KWDocument creating standardStyle " << standardStyle << endl; + standardStyle->format().setFont( m_defaultFont ); + m_styleColl->addStyleTemplate( standardStyle ); + + // And let's do the same for framestyles + KWFrameStyle * standardFrameStyle = new KWFrameStyle( "Plain" ); + standardFrameStyle->setBackgroundColor(Qt::white); + standardFrameStyle->setTopBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); + standardFrameStyle->setRightBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); + standardFrameStyle->setLeftBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); + standardFrameStyle->setBottomBorder(KoBorder(Qt::black,KoBorder::SOLID,0)); + m_frameStyleColl->addFrameStyleTemplate( standardFrameStyle ); + + // And let's do the same for tablestyles + KWTableStyle *standardTableStyle = new KWTableStyle( "Plain", standardStyle, standardFrameStyle ); + m_tableStyleColl->addTableStyleTemplate( standardTableStyle ); +} + +bool KWDocument::loadXML( QIODevice *, const QDomDocument & doc ) +{ + QTime dt; + dt.start(); + emit sigProgress( 0 ); + kdDebug(32001) << "KWDocument::loadXML" << endl; + clear(); + KoPageLayout __pgLayout; KoColumns __columns; __columns.columns = 1; __columns.ptColumnSpacing = m_defaultColumnSpacing; KoKWHeaderFooter __hf; __hf.header = HF_SAME; __hf.footer = HF_SAME; __hf.ptHeaderBodySpacing = 10.0; __hf.ptFooterBodySpacing = 10.0; __hf.ptFootNoteBodySpacing = 10.0; QString value; QDomElement word = doc.documentElement(); value = KWDocument::getAttribute( word, "mime", QString::null ); if ( value.isEmpty() ) { kdError(32001) << "No mime type specified!" << endl; setErrorMessage( i18n( "Invalid document. No mimetype specified." ) ); return false; } else if ( value != "application/x-kword" && value != "application/vnd.kde.kword" ) { kdError(32001) << "Unknown mime type " << value << endl; setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-kword or application/vnd.kde.kword, got %1" ).arg( value ) ); return false; } m_syntaxVersion = KWDocument::getAttribute( word, "syntaxVersion", 0 ); if ( m_syntaxVersion > CURRENT_SYNTAX_VERSION ) { int ret = KMessageBox::warningContinueCancel( 0, i18n("This document was created with a newer version of KWord (syntax version: %1)\n" "Opening it in this version of KWord will lose some information.").arg(m_syntaxVersion), i18n("File Format Mismatch"), KStdGuiItem::cont() ); if ( ret == KMessageBox::Cancel ) { setErrorMessage( "USER_CANCELED" ); return false; } } m_loadingInfo = new KWLoadingInfo; // Looks like support for the old way of naming images internally, // see completeLoading. value = KWDocument::getAttribute( word, "url", QString::null ); if ( !value.isNull() ) { m_urlIntern = KURL( value ).path(); } emit sigProgress(5); // QDomElement paper = word.namedItem( "PAPER" ).toElement(); if ( !paper.isNull() ) { __pgLayout.format = static_cast( KWDocument::getAttribute( paper, "format", 0 ) ); __pgLayout.orientation = static_cast( KWDocument::getAttribute( paper, "orientation", 0 ) ); __pgLayout.ptWidth = getAttribute( paper, "width", 0.0 ); __pgLayout.ptHeight = getAttribute( paper, "height", 0.0 ); kdDebug() << " ptWidth=" << __pgLayout.ptWidth << endl; kdDebug() << " ptHeight=" << __pgLayout.ptHeight << endl; if ( __pgLayout.ptWidth <= 0 || __pgLayout.ptHeight <= 0 ) { // Old document? __pgLayout.ptWidth = getAttribute( paper, "ptWidth", 0.0 ); __pgLayout.ptHeight = getAttribute( paper, "ptHeight", 0.0 ); kdDebug() << " ptWidth=" << __pgLayout.ptWidth << endl; kdDebug() << " ptHeight=" << __pgLayout.ptHeight << endl; // Still wrong? if ( __pgLayout.ptWidth <= 0 || __pgLayout.ptHeight <= 0 ) { setErrorMessage( i18n( "Invalid document. Paper size: %1x%2" ) .arg( __pgLayout.ptWidth ).arg( __pgLayout.ptHeight ) ); return false; } } __hf.header = static_cast( KWDocument::getAttribute( paper, "hType", 0 ) ); __hf.footer = static_cast( KWDocument::getAttribute( paper, "fType", 0 ) ); __hf.ptHeaderBodySpacing = getAttribute( paper, "spHeadBody", 0.0 ); __hf.ptFooterBodySpacing = getAttribute( paper, "spFootBody", 0.0 ); __hf.ptFootNoteBodySpacing = getAttribute( paper, "spFootNoteBody", 10.0 ); m_iFootNoteSeparatorLineLength = getAttribute( paper, "slFootNoteLength", 20); m_footNoteSeparatorLineWidth = getAttribute( paper, "slFootNoteWidth",2.0); m_footNoteSeparatorLineType = static_cast(getAttribute( paper, "slFootNoteType",0)); if ( paper.hasAttribute("slFootNotePosition")) { QString tmp =paper.attribute("slFootNotePosition"); if ( tmp =="centered" ) m_footNoteSeparatorLinePos = SLP_CENTERED; else if ( tmp =="right") m_footNoteSeparatorLinePos = SLP_RIGHT; else if ( tmp =="left" ) m_footNoteSeparatorLinePos = SLP_LEFT; } __columns.columns = KWDocument::getAttribute( paper, "columns", 1 ); __columns.ptColumnSpacing = KWDocument::getAttribute( paper, "columnspacing", 0.0 ); // Now part of the app config //m_zoom = KWDocument::getAttribute( paper, "zoom", 100 ); //if(m_zoom!=100) // setZoomAndResolution( m_zoom, KoGlobal::dpiX(), KoGlobal::dpiY(), false, false ); // Support the undocumented syntax actually used by KDE 2.0 for some of the above (:-(). // Do not add anything to this block! if ( __pgLayout.ptWidth == 0.0 ) __pgLayout.ptWidth = getAttribute( paper, "ptWidth", 0.0 ); if ( __pgLayout.ptHeight == 0.0 ) __pgLayout.ptHeight = getAttribute( paper, "ptHeight", 0.0 ); if ( __hf.ptHeaderBodySpacing == 0.0 ) __hf.ptHeaderBodySpacing = getAttribute( paper, "ptHeadBody", 0.0 ); if ( __hf.ptFooterBodySpacing == 0.0 ) __hf.ptFooterBodySpacing = getAttribute( paper, "ptFootBody", 0.0 ); if ( __columns.ptColumnSpacing == 0.0 ) __columns.ptColumnSpacing = getAttribute( paper, "ptColumnspc", 0.0 ); // QDomElement paperborders = paper.namedItem( "PAPERBORDERS" ).toElement(); if ( !paperborders.isNull() ) { __pgLayout.ptLeft = getAttribute( paperborders, "left", 0.0 ); __pgLayout.ptTop = getAttribute( paperborders, "top", 0.0 ); __pgLayout.ptRight = getAttribute( paperborders, "right", 0.0 ); __pgLayout.ptBottom = getAttribute( paperborders, "bottom", 0.0 ); // Support the undocumented syntax actually used by KDE 2.0 for some of the above (:-(). if ( __pgLayout.ptLeft == 0.0 ) __pgLayout.ptLeft = getAttribute( paperborders, "ptLeft", 0.0 ); if ( __pgLayout.ptTop == 0.0 ) __pgLayout.ptTop = getAttribute( paperborders, "ptTop", 0.0 ); if ( __pgLayout.ptRight == 0.0 ) __pgLayout.ptRight = getAttribute( paperborders, "ptRight", 0.0 ); if ( __pgLayout.ptBottom == 0.0 ) __pgLayout.ptBottom = getAttribute( paperborders, "ptBottom", 0.0 ); } else kdWarning() << "No tag!" << endl; } else kdWarning() << "No tag! This is a mandatory tag! Expect weird page sizes..." << endl; // m_unit = KoUnit::U_CM; QDomElement attributes = word.namedItem( "ATTRIBUTES" ).toElement(); if ( !attributes.isNull() ) { m_processingType = static_cast( KWDocument::getAttribute( attributes, "processing", 0 ) ); //KWDocument::getAttribute( attributes, "standardpage", QString::null ); m_headerVisible = static_cast( KWDocument::getAttribute( attributes, "hasHeader", 0 ) ); m_footerVisible = static_cast( KWDocument::getAttribute( attributes, "hasFooter", 0 ) ); if ( attributes.hasAttribute( "unit" ) ) m_unit = KoUnit::unit( attributes.attribute( "unit" ) ); m_hasTOC = static_cast(KWDocument::getAttribute( attributes,"hasTOC", 0 ) ); m_tabStop = KWDocument::getAttribute( attributes, "tabStopValue", MM_TO_POINT(15) ); m_initialEditing = new InitialEditing(); m_initialEditing->m_initialFrameSet = attributes.attribute( "activeFrameset" ); m_initialEditing->m_initialCursorParag = attributes.attribute( "cursorParagraph" ).toInt(); m_initialEditing->m_initialCursorIndex = attributes.attribute( "cursorIndex" ).toInt(); } else { m_processingType = WP; m_headerVisible = false; m_footerVisible = false; m_hasTOC = false; m_tabStop = MM_TO_POINT(15); delete m_initialEditing; m_initialEditing = 0L; } setPageLayout( __pgLayout, __columns, __hf, false ); getVariableCollection()->variableSetting()->load(word ); //by default display real variable value if ( !isReadWrite()) getVariableCollection()->variableSetting()->setDisplayFieldCode(false); emit sigProgress(10); QDomElement mailmerge = word.namedItem( "MAILMERGE" ).toElement(); if (mailmerge!=QDomElement()) { m_slDataBase->load(mailmerge); } emit sigProgress(15); // Load all styles before the corresponding paragraphs try to use them! QDomElement stylesElem = word.namedItem( "STYLES" ).toElement(); if ( !stylesElem.isNull() ) loadStyleTemplates( stylesElem ); emit sigProgress(17); QDomElement frameStylesElem = word.namedItem( "FRAMESTYLES" ).toElement(); if ( !frameStylesElem.isNull() ) loadFrameStyleTemplates( frameStylesElem ); else // load default styles loadDefaultFrameStyleTemplates(); emit sigProgress(18); QDomElement tableStylesElem = word.namedItem( "TABLESTYLES" ).toElement(); if ( !tableStylesElem.isNull() ) loadTableStyleTemplates( tableStylesElem ); else // load default styles loadDefaultTableStyleTemplates(); emit sigProgress(19); loadDefaultTableTemplates(); emit sigProgress(20); QDomElement bookmark = word.namedItem( "BOOKMARKS" ).toElement(); if( !bookmark.isNull() ) { QDomElement bookmarkitem = word.namedItem("BOOKMARKS").toElement(); bookmarkitem = bookmarkitem.firstChild().toElement(); while ( !bookmarkitem.isNull() ) { if ( bookmarkitem.tagName() == "BOOKMARKITEM" ) { KWLoadingInfo::BookMark bk; bk.bookname=bookmarkitem.attribute("name"); bk.cursorStartIndex=bookmarkitem.attribute("cursorIndexStart").toInt(); bk.frameSetName=bookmarkitem.attribute("frameset"); bk.paragStartIndex = bookmarkitem.attribute("startparag").toInt(); bk.paragEndIndex = bookmarkitem.attribute("endparag").toInt(); bk.cursorEndIndex = bookmarkitem.attribute("cursorIndexEnd").toInt(); Q_ASSERT( m_loadingInfo ); m_loadingInfo->bookMarkList.append( bk ); } bookmarkitem = bookmarkitem.nextSibling().toElement(); } } QDomElement spellCheckIgnore = word.namedItem( "SPELLCHECKIGNORELIST" ).toElement(); if( !spellCheckIgnore.isNull() ) { QDomElement spellWord=word.namedItem("SPELLCHECKIGNORELIST").toElement(); spellWord=spellWord.firstChild().toElement(); while ( !spellWord.isNull() ) { if ( spellWord.tagName()=="SPELLCHECKIGNOREWORD" ) m_spellListIgnoreAll.append(spellWord.attribute("word")); spellWord=spellWord.nextSibling().toElement(); } } emit sigProgress(25); QDomElement framesets = word.namedItem( "FRAMESETS" ).toElement(); if ( !framesets.isNull() ) loadFrameSets( framesets ); emit sigProgress(85); loadPictureMap( word ); emit sigProgress(90); // loadEmbeddedObjects( word ); emit sigProgress(100); // the rest is only processing, not loading kdDebug(32001) << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl; endOfLoading(); return true; } void KWDocument::endOfLoading() { bool _first_footer = false, _even_footer = false, _odd_footer = false; bool _first_header = false, _even_header = false, _odd_header = false; QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { switch( fit.current()->frameSetInfo() ) { case KWFrameSet::FI_FIRST_HEADER: _first_header = true; break; case KWFrameSet::FI_ODD_HEADER: _odd_header = true; break; case KWFrameSet::FI_EVEN_HEADER: _even_header = true; break; case KWFrameSet::FI_FIRST_FOOTER: _first_footer = true; break; case KWFrameSet::FI_ODD_FOOTER: _odd_footer = true; break; case KWFrameSet::FI_EVEN_FOOTER: _even_footer = true; break; case KWFrameSet::FI_FOOTNOTE: break; default: break; } } // create defaults if they were not in the input file. if ( !_first_header ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "First Page Header" ) ); //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl; fs->setFrameSetInfo( KWFrameSet::FI_FIRST_HEADER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptTopBorder(), ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << frame << endl; frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_odd_header ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Odd Pages Header" ) ); fs->setFrameSetInfo( KWFrameSet::FI_ODD_HEADER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptTopBorder(), ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_even_header ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Even Pages Header" ) ); fs->setFrameSetInfo( KWFrameSet::FI_EVEN_HEADER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptTopBorder(), ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_first_footer ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "First Page Footer" ) ); fs->setFrameSetInfo( KWFrameSet::FI_FIRST_FOOTER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptPaperHeight() - ptTopBorder() - 20, ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_odd_footer ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Odd Pages Footer" ) ); fs->setFrameSetInfo( KWFrameSet::FI_ODD_FOOTER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptPaperHeight() - ptTopBorder() - 20, ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_even_footer ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Even Pages Footer" ) ); fs->setFrameSetInfo( KWFrameSet::FI_EVEN_FOOTER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptPaperHeight() - ptTopBorder() - 20, ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } // do some sanity checking on document. for (int i = numFrameSets()-1; i>-1; i--) { KWFrameSet *fs = frameSet(i); if(!fs) { kdWarning() << "frameset " << i << " is NULL!!" << endl; m_lstFrameSet.remove(i); } else if( fs->type()==FT_TABLE) { static_cast( fs )->validate(); } else if(!fs->getNumFrames()) { kdWarning () << "frameset " << i << " " << fs->getName() << " has no frames" << endl; removeFrameSet(fs); if ( fs->type() == FT_PART ) delete static_cast(fs)->getChild(); delete fs; } else if (fs->type() == FT_TEXT) { for (int f=fs->getNumFrames()-1; f>=0; f--) { KWFrame *frame = fs->frame(f); if(frame->height() < s_minFrameHeight) { kdWarning() << fs->getName() << " frame " << f << " height is so small no text will fit, adjusting (was: " << frame->height() << " is: " << s_minFrameHeight << ")" << endl; frame->setHeight(s_minFrameHeight); } if(frame->width() < s_minFrameWidth) { kdWarning() << fs->getName() << " frame " << f << " width is so small no text will fit, adjusting (was: " << frame->width() << " is: " << s_minFrameWidth << ")" << endl; frame->setWidth(s_minFrameWidth); } } } } // Renumber footnotes KWTextFrameSet *frameset = dynamic_cast( m_lstFrameSet.getFirst() ); if ( frameset ) frameset->renumberFootNotes( false /*no repaint*/ ); emit sigProgress(-1); //kdDebug(32001) << "KWDocument::loadXML done" << endl; setModified( false ); // Connect to notifications from main text-frameset if ( frameset ) { connect( frameset->textObject(), SIGNAL( chapterParagraphFormatted( KoTextParag * ) ), SLOT( slotChapterParagraphFormatted( KoTextParag * ) ) ); connect( frameset, SIGNAL( mainTextHeightChanged() ), SIGNAL( mainTextHeightChanged() ) ); } } void KWDocument::startBackgroundSpellCheck() { //don't start bg spell checking if if(backgroundSpellCheckEnabled() && isReadWrite()) { #ifdef HAVE_LIBKSPELL2 m_bgSpellCheck->start(); #endif } } void KWDocument::loadEmbeddedObjects( QDomElement& word ) { QDomNodeList listEmbedded = word.elementsByTagName ( "EMBEDDED" ); for (unsigned int item = 0; item < listEmbedded.count(); item++) { QDomElement embedded = listEmbedded.item( item ).toElement(); loadEmbedded( embedded ); } } void KWDocument::loadEmbedded( const QDomElement &embedded ) { QDomElement object = embedded.namedItem( "OBJECT" ).toElement(); if ( !object.isNull() ) { KWChild *ch = new KWChild( this ); ch->load( object, true ); insertChild( ch ); QDomElement settings = embedded.namedItem( "SETTINGS" ).toElement(); QString name; if ( !settings.isNull() ) name = settings.attribute( "name" ); KWPartFrameSet *fs = new KWPartFrameSet( this, ch, name ); m_lstFrameSet.append( fs ); if ( !settings.isNull() ) { kdDebug(32001) << "KWDocument::loadXML loading embedded object" << endl; fs->load( settings ); } else kdError(32001) << "No tag in EMBEDDED" << endl; emit sig_insertObject( ch, fs ); } else kdError(32001) << "No tag in EMBEDDED" << endl; } void KWDocument::loadStyleTemplates( const QDomElement &stylesElem ) { QValueList followingStyles; QDomNodeList listStyles = stylesElem.elementsByTagName( "STYLE" ); if( listStyles.count() > 0) { // we are going to import at least one style. KoParagStyle *s = m_styleColl->findStyle("Standard"); //kdDebug(32001) << "KWDocument::loadStyleTemplates looking for Standard, to delete it. Found " << s << endl; if(s) // delete the standard style. m_styleColl->removeStyleTemplate(s); } for (unsigned int item = 0; item < listStyles.count(); item++) { QDomElement styleElem = listStyles.item( item ).toElement(); KoParagStyle *sty = new KoParagStyle( QString::null ); // Load the style from the