diff options
Diffstat (limited to 'kword/KWAnchor.cpp')
-rw-r--r-- | kword/KWAnchor.cpp | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/kword/KWAnchor.cpp b/kword/KWAnchor.cpp new file mode 100644 index 00000000..33242554 --- /dev/null +++ b/kword/KWAnchor.cpp @@ -0,0 +1,306 @@ +/* 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( QPoint( 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( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& 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(); + QRect 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 + + QRect crectLU = QRect( (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 + QPoint topLeftLU = crectLU.topLeft(); + QPoint 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 + QPoint 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 + QRect 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 + QPtrListIterator<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(); + + QPoint 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 + + QColorGroup cg2( cg ); + + KWFrameViewManager *fvm = 0; + if(m_frameset->kWordDocument()) { + QValueList<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() != QInternal::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. + QRect frameRect = crect; +#ifdef DEBUG_DRAWING + kdDebug() << "KWAnchor::draw selected frame. frameRect=" << frameRect << endl; +#endif + p->fillRect( frameRect, QBrush( cg.highlight(), QBrush::Dense4Pattern) ); + } + p->restore(); + +#ifdef DEBUG_DRAWING + kdDebug() << "KWAnchor::draw done" << endl; +#endif +} + +QSize 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(); + QSize 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 = QSize( 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; + QSize 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( QDomElement &parentElem ) +{ + QDomElement 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; +} |