kword

KWFrameSet.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999, 2000 Reginald Stadlbauer <reggie@kde.org>
00003    Copyright (C) 2005 Thomas Zander <zander@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "KWFrameSet.h"
00022 #include "KWDocument.h"
00023 #include "KWViewMode.h"
00024 #include "KWCommand.h"
00025 #include "KWFrame.h"
00026 #include "KWTextFrameSet.h"
00027 #include "KWTableFrameSet.h"
00028 #include "KWAnchor.h"
00029 #include "KWordFrameSetIface.h"
00030 #include "KWFrameList.h"
00031 #include "KWPageManager.h"
00032 #include "KWPage.h"
00033 #include "KWFrameViewManager.h"
00034 #include "KWFrameView.h"
00035 
00036 #include <KoOasisContext.h>
00037 #include <KoXmlNS.h>
00038 #include <KoXmlWriter.h>
00039 
00040 #include <qpopupmenu.h>
00041 #include <qapplication.h>
00042 
00043 //#define DEBUG_DRAW
00044 
00045 KWFrameSet::KWFrameSet( KWDocument *doc )
00046     : m_doc( doc ), m_frames(), m_framesInPage(), m_firstPage( 0 ), m_emptyList(),
00047       m_info( FI_BODY ),
00048       m_groupmanager( 0L ), m_visible( true ),
00049       m_protectSize( false ),
00050       m_anchorTextFs( 0L ), m_dcop( 0L ), m_pageManager( 0 )
00051 {
00052     // Send our "repaintChanged" signals to the document.
00053     setName("KWFrameSet");
00054     if(m_doc) {
00055         connect( this, SIGNAL( repaintChanged( KWFrameSet * ) ),
00056              doc, SLOT( slotRepaintChanged( KWFrameSet * ) ) );
00057         m_pageManager = doc->pageManager();
00058     }
00059     m_frames.setAutoDelete( true );
00060     m_framesInPage.setAutoDelete( true ); // autodelete the lists in the array (not the frames;)
00061 }
00062 
00063 KWordFrameSetIface* KWFrameSet::dcopObject()
00064  {
00065     if ( !m_dcop )
00066         m_dcop = new KWordFrameSetIface( this );
00067 
00068     return m_dcop;
00069 }
00070 
00071 
00072 KWFrameSet::~KWFrameSet()
00073 {
00074     delete m_dcop;
00075 }
00076 
00077 void KWFrameSet::addFrame( KWFrame *frame, bool recalc )
00078 {
00079     if ( m_frames.findRef( frame ) != -1 )
00080         return;
00081 
00082     //kdDebug(32001) << k_funcinfo << name() << " adding frame" <<  frame << " recalc=" << recalc << endl;
00083     if(m_doc)
00084         KWFrameList::createFrameList(frame, m_doc);
00085     frame->setFrameSet(this);
00086     m_frames.append( frame );
00087     if(recalc)
00088         updateFrames();
00089 
00090     emit sigFrameAdded(frame);
00091 }
00092 
00093 void KWFrameSet::deleteFrame( unsigned int num, bool remove, bool recalc )
00094 {
00095     //kdDebug(32001) << k_funcinfo << name() << " deleting frame" <<  num << " remove=" << remove << " recalc=" << recalc << endl; //kdBacktrace();
00096     KWFrame *frm = m_frames.at( num );
00097     Q_ASSERT( frm );
00098     m_frames.take( num );
00099     Q_ASSERT( !m_frames.contains(frm) );
00100 
00101     unsigned int index = frm->pageNumber() - m_firstPage;
00102     if(m_framesInPage.count() >= index) {
00103         QPtrList<KWFrame> *lst = m_framesInPage.at(index);
00104         lst->remove(frm);
00105     }
00106 
00107     KWFrameList *stack = frm->frameStack();
00108     if( stack ) {
00109         stack->update(); // will update the other frames on the page.
00110         frm->setFrameStack(0);
00111         delete stack;
00112     }
00113     emit sigFrameRemoved(frm);
00114     if ( !remove )
00115         frm->setFrameSet(0L);
00116     else {
00117         // ###### should something similar be done when just removing a frame from the list?
00118         frameDeleted( frm, recalc ); // inform kwtableframeset if necessary
00119         delete frm;
00120         //kdDebug(32001) << k_funcinfo << frm << " deleted. Now I have " << m_frames.count() << " m_frames" << endl;
00121     }
00122 
00123     if ( recalc )
00124         updateFrames();
00125 }
00126 
00127 void KWFrameSet::deleteFrame( KWFrame *frm, bool remove, bool recalc )
00128 {
00129     //kdDebug(32001) << "KWFrameSet::deleteFrame " << frm << " remove=" << remove << endl;
00130     int num = m_frames.findRef( frm );
00131     Q_ASSERT( num != -1 );
00132     if ( num == -1 )
00133         return;
00134 
00135     deleteFrame( num, remove, recalc );
00136 }
00137 
00138 void KWFrameSet::deleteAllFrames()
00139 {
00140     if ( !m_frames.isEmpty() )
00141     {
00142         for ( QPtrListIterator<KWFrame> frameIt( m_frames ); frameIt.current(); ++frameIt )
00143             emit sigFrameRemoved( *frameIt );
00144         m_frames.clear();
00145         updateFrames();
00146     }
00147 }
00148 
00149 void KWFrameSet::deleteAllCopies()
00150 {
00151     if ( m_frames.count() > 1 )
00152     {
00153         KWFrame * firstFrame = m_frames.take(0);
00154         deleteAllFrames();
00155         m_frames.append( firstFrame );
00156         updateFrames();
00157     }
00158 }
00159 
00160 void KWFrameSet::createEmptyRegion( const QRect & crect, QRegion & emptyRegion, KWViewMode *viewMode )
00161 {
00162     KWPage *page = m_doc->pageManager()->page( frame(0) );
00163     if( !page ) {
00164         kdWarning(31001) << "The first frame of '" << name() << "' is outside all pages!!" << endl;
00165         return;
00166     }
00167     double paperHeight = page->height();
00168     //kdDebug(32001) << "KWFrameSet::createEmptyRegion " << name() << endl;
00169     for (QPtrListIterator<KWFrame> frameIt = frameIterator(); frameIt.current(); ++frameIt )
00170     {
00171         if ( !frameIt.current()->isTransparent() )
00172         {
00173             QRect outerRect( viewMode->normalToView( frameIt.current()->outerRect(viewMode) ) );
00174             //kdDebug(32001) << "KWFrameSet::createEmptyRegion outerRect=" << outerRect << " crect=" << crect << endl;
00175             outerRect &= crect; // This is important, to avoid calling subtract with a Y difference > 65536
00176             if ( !outerRect.isEmpty() )
00177             {
00178                 emptyRegion = emptyRegion.subtract( outerRect );
00179                 //kdDebug(32001) << "KWFrameSet::createEmptyRegion emptyRegion now: " << endl; DEBUGREGION( emptyRegion );
00180             }
00181             if ( crect.bottom() + paperHeight < outerRect.top() )
00182                 return; // Ok, we're far below the crect, abort.
00183         }
00184     }
00185 }
00186 
00187 void KWFrameSet::drawPadding( KWFrame *frame, QPainter *p, const QRect &crect, const QColorGroup &, KWViewMode *viewMode )
00188 {
00189     QRect outerRect( viewMode->normalToView( frame->outerRect(viewMode) ) );
00190     //kdDebug(32001) << "KWFrameSet::drawPadding frame: " << frameFromPtr( frame )
00191     //               << " outerRect: " << outerRect
00192     //               << " crect: " << crect << endl;
00193 
00194     if ( !crect.intersects( outerRect ) )
00195     {
00196 #ifdef DEBUG_DRAW
00197         kdDebug(32001) << "KWFrameSet::drawPadding no intersection with " << crect << endl;
00198 #endif
00199         return;
00200     }
00201     QRect frameRect( viewMode->normalToView( m_doc->zoomRect( *frame ) ) );
00202     p->save();
00203     QBrush bgBrush( frame->backgroundColor() );
00204     bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), p ) );
00205     p->setBrush( bgBrush );
00206     int leftMargin = m_doc->zoomItX(frame->paddingLeft());
00207     int topMargin = m_doc->zoomItY(frame->paddingTop());
00208     int rightMargin = m_doc->zoomItX(frame->paddingRight());
00209     int bottomMargin = m_doc->zoomItY(frame->paddingBottom());
00210     //kdDebug(32001) << "KWFrameSet::drawPadding leftMargin=" << leftMargin << " topMargin=" << topMargin << " rightMargin=" << rightMargin << " bottomMargin=" << bottomMargin << endl;
00211 
00212     if ( topMargin != 0 )
00213     {
00214         QRect r( frameRect.left(), frameRect.top(), frameRect.width(), topMargin );
00215         p->fillRect( r, bgBrush );
00216     }
00217     if ( leftMargin != 0 )
00218     {
00219         QRect r( frameRect.left(), frameRect.top(), leftMargin, frameRect.height() );
00220         p->fillRect( r, bgBrush );
00221     }
00222     if ( rightMargin != 0 )
00223     {
00224         QRect r( frameRect.right()-rightMargin, frameRect.top(), rightMargin, frameRect.height() );
00225         p->fillRect( r, bgBrush );
00226     }
00227     if ( bottomMargin != 0 )
00228     {
00229         QRect r( frameRect.left(), frameRect.bottom()-bottomMargin, frameRect.width(), bottomMargin );
00230         p->fillRect( r, bgBrush );
00231     }
00232     p->restore();
00233 
00234 }
00235 
00236 
00237 void KWFrameSet::drawFrameBorder( QPainter *painter, KWFrame *frame, KWFrame *settingsFrame, const QRect &crect, KWViewMode *viewMode )
00238 {
00239     QRect outerRect( viewMode->normalToView( frame->outerRect( viewMode ) ) );
00240     //kdDebug(32001) << "KWFrameSet::drawFrameBorder frame: " << frameFromPtr( frame )
00241     //               << " outerRect: " << outerRect << endl;
00242 
00243     if ( !crect.intersects( outerRect ) )
00244     {
00245         //kdDebug(32001) << "KWFrameSet::drawFrameBorder no intersection with " << crect << endl;
00246         return;
00247     }
00248 
00249     QRect frameRect( viewMode->normalToView( m_doc->zoomRect(  *frame ) ) );
00250 
00251     painter->save();
00252     QBrush bgBrush( settingsFrame->backgroundColor() );
00253     //bool defaultColor = !bgBrush.color().isValid();
00254     bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), painter ) );
00255     painter->setBrush( bgBrush );
00256 
00257     // Draw default borders using view settings...
00258     QPen viewSetting( QApplication::palette().color( QPalette::Active, QColorGroup::Mid ) );
00259     int minBorder = 1;
00260     // ...except when printing, or embedded doc, or disabled.
00261     if ( !viewMode || !viewMode->drawFrameBorders() )
00262     {
00263         viewSetting = NoPen;
00264         minBorder = 0;
00265     }
00266 
00267     // Draw borders either as the user defined them, or using the view settings.
00268     // Borders should be drawn _outside_ of the frame area
00269     // otherwise the frames will erase the border when painting themselves.
00270 
00271     KoBorder::drawBorders( *painter, m_doc, frameRect,
00272                            settingsFrame->leftBorder(), settingsFrame->rightBorder(),
00273                            settingsFrame->topBorder(), settingsFrame->bottomBorder(),
00274                            minBorder, viewSetting );
00275     painter->restore();
00276 }
00277 
00278 void KWFrameSet::setFloating()
00279 {
00280     // Find main text frame
00281     QPtrListIterator<KWFrameSet> fit = m_doc->framesetsIterator();
00282     for ( ; fit.current() ; ++fit )
00283     {
00284         KWTextFrameSet * frameSet = dynamic_cast<KWTextFrameSet *>( fit.current() );
00285         if ( !frameSet || frameSet->frameSetInfo() != FI_BODY )
00286             continue;
00287 
00288         KoTextParag* parag = 0L;
00289         int index = 0;
00290         KoPoint dPoint( m_frames.first()->topLeft() );
00291         kdDebug(32001) << "KWFrameSet::setFloating looking for pos at " << dPoint.x() << " " << dPoint.y() << endl;
00292         frameSet->findPosition( dPoint, parag, index );
00293         // Create anchor. TODO: refcount the anchors!
00294         setAnchored( frameSet, parag, index );
00295         frameSet->layout();
00296         m_doc->frameChanged( m_frames.first() );
00297         return;
00298     }
00299 }
00300 
00301 void KWFrameSet::setProtectSize( bool b)
00302 {
00303     m_protectSize = b;
00304 }
00305 
00306 void KWFrameSet::setAnchored( KWTextFrameSet* textfs, int paragId, int index, bool placeHolderExists /* = false */, bool repaint )
00307 {
00308     KWTextParag * parag = static_cast<KWTextParag *>( textfs->textDocument()->paragAt( paragId ) );
00309     Q_ASSERT( parag );
00310     if ( parag )
00311         setAnchored( textfs, parag, index, placeHolderExists, repaint );
00312 }
00313 
00314 void KWFrameSet::setAnchored( KWTextFrameSet* textfs, KoTextParag* parag, int index, bool placeHolderExists /* = false */, bool repaint )
00315 {
00316     kdDebug(32001) << "KWFrameSet::setAnchored " << textfs << " " << parag->paragId() << " " << index << " " << placeHolderExists << endl;
00317     Q_ASSERT( textfs );
00318     Q_ASSERT( parag );
00319     if ( isFloating() )
00320         deleteAnchors();
00321     m_anchorTextFs = textfs;
00322     KWFrameList::createFrameList(textfs, m_doc); // remove ourselves from others list now we are inline
00323     if ( parag )
00324         createAnchors( parag, index, placeHolderExists, repaint );
00325 
00326     if ( !placeHolderExists ) // i.e. not while loading
00327     {
00328         m_doc->updateAllFrames(); // We just became floating, so we need to be removed from "frames on top/below".
00329         // TODO pass page number to updateAllFrames - hmm, we could have several frames in theory
00330     }
00331 }
00332 
00333 void KWFrameSet::setAnchored( KWTextFrameSet* textfs )
00334 {
00335     m_anchorTextFs = textfs;
00336     m_doc->updateAllFrames(); // We just became floating, so we need to be removed from "frames on top/below".
00337     // TODO pass page number - hmm, we could have several frames in theory
00338 }
00339 
00340 // Find where our anchor is ( if we are anchored ).
00341 // We can't store a pointers to anchors, because over time we might change anchors
00342 // (Especially, undo/redo of insert/delete can reuse an old anchor and forget a newer one etc.)
00343 KWAnchor * KWFrameSet::findAnchor( int frameNum )
00344 {
00345     Q_ASSERT( m_anchorTextFs );
00346     // Yes, a linear search, but only among all customitems of the correct textdoc,
00347     // whose number is assumed to be quite small.
00348     QPtrListIterator<KoTextCustomItem> cit( m_anchorTextFs->textDocument()->allCustomItems() );
00349     for ( ; cit.current() ; ++cit )
00350     {
00351         KWAnchor * anchor = dynamic_cast<KWAnchor *>( cit.current() );
00352         if ( anchor && !anchor->isDeleted()
00353              && anchor->frameSet() == this && anchor->frameNum() == frameNum )
00354                 return anchor;
00355     }
00356     kdWarning() << "KWFrameSet::findAnchor anchor not found (frameset='" << name()
00357                 << "' frameNum=" << frameNum << ")" << endl;
00358     return 0L;
00359 }
00360 
00361 void KWFrameSet::setFixed()
00362 {
00363     kdDebug(32001) << "KWFrameSet::setFixed" << endl;
00364     if ( isFloating() )
00365         deleteAnchors();
00366     m_anchorTextFs = 0L;
00367     // make sure the frames are on top
00368     // (their z-order didn't matter when they were inline)
00369     QPtrListIterator<KWFrame> frameIt = frameIterator();
00370     for ( ; frameIt.current(); ++frameIt )
00371         frameIt.current()->setZOrder( m_doc->maxZOrder( frameIt.current()->pageNumber(m_doc) ) + 1 );
00372 
00373     m_doc->repaintAllViews();
00374     m_doc->updateRulerFrameStartEnd();
00375 }
00376 
00377 KWAnchor * KWFrameSet::createAnchor( KoTextDocument *txt, int frameNum )
00378 {
00379     KWAnchor * anchor = new KWAnchor( txt, this, frameNum );
00380     return anchor;
00381 }
00382 
00383 void KWFrameSet::createAnchors( KoTextParag * parag, int index, bool placeHolderExists /*= false */ /*only used when loading*/,
00384                                 bool repaint )
00385 {
00386     kdDebug(32001) << "KWFrameSet::createAnchors" << endl;
00387     Q_ASSERT( m_anchorTextFs );
00388     QPtrListIterator<KWFrame> frameIt = frameIterator();
00389     for ( ; frameIt.current(); ++frameIt, ++index )
00390     {
00391         //if ( ! frameIt.current()->anchor() )
00392         {
00393             // Anchor this frame, after the previous one
00394             KWAnchor * anchor = createAnchor( m_anchorTextFs->textDocument(), frameFromPtr( frameIt.current() ) );
00395             if ( !placeHolderExists )
00396                 parag->insert( index, KoTextObject::customItemChar() );
00397             parag->setCustomItem( index, anchor, 0 );
00398         }
00399     }
00400     parag->setChanged( true );
00401     if ( repaint )
00402         emit repaintChanged( m_anchorTextFs );
00403 }
00404 
00405 void KWFrameSet::deleteAnchor( KWAnchor * anchor )
00406 {
00407     // Simple deletion, no undo/redo
00408     KoTextCursor c( m_anchorTextFs->textDocument() );
00409     c.setParag( anchor->paragraph() );
00410     c.setIndex( anchor->index() );
00411     anchor->setDeleted( true ); // this sets m_anchorTextFs to 0L
00412 
00413     static_cast<KWTextParag*>(c.parag())->removeCustomItem(c.index());
00414     c.remove(); // This deletes the character where the anchor was
00415     // We don't delete the anchor since it might be in a customitemmap in a text-insert command
00416     // TODO: refcount the anchors
00417     c.parag()->setChanged( true );
00418 }
00419 
00420 void KWFrameSet::deleteAnchors()
00421 {
00422     kdDebug(32002) << "KWFrameSet::deleteAnchors" << endl;
00423     KWTextFrameSet * textfs = m_anchorTextFs;
00424     Q_ASSERT( textfs );
00425     if ( !textfs )
00426         return;
00427     //QPtrListIterator<KWFrame> frameIt = frameIterator();
00428     int frameNum = 0;
00429     // At the moment there's only one anchor per frameset
00430     // With tables the loop below will be wrong anyway...
00431     //for ( ; frameIt.current(); ++frameIt, ++frameNum )
00432     {
00433 /*        if ( frameIt.current()->anchor() )
00434             deleteAnchor( frameIt.current()->anchor() );
00435         frameIt.current()->setAnchor( 0L );
00436 */
00437         KWAnchor * anchor = findAnchor( frameNum );
00438         deleteAnchor( anchor );
00439     }
00440     emit repaintChanged( textfs );
00441 }
00442 
00443 void KWFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position )
00444 {
00445     KWFrame * frame = m_frames.at( frameNum );
00446     Q_ASSERT( frame );
00447     if ( !frame ) return;
00448 
00449     KoPoint pos( position );
00450     // position includes the border, we need to adjust accordingly
00451     pos.rx() += frame->leftBorder().width();
00452     pos.ry() += frame->topBorder().width();
00453     if ( frame->topLeft() != pos )
00454     {
00455         kdDebug(32002) << "KWFrameSet::moveFloatingFrame " << pos.x() << "," << pos.y() << endl;
00456         int oldPageNum = frame->pageNumber();
00457         frame->moveTopLeft( pos );
00458 
00459         updateFrames();
00460         if( frame->frameStack() )
00461             frame->frameStack()->updateAfterMove( oldPageNum );
00462     }
00463     invalidate();
00464 }
00465 
00466 KoRect KWFrameSet::floatingFrameRect( int frameNum )
00467 {
00468     KWFrame * frame = m_frames.at( frameNum );
00469     Q_ASSERT( frame );
00470     Q_ASSERT( isFloating() );
00471 
00472     KWAnchor* anchor = findAnchor( frameNum );
00473     Q_ASSERT( anchor );
00474     QRect paragRect = anchor->paragraph()->rect();
00475     int x = anchor->x() + paragRect.x(); // in LU
00476     int y = anchor->y() + paragRect.y(); // in LU
00477 
00478     KoPoint topLeft( m_doc->layoutUnitToPixelX( x ), m_doc->layoutUnitToPixelY( y ) );
00479     return KoRect( topLeft, frame->outerKoRect().size() );
00480 }
00481 
00482 KoSize KWFrameSet::floatingFrameSize( int frameNum )
00483 {
00484     KWFrame * frame = m_frames.at( frameNum );
00485     Q_ASSERT( frame );
00486     return frame->outerKoRect().size();
00487 }
00488 
00489 KCommand * KWFrameSet::anchoredObjectCreateCommand( int frameNum )
00490 {
00491     KWFrame * frame = m_frames.at( frameNum );
00492     Q_ASSERT( frame );
00493     return new KWCreateFrameCommand( QString::null, frame );
00494 }
00495 
00496 KCommand * KWFrameSet::anchoredObjectDeleteCommand( int frameNum )
00497 {
00498     KWFrame * frame = m_frames.at( frameNum );
00499     Q_ASSERT( frame );
00500     return new KWDeleteFrameCommand( QString::null, frame );
00501 }
00502 
00503 KWFrame * KWFrameSet::frameAtPos( double x, double y ) const
00504 {
00505     KoPoint docPoint( x, y );
00506     QPtrListIterator<KWFrame> frameIt = frameIterator();
00507     for ( ; frameIt.current(); ++frameIt )
00508         if ( frameIt.current()->contains( docPoint ) )
00509             return frameIt.current();
00510     return 0L;
00511 }
00512 
00513 KWFrame *KWFrameSet::frame( unsigned int num ) const
00514 {
00515     // QPtrList sucks
00516     return const_cast<KWFrameSet*>( this )->m_frames.at( num );
00517 }
00518 
00519 int KWFrameSet::frameFromPtr( KWFrame *frame )
00520 {
00521     return m_frames.findRef( frame );
00522 }
00523 
00524 KWFrame * KWFrameSet::settingsFrame( const KWFrame* frame )
00525 {
00526     if ( !frame->isCopy() )
00527         return const_cast<KWFrame *>( frame );
00528     KWFrame* lastRealFrame=0L;
00529     QPtrListIterator<KWFrame> frameIt( frame->frameSet()->frameIterator() );
00530     for ( ; frameIt.current(); ++frameIt )
00531     {
00532         KWFrame *curFrame = frameIt.current();
00533         if ( curFrame == frame )
00534             return lastRealFrame ? lastRealFrame : const_cast<KWFrame *>( frame );
00535         if ( !lastRealFrame || !curFrame->isCopy() )
00536             lastRealFrame = curFrame;
00537     }
00538     return const_cast<KWFrame *>( frame ); //fallback, should never happen
00539 }
00540 
00541 void KWFrameSet::updateFrames( int flags )
00542 {
00543     if ( m_frames.isEmpty() )
00544         return; // No frames. This happens when the frameset is deleted (still exists for undo/redo)
00545 
00546     // Not visible ? Don't bother then.
00547     if ( !isVisible() )
00548         return;
00549 
00550     //kdDebug(32001) << "KWFrameSet::updateFrames " << this << " " << name() << endl;
00551 
00552     if ( flags & UpdateFramesInPage ) {
00553         // For each of our frames, clear old list of frames on top, and grab min/max page nums
00554         m_firstPage = m_frames.first()->pageNumber(); // we know m_frames is not empty here
00555         int lastPage = m_firstPage;
00556         QPtrListIterator<KWFrame> fIt( frameIterator() );
00557         for ( ; fIt.current(); ++fIt ) {
00558             int pg = fIt.current()->pageNumber();
00559             m_firstPage = KMIN( m_firstPage, pg );
00560             lastPage = KMAX( lastPage, pg );
00561         }
00562         //kdDebug(32001) << "firstPage=" << m_firstPage << " lastPage=" << lastPage << endl;
00563 
00564         // Prepare the m_framesInPage structure
00565         int oldSize = m_framesInPage.size();
00566         m_framesInPage.resize( lastPage - m_firstPage + 1 );
00567         // Clear the old elements
00568         int oldElements = KMIN( oldSize, (int)m_framesInPage.size() );
00569         for ( int i = 0 ; i < oldElements ; ++i )
00570             m_framesInPage[i]->clear();
00571         // Initialize the new elements.
00572         for ( int i = oldElements ; i < (int)m_framesInPage.size() ; ++i )
00573             m_framesInPage.insert( i, new QPtrList<KWFrame>() );
00574 
00575         // Iterate over m_frames again, to fill the m_framesInPage array
00576         fIt.toFirst();
00577         for ( ; fIt.current(); ++fIt ) {
00578             int pg = fIt.current()->pageNumber();
00579             Q_ASSERT( pg <= lastPage );
00580             m_framesInPage[pg - m_firstPage]->append( fIt.current() );
00581         }
00582     }
00583 
00584     if ( isFloating() )
00585     {
00586         //kdDebug(32001) << "KWFrameSet::updateFrames " << name() << " is floating" << endl;
00587         QPtrListIterator<KWFrame> frameIt = frameIterator();
00588         int frameNum = 0;
00589         // At the moment there's only one anchor per frameset
00590         //for ( ; frameIt.current(); ++frameIt, ++frameNum )
00591         {
00592             KWAnchor * anchor = findAnchor( frameNum );
00593             //kdDebug(32001) << "KWFrameSet::updateFrames anchor=" << anchor << endl;
00594             if ( anchor )
00595                 anchor->resize();
00596         }
00597     }
00598 }
00599 
00600 bool KWFrameSet::isPaintedBy( KWFrameSet* fs ) const
00601 {
00602     if ( fs == this )
00603         return true;
00604     if ( isFloating() )
00605     {
00606         KWFrameSet* parentFs = anchorFrameset();
00607         if ( parentFs && parentFs->isPaintedBy( fs ) )
00608             return true;
00609     }
00610     if ( groupmanager() )
00611     {
00612         if ( groupmanager()->isPaintedBy( fs ) )
00613             return true;
00614     }
00615     return false;
00616 }
00617 
00618 const QPtrList<KWFrame> & KWFrameSet::framesInPage( int pageNum ) const
00619 {
00620     if ( pageNum < m_firstPage || pageNum >= (int)m_framesInPage.size() + m_firstPage )
00621     {
00622 #ifdef DEBUG_DTI
00623         kdWarning(32002) << name() << " framesInPage called for pageNum=" << pageNum << ". "
00624                     << " Min value: " << m_firstPage
00625                     << " Max value: " << m_framesInPage.size() + m_firstPage - 1 << endl;
00626 #endif
00627         return m_emptyList; // QPtrList<KWFrame>() doesn't work, it's a temporary
00628     }
00629     return * m_framesInPage[pageNum - m_firstPage];
00630 }
00631 
00632 void KWFrameSet::drawContents( QPainter *p, const QRect & crect, const QColorGroup &cg,
00633                                bool onlyChanged, bool resetChanged,
00634                                KWFrameSetEdit *edit, KWViewMode *viewMode,
00635                                KWFrameViewManager *frameViewManager )
00636 {
00637 #ifdef DEBUG_DRAW
00638     kdDebug(32001) << "\nKWFrameSet::drawContents " << this << " " << name()
00639                    << " onlyChanged=" << onlyChanged << " resetChanged=" << resetChanged
00640                    << " crect= " << crect
00641                    << endl;
00642 #endif
00643     if ( !viewMode->isTextModeFrameset( this ) )
00644     {
00645         QPtrListIterator<KWFrame> frameIt( frameIterator() );
00646         KWFrame * lastRealFrame = 0L;
00647         //double lastRealFrameTop = 0;
00648         //double totalHeight = 0; // in pt, to avoid accumulating rounding errors
00649         for ( ; frameIt.current(); )
00650         {
00651             KWFrame *frame = frameIt.current();
00652             ++frameIt; // Point to the next one, to detect "last copy"
00653             // The settings come from this frame
00654             KWFrame * settingsFrame = ( frame->isCopy() && lastRealFrame ) ? lastRealFrame : frame;
00655             bool lastCopy = !frameIt.current() || !frameIt.current()->isCopy();
00656             drawFrameAndBorders( frame, p, crect, cg, onlyChanged,
00657                                  // Only reset the changed flag in the last copy of a given frame (#60678)
00658                                  resetChanged && lastCopy,
00659                                  edit,
00660                                  viewMode, settingsFrame, true /*transparency & double-buffering*/ );
00661             if(viewMode->drawSelections() && frameViewManager)
00662                 frameViewManager->view(frame)->paintFrameAttributes(p, crect, viewMode, m_doc);
00663 
00664             if ( !lastRealFrame || !frame->isCopy() )
00665             {
00666                 lastRealFrame = frame;
00667                 //lastRealFrameTop = totalHeight;
00668             }
00669             //totalHeight += frame->innerHeight();
00670         }
00671     }
00672     else { // Text view mode
00673         QRect normalRect = viewMode->viewToNormal(crect);
00674         drawFrame( 0L /*frame*/, p, normalRect, crect, QPoint(KWViewModeText::OFFSET, 0),
00675                    0L /*settingsFrame*/, cg, onlyChanged, resetChanged, edit, viewMode, true );
00676     }
00677 }
00678 
00679 void KWFrameSet::drawFrameAndBorders( KWFrame *frame,
00680                                       QPainter *painter, const QRect &crect,
00681                                       const QColorGroup &cg, bool onlyChanged, bool resetChanged,
00682                                       KWFrameSetEdit *edit, KWViewMode *viewMode,
00683                                       KWFrame *settingsFrame, bool drawUnderlyingFrames )
00684 {
00685     if ( !frame->isValid() )
00686     {
00687         kdDebug(32002) << "KWFrameSet::drawFrameAndBorders " << name() << " frame " << frameFromPtr( frame ) << " " << frame << " isn't valid" << endl;
00688         return;
00689     }
00690 
00691     QRect normalOuterFrameRect( frame->outerRect( viewMode ) );
00692     QRect outerFrameRect( viewMode->normalToView( normalOuterFrameRect ) );
00693     QRect outerCRect = crect.intersect( outerFrameRect );
00694 #ifdef DEBUG_DRAW
00695     kdDebug(32001) << "KWFrameSet::drawFrameAndBorders " << name() << " frame " << frameFromPtr( frame ) << " " << *frame << endl;
00696     kdDebug(32001) << "                    (outer) normalFrameRect=" << normalOuterFrameRect << " frameRect=" << outerFrameRect << endl;
00697     kdDebug(32001) << "                    crect=" << crect << " intersec=" << outerCRect << " todraw=" << !outerCRect.isEmpty() << endl;
00698 #endif
00699     if ( !outerCRect.isEmpty() )
00700     {
00701         // Determine settingsFrame if not passed (for speedup)
00702         if ( !settingsFrame )
00703             settingsFrame = this->settingsFrame( frame );
00704 
00705         QRect normalInnerFrameRect( m_doc->zoomRect( frame->innerRect() ) );
00706         QRect innerFrameRect( viewMode->normalToView( normalInnerFrameRect ) );
00707 
00708         // This translates the coordinates in the document contents
00709         // ( frame and r are up to here in this system )
00710         // into the frame's own coordinate system.
00711         int offsetX = normalInnerFrameRect.left();
00712         int offsetY = normalInnerFrameRect.top() - m_doc->zoomItY( frame->internalY() );
00713 
00714         QRect innerCRect = outerCRect.intersect( innerFrameRect );
00715         if ( !innerCRect.isEmpty() )
00716         {
00717             QRect fcrect = viewMode->viewToNormal( innerCRect );
00718 #ifdef DEBUG_DRAW
00719             kdDebug(32001) << "                    (inner) normalFrameRect=" << normalInnerFrameRect << " frameRect=" << innerFrameRect << endl;
00720             //kdDebug(32001) << "                    crect after view-to-normal:" << fcrect << "." << " Will move by (" << -offsetX << ", -(" << normalInnerFrameRect.top() << "-" << m_doc->zoomItY(frame->internalY()) << ") == " << -offsetY << ")." << endl;
00721 #endif
00722             fcrect.moveBy( -offsetX, -offsetY );
00723             Q_ASSERT( fcrect.x() >= 0 );
00724             Q_ASSERT( fcrect.y() >= 0 );
00725 
00726             // fcrect is now the portion of the frame to be drawn,
00727             // in the frame's coordinates and in pixels
00728 #ifdef DEBUG_DRAW
00729             kdDebug(32001) << "KWFrameSet::drawFrameAndBorders in frame coords:" << fcrect << ". Will translate painter by intersec-fcrect: " << innerCRect.x()-fcrect.x() << "," << innerCRect.y()-fcrect.y() << "." << endl;
00730 #endif
00731             QRegion reg;
00732             if ( drawUnderlyingFrames )
00733                 reg = frameClipRegion( painter, frame, outerCRect, viewMode );
00734             else // false means we are being drawn _as_ an underlying frame, so no clipping!
00735                 reg = painter->xForm( outerCRect );
00736             if ( !reg.isEmpty() )
00737             {
00738                 painter->save();
00739                 painter->setClipRegion( reg );
00740 
00741                 drawFrame( frame, painter, fcrect, outerCRect,
00742                            innerCRect.topLeft() - fcrect.topLeft(), // This assume that viewToNormal() is only a translation
00743                            settingsFrame, cg, onlyChanged, resetChanged,
00744                            edit, viewMode, drawUnderlyingFrames );
00745 
00746                 if( !groupmanager() ) // not for table cells
00747                     drawFrameBorder( painter, frame, settingsFrame, outerCRect, viewMode );
00748                 painter->restore();
00749             }
00750         }
00751     }
00752 }
00753 
00754 void KWFrameSet::drawFrame( KWFrame *frame, QPainter *painter, const QRect &fcrect, const QRect &outerCRect,
00755                             const QPoint& translationOffset,
00756                             KWFrame *settingsFrame, const QColorGroup &cg, bool onlyChanged, bool resetChanged,
00757                             KWFrameSetEdit *edit, KWViewMode* viewMode, bool drawUnderlyingFrames )
00758 {
00759     // In this method the painter is NOT translated yet. It's still in view coordinates.
00760     if ( outerCRect.isEmpty() )
00761         return;
00762 #ifdef DEBUG_DRAW
00763     kdDebug(32001) << "\nKWFrameSet::drawFrame " << name() << " outerCRect=" << outerCRect << " frameCrect=" << fcrect << " drawUnderlyingFrames=" << drawUnderlyingFrames << endl;
00764 #endif
00765     Q_ASSERT( fcrect.isValid() );
00766 
00767     QColorGroup frameColorGroup( cg );
00768     if ( settingsFrame ) // 0L in text viewmode
00769     {
00770         QBrush bgBrush( settingsFrame->backgroundColor() );
00771         bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), painter ) );
00772         frameColorGroup.setBrush( QColorGroup::Base, bgBrush );
00773     }
00774 
00775     if ( drawUnderlyingFrames && frame && frame->frameStack()) {
00776         QValueList<KWFrame*> below = frame->frameStack()->framesBelow();
00777         if ( !below.isEmpty() )
00778         {
00779             // Double-buffering - not when printing
00780             QPainter* doubleBufPainter = painter;
00781             QPixmap* pix = 0L;
00782             if ( painter->device()->devType() != QInternal::Printer )
00783             {
00784                 pix = m_doc->doubleBufferPixmap( outerCRect.size() );
00785                 doubleBufPainter = new QPainter;
00786                 doubleBufPainter->begin( pix );
00787                 // Initialize the pixmap to the page background color
00788                 // (if the frame is over the page margins, no underlying frame will paint anything there)
00789                 doubleBufPainter->fillRect( 0, 0, outerCRect.width(), outerCRect.height(), QApplication::palette().active().brush( QColorGroup::Base ) );
00790 
00791                 // The double-buffer pixmap has (0,0) at outerCRect.topLeft(), so we need to
00792                 // translate the double-buffer painter; drawFrameAndBorders will draw using view coordinates.
00793                 doubleBufPainter->translate( -outerCRect.x(), -outerCRect.y() );
00794 #ifdef DEBUG_DRAW
00795     //            kdDebug(32001) << "  ... using double buffering. Portion covered: " << outerCRect << endl;
00796 #endif
00797             }
00798 
00799             // Transparency handling
00800 #ifdef DEBUG_DRAW
00801             kdDebug(32001) << "  below: " << below.count() << endl;
00802 #endif
00803             for (QValueListIterator<KWFrame*> it = below.begin(); it != below.end(); ++it )
00804             {
00805                 KWFrame* f = (*it);
00806 
00807 #ifdef DEBUG_DRAW
00808                 kdDebug(32001) << "  looking at frame below us: " << f->frameSet()->name() << " frame " << frameFromPtr( frame ) << endl;
00809 #endif
00810                 QRect viewFrameCRect = outerCRect.intersect( viewMode->normalToView( f->outerRect( viewMode ) ) );
00811                 if ( !viewFrameCRect.isEmpty() )
00812                 {
00813 #ifdef DEBUG_DRAW
00814                     kdDebug(32001) << "  viewFrameRect=" << viewFrameCRect << " calling drawFrameAndBorders." << endl;
00815 #endif
00816                     f->frameSet()->drawFrameAndBorders( f, doubleBufPainter, viewFrameCRect, cg,
00817                             false, resetChanged, edit, viewMode, 0L, false );
00818                 }
00819             }
00820 
00821             if ( frame->paddingLeft() || frame->paddingTop() || frame->paddingRight() || frame->paddingBottom() )
00822                 drawPadding( frame, doubleBufPainter, outerCRect, cg, viewMode );
00823             doubleBufPainter->save();
00824 #ifdef DEBUG_DRAW
00825             kdDebug(32001) << "  translating by " << translationOffset.x() << ", " << translationOffset.y() << " before drawFrameContents" << endl;
00826 #endif
00827             doubleBufPainter->translate( translationOffset.x(), translationOffset.y() ); // This assume that viewToNormal() is only a translation
00828             // We can't "repaint changed parags only" if we just drew the underlying frames, hence the "false"
00829             drawFrameContents( frame, doubleBufPainter, fcrect, frameColorGroup, false, resetChanged, edit, viewMode );
00830             doubleBufPainter->restore();
00831 
00832             if ( painter->device()->devType() != QInternal::Printer )
00833             {
00834                 doubleBufPainter->end();
00835 #ifdef DEBUG_DRAW
00836                 kdDebug(32001) << "  painting double-buf pixmap at position " << outerCRect.topLeft() << " (real painter pos:" << painter->xForm( outerCRect.topLeft() ) << ")" << endl;
00837 #endif
00838                 painter->drawPixmap( outerCRect.topLeft(), *pix );
00839                 delete doubleBufPainter;
00840             }
00841             return; // done! :)
00842         }
00843         else
00844         {
00845             // nothing below? paint a bg color then
00846             frameColorGroup.setBrush( QColorGroup::Base, m_doc->defaultBgColor( painter ) );
00847         }
00848     }
00849     if ( frame && (frame->paddingLeft() || frame->paddingTop() ||
00850                 frame->paddingRight() || frame->paddingBottom()) )
00851         drawPadding( frame, painter, outerCRect, cg, viewMode );
00852     painter->save();
00853     painter->translate( translationOffset.x(), translationOffset.y() );
00854 
00855     drawFrameContents( frame, painter, fcrect, frameColorGroup, onlyChanged, resetChanged, edit, viewMode );
00856     painter->restore();
00857 }
00858 
00859 void KWFrameSet::drawFrameContents( KWFrame *, QPainter *, const QRect &,
00860                                     const QColorGroup &, bool, bool, KWFrameSetEdit*, KWViewMode * )
00861 {
00862     kdWarning() << "Default implementation of drawFrameContents called for " << className() << " " << this << " " << name() << kdBacktrace();
00863 }
00864 
00865 void KWFrameSet::saveCommon( QDomElement &parentElem, bool saveFrames )
00866 {
00867     if ( m_frames.isEmpty() ) // Deleted frameset -> don't save
00868         return;
00869 
00870     // Save all the common attributes for framesets.
00871     parentElem.setAttribute( "frameType", static_cast<int>( type() ) );
00872     parentElem.setAttribute( "frameInfo", static_cast<int>( m_info ) );
00873     parentElem.setAttribute( "name", m_name );
00874     parentElem.setAttribute( "visible", static_cast<int>( m_visible ) );
00875     parentElem.setAttribute( "protectSize", static_cast<int>( m_protectSize ) );
00876     if ( saveFrames )
00877     {
00878         QPtrListIterator<KWFrame> frameIt = frameIterator();
00879         for ( ; frameIt.current(); ++frameIt )
00880         {
00881             KWFrame *frame = frameIt.current();
00882             QDomElement frameElem = parentElem.ownerDocument().createElement( "FRAME" );
00883             parentElem.appendChild( frameElem );
00884 
00885             frame->save( frameElem );
00886 
00887             if(m_doc->processingType() == KWDocument::WP) {
00888                 // Assume that all header/footer frames in the same frameset are
00889                 // perfect copies. This might not be the case some day though.
00890                 if(frameSetInfo() == FI_FIRST_HEADER ||
00891                    frameSetInfo() == FI_EVEN_HEADER ||
00892                    frameSetInfo() == FI_ODD_HEADER ||
00893                    frameSetInfo() == FI_FIRST_FOOTER ||
00894                    frameSetInfo() == FI_EVEN_FOOTER ||
00895                    frameSetInfo() == FI_ODD_FOOTER ||
00896                    frameSetInfo() == FI_FOOTNOTE) break;
00897             }
00898         }
00899     }
00900 }
00901 
00902 //
00903 // This function is intended as a helper for all the derived classes. It reads
00904 // in all the attributes common to all framesets and loads all frames.
00905 //
00906 void KWFrameSet::load( QDomElement &framesetElem, bool loadFrames )
00907 {
00908     m_info = static_cast<KWFrameSet::Info>( KWDocument::getAttribute( framesetElem, "frameInfo", KWFrameSet::FI_BODY ) );
00909     m_visible = static_cast<bool>( KWDocument::getAttribute( framesetElem, "visible", true ) );
00910     m_protectSize=static_cast<bool>( KWDocument::getAttribute( framesetElem, "protectSize", false ) );
00911     if ( loadFrames )
00912     {
00913         // <FRAME>
00914         QDomElement frameElem = framesetElem.firstChild().toElement();
00915         for ( ; !frameElem.isNull() ; frameElem = frameElem.nextSibling().toElement() )
00916         {
00917             if ( frameElem.tagName() == "FRAME" )
00918             {
00919                 KoRect rect;
00920                 rect.setLeft( KWDocument::getAttribute( frameElem, "left", 0.0 ) );
00921                 rect.setTop( KWDocument::getAttribute( frameElem, "top", 0.0 ) );
00922                 rect.setRight( KWDocument::getAttribute( frameElem, "right", 0.0 ) );
00923                 rect.setBottom( KWDocument::getAttribute( frameElem, "bottom", 0.0 ) );
00924                 KWFrame * frame = new KWFrame(this, rect.x(), rect.y(), rect.width(), rect.height() );
00925                 frame->load( frameElem, this, m_doc->syntaxVersion() );
00926                 addFrame( frame, false );
00927                 m_doc->progressItemLoaded();
00928             }
00929         }
00930     }
00931 }
00932 
00933 KWFrame* KWFrameSet::loadOasisFrame( const QDomElement& tag, KoOasisContext& context )
00934 {
00935     double width = 100;
00936     if ( tag.hasAttributeNS( KoXmlNS::svg, "width" ) ) { // fixed width
00937         // TODO handle percentage (of enclosing table/frame/page)
00938         width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00939     } else if ( tag.hasAttributeNS( KoXmlNS::fo, "min-width" ) ) {
00940         // min-width is not supported in KWord. Let's use it as a fixed width.
00941         width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::fo, "min-width", QString::null ) );
00942     } else {
00943         kdWarning(32001) << "Error in frame " << tag.tagName() << " " << tag.attributeNS( KoXmlNS::draw, "name", QString::null ) << " : neither width nor min-width specified!" << endl;
00944     }
00945     double height = 100;
00946     if ( tag.hasAttributeNS( KoXmlNS::svg, "height" ) ) { // fixed height
00947         // TODO handle percentage (of enclosing table/frame/page)
00948         height = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "height", QString::null ) );
00949     }
00950     //kdDebug(32001) << k_funcinfo << "width=" << width << " height=" << height << " pt" << endl;
00951 
00952     KWFrame * frame = new KWFrame(this,
00953                                   KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "x", QString::null ) ),
00954                                   KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "y", QString::null ) ),
00955                                   width, height );
00956 
00957     frame->setZOrder( tag.attributeNS( KoXmlNS::draw, "z-index", QString::null ).toInt() );
00958     // Copy-frames.
00959     // We currently ignore the value of the copy-of attribute. It probably needs to
00960     // be handled like chain-next-name (kwtextframeset.cc) but for all types of frameset.
00961     frame->setCopy( tag.hasAttributeNS( KoXmlNS::draw, "copy-of" ) );
00962     frame->loadCommonOasisProperties( context, this, "graphic" );
00963 
00964     addFrame( frame, false );
00965 
00966     // Protect (OASIS 14.27.7, also in OO-1.1)
00967     // A frame with protected contents means that the frameset is protected (makes sense)
00968     // A frame with protected size means that the frameset is size-protected (hmm, kword did it that way)
00969     // TODO implement position protection
00970     QString protectList = context.styleStack().attributeNS( KoXmlNS::style, "protect" );
00971     if ( protectList.contains( "content" ) )
00972         setProtectContent( true );
00973     if ( protectList.contains( "size" ) )
00974         m_protectSize = true;
00975 
00976     // TODO m_visible ? User-toggeable or internal?
00977 
00978     return frame;
00979 }
00980 
00981 void KWFrameSet::setVisible( bool v )
00982 {
00983     m_visible = v;
00984     if ( m_visible )
00985         // updateFrames was disabled while we were invisible
00986         updateFrames();
00987 }
00988 
00989 bool KWFrameSet::isVisible( KWViewMode* viewMode ) const
00990 {
00991     if ( !m_visible || m_frames.isEmpty() )
00992         return false;
00993     if ( isAHeader() && !m_doc->isHeaderVisible() )
00994         return false;
00995     if ( isAFooter() && !m_doc->isFooterVisible() )
00996         return false;
00997     if ( viewMode && !viewMode->isFrameSetVisible(this) )
00998         return false;
00999     if ( isFloating() && !anchorFrameset()->isVisible( viewMode ) )
01000          return false;
01001 
01002     KoHFType ht = m_doc != 0 ? m_doc->headerType(): HF_FIRST_DIFF;
01003     KoHFType ft = m_doc != 0 ? m_doc->footerType(): HF_FIRST_DIFF;
01004     switch( m_info )
01005     {
01006     case FI_FIRST_HEADER:
01007         return ( ht == HF_FIRST_DIFF || ht == HF_FIRST_EO_DIFF );
01008     case FI_ODD_HEADER:
01009         return true;
01010     case FI_EVEN_HEADER:
01011         return ( ht == HF_EO_DIFF || ht == HF_FIRST_EO_DIFF );
01012     case FI_FIRST_FOOTER:
01013         return ( ft == HF_FIRST_DIFF || ft == HF_FIRST_EO_DIFF );
01014     case FI_ODD_FOOTER:
01015         return true;
01016     case FI_EVEN_FOOTER:
01017         return ( ft == HF_EO_DIFF || ft == HF_FIRST_EO_DIFF );
01018     default:
01019         return true;
01020     }
01021 }
01022 
01023 bool KWFrameSet::isAHeader() const
01024 {
01025     return ( m_info == FI_FIRST_HEADER || m_info == FI_ODD_HEADER || m_info == FI_EVEN_HEADER );
01026 }
01027 
01028 bool KWFrameSet::isAFooter() const
01029 {
01030     return ( m_info == FI_FIRST_FOOTER || m_info == FI_ODD_FOOTER || m_info == FI_EVEN_FOOTER );
01031 }
01032 
01033 bool KWFrameSet::isFootEndNote() const
01034 {
01035     return m_info == FI_FOOTNOTE;
01036 }
01037 
01038 bool KWFrameSet::isMainFrameset() const
01039 {
01040     return ( m_doc && m_doc->processingType() == KWDocument::WP &&
01041              m_doc->frameSet( 0 ) == this );
01042 }
01043 
01044 bool KWFrameSet::isMoveable() const
01045 {
01046     if ( isHeaderOrFooter() )
01047         return false;
01048     return !isMainFrameset() && !isFloating();
01049 }
01050 
01051 const char* KWFrameSet::headerFooterTag() const
01052 {
01053     switch ( m_info ) {
01054     case KWFrameSet::FI_ODD_HEADER:
01055         return "style:header";
01056     case KWFrameSet::FI_EVEN_HEADER:
01057         return "style:header-left";
01058     case KWFrameSet::FI_ODD_FOOTER:
01059         return "style:footer";
01060     case KWFrameSet::FI_EVEN_FOOTER:
01061         return "style:footer-left";
01062     case KWFrameSet::FI_FIRST_HEADER:
01063         return "style:header-first"; // NOT OASIS COMPLIANT
01064     case KWFrameSet::FI_FIRST_FOOTER:
01065         return "style:footer-first"; // NOT OASIS COMPLIANT
01066     default: // shouldn't be called for body or footnote
01067         return 0;
01068     }
01069 }
01070 
01071 void KWFrameSet::finalize()
01072 {
01073     //kdDebug(32001) << "KWFrameSet::finalize ( calls updateFrames + zoom ) " << this << endl;
01074     updateFrames();
01075 }
01076 
01077 QRegion KWFrameSet::frameClipRegion( QPainter * painter, KWFrame *frame, const QRect & crect,
01078                                      KWViewMode * viewMode )
01079 {
01080 //    KWDocument * doc = kWordDocument();
01081     QRect rc = painter->xForm( crect );
01082 #ifdef DEBUG_DRAW
01083     //kdDebug(32002) << "KWFrameSet::frameClipRegion rc initially " << rc << endl;
01084 #endif
01085 
01086     Q_ASSERT( frame );
01087 #if 0 // done later
01088     if ( clipFrame )
01089     {
01090         rc &= painter->xForm( viewMode->normalToView( doc->zoomRect( (*frame) ) ) ); // intersect
01091 #ifdef DEBUG_DRAW
01092         kdDebug(32002) << "KWFrameSet::frameClipRegion frame=" << *frame
01093                        << " clip region rect=" << rc
01094                        << " rc.isEmpty()=" << rc.isEmpty() << endl;
01095 #endif
01096     }
01097 #endif
01098     if ( !rc.isEmpty() )
01099     {
01100         QRegion reg( rc );
01101         // This breaks when a frame is under another one, it still appears if !onlyChanged.
01102         // cvs log says this is about frame borders... hmm.
01104 
01105         Q_ASSERT( frame->frameStack() );
01106 
01107         QValueList<KWFrame *> onTop = frame->frameStack()->framesOnTop();
01108         for (QValueListIterator<KWFrame*> fIt = onTop.begin(); fIt != onTop.end(); ++fIt )
01109         {
01110             KWFrame* frameOnTop = (*fIt);
01111             Q_ASSERT( frameOnTop->frameSet() );
01112             QRect r = painter->xForm( viewMode->normalToView( frameOnTop->outerRect( viewMode ) ) );
01113 #ifdef DEBUG_DRAW
01114             //kdDebug(32002) << "frameClipRegion subtract rect "<< r << endl;
01115 #endif
01116             reg -= r; // subtract
01117         }
01118 #ifdef DEBUG_DRAW
01119         //kdDebug(32002) << "KWFrameSet::frameClipRegion result:" << reg << endl;
01120 #endif
01121         return reg;
01122     }
01123     return QRegion();
01124 }
01125 
01126 bool KWFrameSet::canRemovePage( int num )
01127 {
01128     QPtrListIterator<KWFrame> frameIt( frameIterator() );
01129     for ( ; frameIt.current(); ++frameIt )
01130     {
01131         KWFrame * frame = frameIt.current();
01132         if ( frame->pageNumber() == num ) // ## TODO: use framesInPage, see KWTextFrameSet
01133         {
01134             // Ok, so we have a frame on that page -> we can't remove it unless it's a copied frame
01135             if ( ! ( frame->isCopy() && frameIt.current() != m_frames.first() ) )
01136             {
01137                 kdDebug(32001) << "KWFrameSet::canRemovePage " << name() << " frame on page " << num << " -> false" << endl;
01138                 return false;
01139             }
01140         }
01141     }
01142     return true;
01143 }
01144 
01145 void KWFrameSet::setFrameBehavior( KWFrame::FrameBehavior fb ) {
01146     for(KWFrame *f=m_frames.first();f;f=m_frames.next())
01147         f->setFrameBehavior(fb);
01148 }
01149 
01150 void KWFrameSet::setNewFrameBehavior( KWFrame::NewFrameBehavior nfb ) {
01151     for(KWFrame *f=m_frames.first();f;f=m_frames.next())
01152         f->setNewFrameBehavior(nfb);
01153 }
01154 
01155 // ## this should pass the viewmode as argument, probably.
01156 bool KWFrameSet::isFrameAtPos( const KWFrame* frame, const QPoint& point, bool borderOfFrameOnly) const {
01157     QRect outerRect( frame->outerRect( m_doc->layoutViewMode() ) );
01158     // Give the user a bit of margin for clicking on it :)
01159     const int margin = 2;
01160     outerRect.rLeft() -= margin;
01161     outerRect.rTop() -= margin;
01162     outerRect.rRight() += margin;
01163     outerRect.rBottom() += margin;
01164     if ( outerRect.contains( point ) ) {
01165         if(borderOfFrameOnly) {
01166             QRect innerRect( m_doc->zoomRect( *frame ) );
01167             innerRect.rLeft() += margin;
01168             innerRect.rTop() += margin;
01169             innerRect.rRight() -= margin;
01170             innerRect.rBottom() -= margin;
01171             return (!innerRect.contains(point) );
01172         }
01173         return true;
01174     }
01175     return false;
01176 }
01177 
01178 void KWFrameSet::setZOrder()
01179 {
01180     //kdDebug(32001) << "KWFrameSet::setZOrder (to max) " << name() << endl;
01181     QPtrListIterator<KWFrame> fit = frameIterator();
01182     for ( ; fit.current() ; ++fit )
01183         fit.current()->setZOrder( m_doc->maxZOrder( fit.current()->pageNumber(m_doc) ) + 1 );
01184 }
01185 
01186 void KWFrameSet::setName( const QString &name )
01187 {
01188     m_name = name;
01189     emit sigNameChanged(this);
01190 }
01191 
01192 #ifndef NDEBUG
01193 #include "KWFrameViewManager.h"
01194 #include "KWFrameView.h"
01195 void KWFrameSet::printDebug()
01196 {
01197     static const char * typeFrameset[] = { "base", "txt", "picture", "part", "formula", "clipart",
01198                                            "6", "7", "8", "9", "table",
01199                                            "ERROR" };
01200     static const char * infoFrameset[] = { "body", "first header", "even headers", "odd headers",
01201                                            "first footer", "even footers", "odd footers", "footnote", "ERROR" };
01202     static const char * frameBh[] = { "AutoExtendFrame", "AutoCreateNewFrame", "Ignore", "ERROR" };
01203     static const char * newFrameBh[] = { "Reconnect", "NoFollowup", "Copy" };
01204     static const char * runaround[] = { "No Runaround", "Bounding Rect", "Skip", "ERROR" };
01205     static const char * runaroundSide[] = { "Biggest", "Left", "Right", "ERROR" };
01206 
01207     KWFrameViewManager *fvm = 0;
01208     if ( !m_doc->getAllViews().isEmpty() ) {
01209         KWView *view = m_doc->getAllViews().first();
01210         if(view)
01211             fvm = view->frameViewManager();
01212     }
01213 
01214     kdDebug() << " |  Visible: " << isVisible() << endl;
01215     kdDebug() << " |  Type: " << typeFrameset[ type() ] << endl;
01216     kdDebug() << " |  Info: " << infoFrameset[ frameSetInfo() ] << endl;
01217     kdDebug() << " |  Floating: " << isFloating() << endl;
01218     kdDebug() << " |  Frames in page array: " << endl;
01219     for ( uint i = 0 ; i < m_framesInPage.size() ; ++i )
01220     {
01221         QPtrListIterator<KWFrame> it( *m_framesInPage[i] );
01222         int pgNum = i + m_firstPage;
01223         for ( ; it.current() ; ++it )
01224             kdDebug() << " |     " << pgNum << ": " << it.current() << "   " << *it.current()
01225                       << " internalY=" << it.current()->internalY() << "pt "
01226                       << " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->internalY() ) << ")"
01227                       << " innerHeight=" << it.current()->innerHeight()
01228                       << " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->innerHeight() ) << ")"
01229                       << endl;
01230     }
01231 
01232     QPtrListIterator<KWFrame> frameIt = frameIterator();
01233     for ( unsigned int j = 0; frameIt.current(); ++frameIt, ++j ) {
01234         KWFrame * frame = frameIt.current();
01235         QCString copy = frame->isCopy() ? "[copy]" : "";
01236         kdDebug() << " +-- Frame " << j << " of "<< frameCount() << "    (" << frame << ")  " << copy << endl;
01237         printDebug( frame );
01238         kdDebug() << "     Rectangle : " << frame->x() << "," << frame->y() << " " << frame->width() << "x" << frame->height() << endl;
01239         kdDebug() << "     RunAround: "<< runaround[ frame->runAround() ] << " side:" << runaroundSide[ frame->runAroundSide() ]<< endl;
01240         kdDebug() << "     FrameBehavior: "<< frameBh[ frame->frameBehavior() ] << endl;
01241         kdDebug() << "     NewFrameBehavior: "<< newFrameBh[ frame->newFrameBehavior() ] << endl;
01242         QColor col = frame->backgroundColor().color();
01243         kdDebug() << "     BackgroundColor: "<< ( col.isValid() ? col.name().latin1() : "(default)" ) << endl;
01244         kdDebug() << "     SheetSide "<< frame->sheetSide() << endl;
01245         kdDebug() << "     Z Order: " << frame->zOrder() << endl;
01246 
01247         if( frame->frameStack() ) {
01248             QValueList<KWFrame*> onTop = frame->frameStack()->framesOnTop();
01249             QValueList<KWFrame*> below = frame->frameStack()->framesBelow();
01250 
01251             kdDebug() << "     Frames below: " << below.count()
01252                       << ", frames on top: " << onTop.count() << endl;
01253         }
01254         else
01255             kdDebug() << "     no frameStack set." << endl;
01256         kdDebug() << "     minFrameHeight "<< frame->minimumFrameHeight() << endl;
01257         QString page = pageManager() && pageManager()->pageCount() > 0 ? QString::number(frame->pageNumber()) : " [waiting for pages to be created]";
01258 
01259         KWFrameView *fv = 0;
01260         if(fvm) fv = fvm->view(frame);
01261         if(fv && fv->selected())
01262             kdDebug() << " *   Page "<< page << endl;
01263         else
01264             kdDebug() << "     Page "<< page << endl;
01265     }
01266 }
01267 
01268 void KWFrameSet::printDebug( KWFrame * )
01269 {
01270 }
01271 
01272 #endif
01273 
01274 #include "KWFrameSet.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys