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                 KWFrameView* view = frameViewManager->view(frame);
00663                 if(view)
00664                     view->paintFrameAttributes(p, crect, viewMode, m_doc);
00665             }
00666 
00667             if ( !lastRealFrame || !frame->isCopy() )
00668             {
00669                 lastRealFrame = frame;
00670                 //lastRealFrameTop = totalHeight;
00671             }
00672             //totalHeight += frame->innerHeight();
00673         }
00674     }
00675     else { // Text view mode
00676         QRect normalRect = viewMode->viewToNormal(crect);
00677         drawFrame( 0L /*frame*/, p, normalRect, crect, QPoint(KWViewModeText::OFFSET, 0),
00678                    0L /*settingsFrame*/, cg, onlyChanged, resetChanged, edit, viewMode, true );
00679     }
00680 }
00681 
00682 void KWFrameSet::drawFrameAndBorders( KWFrame *frame,
00683                                       QPainter *painter, const QRect &crect,
00684                                       const QColorGroup &cg, bool onlyChanged, bool resetChanged,
00685                                       KWFrameSetEdit *edit, KWViewMode *viewMode,
00686                                       KWFrame *settingsFrame, bool drawUnderlyingFrames )
00687 {
00688     if ( !frame->isValid() )
00689     {
00690         kdDebug(32002) << "KWFrameSet::drawFrameAndBorders " << name() << " frame " << frameFromPtr( frame ) << " " << frame << " isn't valid" << endl;
00691         return;
00692     }
00693 
00694     QRect normalOuterFrameRect( frame->outerRect( viewMode ) );
00695     QRect outerFrameRect( viewMode->normalToView( normalOuterFrameRect ) );
00696     QRect outerCRect = crect.intersect( outerFrameRect );
00697 #ifdef DEBUG_DRAW
00698     kdDebug(32001) << "KWFrameSet::drawFrameAndBorders " << name() << " frame " << frameFromPtr( frame ) << " " << *frame << endl;
00699     kdDebug(32001) << "                    (outer) normalFrameRect=" << normalOuterFrameRect << " frameRect=" << outerFrameRect << endl;
00700     kdDebug(32001) << "                    crect=" << crect << " intersec=" << outerCRect << " todraw=" << !outerCRect.isEmpty() << endl;
00701 #endif
00702     if ( !outerCRect.isEmpty() )
00703     {
00704         // Determine settingsFrame if not passed (for speedup)
00705         if ( !settingsFrame )
00706             settingsFrame = this->settingsFrame( frame );
00707 
00708         QRect normalInnerFrameRect( m_doc->zoomRect( frame->innerRect() ) );
00709         QRect innerFrameRect( viewMode->normalToView( normalInnerFrameRect ) );
00710 
00711         // This translates the coordinates in the document contents
00712         // ( frame and r are up to here in this system )
00713         // into the frame's own coordinate system.
00714         int offsetX = normalInnerFrameRect.left();
00715         int offsetY = normalInnerFrameRect.top() - m_doc->zoomItY( frame->internalY() );
00716 
00717         QRect innerCRect = outerCRect.intersect( innerFrameRect );
00718         if ( !innerCRect.isEmpty() )
00719         {
00720             QRect fcrect = viewMode->viewToNormal( innerCRect );
00721 #ifdef DEBUG_DRAW
00722             kdDebug(32001) << "                    (inner) normalFrameRect=" << normalInnerFrameRect << " frameRect=" << innerFrameRect << endl;
00723             //kdDebug(32001) << "                    crect after view-to-normal:" << fcrect << "." << " Will move by (" << -offsetX << ", -(" << normalInnerFrameRect.top() << "-" << m_doc->zoomItY(frame->internalY()) << ") == " << -offsetY << ")." << endl;
00724 #endif
00725             fcrect.moveBy( -offsetX, -offsetY );
00726             Q_ASSERT( fcrect.x() >= 0 );
00727             Q_ASSERT( fcrect.y() >= 0 );
00728 
00729             // fcrect is now the portion of the frame to be drawn,
00730             // in the frame's coordinates and in pixels
00731 #ifdef DEBUG_DRAW
00732             kdDebug(32001) << "KWFrameSet::drawFrameAndBorders in frame coords:" << fcrect << ". Will translate painter by intersec-fcrect: " << innerCRect.x()-fcrect.x() << "," << innerCRect.y()-fcrect.y() << "." << endl;
00733 #endif
00734             QRegion reg;
00735             if ( drawUnderlyingFrames )
00736                 reg = frameClipRegion( painter, frame, outerCRect, viewMode );
00737             else // false means we are being drawn _as_ an underlying frame, so no clipping!
00738                 reg = painter->xForm( outerCRect );
00739             if ( !reg.isEmpty() )
00740             {
00741                 painter->save();
00742                 painter->setClipRegion( reg );
00743 
00744                 drawFrame( frame, painter, fcrect, outerCRect,
00745                            innerCRect.topLeft() - fcrect.topLeft(), // This assume that viewToNormal() is only a translation
00746                            settingsFrame, cg, onlyChanged, resetChanged,
00747                            edit, viewMode, drawUnderlyingFrames );
00748 
00749                 if( !groupmanager() ) // not for table cells
00750                     drawFrameBorder( painter, frame, settingsFrame, outerCRect, viewMode );
00751                 painter->restore();
00752             }
00753         }
00754     }
00755 }
00756 
00757 void KWFrameSet::drawFrame( KWFrame *frame, QPainter *painter, const QRect &fcrect, const QRect &outerCRect,
00758                             const QPoint& translationOffset,
00759                             KWFrame *settingsFrame, const QColorGroup &cg, bool onlyChanged, bool resetChanged,
00760                             KWFrameSetEdit *edit, KWViewMode* viewMode, bool drawUnderlyingFrames )
00761 {
00762     // In this method the painter is NOT translated yet. It's still in view coordinates.
00763     if ( outerCRect.isEmpty() )
00764         return;
00765 #ifdef DEBUG_DRAW
00766     kdDebug(32001) << "\nKWFrameSet::drawFrame " << name() << " outerCRect=" << outerCRect << " frameCrect=" << fcrect << " drawUnderlyingFrames=" << drawUnderlyingFrames << endl;
00767 #endif
00768     Q_ASSERT( fcrect.isValid() );
00769 
00770     QColorGroup frameColorGroup( cg );
00771     if ( settingsFrame ) // 0L in text viewmode
00772     {
00773         QBrush bgBrush( settingsFrame->backgroundColor() );
00774         bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), painter ) );
00775         frameColorGroup.setBrush( QColorGroup::Base, bgBrush );
00776     }
00777 
00778     if ( drawUnderlyingFrames && frame && frame->frameStack()) {
00779         QValueList<KWFrame*> below = frame->frameStack()->framesBelow();
00780         if ( !below.isEmpty() )
00781         {
00782             // Double-buffering - not when printing
00783             QPainter* doubleBufPainter = painter;
00784             QPixmap* pix = 0L;
00785             if ( painter->device()->devType() != QInternal::Printer )
00786             {
00787                 pix = m_doc->doubleBufferPixmap( outerCRect.size() );
00788                 doubleBufPainter = new QPainter;
00789                 doubleBufPainter->begin( pix );
00790                 // Initialize the pixmap to the page background color
00791                 // (if the frame is over the page margins, no underlying frame will paint anything there)
00792                 doubleBufPainter->fillRect( 0, 0, outerCRect.width(), outerCRect.height(), QApplication::palette().active().brush( QColorGroup::Base ) );
00793 
00794                 // The double-buffer pixmap has (0,0) at outerCRect.topLeft(), so we need to
00795                 // translate the double-buffer painter; drawFrameAndBorders will draw using view coordinates.
00796                 doubleBufPainter->translate( -outerCRect.x(), -outerCRect.y() );
00797 #ifdef DEBUG_DRAW
00798     //            kdDebug(32001) << "  ... using double buffering. Portion covered: " << outerCRect << endl;
00799 #endif
00800             }
00801 
00802             // Transparency handling
00803 #ifdef DEBUG_DRAW
00804             kdDebug(32001) << "  below: " << below.count() << endl;
00805 #endif
00806             for (QValueListIterator<KWFrame*> it = below.begin(); it != below.end(); ++it )
00807             {
00808                 KWFrame* f = (*it);
00809 
00810 #ifdef DEBUG_DRAW
00811                 kdDebug(32001) << "  looking at frame below us: " << f->frameSet()->name() << " frame " << frameFromPtr( frame ) << endl;
00812 #endif
00813                 QRect viewFrameCRect = outerCRect.intersect( viewMode->normalToView( f->outerRect( viewMode ) ) );
00814                 if ( !viewFrameCRect.isEmpty() )
00815                 {
00816 #ifdef DEBUG_DRAW
00817                     kdDebug(32001) << "  viewFrameRect=" << viewFrameCRect << " calling drawFrameAndBorders." << endl;
00818 #endif
00819                     f->frameSet()->drawFrameAndBorders( f, doubleBufPainter, viewFrameCRect, cg,
00820                             false, resetChanged, edit, viewMode, 0L, false );
00821                 }
00822             }
00823 
00824             if ( frame->paddingLeft() || frame->paddingTop() || frame->paddingRight() || frame->paddingBottom() )
00825                 drawPadding( frame, doubleBufPainter, outerCRect, cg, viewMode );
00826             doubleBufPainter->save();
00827 #ifdef DEBUG_DRAW
00828             kdDebug(32001) << "  translating by " << translationOffset.x() << ", " << translationOffset.y() << " before drawFrameContents" << endl;
00829 #endif
00830             doubleBufPainter->translate( translationOffset.x(), translationOffset.y() ); // This assume that viewToNormal() is only a translation
00831             // We can't "repaint changed parags only" if we just drew the underlying frames, hence the "false"
00832             drawFrameContents( frame, doubleBufPainter, fcrect, frameColorGroup, false, resetChanged, edit, viewMode );
00833             doubleBufPainter->restore();
00834 
00835             if ( painter->device()->devType() != QInternal::Printer )
00836             {
00837                 doubleBufPainter->end();
00838 #ifdef DEBUG_DRAW
00839                 kdDebug(32001) << "  painting double-buf pixmap at position " << outerCRect.topLeft() << " (real painter pos:" << painter->xForm( outerCRect.topLeft() ) << ")" << endl;
00840 #endif
00841                 painter->drawPixmap( outerCRect.topLeft(), *pix );
00842                 delete doubleBufPainter;
00843             }
00844             return; // done! :)
00845         }
00846         else
00847         {
00848             // nothing below? paint a bg color then
00849             frameColorGroup.setBrush( QColorGroup::Base, m_doc->defaultBgColor( painter ) );
00850         }
00851     }
00852     if ( frame && (frame->paddingLeft() || frame->paddingTop() ||
00853                 frame->paddingRight() || frame->paddingBottom()) )
00854         drawPadding( frame, painter, outerCRect, cg, viewMode );
00855     painter->save();
00856     painter->translate( translationOffset.x(), translationOffset.y() );
00857 
00858     drawFrameContents( frame, painter, fcrect, frameColorGroup, onlyChanged, resetChanged, edit, viewMode );
00859     painter->restore();
00860 }
00861 
00862 void KWFrameSet::drawFrameContents( KWFrame *, QPainter *, const QRect &,
00863                                     const QColorGroup &, bool, bool, KWFrameSetEdit*, KWViewMode * )
00864 {
00865     kdWarning() << "Default implementation of drawFrameContents called for " << className() << " " << this << " " << name() << kdBacktrace();
00866 }
00867 
00868 void KWFrameSet::saveCommon( QDomElement &parentElem, bool saveFrames )
00869 {
00870     if ( m_frames.isEmpty() ) // Deleted frameset -> don't save
00871         return;
00872 
00873     // Save all the common attributes for framesets.
00874     parentElem.setAttribute( "frameType", static_cast<int>( type() ) );
00875     parentElem.setAttribute( "frameInfo", static_cast<int>( m_info ) );
00876     parentElem.setAttribute( "name", m_name );
00877     parentElem.setAttribute( "visible", static_cast<int>( m_visible ) );
00878     parentElem.setAttribute( "protectSize", static_cast<int>( m_protectSize ) );
00879     if ( saveFrames )
00880     {
00881         QPtrListIterator<KWFrame> frameIt = frameIterator();
00882         for ( ; frameIt.current(); ++frameIt )
00883         {
00884             KWFrame *frame = frameIt.current();
00885             QDomElement frameElem = parentElem.ownerDocument().createElement( "FRAME" );
00886             parentElem.appendChild( frameElem );
00887 
00888             frame->save( frameElem );
00889 
00890             if(m_doc->processingType() == KWDocument::WP) {
00891                 // Assume that all header/footer frames in the same frameset are
00892                 // perfect copies. This might not be the case some day though.
00893                 if(frameSetInfo() == FI_FIRST_HEADER ||
00894                    frameSetInfo() == FI_EVEN_HEADER ||
00895                    frameSetInfo() == FI_ODD_HEADER ||
00896                    frameSetInfo() == FI_FIRST_FOOTER ||
00897                    frameSetInfo() == FI_EVEN_FOOTER ||
00898                    frameSetInfo() == FI_ODD_FOOTER ||
00899                    frameSetInfo() == FI_FOOTNOTE) break;
00900             }
00901         }
00902     }
00903 }
00904 
00905 //
00906 // This function is intended as a helper for all the derived classes. It reads
00907 // in all the attributes common to all framesets and loads all frames.
00908 //
00909 void KWFrameSet::load( QDomElement &framesetElem, bool loadFrames )
00910 {
00911     m_info = static_cast<KWFrameSet::Info>( KWDocument::getAttribute( framesetElem, "frameInfo", KWFrameSet::FI_BODY ) );
00912     m_visible = static_cast<bool>( KWDocument::getAttribute( framesetElem, "visible", true ) );
00913     m_protectSize=static_cast<bool>( KWDocument::getAttribute( framesetElem, "protectSize", false ) );
00914     if ( loadFrames )
00915     {
00916         // <FRAME>
00917         QDomElement frameElem = framesetElem.firstChild().toElement();
00918         for ( ; !frameElem.isNull() ; frameElem = frameElem.nextSibling().toElement() )
00919         {
00920             if ( frameElem.tagName() == "FRAME" )
00921             {
00922                 KoRect rect;
00923                 rect.setLeft( KWDocument::getAttribute( frameElem, "left", 0.0 ) );
00924                 rect.setTop( KWDocument::getAttribute( frameElem, "top", 0.0 ) );
00925                 rect.setRight( KWDocument::getAttribute( frameElem, "right", 0.0 ) );
00926                 rect.setBottom( KWDocument::getAttribute( frameElem, "bottom", 0.0 ) );
00927                 KWFrame * frame = new KWFrame(this, rect.x(), rect.y(), rect.width(), rect.height() );
00928                 frame->load( frameElem, this, m_doc->syntaxVersion() );
00929                 addFrame( frame, false );
00930                 m_doc->progressItemLoaded();
00931             }
00932         }
00933     }
00934 }
00935 
00936 KWFrame* KWFrameSet::loadOasisFrame( const QDomElement& tag, KoOasisContext& context )
00937 {
00938     double width = 100;
00939     if ( tag.hasAttributeNS( KoXmlNS::svg, "width" ) ) { // fixed width
00940         // TODO handle percentage (of enclosing table/frame/page)
00941         width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "width", QString::null ) );
00942     } else if ( tag.hasAttributeNS( KoXmlNS::fo, "min-width" ) ) {
00943         // min-width is not supported in KWord. Let's use it as a fixed width.
00944         width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::fo, "min-width", QString::null ) );
00945     } else {
00946         kdWarning(32001) << "Error in frame " << tag.tagName() << " " << tag.attributeNS( KoXmlNS::draw, "name", QString::null ) << " : neither width nor min-width specified!" << endl;
00947     }
00948     double height = 100;
00949     if ( tag.hasAttributeNS( KoXmlNS::svg, "height" ) ) { // fixed height
00950         // TODO handle percentage (of enclosing table/frame/page)
00951         height = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "height", QString::null ) );
00952     }
00953     //kdDebug(32001) << k_funcinfo << "width=" << width << " height=" << height << " pt" << endl;
00954 
00955     KWFrame * frame = new KWFrame(this,
00956                                   KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "x", QString::null ) ),
00957                                   KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "y", QString::null ) ),
00958                                   width, height );
00959 
00960     frame->setZOrder( tag.attributeNS( KoXmlNS::draw, "z-index", QString::null ).toInt() );
00961     // Copy-frames.
00962     // We currently ignore the value of the copy-of attribute. It probably needs to
00963     // be handled like chain-next-name (kwtextframeset.cc) but for all types of frameset.
00964     frame->setCopy( tag.hasAttributeNS( KoXmlNS::draw, "copy-of" ) );
00965     frame->loadCommonOasisProperties( context, this, "graphic" );
00966 
00967     addFrame( frame, false );
00968 
00969     // Protect (OASIS 14.27.7, also in OO-1.1)
00970     // A frame with protected contents means that the frameset is protected (makes sense)
00971     // A frame with protected size means that the frameset is size-protected (hmm, kword did it that way)
00972     // TODO implement position protection
00973     QString protectList = context.styleStack().attributeNS( KoXmlNS::style, "protect" );
00974     if ( protectList.contains( "content" ) )
00975         setProtectContent( true );
00976     if ( protectList.contains( "size" ) )
00977         m_protectSize = true;
00978 
00979     // TODO m_visible ? User-toggeable or internal?
00980 
00981     return frame;
00982 }
00983 
00984 void KWFrameSet::setVisible( bool v )
00985 {
00986     m_visible = v;
00987     if ( m_visible )
00988         // updateFrames was disabled while we were invisible
00989         updateFrames();
00990 }
00991 
00992 bool KWFrameSet::isVisible( KWViewMode* viewMode ) const
00993 {
00994     if ( !m_visible || m_frames.isEmpty() )
00995         return false;
00996     if ( isAHeader() && !m_doc->isHeaderVisible() )
00997         return false;
00998     if ( isAFooter() && !m_doc->isFooterVisible() )
00999         return false;
01000     if ( viewMode && !viewMode->isFrameSetVisible(this) )
01001         return false;
01002     if ( isFloating() && !anchorFrameset()->isVisible( viewMode ) )
01003          return false;
01004 
01005     KoHFType ht = m_doc != 0 ? m_doc->headerType(): HF_FIRST_DIFF;
01006     KoHFType ft = m_doc != 0 ? m_doc->footerType(): HF_FIRST_DIFF;
01007     switch( m_info )
01008     {
01009     case FI_FIRST_HEADER:
01010         return ( ht == HF_FIRST_DIFF || ht == HF_FIRST_EO_DIFF );
01011     case FI_ODD_HEADER:
01012         return true;
01013     case FI_EVEN_HEADER:
01014         return ( ht == HF_EO_DIFF || ht == HF_FIRST_EO_DIFF );
01015     case FI_FIRST_FOOTER:
01016         return ( ft == HF_FIRST_DIFF || ft == HF_FIRST_EO_DIFF );
01017     case FI_ODD_FOOTER:
01018         return true;
01019     case FI_EVEN_FOOTER:
01020         return ( ft == HF_EO_DIFF || ft == HF_FIRST_EO_DIFF );
01021     default:
01022         return true;
01023     }
01024 }
01025 
01026 bool KWFrameSet::isAHeader() const
01027 {
01028     return ( m_info == FI_FIRST_HEADER || m_info == FI_ODD_HEADER || m_info == FI_EVEN_HEADER );
01029 }
01030 
01031 bool KWFrameSet::isAFooter() const
01032 {
01033     return ( m_info == FI_FIRST_FOOTER || m_info == FI_ODD_FOOTER || m_info == FI_EVEN_FOOTER );
01034 }
01035 
01036 bool KWFrameSet::isFootEndNote() const
01037 {
01038     return m_info == FI_FOOTNOTE;
01039 }
01040 
01041 bool KWFrameSet::isMainFrameset() const
01042 {
01043     return ( m_doc && m_doc->processingType() == KWDocument::WP &&
01044              m_doc->frameSet( 0 ) == this );
01045 }
01046 
01047 bool KWFrameSet::isMoveable() const
01048 {
01049     if ( isHeaderOrFooter() )
01050         return false;
01051     return !isMainFrameset() && !isFloating();
01052 }
01053 
01054 const char* KWFrameSet::headerFooterTag() const
01055 {
01056     switch ( m_info ) {
01057     case KWFrameSet::FI_ODD_HEADER:
01058         return "style:header";
01059     case KWFrameSet::FI_EVEN_HEADER:
01060         return "style:header-left";
01061     case KWFrameSet::FI_ODD_FOOTER:
01062         return "style:footer";
01063     case KWFrameSet::FI_EVEN_FOOTER:
01064         return "style:footer-left";
01065     case KWFrameSet::FI_FIRST_HEADER:
01066         return "style:header-first"; // NOT OASIS COMPLIANT
01067     case KWFrameSet::FI_FIRST_FOOTER:
01068         return "style:footer-first"; // NOT OASIS COMPLIANT
01069     default: // shouldn't be called for body or footnote
01070         return 0;
01071     }
01072 }
01073 
01074 void KWFrameSet::finalize()
01075 {
01076     //kdDebug(32001) << "KWFrameSet::finalize ( calls updateFrames + zoom ) " << this << endl;
01077     updateFrames();
01078 }
01079 
01080 QRegion KWFrameSet::frameClipRegion( QPainter * painter, KWFrame *frame, const QRect & crect,
01081                                      KWViewMode * viewMode )
01082 {
01083 //    KWDocument * doc = kWordDocument();
01084     QRect rc = painter->xForm( crect );
01085 #ifdef DEBUG_DRAW
01086     //kdDebug(32002) << "KWFrameSet::frameClipRegion rc initially " << rc << endl;
01087 #endif
01088 
01089     Q_ASSERT( frame );
01090 #if 0 // done later
01091     if ( clipFrame )
01092     {
01093         rc &= painter->xForm( viewMode->normalToView( doc->zoomRect( (*frame) ) ) ); // intersect
01094 #ifdef DEBUG_DRAW
01095         kdDebug(32002) << "KWFrameSet::frameClipRegion frame=" << *frame
01096                        << " clip region rect=" << rc
01097                        << " rc.isEmpty()=" << rc.isEmpty() << endl;
01098 #endif
01099     }
01100 #endif
01101     if ( !rc.isEmpty() )
01102     {
01103         QRegion reg( rc );
01104         // This breaks when a frame is under another one, it still appears if !onlyChanged.
01105         // cvs log says this is about frame borders... hmm.
01107 
01108         Q_ASSERT( frame->frameStack() );
01109 
01110         QValueList<KWFrame *> onTop = frame->frameStack()->framesOnTop();
01111         for (QValueListIterator<KWFrame*> fIt = onTop.begin(); fIt != onTop.end(); ++fIt )
01112         {
01113             KWFrame* frameOnTop = (*fIt);
01114             Q_ASSERT( frameOnTop->frameSet() );
01115             QRect r = painter->xForm( viewMode->normalToView( frameOnTop->outerRect( viewMode ) ) );
01116 #ifdef DEBUG_DRAW
01117             //kdDebug(32002) << "frameClipRegion subtract rect "<< r << endl;
01118 #endif
01119             reg -= r; // subtract
01120         }
01121 #ifdef DEBUG_DRAW
01122         //kdDebug(32002) << "KWFrameSet::frameClipRegion result:" << reg << endl;
01123 #endif
01124         return reg;
01125     }
01126     return QRegion();
01127 }
01128 
01129 bool KWFrameSet::canRemovePage( int num )
01130 {
01131     QPtrListIterator<KWFrame> frameIt( frameIterator() );
01132     for ( ; frameIt.current(); ++frameIt )
01133     {
01134         KWFrame * frame = frameIt.current();
01135         if ( frame->pageNumber() == num ) // ## TODO: use framesInPage, see KWTextFrameSet
01136         {
01137             // Ok, so we have a frame on that page -> we can't remove it unless it's a copied frame
01138             if ( ! ( frame->isCopy() && frameIt.current() != m_frames.first() ) )
01139             {
01140                 kdDebug(32001) << "KWFrameSet::canRemovePage " << name() << " frame on page " << num << " -> false" << endl;
01141                 return false;
01142             }
01143         }
01144     }
01145     return true;
01146 }
01147 
01148 void KWFrameSet::setFrameBehavior( KWFrame::FrameBehavior fb ) {
01149     for(KWFrame *f=m_frames.first();f;f=m_frames.next())
01150         f->setFrameBehavior(fb);
01151 }
01152 
01153 void KWFrameSet::setNewFrameBehavior( KWFrame::NewFrameBehavior nfb ) {
01154     for(KWFrame *f=m_frames.first();f;f=m_frames.next())
01155         f->setNewFrameBehavior(nfb);
01156 }
01157 
01158 // ## this should pass the viewmode as argument, probably.
01159 bool KWFrameSet::isFrameAtPos( const KWFrame* frame, const QPoint& point, bool borderOfFrameOnly) const {
01160     QRect outerRect( frame->outerRect( m_doc->layoutViewMode() ) );
01161     // Give the user a bit of margin for clicking on it :)
01162     const int margin = 2;
01163     outerRect.rLeft() -= margin;
01164     outerRect.rTop() -= margin;
01165     outerRect.rRight() += margin;
01166     outerRect.rBottom() += margin;
01167     if ( outerRect.contains( point ) ) {
01168         if(borderOfFrameOnly) {
01169             QRect innerRect( m_doc->zoomRect( *frame ) );
01170             innerRect.rLeft() += margin;
01171             innerRect.rTop() += margin;
01172             innerRect.rRight() -= margin;
01173             innerRect.rBottom() -= margin;
01174             return (!innerRect.contains(point) );
01175         }
01176         return true;
01177     }
01178     return false;
01179 }
01180 
01181 void KWFrameSet::setZOrder()
01182 {
01183     //kdDebug(32001) << "KWFrameSet::setZOrder (to max) " << name() << endl;
01184     QPtrListIterator<KWFrame> fit = frameIterator();
01185     for ( ; fit.current() ; ++fit )
01186         fit.current()->setZOrder( m_doc->maxZOrder( fit.current()->pageNumber(m_doc) ) + 1 );
01187 }
01188 
01189 void KWFrameSet::setName( const QString &name )
01190 {
01191     m_name = name;
01192     emit sigNameChanged(this);
01193 }
01194 
01195 #ifndef NDEBUG
01196 #include "KWFrameViewManager.h"
01197 #include "KWFrameView.h"
01198 void KWFrameSet::printDebug()
01199 {
01200     static const char * typeFrameset[] = { "base", "txt", "picture", "part", "formula", "clipart",
01201                                            "6", "7", "8", "9", "table",
01202                                            "ERROR" };
01203     static const char * infoFrameset[] = { "body", "first header", "even headers", "odd headers",
01204                                            "first footer", "even footers", "odd footers", "footnote", "ERROR" };
01205     static const char * frameBh[] = { "AutoExtendFrame", "AutoCreateNewFrame", "Ignore", "ERROR" };
01206     static const char * newFrameBh[] = { "Reconnect", "NoFollowup", "Copy" };
01207     static const char * runaround[] = { "No Runaround", "Bounding Rect", "Skip", "ERROR" };
01208     static const char * runaroundSide[] = { "Biggest", "Left", "Right", "ERROR" };
01209 
01210     KWFrameViewManager *fvm = 0;
01211     if ( !m_doc->getAllViews().isEmpty() ) {
01212         KWView *view = m_doc->getAllViews().first();
01213         if(view)
01214             fvm = view->frameViewManager();
01215     }
01216 
01217     kdDebug() << " |  Visible: " << isVisible() << endl;
01218     kdDebug() << " |  Type: " << typeFrameset[ type() ] << endl;
01219     kdDebug() << " |  Info: " << infoFrameset[ frameSetInfo() ] << endl;
01220     kdDebug() << " |  Floating: " << isFloating() << endl;
01221     kdDebug() << " |  Frames in page array: " << endl;
01222     for ( uint i = 0 ; i < m_framesInPage.size() ; ++i )
01223     {
01224         QPtrListIterator<KWFrame> it( *m_framesInPage[i] );
01225         int pgNum = i + m_firstPage;
01226         for ( ; it.current() ; ++it )
01227             kdDebug() << " |     " << pgNum << ": " << it.current() << "   " << *it.current()
01228                       << " internalY=" << it.current()->internalY() << "pt "
01229                       << " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->internalY() ) << ")"
01230                       << " innerHeight=" << it.current()->innerHeight()
01231                       << " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->innerHeight() ) << ")"
01232                       << endl;
01233     }
01234 
01235     QPtrListIterator<KWFrame> frameIt = frameIterator();
01236     for ( unsigned int j = 0; frameIt.current(); ++frameIt, ++j ) {
01237         KWFrame * frame = frameIt.current();
01238         QCString copy = frame->isCopy() ? "[copy]" : "";
01239         kdDebug() << " +-- Frame " << j << " of "<< frameCount() << "    (" << frame << ")  " << copy << endl;
01240         printDebug( frame );
01241         kdDebug() << "     Rectangle : " << frame->x() << "," << frame->y() << " " << frame->width() << "x" << frame->height() << endl;
01242         kdDebug() << "     RunAround: "<< runaround[ frame->runAround() ] << " side:" << runaroundSide[ frame->runAroundSide() ]<< endl;
01243         kdDebug() << "     FrameBehavior: "<< frameBh[ frame->frameBehavior() ] << endl;
01244         kdDebug() << "     NewFrameBehavior: "<< newFrameBh[ frame->newFrameBehavior() ] << endl;
01245         QColor col = frame->backgroundColor().color();
01246         kdDebug() << "     BackgroundColor: "<< ( col.isValid() ? col.name().latin1() : "(default)" ) << endl;
01247         kdDebug() << "     SheetSide "<< frame->sheetSide() << endl;
01248         kdDebug() << "     Z Order: " << frame->zOrder() << endl;
01249 
01250         if( frame->frameStack() ) {
01251             QValueList<KWFrame*> onTop = frame->frameStack()->framesOnTop();
01252             QValueList<KWFrame*> below = frame->frameStack()->framesBelow();
01253 
01254             kdDebug() << "     Frames below: " << below.count()
01255                       << ", frames on top: " << onTop.count() << endl;
01256         }
01257         else
01258             kdDebug() << "     no frameStack set." << endl;
01259         kdDebug() << "     minFrameHeight "<< frame->minimumFrameHeight() << endl;
01260         QString page = pageManager() && pageManager()->pageCount() > 0 ? QString::number(frame->pageNumber()) : " [waiting for pages to be created]";
01261 
01262         KWFrameView *fv = 0;
01263         if(fvm) fv = fvm->view(frame);
01264         if(fv && fv->selected())
01265             kdDebug() << " *   Page "<< page << endl;
01266         else
01267             kdDebug() << "     Page "<< page << endl;
01268     }
01269 }
01270 
01271 void KWFrameSet::printDebug( KWFrame * )
01272 {
01273 }
01274 
01275 #endif
01276 
01277 #include "KWFrameSet.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys