kword

KWAnchor.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "KWAnchor.h"
00021 #include "KWTextFrameSet.h"
00022 #include "KWDocument.h"
00023 #include "KWViewMode.h"
00024 #include "KWView.h"
00025 #include <KoXmlWriter.h>
00026 #include <kdebug.h>
00027 
00028 //#define DEBUG_DRAWING
00029 
00030 KWAnchor::KWAnchor( KoTextDocument *textDocument, KWFrameSet * frameset, int frameNum )
00031     : KoTextCustomItem( textDocument),
00032       m_frameset( frameset ),
00033       m_frameNum( frameNum )
00034 {
00035 }
00036 
00037 KWAnchor::~KWAnchor()
00038 {
00039     kdDebug(32001) << "KWAnchor::~KWAnchor" << endl;
00040 }
00041 
00042 void KWAnchor::setFormat( KoTextFormat* format )
00043 {
00044     m_frameset->setAnchorFormat( format, m_frameNum );
00045 }
00046 
00047 void KWAnchor::finalize()
00048 {
00049     if ( m_deleted )
00050         return;
00051 
00052     int paragx = paragraph()->rect().x();
00053     int paragy = paragraph()->rect().y();
00054     kdDebug(32001) << this << " KWAnchor::finalize " << x() << "," << y() << " paragx=" << paragx << " paragy=" << paragy << endl;
00055 
00056     KWTextFrameSet * fs = static_cast<KWTextDocument *>(textDocument())->textFrameSet();
00057     KoPoint dPoint;
00058     if ( fs->internalToDocument( QPoint( x()+paragx, y()+paragy ), dPoint ) )
00059     {
00060         //kdDebug(32001) << "KWAnchor::finalize moving frame to " << dPoint.x() << "," << dPoint.y() << endl;
00061         // Move the frame to position dPoint.
00062         m_frameset->moveFloatingFrame( m_frameNum, dPoint );
00063     } else
00064     {
00065         // This can happen if the page hasn't been created yet
00066         kdDebug(32001) << "KWAnchor::move internalToDocument returned 0L for " << x()+paragx << ", " << y()+paragy << endl;
00067     }
00068 }
00069 
00070 void KWAnchor::draw( QPainter* p, int x, int y, int cx, int cy, int cw, int ch, const QColorGroup& cg, bool selected )
00071 {
00072     // (x,y) is the position of the inline item (in Layout Units)
00073     // (cx,cy,cw,ch) is the rectangle to be painted, in layout units too
00074 
00075     if ( m_deleted )
00076         return;
00077 
00078     Q_ASSERT( x == xpos );
00079     Q_ASSERT( y == ypos );
00080     if ( x != xpos || y != ypos )
00081         kdDebug() << "Warning: x=" << x << " y=" << y << " xpos=" << xpos << " ypos=" << ypos << endl;
00082 
00083     // The containing text-frameset.
00084     KWTextFrameSet * fs = static_cast<KWTextDocument *>(textDocument())->textFrameSet();
00085     KoTextZoomHandler* zh = fs->textDocument()->paintingZoomHandler();
00086 
00087     int paragx = paragraph()->rect().x();
00088     int paragy = paragraph()->rect().y();
00089     QRect inlineFrameLU( paragx+xpos, paragy+ypos, width, height );
00090 #ifdef DEBUG_DRAWING
00091     kdDebug(32001) << "KWAnchor::draw x:" << x << ", y:" << y << " paragx=" << paragx << " paragy=" << paragy << endl;
00092     kdDebug(32001) << "               inline frame in LU coordinates: " << inlineFrameLU << endl;
00093 #endif
00094 
00095     QRect crectLU = QRect( (cx > 0 ? cx : 0)+paragx, cy+paragy, cw, ch );
00096 #ifdef DEBUG_DRAWING
00097     kdDebug(32001) << "               crect in LU coordinates: " << DEBUGRECT( crectLU ) << endl;
00098 #endif
00099 
00100     crectLU = crectLU.intersect ( inlineFrameLU ); // KoTextParag::paintDefault could even do this
00101 
00102 
00103 #ifdef DEBUG_DRAWING
00104     kdDebug(32001) << "               crect&frame in LU coordinates: " << DEBUGRECT( crectLU ) << endl;
00105 #endif
00106 
00107     // Convert crect to document coordinates, first topleft then bottomright
00108     QPoint topLeftLU = crectLU.topLeft();
00109     QPoint bottomRightLU = crectLU.bottomRight();
00110     KWFrame* containingFrame = fs->currentDrawnFrame(); // always set, except in the textviewmode
00111     if(containingFrame)
00112         containingFrame = KWFrameSet::settingsFrame(containingFrame);
00113     else { // if its not set (in textviewmode) try to get it from the FS
00114         QPoint paragPos = inlineFrameLU.topLeft();
00115         KoPoint dummy(0, 0);
00116         containingFrame = fs->internalToDocument(paragPos, dummy);
00117     }
00118     KoPoint topLeftPt = fs->internalToDocumentKnowingFrame( topLeftLU, containingFrame );
00119 
00120     // Now we can convert the bottomright
00121     KoPoint bottomRightPt = fs->internalToDocumentKnowingFrame( bottomRightLU, containingFrame );
00122     KoRect crectPt( topLeftPt, bottomRightPt );
00123 
00124     // Convert crect to view coords
00125     QRect crect = fs->currentViewMode()->normalToView( zh->zoomRect( crectPt ) );
00126     // and add 1 to right and bottom, to avoid rounding errors (and due to qrect semantics)
00127     crect.rBottom() += 2; // HACK: 1 doesn't do it, it leaves a white line along window borders
00128     crect.rRight() += 1;
00129 #ifdef DEBUG_DRAWING
00130     kdDebug() << "               crect in view coordinates (pixel) : " << DEBUGRECT( crect ) << endl;
00131 #endif
00132 
00133     // Ok, we finally have our crect in view coordinates!
00134     // Now ensure the containing frame is the one actually containing our text
00135     // (for copies, e.g. headers and footers, we need to go back until finding a real frame)
00136 
00137     if ( containingFrame && containingFrame->isCopy() )
00138     {
00139         // Find last real frame, in case we are in a copied frame
00140         QPtrListIterator<KWFrame> frameIt( fs->frameIterator() );
00141         frameIt.toLast(); // from the end to avoid a 2*N in the worst case
00142         while ( !frameIt.atFirst() && frameIt.current() != containingFrame ) // look for 'containingFrame'
00143             --frameIt;
00144         if ( frameIt.atFirst() && frameIt.current() != containingFrame )
00145             kdWarning() << "KWAnchor::draw: containingFrame not found " << containingFrame << endl;
00146         while ( !frameIt.atFirst() && frameIt.current()->isCopy() ) // go back to last non-copy
00147             --frameIt;
00148         containingFrame = frameIt.current();
00149         //kdDebug() << "KWAnchor::draw frame=" << containingFrame << endl;
00150     }
00151 
00152     // Same calculation as in internalToDocument, but we know the frame already
00153     KoPoint topLeftParagPt( 0, 0 );
00154     if ( containingFrame ) // 0 in the textviewmode
00155         topLeftParagPt = containingFrame->innerRect().topLeft();
00156 
00157     topLeftParagPt.rx() += zh->layoutUnitPtToPt( zh->pixelYToPt( paragx ) );
00158     topLeftParagPt.ry() += zh->layoutUnitPtToPt( zh->pixelYToPt( paragy ) );
00159     if ( containingFrame ) // 0 in the textviewmode
00160         topLeftParagPt.ry() -= containingFrame->internalY();
00161 
00162     QPoint topLeftParag = fs->currentViewMode()->normalToView( zh->zoomPoint( topLeftParagPt ) );
00163 
00164     // Finally, make the painter go back to view coord system
00165     // (this is exactly the opposite of the code in KWFrameSet::drawContents)
00166     // (It does translate(view - internal), so we do translate(internal - view) - e.g. with (0,0) for internal)
00167     p->save();
00168     p->translate( -topLeftParag.x(), -topLeftParag.y() );
00169 #ifdef DEBUG_DRAWING
00170     kdDebug() << "               translating by " << -topLeftParag.x() << "," << -topLeftParag.y() << endl;
00171 #endif
00172 
00173     QColorGroup cg2( cg );
00174 
00175     KWFrameViewManager *fvm = 0;
00176     if(m_frameset->kWordDocument()) {
00177         QValueList<KWView *> views = m_frameset->kWordDocument()->getAllViews();
00178         // Note that "views" is empty when the KWDocument is an (inactive) embedded document
00179         if ( !views.isEmpty() )
00180             fvm = views.first()->frameViewManager();
00181     }
00182     m_frameset->drawContents( p, crect, cg2, false, true, 0L, fs->currentViewMode(), fvm);
00183 
00184     if( selected && placement() == PlaceInline && p->device()->devType() != QInternal::Printer )
00185     {
00186         // The above rects are about the containing frame.
00187         // To draw the inline frame as selected, we need to look at the inline frame's own size.
00188         QRect frameRect = crect;
00189 #ifdef DEBUG_DRAWING
00190         kdDebug() << "KWAnchor::draw selected frame. frameRect=" << frameRect << endl;
00191 #endif
00192         p->fillRect( frameRect, QBrush( cg.highlight(), QBrush::Dense4Pattern) );
00193     }
00194     p->restore();
00195 
00196 #ifdef DEBUG_DRAWING
00197     kdDebug() << "KWAnchor::draw done" << endl;
00198 #endif
00199 }
00200 
00201 QSize KWAnchor::size() const
00202 {
00203     KoSize kosz = m_frameset->floatingFrameSize( m_frameNum );
00204     //kdDebug() << "KWAnchor::size in pt: " << kosz.width() << "x" << kosz.height() << endl;
00205     KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
00206     QSize sz( zh->ptToLayoutUnitPixX( kosz.width() ), zh->ptToLayoutUnitPixY( kosz.height() ) );
00207     //kdDebug() << "KWAnchor::size in LU: " << sz.width() << "x" << sz.height() << endl;
00208     //kdDebug() << "          size in pixels: " << zh->layoutUnitToPixelX( sz.width() ) << "x"
00209     //          << zh->layoutUnitToPixelY( sz.height() ) << endl;
00210     if ( sz.isNull() ) // for some reason, we don't know the size yet
00211         sz = QSize( width, height ); // LU
00212     return sz;
00213 }
00214 
00215 int KWAnchor::ascent() const
00216 {
00217     int baseline = m_frameset->floatingFrameBaseline( m_frameNum );
00218     int ret = ( baseline == -1 ) ? height : baseline;
00219     //kdDebug() << "KWAnchor::ascent " << ret << endl;
00220     return ret;
00221 }
00222 
00223 void KWAnchor::resize()
00224 {
00225     if ( m_deleted )
00226         return;
00227     QSize s = size();
00228     if ( width != s.width() || height != s.height() )
00229     {
00230         width = s.width();
00231         height = s.height();
00232         kdDebug(32001) << "KWAnchor::resize " << width << "x" << height << endl;
00233         KoTextParag * parag = paragraph();
00234         if ( parag )
00235         {
00236             kdDebug(32001) << "KWAnchor::resize invalidating parag " << parag->paragId() << endl;
00237             parag->invalidate( 0 );
00238         }
00239     }
00240 }
00241 
00242 KCommand * KWAnchor::createCommand()
00243 {
00244     kdDebug(32001) << "KWAnchor::addCreateCommand" << endl;
00245     return m_frameset->anchoredObjectCreateCommand( m_frameNum );
00246 }
00247 
00248 KCommand * KWAnchor::deleteCommand()
00249 {
00250     kdDebug(32001) << "KWAnchor::addDeleteCommand" << endl;
00251     return m_frameset->anchoredObjectDeleteCommand( m_frameNum );
00252 }
00253 
00254 void KWAnchor::setDeleted( bool b )
00255 {
00256     // Do this first, because setAnchored->updateAllFrames->isDeleted, so it must have the right value already
00257     KoTextCustomItem::setDeleted( b );
00258 
00259     kdDebug() << "KWAnchor::setDeleted " << b << endl;
00260     if ( b )
00261         m_frameset->setAnchored( 0L );
00262     else
00263         m_frameset->setAnchored( static_cast<KWTextDocument *>(textDocument())->textFrameSet() );
00264 }
00265 
00266 void KWAnchor::save( QDomElement &parentElem )
00267 {
00268     QDomElement anchorElem = parentElem.ownerDocument().createElement( "ANCHOR" );
00269     parentElem.appendChild( anchorElem );
00270     anchorElem.setAttribute( "type", "frameset" ); // the only possible value currently
00271     //KWDocument * doc = textDocument()->textFrameSet()->kWordDocument();
00272     // ## TODO save the frame number as well ? Only the first frame ? to be determined
00273     // ## or maybe use len=<number of frames>. Difficult :}
00274     anchorElem.setAttribute( "instance", m_frameset->name() );
00275 }
00276 
00277 void KWAnchor::saveOasis( KoXmlWriter& writer, KoSavingContext& context ) const
00278 {
00279     if ( m_frameset->canBeSavedAsInlineCharacter() )
00280         m_frameset->saveOasis( writer, context, true );
00281     else // special case for inline tables [which are not alone in their paragraph, see KWTextParag]
00282     {
00283         writer.startElement( "draw:frame" );
00284         writer.addAttribute( "draw:name", m_frameset->name() + "-Wrapper" );
00285         // Mark as wrapper frame. KWTextDocument::loadSpanTag will try to get rid of it upon loading.
00286         writer.addAttribute( "koffice:is-wrapper-frame", "true" );
00287         //writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) );
00288         KoSize kosz = m_frameset->floatingFrameSize( m_frameNum );
00289         writer.addAttributePt( "svg:width", kosz.width() );
00290         writer.addAttributePt( "svg:height", kosz.height() );
00291         writer.startElement( "draw:text-box" );
00292         m_frameset->saveOasis( writer, context, true );
00293         writer.endElement();
00294         writer.endElement();
00295     }
00296 }
00297 
00298 bool KWAnchor::ownLine() const
00299 {
00300     if ( m_deleted )
00301         return FALSE;
00302 
00303     if ( m_frameset)
00304         return m_frameset->ownLine();
00305     return FALSE;
00306 }
KDE Home | KDE Accessibility Home | Description of Access Keys