|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2001 David Faure <faure@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 "KWAnchor.h"
|
|
|
|
#include "KWTextFrameSet.h"
|
|
|
|
#include "KWDocument.h"
|
|
|
|
#include "KWViewMode.h"
|
|
|
|
#include "KWView.h"
|
|
|
|
#include <KoXmlWriter.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
|
|
|
|
//#define DEBUG_DRAWING
|
|
|
|
|
|
|
|
KWAnchor::KWAnchor( KoTextDocument *textDocument, KWFrameSet * frameset, int frameNum )
|
|
|
|
: KoTextCustomItem( textDocument),
|
|
|
|
m_frameset( frameset ),
|
|
|
|
m_frameNum( frameNum )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
KWAnchor::~KWAnchor()
|
|
|
|
{
|
|
|
|
kdDebug(32001) << "KWAnchor::~KWAnchor" << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWAnchor::setFormat( KoTextFormat* format )
|
|
|
|
{
|
|
|
|
m_frameset->setAnchorFormat( format, m_frameNum );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWAnchor::finalize()
|
|
|
|
{
|
|
|
|
if ( m_deleted )
|
|
|
|
return;
|
|
|
|
|
|
|
|
int paragx = paragraph()->rect().x();
|
|
|
|
int paragy = paragraph()->rect().y();
|
|
|
|
kdDebug(32001) << this << " KWAnchor::finalize " << x() << "," << y() << " paragx=" << paragx << " paragy=" << paragy << endl;
|
|
|
|
|
|
|
|
KWTextFrameSet * fs = static_cast<KWTextDocument *>(textDocument())->textFrameSet();
|
|
|
|
KoPoint dPoint;
|
|
|
|
if ( fs->internalToDocument( TQPoint( x()+paragx, y()+paragy ), dPoint ) )
|
|
|
|
{
|
|
|
|
//kdDebug(32001) << "KWAnchor::finalize moving frame to " << dPoint.x() << "," << dPoint.y() << endl;
|
|
|
|
// Move the frame to position dPoint.
|
|
|
|
m_frameset->moveFloatingFrame( m_frameNum, dPoint );
|
|
|
|
} else
|
|
|
|
{
|
|
|
|
// This can happen if the page hasn't been created yet
|
|
|
|
kdDebug(32001) << "KWAnchor::move internalToDocument returned 0L for " << x()+paragx << ", " << y()+paragy << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWAnchor::draw( TQPainter* p, int x, int y, int cx, int cy, int cw, int ch, const TQColorGroup& cg, bool selected )
|
|
|
|
{
|
|
|
|
// (x,y) is the position of the inline item (in Layout Units)
|
|
|
|
// (cx,cy,cw,ch) is the rectangle to be painted, in layout units too
|
|
|
|
|
|
|
|
if ( m_deleted )
|
|
|
|
return;
|
|
|
|
|
|
|
|
Q_ASSERT( x == xpos );
|
|
|
|
Q_ASSERT( y == ypos );
|
|
|
|
if ( x != xpos || y != ypos )
|
|
|
|
kdDebug() << "Warning: x=" << x << " y=" << y << " xpos=" << xpos << " ypos=" << ypos << endl;
|
|
|
|
|
|
|
|
// The containing text-frameset.
|
|
|
|
KWTextFrameSet * fs = static_cast<KWTextDocument *>(textDocument())->textFrameSet();
|
|
|
|
KoTextZoomHandler* zh = fs->textDocument()->paintingZoomHandler();
|
|
|
|
|
|
|
|
int paragx = paragraph()->rect().x();
|
|
|
|
int paragy = paragraph()->rect().y();
|
|
|
|
TQRect inlineFrameLU( paragx+xpos, paragy+ypos, width, height );
|
|
|
|
#ifdef DEBUG_DRAWING
|
|
|
|
kdDebug(32001) << "KWAnchor::draw x:" << x << ", y:" << y << " paragx=" << paragx << " paragy=" << paragy << endl;
|
|
|
|
kdDebug(32001) << " inline frame in LU coordinates: " << inlineFrameLU << endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TQRect crectLU = TQRect( (cx > 0 ? cx : 0)+paragx, cy+paragy, cw, ch );
|
|
|
|
#ifdef DEBUG_DRAWING
|
|
|
|
kdDebug(32001) << " crect in LU coordinates: " << DEBUGRECT( crectLU ) << endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
crectLU = crectLU.intersect ( inlineFrameLU ); // KoTextParag::paintDefault could even do this
|
|
|
|
|
|
|
|
|
|
|
|
#ifdef DEBUG_DRAWING
|
|
|
|
kdDebug(32001) << " crect&frame in LU coordinates: " << DEBUGRECT( crectLU ) << endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Convert crect to document coordinates, first topleft then bottomright
|
|
|
|
TQPoint topLeftLU = crectLU.topLeft();
|
|
|
|
TQPoint bottomRightLU = crectLU.bottomRight();
|
|
|
|
KWFrame* containingFrame = fs->currentDrawnFrame(); // always set, except in the textviewmode
|
|
|
|
if(containingFrame)
|
|
|
|
containingFrame = KWFrameSet::settingsFrame(containingFrame);
|
|
|
|
else { // if its not set (in textviewmode) try to get it from the FS
|
|
|
|
TQPoint paragPos = inlineFrameLU.topLeft();
|
|
|
|
KoPoint dummy(0, 0);
|
|
|
|
containingFrame = fs->internalToDocument(paragPos, dummy);
|
|
|
|
}
|
|
|
|
KoPoint topLeftPt = fs->internalToDocumentKnowingFrame( topLeftLU, containingFrame );
|
|
|
|
|
|
|
|
// Now we can convert the bottomright
|
|
|
|
KoPoint bottomRightPt = fs->internalToDocumentKnowingFrame( bottomRightLU, containingFrame );
|
|
|
|
KoRect crectPt( topLeftPt, bottomRightPt );
|
|
|
|
|
|
|
|
// Convert crect to view coords
|
|
|
|
TQRect crect = fs->currentViewMode()->normalToView( zh->zoomRect( crectPt ) );
|
|
|
|
// and add 1 to right and bottom, to avoid rounding errors (and due to qrect semantics)
|
|
|
|
crect.rBottom() += 2; // HACK: 1 doesn't do it, it leaves a white line along window borders
|
|
|
|
crect.rRight() += 1;
|
|
|
|
#ifdef DEBUG_DRAWING
|
|
|
|
kdDebug() << " crect in view coordinates (pixel) : " << DEBUGRECT( crect ) << endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Ok, we finally have our crect in view coordinates!
|
|
|
|
// Now ensure the containing frame is the one actually containing our text
|
|
|
|
// (for copies, e.g. headers and footers, we need to go back until finding a real frame)
|
|
|
|
|
|
|
|
if ( containingFrame && containingFrame->isCopy() )
|
|
|
|
{
|
|
|
|
// Find last real frame, in case we are in a copied frame
|
|
|
|
TQPtrListIterator<KWFrame> frameIt( fs->frameIterator() );
|
|
|
|
frameIt.toLast(); // from the end to avoid a 2*N in the worst case
|
|
|
|
while ( !frameIt.atFirst() && frameIt.current() != containingFrame ) // look for 'containingFrame'
|
|
|
|
--frameIt;
|
|
|
|
if ( frameIt.atFirst() && frameIt.current() != containingFrame )
|
|
|
|
kdWarning() << "KWAnchor::draw: containingFrame not found " << containingFrame << endl;
|
|
|
|
while ( !frameIt.atFirst() && frameIt.current()->isCopy() ) // go back to last non-copy
|
|
|
|
--frameIt;
|
|
|
|
containingFrame = frameIt.current();
|
|
|
|
//kdDebug() << "KWAnchor::draw frame=" << containingFrame << endl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Same calculation as in internalToDocument, but we know the frame already
|
|
|
|
KoPoint topLeftParagPt( 0, 0 );
|
|
|
|
if ( containingFrame ) // 0 in the textviewmode
|
|
|
|
topLeftParagPt = containingFrame->innerRect().topLeft();
|
|
|
|
|
|
|
|
topLeftParagPt.rx() += zh->layoutUnitPtToPt( zh->pixelYToPt( paragx ) );
|
|
|
|
topLeftParagPt.ry() += zh->layoutUnitPtToPt( zh->pixelYToPt( paragy ) );
|
|
|
|
if ( containingFrame ) // 0 in the textviewmode
|
|
|
|
topLeftParagPt.ry() -= containingFrame->internalY();
|
|
|
|
|
|
|
|
TQPoint topLeftParag = fs->currentViewMode()->normalToView( zh->zoomPoint( topLeftParagPt ) );
|
|
|
|
|
|
|
|
// Finally, make the painter go back to view coord system
|
|
|
|
// (this is exactly the opposite of the code in KWFrameSet::drawContents)
|
|
|
|
// (It does translate(view - internal), so we do translate(internal - view) - e.g. with (0,0) for internal)
|
|
|
|
p->save();
|
|
|
|
p->translate( -topLeftParag.x(), -topLeftParag.y() );
|
|
|
|
#ifdef DEBUG_DRAWING
|
|
|
|
kdDebug() << " translating by " << -topLeftParag.x() << "," << -topLeftParag.y() << endl;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
TQColorGroup cg2( cg );
|
|
|
|
|
|
|
|
KWFrameViewManager *fvm = 0;
|
|
|
|
if(m_frameset->kWordDocument()) {
|
|
|
|
TQValueList<KWView *> views = m_frameset->kWordDocument()->getAllViews();
|
|
|
|
// Note that "views" is empty when the KWDocument is an (inactive) embedded document
|
|
|
|
if ( !views.isEmpty() )
|
|
|
|
fvm = views.first()->frameViewManager();
|
|
|
|
}
|
|
|
|
m_frameset->drawContents( p, crect, cg2, false, true, 0L, fs->currentViewMode(), fvm);
|
|
|
|
|
|
|
|
if( selected && placement() == PlaceInline && p->device()->devType() != TQInternal::Printer )
|
|
|
|
{
|
|
|
|
// The above rects are about the containing frame.
|
|
|
|
// To draw the inline frame as selected, we need to look at the inline frame's own size.
|
|
|
|
TQRect frameRect = crect;
|
|
|
|
#ifdef DEBUG_DRAWING
|
|
|
|
kdDebug() << "KWAnchor::draw selected frame. frameRect=" << frameRect << endl;
|
|
|
|
#endif
|
|
|
|
p->fillRect( frameRect, TQBrush( cg.highlight(), TQBrush::Dense4Pattern) );
|
|
|
|
}
|
|
|
|
p->restore();
|
|
|
|
|
|
|
|
#ifdef DEBUG_DRAWING
|
|
|
|
kdDebug() << "KWAnchor::draw done" << endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
TQSize KWAnchor::size() const
|
|
|
|
{
|
|
|
|
KoSize kosz = m_frameset->floatingFrameSize( m_frameNum );
|
|
|
|
//kdDebug() << "KWAnchor::size in pt: " << kosz.width() << "x" << kosz.height() << endl;
|
|
|
|
KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
|
|
|
|
TQSize sz( zh->ptToLayoutUnitPixX( kosz.width() ), zh->ptToLayoutUnitPixY( kosz.height() ) );
|
|
|
|
//kdDebug() << "KWAnchor::size in LU: " << sz.width() << "x" << sz.height() << endl;
|
|
|
|
//kdDebug() << " size in pixels: " << zh->layoutUnitToPixelX( sz.width() ) << "x"
|
|
|
|
// << zh->layoutUnitToPixelY( sz.height() ) << endl;
|
|
|
|
if ( sz.isNull() ) // for some reason, we don't know the size yet
|
|
|
|
sz = TQSize( width, height ); // LU
|
|
|
|
return sz;
|
|
|
|
}
|
|
|
|
|
|
|
|
int KWAnchor::ascent() const
|
|
|
|
{
|
|
|
|
int baseline = m_frameset->floatingFrameBaseline( m_frameNum );
|
|
|
|
int ret = ( baseline == -1 ) ? height : baseline;
|
|
|
|
//kdDebug() << "KWAnchor::ascent " << ret << endl;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWAnchor::resize()
|
|
|
|
{
|
|
|
|
if ( m_deleted )
|
|
|
|
return;
|
|
|
|
TQSize s = size();
|
|
|
|
if ( width != s.width() || height != s.height() )
|
|
|
|
{
|
|
|
|
width = s.width();
|
|
|
|
height = s.height();
|
|
|
|
kdDebug(32001) << "KWAnchor::resize " << width << "x" << height << endl;
|
|
|
|
KoTextParag * parag = paragraph();
|
|
|
|
if ( parag )
|
|
|
|
{
|
|
|
|
kdDebug(32001) << "KWAnchor::resize invalidating parag " << parag->paragId() << endl;
|
|
|
|
parag->invalidate( 0 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
KCommand * KWAnchor::createCommand()
|
|
|
|
{
|
|
|
|
kdDebug(32001) << "KWAnchor::addCreateCommand" << endl;
|
|
|
|
return m_frameset->anchoredObjectCreateCommand( m_frameNum );
|
|
|
|
}
|
|
|
|
|
|
|
|
KCommand * KWAnchor::deleteCommand()
|
|
|
|
{
|
|
|
|
kdDebug(32001) << "KWAnchor::addDeleteCommand" << endl;
|
|
|
|
return m_frameset->anchoredObjectDeleteCommand( m_frameNum );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWAnchor::setDeleted( bool b )
|
|
|
|
{
|
|
|
|
// Do this first, because setAnchored->updateAllFrames->isDeleted, so it must have the right value already
|
|
|
|
KoTextCustomItem::setDeleted( b );
|
|
|
|
|
|
|
|
kdDebug() << "KWAnchor::setDeleted " << b << endl;
|
|
|
|
if ( b )
|
|
|
|
m_frameset->setAnchored( 0L );
|
|
|
|
else
|
|
|
|
m_frameset->setAnchored( static_cast<KWTextDocument *>(textDocument())->textFrameSet() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWAnchor::save( TQDomElement &parentElem )
|
|
|
|
{
|
|
|
|
TQDomElement anchorElem = parentElem.ownerDocument().createElement( "ANCHOR" );
|
|
|
|
parentElem.appendChild( anchorElem );
|
|
|
|
anchorElem.setAttribute( "type", "frameset" ); // the only possible value currently
|
|
|
|
//KWDocument * doc = textDocument()->textFrameSet()->kWordDocument();
|
|
|
|
// ## TODO save the frame number as well ? Only the first frame ? to be determined
|
|
|
|
// ## or maybe use len=<number of frames>. Difficult :}
|
|
|
|
anchorElem.setAttribute( "instance", m_frameset->name() );
|
|
|
|
}
|
|
|
|
|
|
|
|
void KWAnchor::saveOasis( KoXmlWriter& writer, KoSavingContext& context ) const
|
|
|
|
{
|
|
|
|
if ( m_frameset->canBeSavedAsInlineCharacter() )
|
|
|
|
m_frameset->saveOasis( writer, context, true );
|
|
|
|
else // special case for inline tables [which are not alone in their paragraph, see KWTextParag]
|
|
|
|
{
|
|
|
|
writer.startElement( "draw:frame" );
|
|
|
|
writer.addAttribute( "draw:name", m_frameset->name() + "-Wrapper" );
|
|
|
|
// Mark as wrapper frame. KWTextDocument::loadSpanTag will try to get rid of it upon loading.
|
|
|
|
writer.addAttribute( "koffice:is-wrapper-frame", "true" );
|
|
|
|
//writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) );
|
|
|
|
KoSize kosz = m_frameset->floatingFrameSize( m_frameNum );
|
|
|
|
writer.addAttributePt( "svg:width", kosz.width() );
|
|
|
|
writer.addAttributePt( "svg:height", kosz.height() );
|
|
|
|
writer.startElement( "draw:text-box" );
|
|
|
|
m_frameset->saveOasis( writer, context, true );
|
|
|
|
writer.endElement();
|
|
|
|
writer.endElement();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool KWAnchor::ownLine() const
|
|
|
|
{
|
|
|
|
if ( m_deleted )
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if ( m_frameset)
|
|
|
|
return m_frameset->ownLine();
|
|
|
|
return FALSE;
|
|
|
|
}
|