kword

KWAnchor.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001 David Faure <faure@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "KWAnchor.h"
21#include "KWTextFrameSet.h"
22#include "KWDocument.h"
23#include "KWViewMode.h"
24#include "KWView.h"
25#include <KoXmlWriter.h>
26#include <kdebug.h>
27
28//#define DEBUG_DRAWING
29
30KWAnchor::KWAnchor( KoTextDocument *textDocument, KWFrameSet * frameset, int frameNum )
31 : KoTextCustomItem( textDocument),
32 m_frameset( frameset ),
33 m_frameNum( frameNum )
34{
35}
36
37KWAnchor::~KWAnchor()
38{
39 kdDebug(32001) << "KWAnchor::~KWAnchor" << endl;
40}
41
42void KWAnchor::setFormat( KoTextFormat* format )
43{
44 m_frameset->setAnchorFormat( format, m_frameNum );
45}
46
47void KWAnchor::finalize()
48{
49 if ( m_deleted )
50 return;
51
52 int paragx = paragraph()->rect().x();
53 int paragy = paragraph()->rect().y();
54 kdDebug(32001) << this << " KWAnchor::finalize " << x() << "," << y() << " paragx=" << paragx << " paragy=" << paragy << endl;
55
56 KWTextFrameSet * fs = static_cast<KWTextDocument *>(textDocument())->textFrameSet();
57 KoPoint dPoint;
58 if ( fs->internalToDocument( TQPoint( x()+paragx, y()+paragy ), dPoint ) )
59 {
60 //kdDebug(32001) << "KWAnchor::finalize moving frame to " << dPoint.x() << "," << dPoint.y() << endl;
61 // Move the frame to position dPoint.
62 m_frameset->moveFloatingFrame( m_frameNum, dPoint );
63 } else
64 {
65 // This can happen if the page hasn't been created yet
66 kdDebug(32001) << "KWAnchor::move internalToDocument returned 0L for " << x()+paragx << ", " << y()+paragy << endl;
67 }
68}
69
70void KWAnchor::draw( TQPainter* p, int x, int y, int cx, int cy, int cw, int ch, const TQColorGroup& cg, bool selected )
71{
72 // (x,y) is the position of the inline item (in Layout Units)
73 // (cx,cy,cw,ch) is the rectangle to be painted, in layout units too
74
75 if ( m_deleted )
76 return;
77
78 Q_ASSERT( x == xpos );
79 Q_ASSERT( y == ypos );
80 if ( x != xpos || y != ypos )
81 kdDebug() << "Warning: x=" << x << " y=" << y << " xpos=" << xpos << " ypos=" << ypos << endl;
82
83 // The containing text-frameset.
84 KWTextFrameSet * fs = static_cast<KWTextDocument *>(textDocument())->textFrameSet();
85 KoTextZoomHandler* zh = fs->textDocument()->paintingZoomHandler();
86
87 int paragx = paragraph()->rect().x();
88 int paragy = paragraph()->rect().y();
89 TQRect inlineFrameLU( paragx+xpos, paragy+ypos, width, height );
90#ifdef DEBUG_DRAWING
91 kdDebug(32001) << "KWAnchor::draw x:" << x << ", y:" << y << " paragx=" << paragx << " paragy=" << paragy << endl;
92 kdDebug(32001) << " inline frame in LU coordinates: " << inlineFrameLU << endl;
93#endif
94
95 TQRect crectLU = TQRect( (cx > 0 ? cx : 0)+paragx, cy+paragy, cw, ch );
96#ifdef DEBUG_DRAWING
97 kdDebug(32001) << " crect in LU coordinates: " << DEBUGRECT( crectLU ) << endl;
98#endif
99
100 crectLU = crectLU.intersect ( inlineFrameLU ); // KoTextParag::paintDefault could even do this
101
102
103#ifdef DEBUG_DRAWING
104 kdDebug(32001) << " crect&frame in LU coordinates: " << DEBUGRECT( crectLU ) << endl;
105#endif
106
107 // Convert crect to document coordinates, first topleft then bottomright
108 TQPoint topLeftLU = crectLU.topLeft();
109 TQPoint bottomRightLU = crectLU.bottomRight();
110 KWFrame* containingFrame = fs->currentDrawnFrame(); // always set, except in the textviewmode
111 if(containingFrame)
112 containingFrame = KWFrameSet::settingsFrame(containingFrame);
113 else { // if its not set (in textviewmode) try to get it from the FS
114 TQPoint paragPos = inlineFrameLU.topLeft();
115 KoPoint dummy(0, 0);
116 containingFrame = fs->internalToDocument(paragPos, dummy);
117 }
118 KoPoint topLeftPt = fs->internalToDocumentKnowingFrame( topLeftLU, containingFrame );
119
120 // Now we can convert the bottomright
121 KoPoint bottomRightPt = fs->internalToDocumentKnowingFrame( bottomRightLU, containingFrame );
122 KoRect crectPt( topLeftPt, bottomRightPt );
123
124 // Convert crect to view coords
125 TQRect crect = fs->currentViewMode()->normalToView( zh->zoomRect( crectPt ) );
126 // and add 1 to right and bottom, to avoid rounding errors (and due to qrect semantics)
127 crect.rBottom() += 2; // HACK: 1 doesn't do it, it leaves a white line along window borders
128 crect.rRight() += 1;
129#ifdef DEBUG_DRAWING
130 kdDebug() << " crect in view coordinates (pixel) : " << DEBUGRECT( crect ) << endl;
131#endif
132
133 // Ok, we finally have our crect in view coordinates!
134 // Now ensure the containing frame is the one actually containing our text
135 // (for copies, e.g. headers and footers, we need to go back until finding a real frame)
136
137 if ( containingFrame && containingFrame->isCopy() )
138 {
139 // Find last real frame, in case we are in a copied frame
140 TQPtrListIterator<KWFrame> frameIt( fs->frameIterator() );
141 frameIt.toLast(); // from the end to avoid a 2*N in the worst case
142 while ( !frameIt.atFirst() && frameIt.current() != containingFrame ) // look for 'containingFrame'
143 --frameIt;
144 if ( frameIt.atFirst() && frameIt.current() != containingFrame )
145 kdWarning() << "KWAnchor::draw: containingFrame not found " << containingFrame << endl;
146 while ( !frameIt.atFirst() && frameIt.current()->isCopy() ) // go back to last non-copy
147 --frameIt;
148 containingFrame = frameIt.current();
149 //kdDebug() << "KWAnchor::draw frame=" << containingFrame << endl;
150 }
151
152 // Same calculation as in internalToDocument, but we know the frame already
153 KoPoint topLeftParagPt( 0, 0 );
154 if ( containingFrame ) // 0 in the textviewmode
155 topLeftParagPt = containingFrame->innerRect().topLeft();
156
157 topLeftParagPt.rx() += zh->layoutUnitPtToPt( zh->pixelYToPt( paragx ) );
158 topLeftParagPt.ry() += zh->layoutUnitPtToPt( zh->pixelYToPt( paragy ) );
159 if ( containingFrame ) // 0 in the textviewmode
160 topLeftParagPt.ry() -= containingFrame->internalY();
161
162 TQPoint topLeftParag = fs->currentViewMode()->normalToView( zh->zoomPoint( topLeftParagPt ) );
163
164 // Finally, make the painter go back to view coord system
165 // (this is exactly the opposite of the code in KWFrameSet::drawContents)
166 // (It does translate(view - internal), so we do translate(internal - view) - e.g. with (0,0) for internal)
167 p->save();
168 p->translate( -topLeftParag.x(), -topLeftParag.y() );
169#ifdef DEBUG_DRAWING
170 kdDebug() << " translating by " << -topLeftParag.x() << "," << -topLeftParag.y() << endl;
171#endif
172
173 TQColorGroup cg2( cg );
174
175 KWFrameViewManager *fvm = 0;
176 if(m_frameset->kWordDocument()) {
177 TQValueList<KWView *> views = m_frameset->kWordDocument()->getAllViews();
178 // Note that "views" is empty when the KWDocument is an (inactive) embedded document
179 if ( !views.isEmpty() )
180 fvm = views.first()->frameViewManager();
181 }
182 m_frameset->drawContents( p, crect, cg2, false, true, 0L, fs->currentViewMode(), fvm);
183
184 if( selected && placement() == PlaceInline && p->device()->devType() != TQInternal::Printer )
185 {
186 // The above rects are about the containing frame.
187 // To draw the inline frame as selected, we need to look at the inline frame's own size.
188 TQRect frameRect = crect;
189#ifdef DEBUG_DRAWING
190 kdDebug() << "KWAnchor::draw selected frame. frameRect=" << frameRect << endl;
191#endif
192 p->fillRect( frameRect, TQBrush( cg.highlight(), TQBrush::Dense4Pattern) );
193 }
194 p->restore();
195
196#ifdef DEBUG_DRAWING
197 kdDebug() << "KWAnchor::draw done" << endl;
198#endif
199}
200
201TQSize KWAnchor::size() const
202{
203 KoSize kosz = m_frameset->floatingFrameSize( m_frameNum );
204 //kdDebug() << "KWAnchor::size in pt: " << kosz.width() << "x" << kosz.height() << endl;
205 KoTextZoomHandler * zh = textDocument()->formattingZoomHandler();
206 TQSize sz( zh->ptToLayoutUnitPixX( kosz.width() ), zh->ptToLayoutUnitPixY( kosz.height() ) );
207 //kdDebug() << "KWAnchor::size in LU: " << sz.width() << "x" << sz.height() << endl;
208 //kdDebug() << " size in pixels: " << zh->layoutUnitToPixelX( sz.width() ) << "x"
209 // << zh->layoutUnitToPixelY( sz.height() ) << endl;
210 if ( sz.isNull() ) // for some reason, we don't know the size yet
211 sz = TQSize( width, height ); // LU
212 return sz;
213}
214
215int KWAnchor::ascent() const
216{
217 int baseline = m_frameset->floatingFrameBaseline( m_frameNum );
218 int ret = ( baseline == -1 ) ? height : baseline;
219 //kdDebug() << "KWAnchor::ascent " << ret << endl;
220 return ret;
221}
222
223void KWAnchor::resize()
224{
225 if ( m_deleted )
226 return;
227 TQSize s = size();
228 if ( width != s.width() || height != s.height() )
229 {
230 width = s.width();
231 height = s.height();
232 kdDebug(32001) << "KWAnchor::resize " << width << "x" << height << endl;
233 KoTextParag * parag = paragraph();
234 if ( parag )
235 {
236 kdDebug(32001) << "KWAnchor::resize invalidating parag " << parag->paragId() << endl;
237 parag->invalidate( 0 );
238 }
239 }
240}
241
242KCommand * KWAnchor::createCommand()
243{
244 kdDebug(32001) << "KWAnchor::addCreateCommand" << endl;
245 return m_frameset->anchoredObjectCreateCommand( m_frameNum );
246}
247
248KCommand * KWAnchor::deleteCommand()
249{
250 kdDebug(32001) << "KWAnchor::addDeleteCommand" << endl;
251 return m_frameset->anchoredObjectDeleteCommand( m_frameNum );
252}
253
254void KWAnchor::setDeleted( bool b )
255{
256 // Do this first, because setAnchored->updateAllFrames->isDeleted, so it must have the right value already
257 KoTextCustomItem::setDeleted( b );
258
259 kdDebug() << "KWAnchor::setDeleted " << b << endl;
260 if ( b )
261 m_frameset->setAnchored( 0L );
262 else
263 m_frameset->setAnchored( static_cast<KWTextDocument *>(textDocument())->textFrameSet() );
264}
265
266void KWAnchor::save( TQDomElement &parentElem )
267{
268 TQDomElement anchorElem = parentElem.ownerDocument().createElement( "ANCHOR" );
269 parentElem.appendChild( anchorElem );
270 anchorElem.setAttribute( "type", "frameset" ); // the only possible value currently
271 //KWDocument * doc = textDocument()->textFrameSet()->kWordDocument();
272 // ## TODO save the frame number as well ? Only the first frame ? to be determined
273 // ## or maybe use len=<number of frames>. Difficult :}
274 anchorElem.setAttribute( "instance", m_frameset->name() );
275}
276
277void KWAnchor::saveOasis( KoXmlWriter& writer, KoSavingContext& context ) const
278{
279 if ( m_frameset->canBeSavedAsInlineCharacter() )
280 m_frameset->saveOasis( writer, context, true );
281 else // special case for inline tables [which are not alone in their paragraph, see KWTextParag]
282 {
283 writer.startElement( "draw:frame" );
284 writer.addAttribute( "draw:name", m_frameset->name() + "-Wrapper" );
285 // Mark as wrapper frame. KWTextDocument::loadSpanTag will try to get rid of it upon loading.
286 writer.addAttribute( "koffice:is-wrapper-frame", "true" );
287 //writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) );
288 KoSize kosz = m_frameset->floatingFrameSize( m_frameNum );
289 writer.addAttributePt( "svg:width", kosz.width() );
290 writer.addAttributePt( "svg:height", kosz.height() );
291 writer.startElement( "draw:text-box" );
292 m_frameset->saveOasis( writer, context, true );
293 writer.endElement();
294 writer.endElement();
295 }
296}
297
298bool KWAnchor::ownLine() const
299{
300 if ( m_deleted )
301 return false;
302
303 if ( m_frameset)
304 return m_frameset->ownLine();
305 return false;
306}
KWAnchor(KoTextDocument *textdoc, KWFrameSet *frameset, int frameNum)
Constructor.
Definition KWAnchor.cpp:30
int frameNum() const
The index the frameset needs to access which content is displayed in the anchor object.
Definition KWAnchor.h:52
TQSize size() const
Return the size of the item, i.e.
Definition KWAnchor.cpp:201
Class: KWFrameSet Base type, a frameset holds content as well as frames to show that content.
Definition KWFrameSet.h:62
static KWFrame * settingsFrame(const KWFrame *frame)
Returns the original frame that the param frame is a copy off, or the frame itself.
const TQPtrList< KWFrame > & frameIterator() const
Iterator over the child frames.
Definition KWFrameSet.h:159
virtual int floatingFrameBaseline(int)
Get the 'baseline' to use for the "floating frame" identified by frameNum.
Definition KWFrameSet.h:397
bool isCopy() const
Drawing property: if isCopy, this frame is a copy of the previous frame in the frameset.
Definition KWFrame.h:138
KoPoint internalToDocumentKnowingFrame(const KoPoint &relPoint, KWFrame *theFrame) const
A variant of internalToDocument, when the frame is already known.
KWFrame * internalToDocument(const KoPoint &relPoint, KoPoint &dPoint) const
Convert the in the internal qtextdoc coordinates (in layout units) into a point in the document coord...
KWViewMode * currentViewMode() const
The viewmode that was passed to drawContents.
KWFrame * currentDrawnFrame() const
The frame that we are currently drawing in drawFrame.
virtual TQPoint normalToView(const TQPoint &nPoint)=0
Normal coord -> view coord.