19#include "KWFrameLayout.h"
20#include "KWFrameList.h"
21#include "KWPageManager.h"
23#include "KWTextFrameSet.h"
24#include "KWDocument.h"
30#undef DEBUG_FRAMELAYOUT
33KWFrameLayout::HeaderFooterFrameset::HeaderFooterFrameset(
KWTextFrameSet* fs,
int start,
int end,
34 double spacing, OddEvenAll oea )
35 : m_frameset(fs), m_startAtPage(start), m_endAtPage(end), m_oddEvenAll(oea),
36 m_spacing(spacing), m_minY( 0 ), m_positioned( false )
39 m_height = fs->
frame(0)->height();
42 Q_ASSERT( m_height > 0 );
46void KWFrameLayout::HeaderFooterFrameset::debug()
48#ifdef DEBUG_FRAMELAYOUT
49 HeaderFooterFrameset* hff =
this;
50 kdDebug(32002) <<
" * " << hff->m_frameset->name()
51 <<
" pages:" << hff->m_startAtPage <<
"-" << (hff->m_endAtPage==-1?TQString(
"(all)"):TQString::number(hff->m_endAtPage))
52 <<
" page-selection:" << (hff->m_oddEvenAll==HeaderFooterFrameset::Odd ?
"Odd" :
53 hff->m_oddEvenAll==HeaderFooterFrameset::Even ?
"Even" :
"All")
54 <<
" frames:" << hff->m_frameset->frameCount()
55 <<
" height:" << hff->m_height
56 <<
" spacing:" << hff->m_spacing << endl;
60bool KWFrameLayout::HeaderFooterFrameset::deleteFramesAfterLast(
int lastPage )
62 int lastFrame = lastFrameNumber( lastPage );
63#ifdef DEBUG_FRAMELAYOUT
71 if ( fs->isHeaderOrFooter() && lastFrame == -1 ) {
77 while ( (
int)fs->
frameCount() - 1 > lastFrame ) {
78#ifdef DEBUG_FRAMELAYOUT
79 kdDebug(32002) <<
" Final cleanup: deleting frame " << fs->
frameCount() - 1 <<
" of " << fs->
name() << endl;
87int KWFrameLayout::HeaderFooterFrameset::lastFrameNumber(
int lastPage )
const {
88 if ( lastPage < m_startAtPage )
91 if ( m_endAtPage > -1 )
92 pg = TQMIN( m_endAtPage, pg );
95 switch (m_oddEvenAll) {
106int KWFrameLayout::HeaderFooterFrameset::frameNumberForPage(
int page )
const
108 if ( page < m_startAtPage || ( m_endAtPage != -1 && page > m_endAtPage ) )
110 int pg = page - m_startAtPage;
111 switch (m_oddEvenAll) {
132void KWFrameLayout::layout(
KWFrameSet* mainTextFrameSet,
int numColumns,
133 int fromPage,
int toPage, uint flags )
137#ifdef DEBUG_FRAMELAYOUT
138 kdDebug(32002) <<
"KWFrameLayout::layout " << fromPage <<
" to " << toPage << endl;
139 Q_ASSERT( toPage >= fromPage );
140 TQPtrListIterator<HeaderFooterFrameset> itdbg( m_headersFooters );
141 for ( ; itdbg.current() ; ++itdbg )
142 itdbg.current()->debug();
143 TQPtrListIterator<HeaderFooterFrameset> itdbg2( m_footnotes );
144 for ( ; itdbg2.current() ; ++itdbg2 )
145 itdbg2.current()->debug();
146 TQPtrListIterator<HeaderFooterFrameset> itdbg3( m_endnotes );
147 for ( ; itdbg3.current() ; ++itdbg3 )
148 itdbg3.current()->debug();
152 Q_ASSERT( mainTextFrameSet->
type() == FT_TEXT );
153 double textBottom = 0.0;
156 KoPoint textBottomPoint;
157 KoTextParag * lastParag =
static_cast<KWTextFrameSet *
>(mainTextFrameSet)->textDocument()->lastParag();
158 if ( lastParag->isValid() )
160 TQRect rect = lastParag->rect();
161 int bottom = rect.top() + rect.height() + 2;
162#ifdef DEBUG_FRAMELAYOUT
163 kdDebug(32002) <<
"bottom LU=" << bottom << endl;
166 if (
static_cast<KWTextFrameSet *
>(mainTextFrameSet)->internalToDocument( TQPoint(rect.left(), bottom), textBottomPoint ) )
167 textBottom = textBottomPoint.y();
170#ifdef DEBUG_FRAMELAYOUT
171 kdDebug(32002) <<
"textBottom = " << textBottom <<
"pt" << endl;
174 m_framesetsToUpdate.clear();
177 double lastMainFrameBottom = lastMainFrame->bottom();
179 double ptColumnWidth = m_doc->ptColumnWidth();
180 int mainTextFrameResized = -1;
183 for (
int pageNum = fromPage ; pageNum <= toPage ; ++pageNum )
185 KWPage *page = m_doc->pageManager()->page(pageNum);
190 Q_ASSERT( left < right );
191 KoRect oldColumnRect = firstColumnRect( mainTextFrameSet, pageNum, numColumns );
192#ifdef DEBUG_FRAMELAYOUT
193 kdDebug(32002) <<
" Page " << pageNum << endl;
197 for ( TQPtrListIterator<HeaderFooterFrameset> it( m_headersFooters ); it.current() ; ++it )
199 int frameNum = it.current()->frameNumberForPage( pageNum );
200 if ( frameNum != -1 )
202 it.current()->m_positioned =
true;
204#ifdef DEBUG_FRAMELAYOUT
205 kdDebug(32002) <<
" Page " << pageNum <<
": adding frame " << frameNum <<
" from " << fs->
name() << endl;
208 if ( fs->isAHeader() )
210 rect.setRect( left, top, right - left, it.current()->m_height );
211 top += it.current()->m_height + it.current()->m_spacing;
214 double frameHeight = it.current()->m_height;
215 double frameTop = bottom - frameHeight;
216 rect.setRect( left, frameTop, right - left, frameHeight );
217 bottom -= frameHeight + it.current()->m_spacing;
219 Q_ASSERT( bottom > 0 );
220 Q_ASSERT( top < bottom );
221#ifdef DEBUG_FRAMELAYOUT
222 kdDebug(32002) <<
" rect:" << rect <<
" - new_top:" << top <<
" new_bottom:" << bottom << endl;
224 resizeOrCreateHeaderFooter( fs, frameNum, rect );
231 resizeMainTextFrame( mainTextFrameSet, pageNum, numColumns, ptColumnWidth, m_doc->ptColumnSpacing(), left, top, bottom, NoFootNote );
236 bool firstFootNote =
true;
243 double totalFootNotesHeight = 0;
244 for ( TQPtrListIterator<HeaderFooterFrameset> it( m_footnotes ); it.current() ; ++it )
246 int frameNum = it.current()->frameNumberForPage( pageNum );
247 if ( frameNum != -1 )
248 totalFootNotesHeight += it.current()->m_height;
252 for ( TQPtrListIterator<HeaderFooterFrameset> it( m_footnotes ); it.current() ; ++it )
254 int frameNum = it.current()->frameNumberForPage( pageNum );
255 if ( frameNum != -1 )
257 it.current()->m_positioned =
true;
258 totalFootNotesHeight -= it.current()->m_height;
260#ifdef DEBUG_FRAMELAYOUT
261 kdDebug(32002) <<
" Page " << pageNum <<
": adding footnote frame " << frameNum <<
" from " << fs->
name() << endl;
267 if ( fs->isFootEndNote() && !firstFootNote )
270 bottom += it.current()->m_spacing;
273 double frameTop = bottom - it.current()->m_height;
274 double frameHeight = it.current()->m_height;
276 Q_ASSERT ( fs->isFootNote() );
281 double minY = it.current()->m_minY + totalFootNotesHeight;
282#ifdef DEBUG_FRAMELAYOUT
283 kdDebug(32002) <<
" footnote: frameHeight=" << frameHeight <<
" frameTop (" << frameTop <<
") <? minY (" << minY <<
")" << endl;
285 if ( frameTop < minY )
290 it.current()->m_endAtPage++;
294 frameHeight = bottom - frameTop;
295#ifdef DEBUG_FRAMELAYOUT
296 kdDebug(32002) <<
" footnote: new top=" << frameTop <<
" new height=" << frameHeight <<
" remaining height=" << it.current()->m_height - frameHeight << endl;
298 Q_ASSERT( frameHeight < it.current()->m_height );
299 it.current()->m_height -= frameHeight;
303 if ( pageNum == m_doc->pageCount()-1 ) {
304#ifdef DEBUG_FRAMELAYOUT
305 kdDebug(32002) <<
"Adding a page for the footnote overflow." << endl;
308 m_doc->updateAllFrames();
309 toPage = m_doc->pageCount()-1;
313 rect.setRect( left, frameTop, right - left, frameHeight );
314 bottom -= frameHeight + it.current()->m_spacing;
315 Q_ASSERT( bottom > 0 );
316 Q_ASSERT( top < bottom );
317#ifdef DEBUG_FRAMELAYOUT
318 kdDebug(32002) <<
" footnote rect:" << rect <<
" - new_top:" << top <<
" new_bottom:" << bottom << endl;
320 resizeOrCreateHeaderFooter( fs, frameNum, rect );
321 firstFootNote =
false;
324#ifdef DEBUG_FRAMELAYOUT
325 kdDebug(32002) <<
" Laid out a footnote -> call resizeMainTextFrame/checkFootNotes again" << endl;
327 resizeMainTextFrame( mainTextFrameSet, pageNum, numColumns, ptColumnWidth, m_doc->ptColumnSpacing(), left, top, bottom, WithFootNotes );
334 if ( pageNum >= m_lastMainFramePage && m_doc->hasEndNotes() ) {
335 bool pageHasMainText = ( pageNum == m_lastMainFramePage );
336 if ( pageHasMainText )
338 double textBottom = pageHasMainText ? lastMainFrameBottom : top;
340 double endNoteTop = textBottom + m_doc->ptFootnoteBodySpacing();
341#ifdef DEBUG_FRAMELAYOUT
342 kdDebug(32002) <<
" Endnotes: textBottom=" << textBottom <<
"pt, endNoteTop=" << endNoteTop <<
"pt, bottom=" << bottom <<
"pt" << endl;
344 bool firstEndNote =
true;
345 for ( TQPtrListIterator<HeaderFooterFrameset> it( m_endnotes ); it.current() ; ++it )
347 if ( ! it.current()->m_positioned )
350#ifdef DEBUG_FRAMELAYOUT
351 kdDebug(32002) <<
" Page " << pageNum <<
": adding endnote frame from " << fs->
name() << endl;
353 double frameHeight = it.current()->m_height;
354 if ( it.current()->m_startAtPage < 0 )
355 it.current()->m_startAtPage = pageNum;
358 if ( endNoteTop + frameHeight > bottom )
361 frameHeight = bottom - endNoteTop;
363 if ( frameHeight > 1E-10 )
365#ifdef DEBUG_FRAMELAYOUT
366 kdDebug(32002) <<
" endnote: new height=" << frameHeight <<
" remaining height=" << it.current()->m_height - frameHeight << endl;
368 Q_ASSERT( frameHeight < it.current()->m_height );
369 it.current()->m_height -= frameHeight;
372 it.current()->m_startAtPage++;
376 if ( pageNum == m_doc->pageCount()-1 ) {
377#ifdef DEBUG_FRAMELAYOUT
378 kdDebug(32002) <<
"Adding a page for the endnote overflow." << endl;
381 m_doc->updateAllFrames();
382 toPage = m_doc->pageCount()-1;
387 it.current()->m_positioned =
true;
389 KoRect rect( left, endNoteTop, right - left, frameHeight );
390 endNoteTop += frameHeight + 1;
391 Q_ASSERT( bottom > 0 );
392#ifdef DEBUG_FRAMELAYOUT
393 kdDebug(32002) <<
" rect:" << rect <<
" - new_top:" << endNoteTop <<
" new_bottom:" << bottom << endl;
395 int frameNum = pageNum - it.current()->m_startAtPage;
396 resizeOrCreateHeaderFooter( fs, frameNum, rect );
399 if ( pageHasMainText && firstEndNote )
402#ifdef DEBUG_FRAMELAYOUT
403 kdDebug(32002) <<
" Laid out an endnote and the page has a maintextframe too -> call resizeMainTextFrame/checkFootNotes again top=" << top <<
" textBottom=" << textBottom << endl;
405 resizeMainTextFrame( mainTextFrameSet, pageNum, numColumns, ptColumnWidth, m_doc->ptColumnSpacing(), left, top, textBottom, NoChange );
409 firstEndNote =
false;
413 if ( mainTextFrameResized == -1 ) {
415 KoRect newColumnRect = firstColumnRect( mainTextFrameSet, pageNum, numColumns );
416#ifdef DEBUG_FRAMELAYOUT
417 kdDebug(32002) <<
" Comparing old=" << oldColumnRect <<
" and new=" << newColumnRect << endl;
419 if ( oldColumnRect != newColumnRect ) {
420 mainTextFrameResized = pageNum;
421#ifdef DEBUG_FRAMELAYOUT
422 kdDebug(32002) <<
" changed -> mainTextFrameResized=" << mainTextFrameResized << endl;
428 m_lastMainFramePage = lastMainFrame->
pageNumber();
429#ifdef DEBUG_FRAMELAYOUT
430 kdDebug(32002) <<
"m_lastMainFramePage = " << m_lastMainFramePage <<
" lastMainFrameBottom=" << lastMainFrameBottom << endl;
433 if ( ! ( flags & DontRemovePages ) )
435 m_doc->updateAllFrames( KWFrameSet::UpdateFramesInPage );
438 (void)m_doc->tryRemovingPages();
441 const int lastPage = m_doc->lastPage();
443 TQPtrListIterator<HeaderFooterFrameset> it( m_headersFooters );
444 for ( ; it.current() ; ++it )
445 if ( it.current()->deleteFramesAfterLast( lastPage ) )
446 m_framesetsToUpdate.insert( it.current()->m_frameset,
true );
447 TQPtrListIterator<HeaderFooterFrameset> it2( m_footnotes );
448 for ( ; it2.current() ; ++it2 )
449 if ( it2.current()->deleteFramesAfterLast( lastPage ) )
450 m_framesetsToUpdate.insert( it2.current()->m_frameset,
true );
451 if ( mainTextFrameSet ) {
454 int lastFrame = m_lastMainFramePage * numColumns + (numColumns-1);
455#ifdef DEBUG_FRAMELAYOUT
456 kdDebug(32002) <<
"lastFrame: " << lastFrame <<
" due to " << m_lastMainFramePage << endl;
458 bool deleted =
false;
459 while ( (
int)mainTextFrameSet->
frameCount() - 1 > lastFrame ) {
460#ifdef DEBUG_FRAMELAYOUT
461 kdDebug(32002) <<
" Final cleanup: deleting frame " << mainTextFrameSet->
frameCount() - 1 <<
" of main textframeset (lastFrame=" << lastFrame <<
")" << endl;
467 m_framesetsToUpdate.insert( mainTextFrameSet,
true );
469 if ( m_doc->hasEndNotes() ) {
471 if ( lastMainFrame->frameBehavior() != KWFrame::AutoExtendFrame )
473 lastMainFrame->setFrameBehavior( KWFrame::AutoExtendFrame );
475 if ( mainTextFrameResized == -1 )
476 mainTextFrameResized = lastMainFrame->
pageNumber();
481 TQMap<KWFrameSet*, bool>::iterator fsit = m_framesetsToUpdate.begin();
482 for ( ; fsit != m_framesetsToUpdate.end() ; ++fsit )
483 fsit.key()->updateFrames();
488 if ( mainTextFrameResized != -1 && mainTextFrameSet->
type() == FT_TEXT ) {
489#ifdef DEBUG_FRAMELAYOUT
490 kdDebug(32002) <<
" Done. First maintextframe resized: " << mainTextFrameResized << endl;
509#ifdef DEBUG_FRAMELAYOUT
510 kdDebug(32002) <<
" Invalidating from parag " << parag->paragId() << endl;
512 fs->
textObject()->setLastFormattedParag( parag );
519void KWFrameLayout::resizeOrCreateHeaderFooter(
KWTextFrameSet* headerFooter, uint frameNumber,
const KoRect& rect )
521 if ( frameNumber < headerFooter->frameCount() ) {
523 if ( *frame == rect )
525 frame->setRect( rect );
526#ifdef DEBUG_FRAMELAYOUT
527 kdDebug(32002) <<
"KWFrameLayout::resizeOrCreateHeaderFooter frame " << headerFooter->
name() <<
" " << frame <<
" resized to " << rect <<
" pagenum=" << frame->
pageNumber() << endl;
532#ifdef DEBUG_FRAMELAYOUT
533 kdDebug(32002) <<
"KWFrameLayout::resizeOrCreateHeaderFooter creating frame for " << headerFooter->
name() << endl;
535 KWFrame* frame =
new KWFrame( headerFooter, rect.x(), rect.y(), rect.width(), rect.height() );
536 frame->setFrameBehavior( KWFrame::AutoExtendFrame );
537 if ( headerFooter->isHeaderOrFooter() )
539 frame->setNewFrameBehavior( KWFrame::Copy );
540 frame->setCopy(
true );
543 frame->setNewFrameBehavior( KWFrame::NoFollowup );
544 headerFooter->addFrame( frame,
false );
549 m_framesetsToUpdate.insert( headerFooter,
true );
556KoRect KWFrameLayout::firstColumnRect(
KWFrameSet* mainTextFrameSet,
int pageNum,
int numColumns )
const
558 uint frameNum = pageNum * numColumns ;
559 if ( mainTextFrameSet && frameNum < mainTextFrameSet->frameCount() )
560 return * mainTextFrameSet->
frame( frameNum );
565bool KWFrameLayout::resizeMainTextFrame(
KWFrameSet* mainTextFrameSet,
int pageNum,
int numColumns,
double ptColumnWidth,
double ptColumnSpacing,
double left,
double top,
double bottom, HasFootNotes hasFootNotes )
567 if ( !mainTextFrameSet )
569 bool mainTextFrameResized =
false;
570 for (
int col = 0; col < numColumns; col++ ) {
571 Q_ASSERT( bottom > top );
573 KoRect rect( left + col * ( ptColumnWidth + ptColumnSpacing ),
574 top, ptColumnWidth, bottom - top );
575 uint frameNum = (pageNum - m_doc->startPage()) * numColumns + col;
577 if ( frameNum < mainTextFrameSet->frameCount() ) {
579 frame = mainTextFrameSet->
frame( frameNum );
581 if ( m_doc->hasEndNotes() && pageNum >= m_lastMainFramePage )
582 rect.setBottom( frame->bottom() );
583 bool resized = (rect != *frame);
585#ifdef DEBUG_FRAMELAYOUT
586 kdDebug(32002) <<
" Page " << pageNum <<
": resizing main text frame " << frameNum <<
"(" << frame <<
") to " << rect << endl;
588 frame->setRect( rect );
589 frame->updateRulerHandles();
590 mainTextFrameResized =
true;
595 frame =
new KWFrame( mainTextFrameSet, rect.x(), rect.y(), rect.width(), rect.height() );
596#ifdef DEBUG_FRAMELAYOUT
597 kdDebug(32002) <<
" Page " << pageNum <<
": creating new main text frame " << frameNum <<
"(" << frame <<
") to " << rect << endl;
599 mainTextFrameSet->addFrame( frame );
600 Q_ASSERT( frameNum == mainTextFrameSet->
frameCount()-1 );
601 mainTextFrameResized =
true;
604 if ( hasFootNotes == NoFootNote )
606 else if ( hasFootNotes == WithFootNotes )
610 frame->setFrameBehavior( KWFrame::AutoCreateNewFrame );
612 return mainTextFrameResized;
615void KWFrameLayout::checkFootNotes()
619 TQPtrListIterator<HeaderFooterFrameset> it( m_footnotes );
620 for ( ; it.current() ; ++it )
622 HeaderFooterFrameset* hff = it.current();
623 if ( ! hff->m_positioned )
625 Q_ASSERT ( hff->m_frameset->isFootEndNote() );
626 KWFootNoteFrameSet* fnfs =
static_cast<KWFootNoteFrameSet *
>( hff->m_frameset );
633 if ( !fnvar || !fnvar->paragraph() )
635 double varY = fnvar->varY();
638 hff->m_minY = varY + hff->m_spacing + 2 ;
639 int pageNum = m_doc->pageManager()->pageNumber(varY);
640 if ( pageNum != hff->m_startAtPage ) {
641#ifdef DEBUG_FRAMELAYOUT
642 kdDebug(32002) <<
" checkFootNotes: found minY=" << hff->m_minY <<
" start/end=" << pageNum <<
" for footnote " << fnvar->text() << endl;
644 hff->m_startAtPage = pageNum;
645 hff->m_endAtPage = pageNum;
static void recalcFrames(KWDocument *doc, int pageFrom, int pageTo)
Update the z-ordering for all frames in the page section of the whole document.
Class: KWFrameSet Base type, a frameset holds content as well as frames to show that content.
virtual void deleteFrame(unsigned int num, bool remove=true, bool recalc=true)
Delete a frame from the set of frames this frameSet has.
virtual FrameSetType type() const
The type of frameset.
@ SortFrames
kwtextframeset only
const TQPtrList< KWFrame > & frameIterator() const
Iterator over the child frames.
unsigned int frameCount() const
Get number of child frames.
virtual void updateFrames(int flags=0xff)
Called when our frames change, or when another frameset's frames change.
KWFrame * frame(unsigned int _num) const
get a frame by number
TQString name() const
get/set frameset name. For tables in particular, this must be unique
bool hasFramesInPageArray() const
Allows to detect that updateFrames() hasn't been called yet (e.g.
This class represents a single frame.
void setDrawFootNoteLine(bool b)
Only applicable to frames of the main text frameset.
int pageNumber() const
The page on which this frame is.
This class represents a printed page of the document.
double height() const
return the height of this page (in pt)
double leftMargin() const
return the width of the margin at left (in pt);
double topMargin() const
return the height of the margin at top (in pt);
double bottomMargin() const
return the height of the margin at bottom (in pt);
double width() const
return the width of this page (in pt)
double rightMargin() const
return the width of the margin at left (in pt);
double offsetInDocument() const
All Pages are in a document-wide coordinate system that simply puts every page under the next page an...
Class: KWTextFrameSet Contains text (KoTextObject) and frames to display that text.
KoTextObject * textObject() const
Return the contained text object.
virtual void updateFrames(int flags=0xff)
reshuffle frames so text is always displayed from top-left down and then right.
virtual void deleteFrame(unsigned int num, bool remove=true, bool recalc=true)
Delete a frame from the set of frames this frameSet has.
KoTextParag * paragAtLUPos(int yLU) const
Find the parag at the given Y position (in LU)
bool minMaxInternalOnPage(int pageNum, int &topLU, int &bottomLU) const
Return the min and max LU coordinates for the text in the given page, if the frameset has any frames ...
virtual void setVisible(bool v)
set the visibility of the frameset.