You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1278 lines
50 KiB
1278 lines
50 KiB
15 years ago
|
/* This file is part of the KDE project
|
||
|
Copyright (C) 1998, 1999, 2000 Reginald Stadlbauer <reggie@kde.org>
|
||
|
Copyright (C) 2005 Thomas Zander <zander@kde.org>
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Library General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public License
|
||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
* Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
|
||
|
#include "KWFrameSet.h"
|
||
|
#include "KWDocument.h"
|
||
|
#include "KWViewMode.h"
|
||
|
#include "KWCommand.h"
|
||
|
#include "KWFrame.h"
|
||
|
#include "KWTextFrameSet.h"
|
||
|
#include "KWTableFrameSet.h"
|
||
|
#include "KWAnchor.h"
|
||
|
#include "KWordFrameSetIface.h"
|
||
|
#include "KWFrameList.h"
|
||
|
#include "KWPageManager.h"
|
||
|
#include "KWPage.h"
|
||
|
#include "KWFrameViewManager.h"
|
||
|
#include "KWFrameView.h"
|
||
|
|
||
|
#include <KoOasisContext.h>
|
||
|
#include <KoXmlNS.h>
|
||
|
#include <KoXmlWriter.h>
|
||
|
|
||
|
#include <qpopupmenu.h>
|
||
|
#include <qapplication.h>
|
||
|
|
||
|
//#define DEBUG_DRAW
|
||
|
|
||
|
KWFrameSet::KWFrameSet( KWDocument *doc )
|
||
|
: m_doc( doc ), m_frames(), m_framesInPage(), m_firstPage( 0 ), m_emptyList(),
|
||
|
m_info( FI_BODY ),
|
||
|
m_groupmanager( 0L ), m_visible( true ),
|
||
|
m_protectSize( false ),
|
||
|
m_anchorTextFs( 0L ), m_dcop( 0L ), m_pageManager( 0 )
|
||
|
{
|
||
|
// Send our "repaintChanged" signals to the document.
|
||
|
setName("KWFrameSet");
|
||
|
if(m_doc) {
|
||
|
connect( this, SIGNAL( repaintChanged( KWFrameSet * ) ),
|
||
|
doc, SLOT( slotRepaintChanged( KWFrameSet * ) ) );
|
||
|
m_pageManager = doc->pageManager();
|
||
|
}
|
||
|
m_frames.setAutoDelete( true );
|
||
|
m_framesInPage.setAutoDelete( true ); // autodelete the lists in the array (not the frames;)
|
||
|
}
|
||
|
|
||
|
KWordFrameSetIface* KWFrameSet::dcopObject()
|
||
|
{
|
||
|
if ( !m_dcop )
|
||
|
m_dcop = new KWordFrameSetIface( this );
|
||
|
|
||
|
return m_dcop;
|
||
|
}
|
||
|
|
||
|
|
||
|
KWFrameSet::~KWFrameSet()
|
||
|
{
|
||
|
delete m_dcop;
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::addFrame( KWFrame *frame, bool recalc )
|
||
|
{
|
||
|
if ( m_frames.findRef( frame ) != -1 )
|
||
|
return;
|
||
|
|
||
|
//kdDebug(32001) << k_funcinfo << name() << " adding frame" << frame << " recalc=" << recalc << endl;
|
||
|
if(m_doc)
|
||
|
KWFrameList::createFrameList(frame, m_doc);
|
||
|
frame->setFrameSet(this);
|
||
|
m_frames.append( frame );
|
||
|
if(recalc)
|
||
|
updateFrames();
|
||
|
|
||
|
emit sigFrameAdded(frame);
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::deleteFrame( unsigned int num, bool remove, bool recalc )
|
||
|
{
|
||
|
//kdDebug(32001) << k_funcinfo << name() << " deleting frame" << num << " remove=" << remove << " recalc=" << recalc << endl; //kdBacktrace();
|
||
|
KWFrame *frm = m_frames.at( num );
|
||
|
Q_ASSERT( frm );
|
||
|
m_frames.take( num );
|
||
|
Q_ASSERT( !m_frames.contains(frm) );
|
||
|
|
||
|
unsigned int index = frm->pageNumber() - m_firstPage;
|
||
|
if(m_framesInPage.count() >= index) {
|
||
|
QPtrList<KWFrame> *lst = m_framesInPage.at(index);
|
||
|
lst->remove(frm);
|
||
|
}
|
||
|
|
||
|
KWFrameList *stack = frm->frameStack();
|
||
|
if( stack ) {
|
||
|
stack->update(); // will update the other frames on the page.
|
||
|
frm->setFrameStack(0);
|
||
|
delete stack;
|
||
|
}
|
||
|
emit sigFrameRemoved(frm);
|
||
|
if ( !remove )
|
||
|
frm->setFrameSet(0L);
|
||
|
else {
|
||
|
// ###### should something similar be done when just removing a frame from the list?
|
||
|
frameDeleted( frm, recalc ); // inform kwtableframeset if necessary
|
||
|
delete frm;
|
||
|
//kdDebug(32001) << k_funcinfo << frm << " deleted. Now I have " << m_frames.count() << " m_frames" << endl;
|
||
|
}
|
||
|
|
||
|
if ( recalc )
|
||
|
updateFrames();
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::deleteFrame( KWFrame *frm, bool remove, bool recalc )
|
||
|
{
|
||
|
//kdDebug(32001) << "KWFrameSet::deleteFrame " << frm << " remove=" << remove << endl;
|
||
|
int num = m_frames.findRef( frm );
|
||
|
Q_ASSERT( num != -1 );
|
||
|
if ( num == -1 )
|
||
|
return;
|
||
|
|
||
|
deleteFrame( num, remove, recalc );
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::deleteAllFrames()
|
||
|
{
|
||
|
if ( !m_frames.isEmpty() )
|
||
|
{
|
||
|
for ( QPtrListIterator<KWFrame> frameIt( m_frames ); frameIt.current(); ++frameIt )
|
||
|
emit sigFrameRemoved( *frameIt );
|
||
|
m_frames.clear();
|
||
|
updateFrames();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::deleteAllCopies()
|
||
|
{
|
||
|
if ( m_frames.count() > 1 )
|
||
|
{
|
||
|
KWFrame * firstFrame = m_frames.take(0);
|
||
|
deleteAllFrames();
|
||
|
m_frames.append( firstFrame );
|
||
|
updateFrames();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::createEmptyRegion( const QRect & crect, QRegion & emptyRegion, KWViewMode *viewMode )
|
||
|
{
|
||
|
KWPage *page = m_doc->pageManager()->page( frame(0) );
|
||
|
if( !page ) {
|
||
|
kdWarning(31001) << "The first frame of '" << name() << "' is outside all pages!!" << endl;
|
||
|
return;
|
||
|
}
|
||
|
double paperHeight = page->height();
|
||
|
//kdDebug(32001) << "KWFrameSet::createEmptyRegion " << name() << endl;
|
||
|
for (QPtrListIterator<KWFrame> frameIt = frameIterator(); frameIt.current(); ++frameIt )
|
||
|
{
|
||
|
if ( !frameIt.current()->isTransparent() )
|
||
|
{
|
||
|
QRect outerRect( viewMode->normalToView( frameIt.current()->outerRect(viewMode) ) );
|
||
|
//kdDebug(32001) << "KWFrameSet::createEmptyRegion outerRect=" << outerRect << " crect=" << crect << endl;
|
||
|
outerRect &= crect; // This is important, to avoid calling subtract with a Y difference > 65536
|
||
|
if ( !outerRect.isEmpty() )
|
||
|
{
|
||
|
emptyRegion = emptyRegion.subtract( outerRect );
|
||
|
//kdDebug(32001) << "KWFrameSet::createEmptyRegion emptyRegion now: " << endl; DEBUGREGION( emptyRegion );
|
||
|
}
|
||
|
if ( crect.bottom() + paperHeight < outerRect.top() )
|
||
|
return; // Ok, we're far below the crect, abort.
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::drawPadding( KWFrame *frame, QPainter *p, const QRect &crect, const QColorGroup &, KWViewMode *viewMode )
|
||
|
{
|
||
|
QRect outerRect( viewMode->normalToView( frame->outerRect(viewMode) ) );
|
||
|
//kdDebug(32001) << "KWFrameSet::drawPadding frame: " << frameFromPtr( frame )
|
||
|
// << " outerRect: " << outerRect
|
||
|
// << " crect: " << crect << endl;
|
||
|
|
||
|
if ( !crect.intersects( outerRect ) )
|
||
|
{
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << "KWFrameSet::drawPadding no intersection with " << crect << endl;
|
||
|
#endif
|
||
|
return;
|
||
|
}
|
||
|
QRect frameRect( viewMode->normalToView( m_doc->zoomRect( *frame ) ) );
|
||
|
p->save();
|
||
|
QBrush bgBrush( frame->backgroundColor() );
|
||
|
bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), p ) );
|
||
|
p->setBrush( bgBrush );
|
||
|
int leftMargin = m_doc->zoomItX(frame->paddingLeft());
|
||
|
int topMargin = m_doc->zoomItY(frame->paddingTop());
|
||
|
int rightMargin = m_doc->zoomItX(frame->paddingRight());
|
||
|
int bottomMargin = m_doc->zoomItY(frame->paddingBottom());
|
||
|
//kdDebug(32001) << "KWFrameSet::drawPadding leftMargin=" << leftMargin << " topMargin=" << topMargin << " rightMargin=" << rightMargin << " bottomMargin=" << bottomMargin << endl;
|
||
|
|
||
|
if ( topMargin != 0 )
|
||
|
{
|
||
|
QRect r( frameRect.left(), frameRect.top(), frameRect.width(), topMargin );
|
||
|
p->fillRect( r, bgBrush );
|
||
|
}
|
||
|
if ( leftMargin != 0 )
|
||
|
{
|
||
|
QRect r( frameRect.left(), frameRect.top(), leftMargin, frameRect.height() );
|
||
|
p->fillRect( r, bgBrush );
|
||
|
}
|
||
|
if ( rightMargin != 0 )
|
||
|
{
|
||
|
QRect r( frameRect.right()-rightMargin, frameRect.top(), rightMargin, frameRect.height() );
|
||
|
p->fillRect( r, bgBrush );
|
||
|
}
|
||
|
if ( bottomMargin != 0 )
|
||
|
{
|
||
|
QRect r( frameRect.left(), frameRect.bottom()-bottomMargin, frameRect.width(), bottomMargin );
|
||
|
p->fillRect( r, bgBrush );
|
||
|
}
|
||
|
p->restore();
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void KWFrameSet::drawFrameBorder( QPainter *painter, KWFrame *frame, KWFrame *settingsFrame, const QRect &crect, KWViewMode *viewMode )
|
||
|
{
|
||
|
QRect outerRect( viewMode->normalToView( frame->outerRect( viewMode ) ) );
|
||
|
//kdDebug(32001) << "KWFrameSet::drawFrameBorder frame: " << frameFromPtr( frame )
|
||
|
// << " outerRect: " << outerRect << endl;
|
||
|
|
||
|
if ( !crect.intersects( outerRect ) )
|
||
|
{
|
||
|
//kdDebug(32001) << "KWFrameSet::drawFrameBorder no intersection with " << crect << endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QRect frameRect( viewMode->normalToView( m_doc->zoomRect( *frame ) ) );
|
||
|
|
||
|
painter->save();
|
||
|
QBrush bgBrush( settingsFrame->backgroundColor() );
|
||
|
//bool defaultColor = !bgBrush.color().isValid();
|
||
|
bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), painter ) );
|
||
|
painter->setBrush( bgBrush );
|
||
|
|
||
|
// Draw default borders using view settings...
|
||
|
QPen viewSetting( QApplication::palette().color( QPalette::Active, QColorGroup::Mid ) );
|
||
|
int minBorder = 1;
|
||
|
// ...except when printing, or embedded doc, or disabled.
|
||
|
if ( !viewMode || !viewMode->drawFrameBorders() )
|
||
|
{
|
||
|
viewSetting = NoPen;
|
||
|
minBorder = 0;
|
||
|
}
|
||
|
|
||
|
// Draw borders either as the user defined them, or using the view settings.
|
||
|
// Borders should be drawn _outside_ of the frame area
|
||
|
// otherwise the frames will erase the border when painting themselves.
|
||
|
|
||
|
KoBorder::drawBorders( *painter, m_doc, frameRect,
|
||
|
settingsFrame->leftBorder(), settingsFrame->rightBorder(),
|
||
|
settingsFrame->topBorder(), settingsFrame->bottomBorder(),
|
||
|
minBorder, viewSetting );
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setFloating()
|
||
|
{
|
||
|
// Find main text frame
|
||
|
QPtrListIterator<KWFrameSet> fit = m_doc->framesetsIterator();
|
||
|
for ( ; fit.current() ; ++fit )
|
||
|
{
|
||
|
KWTextFrameSet * frameSet = dynamic_cast<KWTextFrameSet *>( fit.current() );
|
||
|
if ( !frameSet || frameSet->frameSetInfo() != FI_BODY )
|
||
|
continue;
|
||
|
|
||
|
KoTextParag* parag = 0L;
|
||
|
int index = 0;
|
||
|
KoPoint dPoint( m_frames.first()->topLeft() );
|
||
|
kdDebug(32001) << "KWFrameSet::setFloating looking for pos at " << dPoint.x() << " " << dPoint.y() << endl;
|
||
|
frameSet->findPosition( dPoint, parag, index );
|
||
|
// Create anchor. TODO: refcount the anchors!
|
||
|
setAnchored( frameSet, parag, index );
|
||
|
frameSet->layout();
|
||
|
m_doc->frameChanged( m_frames.first() );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setProtectSize( bool b)
|
||
|
{
|
||
|
m_protectSize = b;
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setAnchored( KWTextFrameSet* textfs, int paragId, int index, bool placeHolderExists /* = false */, bool repaint )
|
||
|
{
|
||
|
KWTextParag * parag = static_cast<KWTextParag *>( textfs->textDocument()->paragAt( paragId ) );
|
||
|
Q_ASSERT( parag );
|
||
|
if ( parag )
|
||
|
setAnchored( textfs, parag, index, placeHolderExists, repaint );
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setAnchored( KWTextFrameSet* textfs, KoTextParag* parag, int index, bool placeHolderExists /* = false */, bool repaint )
|
||
|
{
|
||
|
kdDebug(32001) << "KWFrameSet::setAnchored " << textfs << " " << parag->paragId() << " " << index << " " << placeHolderExists << endl;
|
||
|
Q_ASSERT( textfs );
|
||
|
Q_ASSERT( parag );
|
||
|
if ( isFloating() )
|
||
|
deleteAnchors();
|
||
|
m_anchorTextFs = textfs;
|
||
|
KWFrameList::createFrameList(textfs, m_doc); // remove ourselves from others list now we are inline
|
||
|
if ( parag )
|
||
|
createAnchors( parag, index, placeHolderExists, repaint );
|
||
|
|
||
|
if ( !placeHolderExists ) // i.e. not while loading
|
||
|
{
|
||
|
m_doc->updateAllFrames(); // We just became floating, so we need to be removed from "frames on top/below".
|
||
|
// TODO pass page number to updateAllFrames - hmm, we could have several frames in theory
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setAnchored( KWTextFrameSet* textfs )
|
||
|
{
|
||
|
m_anchorTextFs = textfs;
|
||
|
m_doc->updateAllFrames(); // We just became floating, so we need to be removed from "frames on top/below".
|
||
|
// TODO pass page number - hmm, we could have several frames in theory
|
||
|
}
|
||
|
|
||
|
// Find where our anchor is ( if we are anchored ).
|
||
|
// We can't store a pointers to anchors, because over time we might change anchors
|
||
|
// (Especially, undo/redo of insert/delete can reuse an old anchor and forget a newer one etc.)
|
||
|
KWAnchor * KWFrameSet::findAnchor( int frameNum )
|
||
|
{
|
||
|
Q_ASSERT( m_anchorTextFs );
|
||
|
// Yes, a linear search, but only among all customitems of the correct textdoc,
|
||
|
// whose number is assumed to be quite small.
|
||
|
QPtrListIterator<KoTextCustomItem> cit( m_anchorTextFs->textDocument()->allCustomItems() );
|
||
|
for ( ; cit.current() ; ++cit )
|
||
|
{
|
||
|
KWAnchor * anchor = dynamic_cast<KWAnchor *>( cit.current() );
|
||
|
if ( anchor && !anchor->isDeleted()
|
||
|
&& anchor->frameSet() == this && anchor->frameNum() == frameNum )
|
||
|
return anchor;
|
||
|
}
|
||
|
kdWarning() << "KWFrameSet::findAnchor anchor not found (frameset='" << name()
|
||
|
<< "' frameNum=" << frameNum << ")" << endl;
|
||
|
return 0L;
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setFixed()
|
||
|
{
|
||
|
kdDebug(32001) << "KWFrameSet::setFixed" << endl;
|
||
|
if ( isFloating() )
|
||
|
deleteAnchors();
|
||
|
m_anchorTextFs = 0L;
|
||
|
// make sure the frames are on top
|
||
|
// (their z-order didn't matter when they were inline)
|
||
|
QPtrListIterator<KWFrame> frameIt = frameIterator();
|
||
|
for ( ; frameIt.current(); ++frameIt )
|
||
|
frameIt.current()->setZOrder( m_doc->maxZOrder( frameIt.current()->pageNumber(m_doc) ) + 1 );
|
||
|
|
||
|
m_doc->repaintAllViews();
|
||
|
m_doc->updateRulerFrameStartEnd();
|
||
|
}
|
||
|
|
||
|
KWAnchor * KWFrameSet::createAnchor( KoTextDocument *txt, int frameNum )
|
||
|
{
|
||
|
KWAnchor * anchor = new KWAnchor( txt, this, frameNum );
|
||
|
return anchor;
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::createAnchors( KoTextParag * parag, int index, bool placeHolderExists /*= false */ /*only used when loading*/,
|
||
|
bool repaint )
|
||
|
{
|
||
|
kdDebug(32001) << "KWFrameSet::createAnchors" << endl;
|
||
|
Q_ASSERT( m_anchorTextFs );
|
||
|
QPtrListIterator<KWFrame> frameIt = frameIterator();
|
||
|
for ( ; frameIt.current(); ++frameIt, ++index )
|
||
|
{
|
||
|
//if ( ! frameIt.current()->anchor() )
|
||
|
{
|
||
|
// Anchor this frame, after the previous one
|
||
|
KWAnchor * anchor = createAnchor( m_anchorTextFs->textDocument(), frameFromPtr( frameIt.current() ) );
|
||
|
if ( !placeHolderExists )
|
||
|
parag->insert( index, KoTextObject::customItemChar() );
|
||
|
parag->setCustomItem( index, anchor, 0 );
|
||
|
}
|
||
|
}
|
||
|
parag->setChanged( true );
|
||
|
if ( repaint )
|
||
|
emit repaintChanged( m_anchorTextFs );
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::deleteAnchor( KWAnchor * anchor )
|
||
|
{
|
||
|
// Simple deletion, no undo/redo
|
||
|
KoTextCursor c( m_anchorTextFs->textDocument() );
|
||
|
c.setParag( anchor->paragraph() );
|
||
|
c.setIndex( anchor->index() );
|
||
|
anchor->setDeleted( true ); // this sets m_anchorTextFs to 0L
|
||
|
|
||
|
static_cast<KWTextParag*>(c.parag())->removeCustomItem(c.index());
|
||
|
c.remove(); // This deletes the character where the anchor was
|
||
|
// We don't delete the anchor since it might be in a customitemmap in a text-insert command
|
||
|
// TODO: refcount the anchors
|
||
|
c.parag()->setChanged( true );
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::deleteAnchors()
|
||
|
{
|
||
|
kdDebug(32002) << "KWFrameSet::deleteAnchors" << endl;
|
||
|
KWTextFrameSet * textfs = m_anchorTextFs;
|
||
|
Q_ASSERT( textfs );
|
||
|
if ( !textfs )
|
||
|
return;
|
||
|
//QPtrListIterator<KWFrame> frameIt = frameIterator();
|
||
|
int frameNum = 0;
|
||
|
// At the moment there's only one anchor per frameset
|
||
|
// With tables the loop below will be wrong anyway...
|
||
|
//for ( ; frameIt.current(); ++frameIt, ++frameNum )
|
||
|
{
|
||
|
/* if ( frameIt.current()->anchor() )
|
||
|
deleteAnchor( frameIt.current()->anchor() );
|
||
|
frameIt.current()->setAnchor( 0L );
|
||
|
*/
|
||
|
KWAnchor * anchor = findAnchor( frameNum );
|
||
|
deleteAnchor( anchor );
|
||
|
}
|
||
|
emit repaintChanged( textfs );
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position )
|
||
|
{
|
||
|
KWFrame * frame = m_frames.at( frameNum );
|
||
|
Q_ASSERT( frame );
|
||
|
if ( !frame ) return;
|
||
|
|
||
|
KoPoint pos( position );
|
||
|
// position includes the border, we need to adjust accordingly
|
||
|
pos.rx() += frame->leftBorder().width();
|
||
|
pos.ry() += frame->topBorder().width();
|
||
|
if ( frame->topLeft() != pos )
|
||
|
{
|
||
|
kdDebug(32002) << "KWFrameSet::moveFloatingFrame " << pos.x() << "," << pos.y() << endl;
|
||
|
int oldPageNum = frame->pageNumber();
|
||
|
frame->moveTopLeft( pos );
|
||
|
|
||
|
updateFrames();
|
||
|
if( frame->frameStack() )
|
||
|
frame->frameStack()->updateAfterMove( oldPageNum );
|
||
|
}
|
||
|
invalidate();
|
||
|
}
|
||
|
|
||
|
KoRect KWFrameSet::floatingFrameRect( int frameNum )
|
||
|
{
|
||
|
KWFrame * frame = m_frames.at( frameNum );
|
||
|
Q_ASSERT( frame );
|
||
|
Q_ASSERT( isFloating() );
|
||
|
|
||
|
KWAnchor* anchor = findAnchor( frameNum );
|
||
|
Q_ASSERT( anchor );
|
||
|
QRect paragRect = anchor->paragraph()->rect();
|
||
|
int x = anchor->x() + paragRect.x(); // in LU
|
||
|
int y = anchor->y() + paragRect.y(); // in LU
|
||
|
|
||
|
KoPoint topLeft( m_doc->layoutUnitToPixelX( x ), m_doc->layoutUnitToPixelY( y ) );
|
||
|
return KoRect( topLeft, frame->outerKoRect().size() );
|
||
|
}
|
||
|
|
||
|
KoSize KWFrameSet::floatingFrameSize( int frameNum )
|
||
|
{
|
||
|
KWFrame * frame = m_frames.at( frameNum );
|
||
|
Q_ASSERT( frame );
|
||
|
return frame->outerKoRect().size();
|
||
|
}
|
||
|
|
||
|
KCommand * KWFrameSet::anchoredObjectCreateCommand( int frameNum )
|
||
|
{
|
||
|
KWFrame * frame = m_frames.at( frameNum );
|
||
|
Q_ASSERT( frame );
|
||
|
return new KWCreateFrameCommand( QString::null, frame );
|
||
|
}
|
||
|
|
||
|
KCommand * KWFrameSet::anchoredObjectDeleteCommand( int frameNum )
|
||
|
{
|
||
|
KWFrame * frame = m_frames.at( frameNum );
|
||
|
Q_ASSERT( frame );
|
||
|
return new KWDeleteFrameCommand( QString::null, frame );
|
||
|
}
|
||
|
|
||
|
KWFrame * KWFrameSet::frameAtPos( double x, double y ) const
|
||
|
{
|
||
|
KoPoint docPoint( x, y );
|
||
|
QPtrListIterator<KWFrame> frameIt = frameIterator();
|
||
|
for ( ; frameIt.current(); ++frameIt )
|
||
|
if ( frameIt.current()->contains( docPoint ) )
|
||
|
return frameIt.current();
|
||
|
return 0L;
|
||
|
}
|
||
|
|
||
|
KWFrame *KWFrameSet::frame( unsigned int num ) const
|
||
|
{
|
||
|
// QPtrList sucks
|
||
|
return const_cast<KWFrameSet*>( this )->m_frames.at( num );
|
||
|
}
|
||
|
|
||
|
int KWFrameSet::frameFromPtr( KWFrame *frame )
|
||
|
{
|
||
|
return m_frames.findRef( frame );
|
||
|
}
|
||
|
|
||
|
KWFrame * KWFrameSet::settingsFrame( const KWFrame* frame )
|
||
|
{
|
||
|
if ( !frame->isCopy() )
|
||
|
return const_cast<KWFrame *>( frame );
|
||
|
KWFrame* lastRealFrame=0L;
|
||
|
QPtrListIterator<KWFrame> frameIt( frame->frameSet()->frameIterator() );
|
||
|
for ( ; frameIt.current(); ++frameIt )
|
||
|
{
|
||
|
KWFrame *curFrame = frameIt.current();
|
||
|
if ( curFrame == frame )
|
||
|
return lastRealFrame ? lastRealFrame : const_cast<KWFrame *>( frame );
|
||
|
if ( !lastRealFrame || !curFrame->isCopy() )
|
||
|
lastRealFrame = curFrame;
|
||
|
}
|
||
|
return const_cast<KWFrame *>( frame ); //fallback, should never happen
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::updateFrames( int flags )
|
||
|
{
|
||
|
if ( m_frames.isEmpty() )
|
||
|
return; // No frames. This happens when the frameset is deleted (still exists for undo/redo)
|
||
|
|
||
|
// Not visible ? Don't bother then.
|
||
|
if ( !isVisible() )
|
||
|
return;
|
||
|
|
||
|
//kdDebug(32001) << "KWFrameSet::updateFrames " << this << " " << name() << endl;
|
||
|
|
||
|
if ( flags & UpdateFramesInPage ) {
|
||
|
// For each of our frames, clear old list of frames on top, and grab min/max page nums
|
||
|
m_firstPage = m_frames.first()->pageNumber(); // we know m_frames is not empty here
|
||
|
int lastPage = m_firstPage;
|
||
|
QPtrListIterator<KWFrame> fIt( frameIterator() );
|
||
|
for ( ; fIt.current(); ++fIt ) {
|
||
|
int pg = fIt.current()->pageNumber();
|
||
|
m_firstPage = KMIN( m_firstPage, pg );
|
||
|
lastPage = KMAX( lastPage, pg );
|
||
|
}
|
||
|
//kdDebug(32001) << "firstPage=" << m_firstPage << " lastPage=" << lastPage << endl;
|
||
|
|
||
|
// Prepare the m_framesInPage structure
|
||
|
int oldSize = m_framesInPage.size();
|
||
|
m_framesInPage.resize( lastPage - m_firstPage + 1 );
|
||
|
// Clear the old elements
|
||
|
int oldElements = KMIN( oldSize, (int)m_framesInPage.size() );
|
||
|
for ( int i = 0 ; i < oldElements ; ++i )
|
||
|
m_framesInPage[i]->clear();
|
||
|
// Initialize the new elements.
|
||
|
for ( int i = oldElements ; i < (int)m_framesInPage.size() ; ++i )
|
||
|
m_framesInPage.insert( i, new QPtrList<KWFrame>() );
|
||
|
|
||
|
// Iterate over m_frames again, to fill the m_framesInPage array
|
||
|
fIt.toFirst();
|
||
|
for ( ; fIt.current(); ++fIt ) {
|
||
|
int pg = fIt.current()->pageNumber();
|
||
|
Q_ASSERT( pg <= lastPage );
|
||
|
m_framesInPage[pg - m_firstPage]->append( fIt.current() );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( isFloating() )
|
||
|
{
|
||
|
//kdDebug(32001) << "KWFrameSet::updateFrames " << name() << " is floating" << endl;
|
||
|
QPtrListIterator<KWFrame> frameIt = frameIterator();
|
||
|
int frameNum = 0;
|
||
|
// At the moment there's only one anchor per frameset
|
||
|
//for ( ; frameIt.current(); ++frameIt, ++frameNum )
|
||
|
{
|
||
|
KWAnchor * anchor = findAnchor( frameNum );
|
||
|
//kdDebug(32001) << "KWFrameSet::updateFrames anchor=" << anchor << endl;
|
||
|
if ( anchor )
|
||
|
anchor->resize();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::isPaintedBy( KWFrameSet* fs ) const
|
||
|
{
|
||
|
if ( fs == this )
|
||
|
return true;
|
||
|
if ( isFloating() )
|
||
|
{
|
||
|
KWFrameSet* parentFs = anchorFrameset();
|
||
|
if ( parentFs && parentFs->isPaintedBy( fs ) )
|
||
|
return true;
|
||
|
}
|
||
|
if ( groupmanager() )
|
||
|
{
|
||
|
if ( groupmanager()->isPaintedBy( fs ) )
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
const QPtrList<KWFrame> & KWFrameSet::framesInPage( int pageNum ) const
|
||
|
{
|
||
|
if ( pageNum < m_firstPage || pageNum >= (int)m_framesInPage.size() + m_firstPage )
|
||
|
{
|
||
|
#ifdef DEBUG_DTI
|
||
|
kdWarning(32002) << name() << " framesInPage called for pageNum=" << pageNum << ". "
|
||
|
<< " Min value: " << m_firstPage
|
||
|
<< " Max value: " << m_framesInPage.size() + m_firstPage - 1 << endl;
|
||
|
#endif
|
||
|
return m_emptyList; // QPtrList<KWFrame>() doesn't work, it's a temporary
|
||
|
}
|
||
|
return * m_framesInPage[pageNum - m_firstPage];
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::drawContents( QPainter *p, const QRect & crect, const QColorGroup &cg,
|
||
|
bool onlyChanged, bool resetChanged,
|
||
|
KWFrameSetEdit *edit, KWViewMode *viewMode,
|
||
|
KWFrameViewManager *frameViewManager )
|
||
|
{
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << "\nKWFrameSet::drawContents " << this << " " << name()
|
||
|
<< " onlyChanged=" << onlyChanged << " resetChanged=" << resetChanged
|
||
|
<< " crect= " << crect
|
||
|
<< endl;
|
||
|
#endif
|
||
|
if ( !viewMode->isTextModeFrameset( this ) )
|
||
|
{
|
||
|
QPtrListIterator<KWFrame> frameIt( frameIterator() );
|
||
|
KWFrame * lastRealFrame = 0L;
|
||
|
//double lastRealFrameTop = 0;
|
||
|
//double totalHeight = 0; // in pt, to avoid accumulating rounding errors
|
||
|
for ( ; frameIt.current(); )
|
||
|
{
|
||
|
KWFrame *frame = frameIt.current();
|
||
|
++frameIt; // Point to the next one, to detect "last copy"
|
||
|
// The settings come from this frame
|
||
|
KWFrame * settingsFrame = ( frame->isCopy() && lastRealFrame ) ? lastRealFrame : frame;
|
||
|
bool lastCopy = !frameIt.current() || !frameIt.current()->isCopy();
|
||
|
drawFrameAndBorders( frame, p, crect, cg, onlyChanged,
|
||
|
// Only reset the changed flag in the last copy of a given frame (#60678)
|
||
|
resetChanged && lastCopy,
|
||
|
edit,
|
||
|
viewMode, settingsFrame, true /*transparency & double-buffering*/ );
|
||
|
if(viewMode->drawSelections() && frameViewManager) {
|
||
|
KWFrameView* view = frameViewManager->view(frame);
|
||
|
if(view)
|
||
|
view->paintFrameAttributes(p, crect, viewMode, m_doc);
|
||
|
}
|
||
|
|
||
|
if ( !lastRealFrame || !frame->isCopy() )
|
||
|
{
|
||
|
lastRealFrame = frame;
|
||
|
//lastRealFrameTop = totalHeight;
|
||
|
}
|
||
|
//totalHeight += frame->innerHeight();
|
||
|
}
|
||
|
}
|
||
|
else { // Text view mode
|
||
|
QRect normalRect = viewMode->viewToNormal(crect);
|
||
|
drawFrame( 0L /*frame*/, p, normalRect, crect, QPoint(KWViewModeText::OFFSET, 0),
|
||
|
0L /*settingsFrame*/, cg, onlyChanged, resetChanged, edit, viewMode, true );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::drawFrameAndBorders( KWFrame *frame,
|
||
|
QPainter *painter, const QRect &crect,
|
||
|
const QColorGroup &cg, bool onlyChanged, bool resetChanged,
|
||
|
KWFrameSetEdit *edit, KWViewMode *viewMode,
|
||
|
KWFrame *settingsFrame, bool drawUnderlyingFrames )
|
||
|
{
|
||
|
if ( !frame->isValid() )
|
||
|
{
|
||
|
kdDebug(32002) << "KWFrameSet::drawFrameAndBorders " << name() << " frame " << frameFromPtr( frame ) << " " << frame << " isn't valid" << endl;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
QRect normalOuterFrameRect( frame->outerRect( viewMode ) );
|
||
|
QRect outerFrameRect( viewMode->normalToView( normalOuterFrameRect ) );
|
||
|
QRect outerCRect = crect.intersect( outerFrameRect );
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << "KWFrameSet::drawFrameAndBorders " << name() << " frame " << frameFromPtr( frame ) << " " << *frame << endl;
|
||
|
kdDebug(32001) << " (outer) normalFrameRect=" << normalOuterFrameRect << " frameRect=" << outerFrameRect << endl;
|
||
|
kdDebug(32001) << " crect=" << crect << " intersec=" << outerCRect << " todraw=" << !outerCRect.isEmpty() << endl;
|
||
|
#endif
|
||
|
if ( !outerCRect.isEmpty() )
|
||
|
{
|
||
|
// Determine settingsFrame if not passed (for speedup)
|
||
|
if ( !settingsFrame )
|
||
|
settingsFrame = this->settingsFrame( frame );
|
||
|
|
||
|
QRect normalInnerFrameRect( m_doc->zoomRect( frame->innerRect() ) );
|
||
|
QRect innerFrameRect( viewMode->normalToView( normalInnerFrameRect ) );
|
||
|
|
||
|
// This translates the coordinates in the document contents
|
||
|
// ( frame and r are up to here in this system )
|
||
|
// into the frame's own coordinate system.
|
||
|
int offsetX = normalInnerFrameRect.left();
|
||
|
int offsetY = normalInnerFrameRect.top() - m_doc->zoomItY( frame->internalY() );
|
||
|
|
||
|
QRect innerCRect = outerCRect.intersect( innerFrameRect );
|
||
|
if ( !innerCRect.isEmpty() )
|
||
|
{
|
||
|
QRect fcrect = viewMode->viewToNormal( innerCRect );
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << " (inner) normalFrameRect=" << normalInnerFrameRect << " frameRect=" << innerFrameRect << endl;
|
||
|
//kdDebug(32001) << " crect after view-to-normal:" << fcrect << "." << " Will move by (" << -offsetX << ", -(" << normalInnerFrameRect.top() << "-" << m_doc->zoomItY(frame->internalY()) << ") == " << -offsetY << ")." << endl;
|
||
|
#endif
|
||
|
fcrect.moveBy( -offsetX, -offsetY );
|
||
|
Q_ASSERT( fcrect.x() >= 0 );
|
||
|
Q_ASSERT( fcrect.y() >= 0 );
|
||
|
|
||
|
// fcrect is now the portion of the frame to be drawn,
|
||
|
// in the frame's coordinates and in pixels
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << "KWFrameSet::drawFrameAndBorders in frame coords:" << fcrect << ". Will translate painter by intersec-fcrect: " << innerCRect.x()-fcrect.x() << "," << innerCRect.y()-fcrect.y() << "." << endl;
|
||
|
#endif
|
||
|
QRegion reg;
|
||
|
if ( drawUnderlyingFrames )
|
||
|
reg = frameClipRegion( painter, frame, outerCRect, viewMode );
|
||
|
else // false means we are being drawn _as_ an underlying frame, so no clipping!
|
||
|
reg = painter->xForm( outerCRect );
|
||
|
if ( !reg.isEmpty() )
|
||
|
{
|
||
|
painter->save();
|
||
|
painter->setClipRegion( reg );
|
||
|
|
||
|
drawFrame( frame, painter, fcrect, outerCRect,
|
||
|
innerCRect.topLeft() - fcrect.topLeft(), // This assume that viewToNormal() is only a translation
|
||
|
settingsFrame, cg, onlyChanged, resetChanged,
|
||
|
edit, viewMode, drawUnderlyingFrames );
|
||
|
|
||
|
if( !groupmanager() ) // not for table cells
|
||
|
drawFrameBorder( painter, frame, settingsFrame, outerCRect, viewMode );
|
||
|
painter->restore();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::drawFrame( KWFrame *frame, QPainter *painter, const QRect &fcrect, const QRect &outerCRect,
|
||
|
const QPoint& translationOffset,
|
||
|
KWFrame *settingsFrame, const QColorGroup &cg, bool onlyChanged, bool resetChanged,
|
||
|
KWFrameSetEdit *edit, KWViewMode* viewMode, bool drawUnderlyingFrames )
|
||
|
{
|
||
|
// In this method the painter is NOT translated yet. It's still in view coordinates.
|
||
|
if ( outerCRect.isEmpty() )
|
||
|
return;
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << "\nKWFrameSet::drawFrame " << name() << " outerCRect=" << outerCRect << " frameCrect=" << fcrect << " drawUnderlyingFrames=" << drawUnderlyingFrames << endl;
|
||
|
#endif
|
||
|
Q_ASSERT( fcrect.isValid() );
|
||
|
|
||
|
QColorGroup frameColorGroup( cg );
|
||
|
if ( settingsFrame ) // 0L in text viewmode
|
||
|
{
|
||
|
QBrush bgBrush( settingsFrame->backgroundColor() );
|
||
|
bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), painter ) );
|
||
|
frameColorGroup.setBrush( QColorGroup::Base, bgBrush );
|
||
|
}
|
||
|
|
||
|
if ( drawUnderlyingFrames && frame && frame->frameStack()) {
|
||
|
QValueList<KWFrame*> below = frame->frameStack()->framesBelow();
|
||
|
if ( !below.isEmpty() )
|
||
|
{
|
||
|
// Double-buffering - not when printing
|
||
|
QPainter* doubleBufPainter = painter;
|
||
|
QPixmap* pix = 0L;
|
||
|
if ( painter->device()->devType() != QInternal::Printer )
|
||
|
{
|
||
|
pix = m_doc->doubleBufferPixmap( outerCRect.size() );
|
||
|
doubleBufPainter = new QPainter;
|
||
|
doubleBufPainter->begin( pix );
|
||
|
// Initialize the pixmap to the page background color
|
||
|
// (if the frame is over the page margins, no underlying frame will paint anything there)
|
||
|
doubleBufPainter->fillRect( 0, 0, outerCRect.width(), outerCRect.height(), QApplication::palette().active().brush( QColorGroup::Base ) );
|
||
|
|
||
|
// The double-buffer pixmap has (0,0) at outerCRect.topLeft(), so we need to
|
||
|
// translate the double-buffer painter; drawFrameAndBorders will draw using view coordinates.
|
||
|
doubleBufPainter->translate( -outerCRect.x(), -outerCRect.y() );
|
||
|
#ifdef DEBUG_DRAW
|
||
|
// kdDebug(32001) << " ... using double buffering. Portion covered: " << outerCRect << endl;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
// Transparency handling
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << " below: " << below.count() << endl;
|
||
|
#endif
|
||
|
for (QValueListIterator<KWFrame*> it = below.begin(); it != below.end(); ++it )
|
||
|
{
|
||
|
KWFrame* f = (*it);
|
||
|
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << " looking at frame below us: " << f->frameSet()->name() << " frame " << frameFromPtr( frame ) << endl;
|
||
|
#endif
|
||
|
QRect viewFrameCRect = outerCRect.intersect( viewMode->normalToView( f->outerRect( viewMode ) ) );
|
||
|
if ( !viewFrameCRect.isEmpty() )
|
||
|
{
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << " viewFrameRect=" << viewFrameCRect << " calling drawFrameAndBorders." << endl;
|
||
|
#endif
|
||
|
f->frameSet()->drawFrameAndBorders( f, doubleBufPainter, viewFrameCRect, cg,
|
||
|
false, resetChanged, edit, viewMode, 0L, false );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( frame->paddingLeft() || frame->paddingTop() || frame->paddingRight() || frame->paddingBottom() )
|
||
|
drawPadding( frame, doubleBufPainter, outerCRect, cg, viewMode );
|
||
|
doubleBufPainter->save();
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << " translating by " << translationOffset.x() << ", " << translationOffset.y() << " before drawFrameContents" << endl;
|
||
|
#endif
|
||
|
doubleBufPainter->translate( translationOffset.x(), translationOffset.y() ); // This assume that viewToNormal() is only a translation
|
||
|
// We can't "repaint changed parags only" if we just drew the underlying frames, hence the "false"
|
||
|
drawFrameContents( frame, doubleBufPainter, fcrect, frameColorGroup, false, resetChanged, edit, viewMode );
|
||
|
doubleBufPainter->restore();
|
||
|
|
||
|
if ( painter->device()->devType() != QInternal::Printer )
|
||
|
{
|
||
|
doubleBufPainter->end();
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32001) << " painting double-buf pixmap at position " << outerCRect.topLeft() << " (real painter pos:" << painter->xForm( outerCRect.topLeft() ) << ")" << endl;
|
||
|
#endif
|
||
|
painter->drawPixmap( outerCRect.topLeft(), *pix );
|
||
|
delete doubleBufPainter;
|
||
|
}
|
||
|
return; // done! :)
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// nothing below? paint a bg color then
|
||
|
frameColorGroup.setBrush( QColorGroup::Base, m_doc->defaultBgColor( painter ) );
|
||
|
}
|
||
|
}
|
||
|
if ( frame && (frame->paddingLeft() || frame->paddingTop() ||
|
||
|
frame->paddingRight() || frame->paddingBottom()) )
|
||
|
drawPadding( frame, painter, outerCRect, cg, viewMode );
|
||
|
painter->save();
|
||
|
painter->translate( translationOffset.x(), translationOffset.y() );
|
||
|
|
||
|
drawFrameContents( frame, painter, fcrect, frameColorGroup, onlyChanged, resetChanged, edit, viewMode );
|
||
|
painter->restore();
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::drawFrameContents( KWFrame *, QPainter *, const QRect &,
|
||
|
const QColorGroup &, bool, bool, KWFrameSetEdit*, KWViewMode * )
|
||
|
{
|
||
|
kdWarning() << "Default implementation of drawFrameContents called for " << className() << " " << this << " " << name() << kdBacktrace();
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::saveCommon( QDomElement &parentElem, bool saveFrames )
|
||
|
{
|
||
|
if ( m_frames.isEmpty() ) // Deleted frameset -> don't save
|
||
|
return;
|
||
|
|
||
|
// Save all the common attributes for framesets.
|
||
|
parentElem.setAttribute( "frameType", static_cast<int>( type() ) );
|
||
|
parentElem.setAttribute( "frameInfo", static_cast<int>( m_info ) );
|
||
|
parentElem.setAttribute( "name", m_name );
|
||
|
parentElem.setAttribute( "visible", static_cast<int>( m_visible ) );
|
||
|
parentElem.setAttribute( "protectSize", static_cast<int>( m_protectSize ) );
|
||
|
if ( saveFrames )
|
||
|
{
|
||
|
QPtrListIterator<KWFrame> frameIt = frameIterator();
|
||
|
for ( ; frameIt.current(); ++frameIt )
|
||
|
{
|
||
|
KWFrame *frame = frameIt.current();
|
||
|
QDomElement frameElem = parentElem.ownerDocument().createElement( "FRAME" );
|
||
|
parentElem.appendChild( frameElem );
|
||
|
|
||
|
frame->save( frameElem );
|
||
|
|
||
|
if(m_doc->processingType() == KWDocument::WP) {
|
||
|
// Assume that all header/footer frames in the same frameset are
|
||
|
// perfect copies. This might not be the case some day though.
|
||
|
if(frameSetInfo() == FI_FIRST_HEADER ||
|
||
|
frameSetInfo() == FI_EVEN_HEADER ||
|
||
|
frameSetInfo() == FI_ODD_HEADER ||
|
||
|
frameSetInfo() == FI_FIRST_FOOTER ||
|
||
|
frameSetInfo() == FI_EVEN_FOOTER ||
|
||
|
frameSetInfo() == FI_ODD_FOOTER ||
|
||
|
frameSetInfo() == FI_FOOTNOTE) break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// This function is intended as a helper for all the derived classes. It reads
|
||
|
// in all the attributes common to all framesets and loads all frames.
|
||
|
//
|
||
|
void KWFrameSet::load( QDomElement &framesetElem, bool loadFrames )
|
||
|
{
|
||
|
m_info = static_cast<KWFrameSet::Info>( KWDocument::getAttribute( framesetElem, "frameInfo", KWFrameSet::FI_BODY ) );
|
||
|
m_visible = static_cast<bool>( KWDocument::getAttribute( framesetElem, "visible", true ) );
|
||
|
m_protectSize=static_cast<bool>( KWDocument::getAttribute( framesetElem, "protectSize", false ) );
|
||
|
if ( loadFrames )
|
||
|
{
|
||
|
// <FRAME>
|
||
|
QDomElement frameElem = framesetElem.firstChild().toElement();
|
||
|
for ( ; !frameElem.isNull() ; frameElem = frameElem.nextSibling().toElement() )
|
||
|
{
|
||
|
if ( frameElem.tagName() == "FRAME" )
|
||
|
{
|
||
|
KoRect rect;
|
||
|
rect.setLeft( KWDocument::getAttribute( frameElem, "left", 0.0 ) );
|
||
|
rect.setTop( KWDocument::getAttribute( frameElem, "top", 0.0 ) );
|
||
|
rect.setRight( KWDocument::getAttribute( frameElem, "right", 0.0 ) );
|
||
|
rect.setBottom( KWDocument::getAttribute( frameElem, "bottom", 0.0 ) );
|
||
|
KWFrame * frame = new KWFrame(this, rect.x(), rect.y(), rect.width(), rect.height() );
|
||
|
frame->load( frameElem, this, m_doc->syntaxVersion() );
|
||
|
addFrame( frame, false );
|
||
|
m_doc->progressItemLoaded();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
KWFrame* KWFrameSet::loadOasisFrame( const QDomElement& tag, KoOasisContext& context )
|
||
|
{
|
||
|
double width = 100;
|
||
|
if ( tag.hasAttributeNS( KoXmlNS::svg, "width" ) ) { // fixed width
|
||
|
// TODO handle percentage (of enclosing table/frame/page)
|
||
|
width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "width", QString::null ) );
|
||
|
} else if ( tag.hasAttributeNS( KoXmlNS::fo, "min-width" ) ) {
|
||
|
// min-width is not supported in KWord. Let's use it as a fixed width.
|
||
|
width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::fo, "min-width", QString::null ) );
|
||
|
} else {
|
||
|
kdWarning(32001) << "Error in frame " << tag.tagName() << " " << tag.attributeNS( KoXmlNS::draw, "name", QString::null ) << " : neither width nor min-width specified!" << endl;
|
||
|
}
|
||
|
double height = 100;
|
||
|
if ( tag.hasAttributeNS( KoXmlNS::svg, "height" ) ) { // fixed height
|
||
|
// TODO handle percentage (of enclosing table/frame/page)
|
||
|
height = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "height", QString::null ) );
|
||
|
}
|
||
|
//kdDebug(32001) << k_funcinfo << "width=" << width << " height=" << height << " pt" << endl;
|
||
|
|
||
|
KWFrame * frame = new KWFrame(this,
|
||
|
KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "x", QString::null ) ),
|
||
|
KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "y", QString::null ) ),
|
||
|
width, height );
|
||
|
|
||
|
frame->setZOrder( tag.attributeNS( KoXmlNS::draw, "z-index", QString::null ).toInt() );
|
||
|
// Copy-frames.
|
||
|
// We currently ignore the value of the copy-of attribute. It probably needs to
|
||
|
// be handled like chain-next-name (kwtextframeset.cc) but for all types of frameset.
|
||
|
frame->setCopy( tag.hasAttributeNS( KoXmlNS::draw, "copy-of" ) );
|
||
|
frame->loadCommonOasisProperties( context, this, "graphic" );
|
||
|
|
||
|
addFrame( frame, false );
|
||
|
|
||
|
// Protect (OASIS 14.27.7, also in OO-1.1)
|
||
|
// A frame with protected contents means that the frameset is protected (makes sense)
|
||
|
// A frame with protected size means that the frameset is size-protected (hmm, kword did it that way)
|
||
|
// TODO implement position protection
|
||
|
QString protectList = context.styleStack().attributeNS( KoXmlNS::style, "protect" );
|
||
|
if ( protectList.contains( "content" ) )
|
||
|
setProtectContent( true );
|
||
|
if ( protectList.contains( "size" ) )
|
||
|
m_protectSize = true;
|
||
|
|
||
|
// TODO m_visible ? User-toggeable or internal?
|
||
|
|
||
|
return frame;
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setVisible( bool v )
|
||
|
{
|
||
|
m_visible = v;
|
||
|
if ( m_visible )
|
||
|
// updateFrames was disabled while we were invisible
|
||
|
updateFrames();
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::isVisible( KWViewMode* viewMode ) const
|
||
|
{
|
||
|
if ( !m_visible || m_frames.isEmpty() )
|
||
|
return false;
|
||
|
if ( isAHeader() && !m_doc->isHeaderVisible() )
|
||
|
return false;
|
||
|
if ( isAFooter() && !m_doc->isFooterVisible() )
|
||
|
return false;
|
||
|
if ( viewMode && !viewMode->isFrameSetVisible(this) )
|
||
|
return false;
|
||
|
if ( isFloating() && !anchorFrameset()->isVisible( viewMode ) )
|
||
|
return false;
|
||
|
|
||
|
KoHFType ht = m_doc != 0 ? m_doc->headerType(): HF_FIRST_DIFF;
|
||
|
KoHFType ft = m_doc != 0 ? m_doc->footerType(): HF_FIRST_DIFF;
|
||
|
switch( m_info )
|
||
|
{
|
||
|
case FI_FIRST_HEADER:
|
||
|
return ( ht == HF_FIRST_DIFF || ht == HF_FIRST_EO_DIFF );
|
||
|
case FI_ODD_HEADER:
|
||
|
return true;
|
||
|
case FI_EVEN_HEADER:
|
||
|
return ( ht == HF_EO_DIFF || ht == HF_FIRST_EO_DIFF );
|
||
|
case FI_FIRST_FOOTER:
|
||
|
return ( ft == HF_FIRST_DIFF || ft == HF_FIRST_EO_DIFF );
|
||
|
case FI_ODD_FOOTER:
|
||
|
return true;
|
||
|
case FI_EVEN_FOOTER:
|
||
|
return ( ft == HF_EO_DIFF || ft == HF_FIRST_EO_DIFF );
|
||
|
default:
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::isAHeader() const
|
||
|
{
|
||
|
return ( m_info == FI_FIRST_HEADER || m_info == FI_ODD_HEADER || m_info == FI_EVEN_HEADER );
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::isAFooter() const
|
||
|
{
|
||
|
return ( m_info == FI_FIRST_FOOTER || m_info == FI_ODD_FOOTER || m_info == FI_EVEN_FOOTER );
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::isFootEndNote() const
|
||
|
{
|
||
|
return m_info == FI_FOOTNOTE;
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::isMainFrameset() const
|
||
|
{
|
||
|
return ( m_doc && m_doc->processingType() == KWDocument::WP &&
|
||
|
m_doc->frameSet( 0 ) == this );
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::isMoveable() const
|
||
|
{
|
||
|
if ( isHeaderOrFooter() )
|
||
|
return false;
|
||
|
return !isMainFrameset() && !isFloating();
|
||
|
}
|
||
|
|
||
|
const char* KWFrameSet::headerFooterTag() const
|
||
|
{
|
||
|
switch ( m_info ) {
|
||
|
case KWFrameSet::FI_ODD_HEADER:
|
||
|
return "style:header";
|
||
|
case KWFrameSet::FI_EVEN_HEADER:
|
||
|
return "style:header-left";
|
||
|
case KWFrameSet::FI_ODD_FOOTER:
|
||
|
return "style:footer";
|
||
|
case KWFrameSet::FI_EVEN_FOOTER:
|
||
|
return "style:footer-left";
|
||
|
case KWFrameSet::FI_FIRST_HEADER:
|
||
|
return "style:header-first"; // NOT OASIS COMPLIANT
|
||
|
case KWFrameSet::FI_FIRST_FOOTER:
|
||
|
return "style:footer-first"; // NOT OASIS COMPLIANT
|
||
|
default: // shouldn't be called for body or footnote
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::finalize()
|
||
|
{
|
||
|
//kdDebug(32001) << "KWFrameSet::finalize ( calls updateFrames + zoom ) " << this << endl;
|
||
|
updateFrames();
|
||
|
}
|
||
|
|
||
|
QRegion KWFrameSet::frameClipRegion( QPainter * painter, KWFrame *frame, const QRect & crect,
|
||
|
KWViewMode * viewMode )
|
||
|
{
|
||
|
// KWDocument * doc = kWordDocument();
|
||
|
QRect rc = painter->xForm( crect );
|
||
|
#ifdef DEBUG_DRAW
|
||
|
//kdDebug(32002) << "KWFrameSet::frameClipRegion rc initially " << rc << endl;
|
||
|
#endif
|
||
|
|
||
|
Q_ASSERT( frame );
|
||
|
#if 0 // done later
|
||
|
if ( clipFrame )
|
||
|
{
|
||
|
rc &= painter->xForm( viewMode->normalToView( doc->zoomRect( (*frame) ) ) ); // intersect
|
||
|
#ifdef DEBUG_DRAW
|
||
|
kdDebug(32002) << "KWFrameSet::frameClipRegion frame=" << *frame
|
||
|
<< " clip region rect=" << rc
|
||
|
<< " rc.isEmpty()=" << rc.isEmpty() << endl;
|
||
|
#endif
|
||
|
}
|
||
|
#endif
|
||
|
if ( !rc.isEmpty() )
|
||
|
{
|
||
|
QRegion reg( rc );
|
||
|
// This breaks when a frame is under another one, it still appears if !onlyChanged.
|
||
|
// cvs log says this is about frame borders... hmm.
|
||
|
/// ### if ( onlyChanged )
|
||
|
|
||
|
Q_ASSERT( frame->frameStack() );
|
||
|
|
||
|
QValueList<KWFrame *> onTop = frame->frameStack()->framesOnTop();
|
||
|
for (QValueListIterator<KWFrame*> fIt = onTop.begin(); fIt != onTop.end(); ++fIt )
|
||
|
{
|
||
|
KWFrame* frameOnTop = (*fIt);
|
||
|
Q_ASSERT( frameOnTop->frameSet() );
|
||
|
QRect r = painter->xForm( viewMode->normalToView( frameOnTop->outerRect( viewMode ) ) );
|
||
|
#ifdef DEBUG_DRAW
|
||
|
//kdDebug(32002) << "frameClipRegion subtract rect "<< r << endl;
|
||
|
#endif
|
||
|
reg -= r; // subtract
|
||
|
}
|
||
|
#ifdef DEBUG_DRAW
|
||
|
//kdDebug(32002) << "KWFrameSet::frameClipRegion result:" << reg << endl;
|
||
|
#endif
|
||
|
return reg;
|
||
|
}
|
||
|
return QRegion();
|
||
|
}
|
||
|
|
||
|
bool KWFrameSet::canRemovePage( int num )
|
||
|
{
|
||
|
QPtrListIterator<KWFrame> frameIt( frameIterator() );
|
||
|
for ( ; frameIt.current(); ++frameIt )
|
||
|
{
|
||
|
KWFrame * frame = frameIt.current();
|
||
|
if ( frame->pageNumber() == num ) // ## TODO: use framesInPage, see KWTextFrameSet
|
||
|
{
|
||
|
// Ok, so we have a frame on that page -> we can't remove it unless it's a copied frame
|
||
|
if ( ! ( frame->isCopy() && frameIt.current() != m_frames.first() ) )
|
||
|
{
|
||
|
kdDebug(32001) << "KWFrameSet::canRemovePage " << name() << " frame on page " << num << " -> false" << endl;
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setFrameBehavior( KWFrame::FrameBehavior fb ) {
|
||
|
for(KWFrame *f=m_frames.first();f;f=m_frames.next())
|
||
|
f->setFrameBehavior(fb);
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setNewFrameBehavior( KWFrame::NewFrameBehavior nfb ) {
|
||
|
for(KWFrame *f=m_frames.first();f;f=m_frames.next())
|
||
|
f->setNewFrameBehavior(nfb);
|
||
|
}
|
||
|
|
||
|
// ## this should pass the viewmode as argument, probably.
|
||
|
bool KWFrameSet::isFrameAtPos( const KWFrame* frame, const QPoint& point, bool borderOfFrameOnly) const {
|
||
|
QRect outerRect( frame->outerRect( m_doc->layoutViewMode() ) );
|
||
|
// Give the user a bit of margin for clicking on it :)
|
||
|
const int margin = 2;
|
||
|
outerRect.rLeft() -= margin;
|
||
|
outerRect.rTop() -= margin;
|
||
|
outerRect.rRight() += margin;
|
||
|
outerRect.rBottom() += margin;
|
||
|
if ( outerRect.contains( point ) ) {
|
||
|
if(borderOfFrameOnly) {
|
||
|
QRect innerRect( m_doc->zoomRect( *frame ) );
|
||
|
innerRect.rLeft() += margin;
|
||
|
innerRect.rTop() += margin;
|
||
|
innerRect.rRight() -= margin;
|
||
|
innerRect.rBottom() -= margin;
|
||
|
return (!innerRect.contains(point) );
|
||
|
}
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setZOrder()
|
||
|
{
|
||
|
//kdDebug(32001) << "KWFrameSet::setZOrder (to max) " << name() << endl;
|
||
|
QPtrListIterator<KWFrame> fit = frameIterator();
|
||
|
for ( ; fit.current() ; ++fit )
|
||
|
fit.current()->setZOrder( m_doc->maxZOrder( fit.current()->pageNumber(m_doc) ) + 1 );
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::setName( const QString &name )
|
||
|
{
|
||
|
m_name = name;
|
||
|
emit sigNameChanged(this);
|
||
|
}
|
||
|
|
||
|
#ifndef NDEBUG
|
||
|
#include "KWFrameViewManager.h"
|
||
|
#include "KWFrameView.h"
|
||
|
void KWFrameSet::printDebug()
|
||
|
{
|
||
|
static const char * typeFrameset[] = { "base", "txt", "picture", "part", "formula", "clipart",
|
||
|
"6", "7", "8", "9", "table",
|
||
|
"ERROR" };
|
||
|
static const char * infoFrameset[] = { "body", "first header", "even headers", "odd headers",
|
||
|
"first footer", "even footers", "odd footers", "footnote", "ERROR" };
|
||
|
static const char * frameBh[] = { "AutoExtendFrame", "AutoCreateNewFrame", "Ignore", "ERROR" };
|
||
|
static const char * newFrameBh[] = { "Reconnect", "NoFollowup", "Copy" };
|
||
|
static const char * runaround[] = { "No Runaround", "Bounding Rect", "Skip", "ERROR" };
|
||
|
static const char * runaroundSide[] = { "Biggest", "Left", "Right", "ERROR" };
|
||
|
|
||
|
KWFrameViewManager *fvm = 0;
|
||
|
if ( !m_doc->getAllViews().isEmpty() ) {
|
||
|
KWView *view = m_doc->getAllViews().first();
|
||
|
if(view)
|
||
|
fvm = view->frameViewManager();
|
||
|
}
|
||
|
|
||
|
kdDebug() << " | Visible: " << isVisible() << endl;
|
||
|
kdDebug() << " | Type: " << typeFrameset[ type() ] << endl;
|
||
|
kdDebug() << " | Info: " << infoFrameset[ frameSetInfo() ] << endl;
|
||
|
kdDebug() << " | Floating: " << isFloating() << endl;
|
||
|
kdDebug() << " | Frames in page array: " << endl;
|
||
|
for ( uint i = 0 ; i < m_framesInPage.size() ; ++i )
|
||
|
{
|
||
|
QPtrListIterator<KWFrame> it( *m_framesInPage[i] );
|
||
|
int pgNum = i + m_firstPage;
|
||
|
for ( ; it.current() ; ++it )
|
||
|
kdDebug() << " | " << pgNum << ": " << it.current() << " " << *it.current()
|
||
|
<< " internalY=" << it.current()->internalY() << "pt "
|
||
|
<< " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->internalY() ) << ")"
|
||
|
<< " innerHeight=" << it.current()->innerHeight()
|
||
|
<< " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->innerHeight() ) << ")"
|
||
|
<< endl;
|
||
|
}
|
||
|
|
||
|
QPtrListIterator<KWFrame> frameIt = frameIterator();
|
||
|
for ( unsigned int j = 0; frameIt.current(); ++frameIt, ++j ) {
|
||
|
KWFrame * frame = frameIt.current();
|
||
|
QCString copy = frame->isCopy() ? "[copy]" : "";
|
||
|
kdDebug() << " +-- Frame " << j << " of "<< frameCount() << " (" << frame << ") " << copy << endl;
|
||
|
printDebug( frame );
|
||
|
kdDebug() << " Rectangle : " << frame->x() << "," << frame->y() << " " << frame->width() << "x" << frame->height() << endl;
|
||
|
kdDebug() << " RunAround: "<< runaround[ frame->runAround() ] << " side:" << runaroundSide[ frame->runAroundSide() ]<< endl;
|
||
|
kdDebug() << " FrameBehavior: "<< frameBh[ frame->frameBehavior() ] << endl;
|
||
|
kdDebug() << " NewFrameBehavior: "<< newFrameBh[ frame->newFrameBehavior() ] << endl;
|
||
|
QColor col = frame->backgroundColor().color();
|
||
|
kdDebug() << " BackgroundColor: "<< ( col.isValid() ? col.name().latin1() : "(default)" ) << endl;
|
||
|
kdDebug() << " SheetSide "<< frame->sheetSide() << endl;
|
||
|
kdDebug() << " Z Order: " << frame->zOrder() << endl;
|
||
|
|
||
|
if( frame->frameStack() ) {
|
||
|
QValueList<KWFrame*> onTop = frame->frameStack()->framesOnTop();
|
||
|
QValueList<KWFrame*> below = frame->frameStack()->framesBelow();
|
||
|
|
||
|
kdDebug() << " Frames below: " << below.count()
|
||
|
<< ", frames on top: " << onTop.count() << endl;
|
||
|
}
|
||
|
else
|
||
|
kdDebug() << " no frameStack set." << endl;
|
||
|
kdDebug() << " minFrameHeight "<< frame->minimumFrameHeight() << endl;
|
||
|
QString page = pageManager() && pageManager()->pageCount() > 0 ? QString::number(frame->pageNumber()) : " [waiting for pages to be created]";
|
||
|
|
||
|
KWFrameView *fv = 0;
|
||
|
if(fvm) fv = fvm->view(frame);
|
||
|
if(fv && fv->selected())
|
||
|
kdDebug() << " * Page "<< page << endl;
|
||
|
else
|
||
|
kdDebug() << " Page "<< page << endl;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void KWFrameSet::printDebug( KWFrame * )
|
||
|
{
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#include "KWFrameSet.moc"
|