summaryrefslogtreecommitdiffstats
path: root/kword/KWInsertTOCCommand.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kword/KWInsertTOCCommand.cpp')
-rw-r--r--kword/KWInsertTOCCommand.cpp261
1 files changed, 261 insertions, 0 deletions
diff --git a/kword/KWInsertTOCCommand.cpp b/kword/KWInsertTOCCommand.cpp
new file mode 100644
index 00000000..5740e125
--- /dev/null
+++ b/kword/KWInsertTOCCommand.cpp
@@ -0,0 +1,261 @@
+/* This file is part of the KDE project
+ Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <KoParagCounter.h>
+
+#include "KWInsertTOCCommand.h"
+#include "KWDocument.h"
+#include "KWTextFrameSet.h"
+#include "KWTextDocument.h"
+#include "KWTextParag.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+
+KWInsertTOCCommand::KWInsertTOCCommand( KWTextFrameSet * fs, KoTextParag *parag )
+ : KoTextDocCommand( fs->textDocument() ), m_paragId( parag->paragId() )
+{
+}
+
+KoTextCursor * KWInsertTOCCommand::execute( KoTextCursor *c )
+{
+ KWTextDocument * textdoc = static_cast<KWTextDocument *>(doc);
+ KWTextFrameSet * fs = textdoc->textFrameSet();
+
+ fs->kWordDocument()->setTocPresent(true);
+
+ KoTextParag *insertionParag = textdoc->paragAt( m_paragId );
+ if ( !insertionParag ) {
+ qWarning( "KWInsertTOCCommand:: can't locate parag at %d, last parag: %d", m_paragId, textdoc->lastParag()->paragId() );
+ return c;
+ }
+ KWTextParag *body = static_cast<KWTextParag *>( insertionParag );
+ // Create new very first paragraph
+ KWTextParag *parag = static_cast<KWTextParag *>( textdoc->createParag( textdoc, body->prev() /*prev*/, body /*next*/, true ) );
+ parag->append( i18n( "Table of Contents" ) );
+ KoParagStyle * style = findOrCreateTOCStyle( fs, -1 ); // "Contents Title"
+ parag->setParagLayout( style->paragLayout() );
+ parag->setFormat( 0, parag->string()->length(), textdoc->formatCollection()->format( &style->format() ) );
+ parag->setPartOfTableOfContents( true );
+
+ // Insert table and THEN set page numbers
+ // Otherwise the page numbers are incorrect
+
+ KWTextParag *p = static_cast<KWTextParag *>(textdoc->firstParag()/*parag->next()*/);
+ //ASSERT( p == body );
+ KWTextParag *prevTOCParag = parag;
+ QMap<KWTextParag *, KWTextParag *> paragMap; // Associate a paragraph form the TOC with the real one from the body
+ while ( p ) {
+ // Include this paragraph in the TOC depending on the isOutline flag of the style
+ if ( p->style() && p->style()->isOutline() )
+ {
+ parag = static_cast<KWTextParag *>(textdoc->createParag( textdoc, prevTOCParag /*prev*/, body /*next*/, true ));
+ parag->setPartOfTableOfContents( true );
+ QString txt = p->toString(); // includes the heading number, if any
+ parag->append( txt );
+ prevTOCParag = parag;
+
+ paragMap.insert( parag, p );
+ }
+ p = static_cast<KWTextParag *>(p->next());
+ }
+ // Set a hard frame break after the last TOC parag
+ kdDebug() << "KWInsertTOCCommand::execute setPageBreaking on " << prevTOCParag << " " << prevTOCParag->paragId() << endl;
+ prevTOCParag->setPageBreaking( prevTOCParag->pageBreaking() | KWParagLayout::HardFrameBreakAfter );
+
+ // Format paragraphs, to take this page break into account and update page numbers
+ fs->layout();
+ fs->updateFrames();
+
+ //kdDebug() << "KWInsertTOCCommand::execute layouting done, setting page numbers" << endl;
+
+ // Now add the page numbers, and apply the style
+ QMap<KWTextParag *, KWTextParag *>::Iterator mapIt = paragMap.begin();
+ for ( ; mapIt != paragMap.end() ; ++mapIt )
+ {
+ KWTextParag * parag = mapIt.key(); // Parag in the TOC
+ KWTextParag * p = mapIt.data(); // Parag in the body
+
+ // Find page number for paragraph
+ KoPoint pt;
+ KWFrame * frame = fs->internalToDocument( QPoint(0, p->rect().top()), pt );
+ if ( frame ) // let's be safe
+ {
+ parag->append( "\t" );
+ parag->append( QString::number( frame->pageNumber() ) );
+ }
+
+ // Apply style
+ int depth = p->counter() ? p->counter()->depth() : 0;
+ KoParagStyle * tocStyle = findOrCreateTOCStyle( fs, depth );
+ parag->setParagLayout( tocStyle->paragLayout() );
+ parag->setFormat( 0, parag->string()->length(), & tocStyle->format() );
+ }
+ // The setParagLayout ruined it, so here it is again :)
+ prevTOCParag->setPageBreaking( prevTOCParag->pageBreaking() | KWParagLayout::HardFrameBreakAfter );
+ return c;
+}
+
+KoTextCursor *KWInsertTOCCommand::unexecute( KoTextCursor *c )
+{
+ KWTextDocument * textdoc = static_cast<KWTextDocument *>(doc);
+ KWTextFrameSet * fs = textdoc->textFrameSet();
+
+ removeTOC( fs, c, 0L );
+ fs->kWordDocument()->setTocPresent(false);
+ return c;
+}
+
+KoTextCursor * KWInsertTOCCommand::removeTOC( KWTextFrameSet *fs, KoTextCursor *cursor, KMacroCommand * /*macroCmd*/ )
+{
+ KoTextDocument * textdoc = fs->textDocument();
+ // Remove existing table of contents, based on the style
+ KoTextCursor start( textdoc );
+ KoTextCursor end( textdoc );
+ // We start from the end, to avoid the parag shifting problem
+ KoTextParag *p = textdoc->lastParag();
+ KoTextCursor *posOfTable=0L;
+ KoTextParag *posOfToc=0L;
+
+ while ( p )
+ {
+ KWTextParag * parag = static_cast<KWTextParag *>(p);
+ if ( parag->partOfTableOfContents() )
+ {
+ kdDebug() << "KWContents::createContents Deleting paragraph " << p << " " << p->paragId() << endl;
+ // This paragraph is part of the TOC -> remove
+
+ /* This method aims to provide an "undo" that restores the previous version of the TOC.
+ Problem is, it screws up the parag style (due to removeSelectedText calling join),
+ and the first parag of the body ends up with the Contents Title style.
+ start.setParag( p );
+ start.setIndex( 0 );
+ textdoc->setSelectionStart( KoTextDocument::Temp, &start );
+ ASSERT( p->next() );
+ end.setParag( p->next() );
+ end.setIndex( 0 );
+ textdoc->setSelectionEnd( KoTextDocument::Temp, &end );
+ KCommand * cmd = fs->removeSelectedTextCommand( cursor, KoTextDocument::Temp );
+ if ( macroCmd )
+ macroCmd->addCommand( cmd );
+ */
+
+ // So instead, we do things by hand, and without undo....
+
+ KoTextParag *prev = p->prev();
+ KoTextParag *next = p->next();
+ // Move cursor out
+ if ( cursor->parag() == p )
+ cursor->setParag( next ? next : prev );
+ delete p;
+ kdDebug() << "KWInsertTOCCommand::removeTOC " << p << " deleted" << endl;
+ p = next;
+ posOfToc = p;
+ kdDebug() << "KWInsertTOCCommand::removeTOC prev=" << prev << " p=" << p << endl;
+ // Fix parag chain
+ if ( prev )
+ {
+ prev->setNext( p );
+ if ( p )
+ p->setParagId( prev->paragId() + 1 );
+ else
+ posOfToc = prev;
+ }
+ else
+ {
+ textdoc->setFirstParag( p );
+ if ( p )
+ {
+ p->setParagId( 0 );
+ } else // completely empty document !
+ {
+ textdoc->clear( true ); // recreate empty parag.
+ cursor->setParag( textdoc->firstParag() );
+ posOfToc = textdoc->firstParag();
+ break;
+ }
+ }
+ if(! p) { // see bug #131122
+ p = prev;
+ continue;
+ }
+ p->setPrev( prev );
+ }
+ p = p->prev();
+ }
+ textdoc->invalidate();
+ if(posOfToc)
+ {
+ posOfTable=new KoTextCursor( textdoc );
+ posOfTable->setParag(posOfToc );
+ posOfTable->setIndex( 0 );//start of parag
+ }
+ // ### TODO propagate parag ID changes.
+ return posOfTable;
+}
+
+KoParagStyle * KWInsertTOCCommand::findOrCreateTOCStyle( KWTextFrameSet *fs, int depth )
+{
+ // Determine style name.
+ QString name;
+ QString displayName;
+ if ( depth >= 0 ) {
+ // Don't add i18n to this one, those are internal names and must have no spaces.
+ name = QString( "Contents_Head_%1" ).arg( depth+1 );
+ displayName = i18n( "Contents Head %1" ).arg( depth+1 );
+ } else {
+ name = "Contents_Title";
+ displayName = i18n( "Contents Title" );
+ }
+ KoParagStyle * style = fs->kWordDocument()->styleCollection()->findStyle( name );
+ if ( !style )
+ {
+ style = new KoParagStyle( name );
+ style->setDisplayName( displayName );
+ style->format().setBold( ( ( depth==-1) || ( depth==0 ) ) ? true : false );
+ style->format().setPointSize( depth==-1 ? 20 : 12 );
+ if ( depth == -1 )
+ {
+ style->paragLayout().topBorder = KoBorder( Qt::black, KoBorder::SOLID, 1 );
+ style->paragLayout().bottomBorder = KoBorder( Qt::black, KoBorder::SOLID, 1 );
+ // Old kword had only top and bottom. But borders are drawn differently now
+ // (not the whole line anymore), so we need the 4 borders.
+ style->paragLayout().leftBorder = KoBorder( Qt::black, KoBorder::SOLID, 1 );
+ style->paragLayout().rightBorder = KoBorder( Qt::black, KoBorder::SOLID, 1 );
+ style->paragLayout().alignment = Qt::AlignHCenter;
+ }
+ else
+ {
+ KoTabulatorList tabList;
+ KoTabulator tab;
+
+ tab.ptPos = KoUnit::fromUserValue( floor( KoUnit::toMM( fs->frame( 0 )->width() ) ), KoUnit::unit("mm") );
+
+ tab.type = T_RIGHT;
+ tab.filling = TF_DOTS;
+ tab.ptWidth = 0.5;
+ tabList.append( tab );
+ style->paragLayout().setTabList( tabList );
+ style->paragLayout().margins[QStyleSheetItem::MarginLeft] = KoUnit::fromUserValue( (depth*4.5), KoUnit::unit("mm") );
+ }
+ style = fs->kWordDocument()->styleCollection()->addStyle( style ); // register the new style
+ fs->kWordDocument()->updateAllStyleLists(); // show it in the UI
+ }
+ return style;
+}