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
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
virtual void moveFloatingFrame(int frameNum, const KoPoint &position)
Move the frame frameNum to the given position - this is called when the frame is anchored and the anc...
virtual void setAnchorFormat(KoTextFormat *, int)
Tell this frame the format of it's anchor.
Definition KWFrameSet.h:380
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 bool canBeSavedAsInlineCharacter() const
If the frameset is inline, is it ok to save it inside an oasis <text:p>? If not, KWAnchor will create...
Definition KWFrameSet.h:326
virtual void drawContents(TQPainter *painter, const TQRect &crect, const TQColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode, KWFrameViewManager *frameViewManager)
Paint this frameset.
void setAnchored(KWTextFrameSet *textfs, KoTextParag *parag, int index, bool placeHolderExists=false, bool repaint=true)
Make this frameset anchored, with the anchor at paragId,index in the text frameset textfs.
virtual int floatingFrameBaseline(int)
Get the 'baseline' to use for the "floating frame" identified by frameNum.
Definition KWFrameSet.h:397
virtual KoSize floatingFrameSize(int frameNum=0)
Get the size of the "floating frame" identified by frameNum.
TQString name() const
get/set frameset name. For tables in particular, this must be unique
Definition KWFrameSet.h:428
virtual KCommand * anchoredObjectCreateCommand(int frameNum)
Store command for creating an anchored object.
virtual void saveOasis(KoXmlWriter &writer, KoSavingContext &context, bool saveFrames) const =0
Save to OASIS format.
virtual KCommand * anchoredObjectDeleteCommand(int frameNum)
Store command for deleting an anchored object.
Class that knows about all the (visible) frames in the document and will act as a manager between the...
This class represents a single frame.
Definition KWFrame.h:68
bool isCopy() const
Drawing property: if isCopy, this frame is a copy of the previous frame in the frameset.
Definition KWFrame.h:138
This is our KoTextDocument reimplementation, to create KWTextParag instead of KoTextParags,...
Class: KWTextFrameSet Contains text (KoTextObject) and frames to display that text.
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.