/* This file is part of the KOffice project
* Copyright ( C ) 2002 - 2005 David Faure < faure @ kde . org >
* Copyright ( C ) 2005 Thomas Zander < zander @ 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 ; version 2.
* 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 "KWFrameLayout.h"
# include "KWFrameList.h"
# include "KWPageManager.h"
# include "KWPage.h"
# include "KWTextFrameSet.h"
# include "KWDocument.h"
# include <tqtimer.h>
// #define DEBUG_FRAMELAYOUT
# ifdef NDEBUG
# undef DEBUG_FRAMELAYOUT
# endif
KWFrameLayout : : HeaderFooterFrameset : : HeaderFooterFrameset ( KWTextFrameSet * fs , int start , int end ,
double spacing , OddEvenAll oea )
: m_frameset ( fs ) , m_startAtPage ( start ) , m_endAtPage ( end ) , m_oddEvenAll ( oea ) ,
m_spacing ( spacing ) , m_minY ( 0 ) , m_positioned ( false )
{
if ( fs - > frameCount ( ) > 0 )
m_height = fs - > frame ( 0 ) - > height ( ) ;
else
m_height = 20 ; // whatever. The text layout will resize it.
Q_ASSERT ( m_height > 0 ) ;
}
void KWFrameLayout : : HeaderFooterFrameset : : debug ( )
{
# ifdef DEBUG_FRAMELAYOUT
HeaderFooterFrameset * hff = this ;
kdDebug ( 32002 ) < < " * " < < hff - > m_frameset - > name ( )
< < " pages: " < < hff - > m_startAtPage < < " - " < < ( hff - > m_endAtPage = = - 1 ? TQString ( " (all) " ) : TQString : : number ( hff - > m_endAtPage ) )
< < " page-selection: " < < ( hff - > m_oddEvenAll = = HeaderFooterFrameset : : Odd ? " Odd " :
hff - > m_oddEvenAll = = HeaderFooterFrameset : : Even ? " Even " : " All " )
< < " frames: " < < hff - > m_frameset - > frameCount ( )
< < " height: " < < hff - > m_height
< < " spacing: " < < hff - > m_spacing < < endl ;
# endif
}
bool KWFrameLayout : : HeaderFooterFrameset : : deleteFramesAfterLast ( int lastPage )
{
int lastFrame = lastFrameNumber ( lastPage ) ;
# ifdef DEBUG_FRAMELAYOUT
//kdDebug(32002) << " Final cleanup: frameset " << m_frameset->name() << ": lastFrame=" << lastFrame << endl;
# endif
KWTextFrameSet * fs = m_frameset ;
// Special case for odd/even headers: keep at least one frame even if it doesn't appear,
// otherwise the frame properties are lost.
if ( fs - > isHeaderOrFooter ( ) & & lastFrame = = - 1 ) {
fs - > setVisible ( false ) ;
lastFrame = 0 ;
}
bool deleted = false ;
while ( ( int ) fs - > frameCount ( ) - 1 > lastFrame ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Final cleanup: deleting frame " < < fs - > frameCount ( ) - 1 < < " of " < < fs - > name ( ) < < endl ;
# endif
fs - > deleteFrame ( fs - > frameCount ( ) - 1 ) ;
deleted = true ;
}
return deleted ;
}
int KWFrameLayout : : HeaderFooterFrameset : : lastFrameNumber ( int lastPage ) const {
if ( lastPage < m_startAtPage )
return - 1 ; // we need none
int pg = lastPage ;
if ( m_endAtPage > - 1 )
pg = TQMIN ( m_endAtPage , pg ) ;
pg - = m_startAtPage ; // always >=0
Q_ASSERT ( pg > = 0 ) ;
switch ( m_oddEvenAll ) {
case Odd :
case Even :
return pg / 2 ; // page 0 and 1 -> 0. page 2 and 3 -> 1.
case All :
return pg ; // page 0 -> 0 etc. ;)
default :
return - 1 ;
}
}
int KWFrameLayout : : HeaderFooterFrameset : : frameNumberForPage ( int page ) const
{
if ( page < m_startAtPage | | ( m_endAtPage ! = - 1 & & page > m_endAtPage ) )
return - 1 ;
int pg = page - m_startAtPage ; // always >=0
switch ( m_oddEvenAll ) {
case Odd :
// we test the absolute page number for odd/even, not pg!
if ( page % 2 )
return pg / 2 ; // page start+(0 or 1) -> frame 0, page start+(2 or 3) -> frame 1
else
return - 1 ;
case Even :
if ( page % 2 = = 0 )
return pg / 2 ; // page start+(0 or 1) -> frame 0, page start+(2 or 3) -> frame 1
else
return - 1 ;
case All :
return pg ; // page 0[+start] -> frame 0, etc.
default :
return - 1 ;
}
}
/////
void KWFrameLayout : : layout ( KWFrameSet * mainTextFrameSet , int numColumns ,
int fromPage , int toPage , uint flags )
{
//kdDebug(32002) << "KWFrameLayout::layout " << kdBacktrace() << endl;
// Just debug stuff
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " KWFrameLayout::layout " < < fromPage < < " to " < < toPage < < endl ;
Q_ASSERT ( toPage > = fromPage ) ;
TQPtrListIterator < HeaderFooterFrameset > itdbg ( m_headersFooters ) ;
for ( ; itdbg . current ( ) ; + + itdbg )
itdbg . current ( ) - > debug ( ) ;
TQPtrListIterator < HeaderFooterFrameset > itdbg2 ( m_footnotes ) ;
for ( ; itdbg2 . current ( ) ; + + itdbg2 )
itdbg2 . current ( ) - > debug ( ) ;
TQPtrListIterator < HeaderFooterFrameset > itdbg3 ( m_endnotes ) ;
for ( ; itdbg3 . current ( ) ; + + itdbg3 )
itdbg3 . current ( ) - > debug ( ) ;
# endif
#if 0 // old code
// Necessary for end notes: calculate where the text goes down to
Q_ASSERT ( mainTextFrameSet - > type ( ) = = FT_TEXT ) ;
double textBottom = 0.0 ;
if ( mainTextFrameSet - > hasFramesInPageArray ( ) )
{
KoPoint textBottomPoint ;
KoTextParag * lastParag = static_cast < KWTextFrameSet * > ( mainTextFrameSet ) - > textDocument ( ) - > lastParag ( ) ;
if ( lastParag - > isValid ( ) )
{
TQRect rect = lastParag - > rect ( ) ;
int bottom = rect . top ( ) + rect . height ( ) + 2 ; // cf kwtextframeset
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " bottom LU= " < < bottom < < endl ;
# endif
if ( static_cast < KWTextFrameSet * > ( mainTextFrameSet ) - > internalToDocument ( TQPoint ( rect . left ( ) , bottom ) , textBottomPoint ) )
textBottom = textBottomPoint . y ( ) ;
}
}
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " textBottom = " < < textBottom < < " pt " < < endl ;
# endif
# endif
m_framesetsToUpdate . clear ( ) ;
// Necessary for end notes: find out the last frame of the main textframeset
KWFrame * lastMainFrame = mainTextFrameSet - > frameIterator ( ) . getLast ( ) ;
double lastMainFrameBottom = lastMainFrame - > bottom ( ) ; // before we change it below!
double ptColumnWidth = m_doc - > ptColumnWidth ( ) ;
int mainTextFrameResized = - 1 ; // contains the page number of the first resized main textframe
// The main loop is: "for each page". We lay out each page separately.
for ( int pageNum = fromPage ; pageNum < = toPage ; + + pageNum )
{
KWPage * page = m_doc - > pageManager ( ) - > page ( pageNum ) ;
double top = page - > offsetInDocument ( ) + page - > topMargin ( ) ;
double bottom = page - > offsetInDocument ( ) + page - > height ( ) - page - > bottomMargin ( ) ;
double left = page - > leftMargin ( ) ;
double right = page - > width ( ) - page - > rightMargin ( ) ;
Q_ASSERT ( left < right ) ;
KoRect oldColumnRect = firstColumnRect ( mainTextFrameSet , pageNum , numColumns ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Page " < < pageNum < < endl ;
# endif
// For each header/footer....
for ( TQPtrListIterator < HeaderFooterFrameset > it ( m_headersFooters ) ; it . current ( ) ; + + it )
{
int frameNum = it . current ( ) - > frameNumberForPage ( pageNum ) ;
if ( frameNum ! = - 1 )
{
it . current ( ) - > m_positioned = true ;
KWTextFrameSet * fs = it . current ( ) - > m_frameset ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Page " < < pageNum < < " : adding frame " < < frameNum < < " from " < < fs - > name ( ) < < endl ;
# endif
KoRect rect ;
if ( fs - > isAHeader ( ) ) // add on top
{
rect . setRect ( left , top , right - left , it . current ( ) - > m_height ) ;
top + = it . current ( ) - > m_height + it . current ( ) - > m_spacing ;
} else // footer, add at bottom
{
double frameHeight = it . current ( ) - > m_height ;
double frameTop = bottom - frameHeight ;
rect . setRect ( left , frameTop , right - left , frameHeight ) ;
bottom - = frameHeight + it . current ( ) - > m_spacing ;
}
Q_ASSERT ( bottom > 0 ) ;
Q_ASSERT ( top < bottom ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " rect: " < < rect < < " - new_top: " < < top < < " new_bottom: " < < bottom < < endl ;
# endif
resizeOrCreateHeaderFooter ( fs , frameNum , rect ) ;
}
}
// All headers/footers for this page have been done,
// now resize the frame from the main textframeset (if any)
// the first time _before_ doing the footnotes.
resizeMainTextFrame ( mainTextFrameSet , pageNum , numColumns , ptColumnWidth , m_doc - > ptColumnSpacing ( ) , left , top , bottom , NoFootNote ) ;
// Recalc footnote pages
checkFootNotes ( ) ;
bool firstFootNote = true ;
//// Stay seated... We need to know if there are any footnotes on top of us, although we're going
//// to lay them out _AFTER_. But we need their total height for the minY stuff.
//// So we first iterate over all footnotes of the page, to get their total height.
//// Then we'll reduce this height after every footnote being positionned, so it's always
//// the "height on top of us".
double totalFootNotesHeight = 0 ;
for ( TQPtrListIterator < HeaderFooterFrameset > it ( m_footnotes ) ; it . current ( ) ; + + it )
{
int frameNum = it . current ( ) - > frameNumberForPage ( pageNum ) ;
if ( frameNum ! = - 1 )
totalFootNotesHeight + = it . current ( ) - > m_height ;
}
// For each footnote (caller sorted them from bottom to top)
for ( TQPtrListIterator < HeaderFooterFrameset > it ( m_footnotes ) ; it . current ( ) ; + + it )
{
int frameNum = it . current ( ) - > frameNumberForPage ( pageNum ) ;
if ( frameNum ! = - 1 )
{
it . current ( ) - > m_positioned = true ;
totalFootNotesHeight - = it . current ( ) - > m_height ; // as discussed above
KWTextFrameSet * fs = it . current ( ) - > m_frameset ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Page " < < pageNum < < " : adding footnote frame " < < frameNum < < " from " < < fs - > name ( ) < < endl ;
# endif
KoRect rect ;
// When two footnotes are in the same page there should be 0 spacing between them
// Yeah, write a generic frame layouter and then realize it's not flexible enough :(
if ( fs - > isFootEndNote ( ) & & ! firstFootNote )
{
// Undo "bottom -= spacing" (done below). This assumes equal spacing for all footnotes
bottom + = it . current ( ) - > m_spacing ;
bottom - = 1 ; // keep them one pixel apart though
}
double frameTop = bottom - it . current ( ) - > m_height ;
double frameHeight = it . current ( ) - > m_height ;
Q_ASSERT ( fs - > isFootNote ( ) ) ;
// This is where we add the "total height of the footnotes on top of this one".
// The footnote variable can't be behind them....
double minY = it . current ( ) - > m_minY + totalFootNotesHeight ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " footnote: frameHeight= " < < frameHeight < < " frameTop ( " < < frameTop < < " ) <? minY ( " < < minY < < " ) " < < endl ;
# endif
if ( frameTop < minY )
{
// Ok, this is the complex case of a footnote var too far down in the page,
// and its footnote text is too big, so both won't fit.
// We do like other WPs: we create a frame on the next page
it . current ( ) - > m_endAtPage + + ; // this will do so
// In the current page we stop at minY
frameTop = minY ;
frameHeight = bottom - frameTop ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " footnote: new top= " < < frameTop < < " new height= " < < frameHeight < < " remaining height= " < < it . current ( ) - > m_height - frameHeight < < endl ;
# endif
Q_ASSERT ( frameHeight < it . current ( ) - > m_height ) ;
it . current ( ) - > m_height - = frameHeight ; // calculate what remains to be done in the next frame
//fnFrameBehavior = KWFrame::Ignore;
// Make sure there'll actually be a next page
if ( pageNum = = m_doc - > pageCount ( ) - 1 ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Adding a page for the footnote overflow. " < < endl ;
# endif
m_doc - > appendPage ( ) ;
m_doc - > updateAllFrames ( ) ;
toPage = m_doc - > pageCount ( ) - 1 ;
}
}
rect . setRect ( left , frameTop , right - left , frameHeight ) ;
bottom - = frameHeight + it . current ( ) - > m_spacing ;
Q_ASSERT ( bottom > 0 ) ;
Q_ASSERT ( top < bottom ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " footnote rect: " < < rect < < " - new_top: " < < top < < " new_bottom: " < < bottom < < endl ;
# endif
resizeOrCreateHeaderFooter ( fs , frameNum , rect ) ;
firstFootNote = false ;
// We added a footnote, update main text frame size
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Laid out a footnote -> call resizeMainTextFrame/checkFootNotes again " < < endl ;
# endif
resizeMainTextFrame ( mainTextFrameSet , pageNum , numColumns , ptColumnWidth , m_doc - > ptColumnSpacing ( ) , left , top , bottom , WithFootNotes ) ;
checkFootNotes ( ) ;
}
} // for all footnotes
// Check for endnotes, on the last page of main text
// and on any end-notes-only page, i.e. after the last page of main text
if ( pageNum > = m_lastMainFramePage & & m_doc - > hasEndNotes ( ) ) {
bool pageHasMainText = ( pageNum = = m_lastMainFramePage ) ;
if ( pageHasMainText )
lastMainFrame - > setDrawFootNoteLine ( true ) ;
double textBottom = pageHasMainText ? lastMainFrameBottom : top ;
// Leave some space on top of the endnotes, for the horizontal line
double endNoteTop = textBottom + m_doc - > ptFootnoteBodySpacing ( ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Endnotes: textBottom= " < < textBottom < < " pt, endNoteTop= " < < endNoteTop < < " pt, bottom= " < < bottom < < " pt " < < endl ;
# endif
bool firstEndNote = true ;
for ( TQPtrListIterator < HeaderFooterFrameset > it ( m_endnotes ) ; it . current ( ) ; + + it )
{
if ( ! it . current ( ) - > m_positioned )
{
KWTextFrameSet * fs = it . current ( ) - > m_frameset ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Page " < < pageNum < < " : adding endnote frame from " < < fs - > name ( ) < < endl ;
# endif
double frameHeight = it . current ( ) - > m_height ;
if ( it . current ( ) - > m_startAtPage < 0 ) // not set yet
it . current ( ) - > m_startAtPage = pageNum ;
// Check if the endnote is bigger than the available space
if ( endNoteTop + frameHeight > bottom )
{
// In the current page we stop at bottom
frameHeight = bottom - endNoteTop ;
if ( frameHeight > 1E-10 ) // means, if frameHeight > 0
{
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " endnote: new height= " < < frameHeight < < " remaining height= " < < it . current ( ) - > m_height - frameHeight < < endl ;
# endif
Q_ASSERT ( frameHeight < it . current ( ) - > m_height ) ;
it . current ( ) - > m_height - = frameHeight ; // calculate what remains to be done in the next frame
} else {
// No room at all on this page. Schedule for next page.
it . current ( ) - > m_startAtPage + + ;
break ;
}
// Make sure there'll actually be a next page
if ( pageNum = = m_doc - > pageCount ( ) - 1 ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Adding a page for the endnote overflow. " < < endl ;
# endif
m_doc - > appendPage ( ) ;
m_doc - > updateAllFrames ( ) ;
toPage = m_doc - > pageCount ( ) - 1 ;
}
}
else // It'll all fit in this page
{
it . current ( ) - > m_positioned = true ;
}
KoRect rect ( left , endNoteTop , right - left , frameHeight ) ;
endNoteTop + = frameHeight + 1 ; // not + it.current()->m_spacing;
Q_ASSERT ( bottom > 0 ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " rect: " < < rect < < " - new_top: " < < endNoteTop < < " new_bottom: " < < bottom < < endl ;
# endif
int frameNum = pageNum - it . current ( ) - > m_startAtPage ;
resizeOrCreateHeaderFooter ( fs , frameNum , rect ) ;
#if 0 // Disabled. The main frame is resized by KWTextFrameSet::slotAfterFormatting already.
if ( pageHasMainText & & firstEndNote )
{
// We positionned the first endnote, update main text frame size
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Laid out an endnote and the page has a maintextframe too -> call resizeMainTextFrame/checkFootNotes again top= " < < top < < " textBottom= " < < textBottom < < endl ;
# endif
resizeMainTextFrame ( mainTextFrameSet , pageNum , numColumns , ptColumnWidth , m_doc - > ptColumnSpacing ( ) , left , top , textBottom , NoChange ) ;
}
# endif
} // if not positionned yet
firstEndNote = false ; // yes, out of the if
} // for all endnotes
} // if page can have endnotes
if ( mainTextFrameResized = = - 1 ) {
// Test if the main text frame for this page was really resized or not.
KoRect newColumnRect = firstColumnRect ( mainTextFrameSet , pageNum , numColumns ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Comparing old= " < < oldColumnRect < < " and new= " < < newColumnRect < < endl ;
# endif
if ( oldColumnRect ! = newColumnRect ) {
mainTextFrameResized = pageNum ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " changed -> mainTextFrameResized= " < < mainTextFrameResized < < endl ;
# endif
}
}
} // for all pages
m_lastMainFramePage = lastMainFrame - > pageNumber ( ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " m_lastMainFramePage = " < < m_lastMainFramePage < < " lastMainFrameBottom= " < < lastMainFrameBottom < < endl ;
# endif
if ( ! ( flags & DontRemovePages ) )
{
m_doc - > updateAllFrames ( KWFrameSet : : UpdateFramesInPage ) ;
// Check if the last page is now empty (e.g. this can happen when removing
// some text above an endnote, so the endnote moves up)
( void ) m_doc - > tryRemovingPages ( ) ;
}
const int lastPage = m_doc - > lastPage ( ) ;
// Final cleanup: delete all frames after lastFrameNumber in each frameset
TQPtrListIterator < HeaderFooterFrameset > it ( m_headersFooters ) ;
for ( ; it . current ( ) ; + + it )
if ( it . current ( ) - > deleteFramesAfterLast ( lastPage ) )
m_framesetsToUpdate . insert ( it . current ( ) - > m_frameset , true ) ;
TQPtrListIterator < HeaderFooterFrameset > it2 ( m_footnotes ) ;
for ( ; it2 . current ( ) ; + + it2 )
if ( it2 . current ( ) - > deleteFramesAfterLast ( lastPage ) )
m_framesetsToUpdate . insert ( it2 . current ( ) - > m_frameset , true ) ;
if ( mainTextFrameSet ) {
// For the last main text frameset, we use m_lastMainFramePage, so that
// there's no frame on the "end notes only" page(s).
int lastFrame = m_lastMainFramePage * numColumns + ( numColumns - 1 ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " lastFrame: " < < lastFrame < < " due to " < < m_lastMainFramePage < < endl ;
# endif
bool deleted = false ;
while ( ( int ) mainTextFrameSet - > frameCount ( ) - 1 > lastFrame ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Final cleanup: deleting frame " < < mainTextFrameSet - > frameCount ( ) - 1 < < " of main textframeset (lastFrame= " < < lastFrame < < " ) " < < endl ;
# endif
mainTextFrameSet - > deleteFrame ( mainTextFrameSet - > frameCount ( ) - 1 , true , false /*do not updateFrames!*/ ) ;
deleted = true ;
}
if ( deleted )
m_framesetsToUpdate . insert ( mainTextFrameSet , true ) ;
// The last frame before the first endnote, is in auto-extend mode
if ( m_doc - > hasEndNotes ( ) ) {
KWFrame * lastMainFrame = mainTextFrameSet - > frameIterator ( ) . getLast ( ) ;
if ( lastMainFrame - > frameBehavior ( ) ! = KWFrame : : AutoExtendFrame )
{
lastMainFrame - > setFrameBehavior ( KWFrame : : AutoExtendFrame ) ;
// make sure it gets resized
if ( mainTextFrameResized = = - 1 )
mainTextFrameResized = lastMainFrame - > pageNumber ( ) ;
}
}
}
TQMap < KWFrameSet * , bool > : : iterator fsit = m_framesetsToUpdate . begin ( ) ;
for ( ; fsit ! = m_framesetsToUpdate . end ( ) ; + + fsit )
fsit . key ( ) - > updateFrames ( ) ;
// ## TODO: only if something changed? (resizing, new frames, or deleted frames...)
KWFrameList : : recalcFrames ( m_doc , fromPage , toPage ) ;
if ( mainTextFrameResized ! = - 1 & & mainTextFrameSet - > type ( ) = = FT_TEXT ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Done. First maintextframe resized: " < < mainTextFrameResized < < endl ;
# endif
KWTextFrameSet * fs = static_cast < KWTextFrameSet * > ( mainTextFrameSet ) ;
// Not right now, this could be called during formatting...
//m_doc->invalidate();
// ### This means the layout will be done during painting. Not good.
// What about mainTextFrameSet->invalidate() or even layout()?
//TQTimer::singleShot( 0, m_doc, TQ_SLOT( invalidate() ) );
// Invalidate main textframeset only, and from top of page only.
// Otherwise loading a long document (with headers/footers) takes ages,
// if we redo it all from the beginning at each new page!
int topLU , bottomLU ;
if ( fs - > minMaxInternalOnPage ( mainTextFrameResized , topLU , bottomLU ) )
{
// Find parag at topLU
KoTextParag * parag = fs - > paragAtLUPos ( topLU ) ;
if ( parag ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Invalidating from parag " < < parag - > paragId ( ) < < endl ;
# endif
fs - > textObject ( ) - > setLastFormattedParag ( parag ) ;
fs - > textObject ( ) - > formatMore ( 2 ) ;
}
}
}
}
void KWFrameLayout : : resizeOrCreateHeaderFooter ( KWTextFrameSet * headerFooter , uint frameNumber , const KoRect & rect )
{
if ( frameNumber < headerFooter - > frameCount ( ) ) {
KWFrame * frame = headerFooter - > frame ( frameNumber ) ;
if ( * frame = = rect )
return ;
frame - > setRect ( rect ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " KWFrameLayout::resizeOrCreateHeaderFooter frame " < < headerFooter - > name ( ) < < " " < < frame < < " resized to " < < rect < < " pagenum= " < < frame - > pageNumber ( ) < < endl ;
# endif
}
else
{
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " KWFrameLayout::resizeOrCreateHeaderFooter creating frame for " < < headerFooter - > name ( ) < < endl ;
# endif
KWFrame * frame = new KWFrame ( headerFooter , rect . x ( ) , rect . y ( ) , rect . width ( ) , rect . height ( ) ) ;
frame - > setFrameBehavior ( KWFrame : : AutoExtendFrame ) ;
if ( headerFooter - > isHeaderOrFooter ( ) ) // not for footnotes!
{
frame - > setNewFrameBehavior ( KWFrame : : Copy ) ;
frame - > setCopy ( true ) ;
}
else
frame - > setNewFrameBehavior ( KWFrame : : NoFollowup ) ;
headerFooter - > addFrame ( frame , false /*no recalc*/ ) ;
}
// This updates e.g. availableHeight. Very important in the case
// of the footnote frameset with 2 frames.
headerFooter - > updateFrames ( 0 /*fast one*/ ) ;
m_framesetsToUpdate . insert ( headerFooter , true ) ;
}
// Called at beginning and end of the layout for a given page,
// to determine if the main-text-frame layout really changed or not.
// Testing in resizeMainTextFrame doesn't work, we call it several times,
// once for each footnote, so it can't detect the "no change" case.
KoRect KWFrameLayout : : firstColumnRect ( KWFrameSet * mainTextFrameSet , int pageNum , int numColumns ) const
{
uint frameNum = pageNum * numColumns /*+ col 0 here*/ ;
if ( mainTextFrameSet & & frameNum < mainTextFrameSet - > frameCount ( ) )
return * mainTextFrameSet - > frame ( frameNum ) ;
else
return KoRect ( ) ;
}
bool KWFrameLayout : : resizeMainTextFrame ( KWFrameSet * mainTextFrameSet , int pageNum , int numColumns , double ptColumnWidth , double ptColumnSpacing , double left , double top , double bottom , HasFootNotes hasFootNotes )
{
if ( ! mainTextFrameSet )
return false ;
bool mainTextFrameResized = false ;
for ( int col = 0 ; col < numColumns ; col + + ) {
Q_ASSERT ( bottom > top ) ;
// Calculate wanted rect for this frame
KoRect rect ( left + col * ( ptColumnWidth + ptColumnSpacing ) ,
top , ptColumnWidth , bottom - top ) ;
uint frameNum = ( pageNum - m_doc - > startPage ( ) ) * numColumns + col ;
KWFrame * frame ;
if ( frameNum < mainTextFrameSet - > frameCount ( ) ) {
// Resize existing frame
frame = mainTextFrameSet - > frame ( frameNum ) ;
// Special case for last-frame-before-endnotes: don't resize its bottom
if ( m_doc - > hasEndNotes ( ) & & pageNum > = m_lastMainFramePage )
rect . setBottom ( frame - > bottom ( ) ) ;
bool resized = ( rect ! = * frame ) ;
if ( resized ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Page " < < pageNum < < " : resizing main text frame " < < frameNum < < " ( " < < frame < < " ) to " < < rect < < endl ;
# endif
frame - > setRect ( rect ) ;
frame - > updateRulerHandles ( ) ;
mainTextFrameResized = true ;
mainTextFrameSet - > updateFrames ( 0xff - KWFrameSet : : SortFrames ) ; // Don't sort frames yet!
}
} else {
// Create new frame
frame = new KWFrame ( mainTextFrameSet , rect . x ( ) , rect . y ( ) , rect . width ( ) , rect . height ( ) ) ;
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " Page " < < pageNum < < " : creating new main text frame " < < frameNum < < " ( " < < frame < < " ) to " < < rect < < endl ;
# endif
mainTextFrameSet - > addFrame ( frame ) ;
Q_ASSERT ( frameNum = = mainTextFrameSet - > frameCount ( ) - 1 ) ;
mainTextFrameResized = true ;
mainTextFrameSet - > updateFrames ( 0xff - KWFrameSet : : SortFrames ) ; // Don't sort frames yet!
}
if ( hasFootNotes = = NoFootNote )
frame - > setDrawFootNoteLine ( false ) ;
else if ( hasFootNotes = = WithFootNotes )
frame - > setDrawFootNoteLine ( true ) ;
// unchanged in the other cases
// By default, all main-text frames are in "auto-create new frames" mode
frame - > setFrameBehavior ( KWFrame : : AutoCreateNewFrame ) ;
}
return mainTextFrameResized ;
}
void KWFrameLayout : : checkFootNotes ( )
{
// We recalculate all footnotes pages, but we return true
// if those on pageNum have changed.
TQPtrListIterator < HeaderFooterFrameset > it ( m_footnotes ) ;
for ( ; it . current ( ) ; + + it )
{
HeaderFooterFrameset * hff = it . current ( ) ;
if ( ! hff - > m_positioned )
{
Q_ASSERT ( hff - > m_frameset - > isFootEndNote ( ) ) ;
KWFootNoteFrameSet * fnfs = static_cast < KWFootNoteFrameSet * > ( hff - > m_frameset ) ;
KWFootNoteVariable * fnvar = fnfs - > footNoteVariable ( ) ;
//necessary to test paragraph because when we delete mutli
//footnote, first footnote who delete call setDelete(true)
//and force recalc, but with multi footnote deleted
//paragraph is null before we apply attribute to
//kotextcustom.
if ( ! fnvar | | ! fnvar - > paragraph ( ) )
continue ;
double varY = fnvar - > varY ( ) ;
if ( varY = = 0 ) // not able to calculate it yet
continue ;
hff - > m_minY = varY + /*2 * */ hff - > m_spacing + 2 /* some spacing */ ;
int pageNum = m_doc - > pageManager ( ) - > pageNumber ( varY ) ;
if ( pageNum ! = hff - > m_startAtPage ) {
# ifdef DEBUG_FRAMELAYOUT
kdDebug ( 32002 ) < < " checkFootNotes: found minY= " < < hff - > m_minY < < " start/end= " < < pageNum < < " for footnote " < < fnvar - > text ( ) < < endl ;
# endif
hff - > m_startAtPage = pageNum ;
hff - > m_endAtPage = pageNum ;
}
}
}
}