kword

KWFormulaFrameSet.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU 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 program 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 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING. 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 <tqfile.h>
21
22#include "KWFormulaFrameSet.h"
23
24#include "KWDocument.h"
25#include "KWView.h"
26#include "KWViewMode.h"
27#include "KWCanvas.h"
28#include "KWFrame.h"
29#include "defs.h"
30
31#include <kformulacontainer.h>
32#include <kformuladocument.h>
33#include <kformulaview.h>
34#include <KoOasisContext.h>
35#include <KoXmlNS.h>
36#include <KoXmlWriter.h>
37
38#include <tdelocale.h>
39#include <tdemessagebox.h>
40#include <kdebug.h>
41#include <tdetempfile.h>
42#include <dcopobject.h>
43#include "KWordFormulaFrameSetIface.h"
44#include "KWordFormulaFrameSetEditIface.h"
45
46#include <assert.h>
47
48// #ifdef __GNUC__
49// #undef k_funcinfo
50// #define k_funcinfo "[\033[36m" << __PRETTY_FUNCTION__ << "\033[m] "
51// #endif
52
53/******************************************************************/
54/* Class: KWFormulaFrameSet */
55/******************************************************************/
56KWFormulaFrameSet::KWFormulaFrameSet( KWDocument *doc, const TQString & name )
57 : KWFrameSet( doc ), m_changed( false ), m_edit( 0 )
58{
59 if ( name.isEmpty() )
60 m_name = doc->generateFramesetName( i18n( "Formula %1" ) );
61 else
62 m_name = name;
63
64 init();
65}
66
67KWFormulaFrameSet::KWFormulaFrameSet( KWDocument* doc, const TQDomElement& frameTag,
68 const TQDomElement& mathTag, KoOasisContext& context )
69 : KWFrameSet( doc ), m_changed( false ), m_edit( 0 )
70{
71 m_name = frameTag.attributeNS( KoXmlNS::draw, "name", TQString() );
72 if ( doc->frameSetByName( m_name ) ) // already exists!
73 m_name = doc->generateFramesetName( m_name + " %1" );
74
75 init();
76
77 context.styleStack().save();
78 context.fillStyleStack( frameTag, KoXmlNS::draw, "style-name", "graphic" ); // get the style for the graphics element
79 /*KWFrame* frame =*/ loadOasisFrame( frameTag, context );
80 context.styleStack().restore();
81
82 formula->loadMathML( mathTag );
83}
84
85void KWFormulaFrameSet::init()
86{
87 // The newly created formula is not yet part of the formula
88 // document. It will be added when a frame is created.
89 formula = m_doc->formulaDocument()->createFormula( -1, false );
90
91 // With the new drawing scheme (drawFrame being called with translated painter)
92 // there is no need to move the KFormulaContainer anymore, it remains at (0,0).
93 formula->moveTo( 0, 0 );
94
95 connect( formula, TQ_SIGNAL( formulaChanged( double, double ) ),
96 this, TQ_SLOT( slotFormulaChanged( double, double ) ) );
97 connect( formula, TQ_SIGNAL( errorMsg( const TQString& ) ),
98 this, TQ_SLOT( slotErrorMessage( const TQString& ) ) );
99
100 /*
101 if ( isFloating() ) {
102 // we need to look for the anchor every time, don't cache this value.
103 // undo/redo creates/deletes anchors
104 KWAnchor * anchor = findAnchor( 0 );
105 if ( anchor ) {
106 KoTextFormat * format = anchor->format();
107 formula->setFontSize( format->pointSize() );
108 }
109 }
110 */
111 TQRect rect = formula->boundingRect();
112 slotFormulaChanged(rect.width(), rect.height());
113}
114
115KWordFrameSetIface* KWFormulaFrameSet::dcopObject()
116{
117 if ( !m_dcop )
118 m_dcop = new KWordFormulaFrameSetIface( this );
119
120 return m_dcop;
121}
122
123KWFormulaFrameSet::~KWFormulaFrameSet()
124{
125 kdDebug() << k_funcinfo << endl;
126 delete formula;
127}
128
129void KWFormulaFrameSet::addFrame( KWFrame *frame, bool recalc )
130{
131 kdDebug() << k_funcinfo << endl;
132 if ( formula ) {
133 frame->setWidth( formula->width() );
134 frame->setHeight( formula->height() );
135 }
136 KWFrameSet::addFrame( frame, recalc );
137 if ( formula ) {
138 formula->registerFormula();
139 }
140}
141
142void KWFormulaFrameSet::deleteFrame( unsigned int num, bool remove, bool recalc )
143{
144 kdDebug() << k_funcinfo << endl;
145 assert( num == 0 );
146 KWFrameSet::deleteFrame( num, remove, recalc );
147 formula->unregisterFormula();
148}
149
150
151KWFrameSetEdit* KWFormulaFrameSet::createFrameSetEdit(KWCanvas* canvas)
152{
153 return new KWFormulaFrameSetEdit(this, canvas);
154}
155
156void KWFormulaFrameSet::drawFrameContents( KWFrame* /*frame*/,
157 TQPainter* painter, const TQRect& crect,
158 const TQColorGroup& cg, bool onlyChanged,
159 bool resetChanged,
160 KWFrameSetEdit* /*edit*/, KWViewMode * )
161{
162 if ( m_changed || !onlyChanged )
163 {
164 if ( resetChanged )
165 m_changed = false;
166
167 bool printing = painter->device()->devType() == TQInternal::Printer;
168 bool clipping = true;
169 TQPainter *p;
170 TQPixmap* pix = 0L;
171 if ( printing ) {
172 p = painter;
173 clipping = painter->hasClipping();
174
175 // That's unfortunate for formulas wider than the page.
176 // However it helps a lot with ordinary formulas.
177 painter->setClipping( false );
178 }
179 else {
180 pix = doubleBufferPixmap( crect.size() );
181 p = new TQPainter( pix );
182 p->translate( -crect.x(), -crect.y() );
183 }
184
185 if ( m_edit ) {
186 //KWFormulaFrameSetEdit * formulaEdit = static_cast<KWFormulaFrameSetEdit *>(edit);
187 if ( m_edit->getFormulaView() ) {
188 m_edit->getFormulaView()->draw( *p, crect, cg );
189 }
190 else {
191 formula->draw( *p, crect, cg );
192 }
193 }
194 else {
195 formula->draw( *p, crect, cg );
196 }
197
198 if ( !printing ) {
199 p->end();
200 delete p;
201 painter->drawPixmap( crect.topLeft(), *pix );
202 }
203 else {
204 painter->setClipping( clipping );
205 }
206 }
207}
208
209
210void KWFormulaFrameSet::slotFormulaChanged( double width, double height )
211{
212 if ( m_frames.isEmpty() )
213 return;
214
215 double oldWidth = m_frames.first()->width();
216 double oldHeight = m_frames.first()->height();
217
218 m_frames.first()->setWidth( width );
219 m_frames.first()->setHeight( height );
220
221 updateFrames();
222 kWordDocument()->layout();
223 if ( ( oldWidth != width ) || ( oldHeight != height ) ) {
224 kWordDocument()->repaintAllViews( false );
225 kWordDocument()->updateRulerFrameStartEnd();
226 }
227
228 m_changed = true;
229
230 if ( !m_edit ) {
231 // A change without a FrameSetEdit! This must be the result of
232 // an undo. We need to evaluate.
233 formula->startEvaluation();
234 }
235}
236
237void KWFormulaFrameSet::slotErrorMessage( const TQString& msg )
238{
239 KMessageBox::error( /*m_widget*/ 0, msg );
240}
241
242MouseMeaning KWFormulaFrameSet::getMouseMeaningInsideFrame( const KoPoint& )
243{
244 return MEANING_MOUSE_INSIDE_TEXT;
245}
246
247TQDomElement KWFormulaFrameSet::save(TQDomElement& parentElem, bool saveFrames)
248{
249 if ( m_frames.isEmpty() ) // Deleted frameset -> don't save
250 return TQDomElement();
251 TQDomElement framesetElem = parentElem.ownerDocument().createElement("FRAMESET");
252 parentElem.appendChild(framesetElem);
253
254 KWFrameSet::saveCommon(framesetElem, saveFrames);
255
256 TQDomElement formulaElem = parentElem.ownerDocument().createElement("FORMULA");
257 framesetElem.appendChild(formulaElem);
258 formula->save(formulaElem);
259 return framesetElem;
260}
261
262void KWFormulaFrameSet::saveOasis(KoXmlWriter& writer, KoSavingContext& context, bool) const
263{
264 KWFrame *frame = m_frames.getFirst();
265 frame->startOasisFrame( writer, context.mainStyles(), name() );
266
267 KTempFile contentTmpFile;
268 contentTmpFile.setAutoDelete( true );
269 TQFile* tmpFile = contentTmpFile.file();
270
271 TQTextStream stream(tmpFile);
272 stream.setEncoding( TQTextStream::UnicodeUTF8 );
273 formula->saveMathML( stream, true );
274 tmpFile->close();
275
276 writer.startElement( "draw:object" );
277 writer.startElement( "math:math" );
278 writer.addCompleteElement( tmpFile );
279 writer.endElement(); // math:math
280 writer.endElement(); // draw:object
281 writer.endElement(); // draw:frame
282}
283
284void KWFormulaFrameSet::load(TQDomElement& attributes, bool loadFrames)
285{
286 KWFrameSet::load(attributes, loadFrames);
287 TQDomElement formulaElem = attributes.namedItem("FORMULA").toElement();
288 paste( formulaElem );
289}
290
291void KWFormulaFrameSet::paste( TQDomNode& formulaElem )
292{
293 if (!formulaElem.isNull()) {
294 if (formula == 0) {
295 formula = m_doc->formulaDocument()->createFormula( -1, false );
296 connect(formula, TQ_SIGNAL(formulaChanged(double, double)),
297 this, TQ_SLOT(slotFormulaChanged(double, double)));
298 connect( formula, TQ_SIGNAL( errorMsg( const TQString& ) ),
299 this, TQ_SLOT( slotErrorMessage( const TQString& ) ) );
300 }
301 m_doc->formulaDocument()->setCreationStrategy( "Oasis" );
302 if ( !formula->loadMathML( formulaElem.firstChild().toElement() ) ) {
303 kdError(32001) << "Error loading formula" << endl;
304 }
305 }
306 else {
307 kdError(32001) << "Missing math tag in FRAMESET" << endl;
308 }
309}
310
311void KWFormulaFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position )
312{
313 kdDebug() << k_funcinfo << endl;
314 KWFrameSet::moveFloatingFrame( frameNum, position );
315 if ( !m_frames.isEmpty() ) {
316 formula->setDocumentPosition( position.x(), position.y()+formula->baseline() );
317 }
318}
319
320int KWFormulaFrameSet::floatingFrameBaseline( int /*frameNum*/ )
321{
322 if ( !m_frames.isEmpty() )
323 {
324 return m_doc->ptToLayoutUnitPixY( formula->baseline() );
325 }
326 return -1;
327}
328
329void KWFormulaFrameSet::setAnchorFormat( KoTextFormat* format, int /*frameNum*/ )
330{
331 if ( !m_frames.isEmpty() ) {
332 formula->setFontSizeDirect( format->pointSize() );
333 }
334}
335
336
337TQPixmap* KWFormulaFrameSet::m_bufPixmap = 0;
338
339// stolen from KWDocument
340// However, I don't see if a formula frame can be an underlying
341// frame. That is why I use my own buffer.
342TQPixmap* KWFormulaFrameSet::doubleBufferPixmap( const TQSize& s )
343{
344 if ( !m_bufPixmap ) {
345 int w = TQABS( s.width() );
346 int h = TQABS( s.height() );
347 m_bufPixmap = new TQPixmap( w, h );
348 } else {
349 if ( m_bufPixmap->width() < s.width() ||
350 m_bufPixmap->height() < s.height() ) {
351 m_bufPixmap->resize( TQMAX( s.width(), m_bufPixmap->width() ),
352 TQMAX( s.height(), m_bufPixmap->height() ) );
353 }
354 }
355
356 return m_bufPixmap;
357}
358
359
360KWFormulaFrameSetEdit::KWFormulaFrameSetEdit(KWFormulaFrameSet* fs, KWCanvas* canvas)
361 : KWFrameSetEdit(fs, canvas)
362{
363 formulaView = new KFormula::View( fs->getFormula() );
364
365 connect( formulaView, TQ_SIGNAL( cursorChanged( bool, bool ) ),
366 this, TQ_SLOT( cursorChanged( bool, bool ) ) );
367 connect( fs->getFormula(), TQ_SIGNAL( leaveFormula( Container*, FormulaCursor*, int ) ),
368 this, TQ_SLOT( slotLeaveFormula( Container*, FormulaCursor*, int ) ) );
369
370 fs->m_edit = this;
371
372 m_canvas->gui()->getView()->showFormulaToolbar(true);
373 focusInEvent();
374 dcop=0;
375}
376
377DCOPObject* KWFormulaFrameSetEdit::dcopObject()
378{
379 if ( !dcop )
380 dcop = new KWordFormulaFrameSetEditIface( this );
381 return dcop;
382}
383
384KWFormulaFrameSetEdit::~KWFormulaFrameSetEdit()
385{
386 formulaFrameSet()->m_edit = 0;
387 focusOutEvent();
388 // this causes a core dump on quit
389 m_canvas->gui()->getView()->showFormulaToolbar(false);
390 delete formulaView;
391 formulaView = 0;
392 formulaFrameSet()->getFormula()->startEvaluation();
393 formulaFrameSet()->setChanged();
394 m_canvas->repaintChanged( formulaFrameSet(), true );
395 delete dcop;
396}
397
398const KFormula::View* KWFormulaFrameSetEdit::getFormulaView() const { return formulaView; }
399KFormula::View* KWFormulaFrameSetEdit::getFormulaView() { return formulaView; }
400
401void KWFormulaFrameSetEdit::keyPressEvent( TQKeyEvent* event )
402{
403 //kdDebug(32001) << "KWFormulaFrameSetEdit::keyPressEvent" << endl;
404 formulaView->keyPressEvent( event );
405}
406
407void KWFormulaFrameSetEdit::mousePressEvent( TQMouseEvent* event,
408 const TQPoint&,
409 const KoPoint& pos )
410{
411 // [Note that this method is called upon RMB and MMB as well, now]
412 KoPoint tl = m_currentFrame->topLeft();
413 formulaView->mousePressEvent( event, pos-tl );
414}
415
416void KWFormulaFrameSetEdit::mouseMoveEvent( TQMouseEvent* event,
417 const TQPoint&,
418 const KoPoint& pos )
419{
420 KoPoint tl = m_currentFrame->topLeft();
421 formulaView->mouseMoveEvent( event, pos-tl );
422}
423
424void KWFormulaFrameSetEdit::mouseReleaseEvent( TQMouseEvent* event,
425 const TQPoint&,
426 const KoPoint& pos )
427{
428 KoPoint tl = m_currentFrame->topLeft();
429 formulaView->mouseReleaseEvent( event, pos-tl );
430}
431
432void KWFormulaFrameSetEdit::focusInEvent()
433{
434 //kdDebug(32001) << "KWFormulaFrameSetEdit::focusInEvent" << endl;
435 if ( formulaView != 0 ) {
436 formulaView->focusInEvent(0);
437 }
438}
439
440void KWFormulaFrameSetEdit::focusOutEvent()
441{
442 //kdDebug(32001) << "KWFormulaFrameSetEdit::focusOutEvent" <<
443 //endl;
444 if ( formulaView != 0 ) {
445 formulaView->focusOutEvent(0);
446 }
447}
448
449void KWFormulaFrameSetEdit::copy()
450{
451 formulaView->getDocument()->copy();
452}
453
454void KWFormulaFrameSetEdit::cut()
455{
456 formulaView->getDocument()->cut();
457}
458
459void KWFormulaFrameSetEdit::paste()
460{
461 formulaView->getDocument()->paste();
462}
463
464void KWFormulaFrameSetEdit::pasteData( TQMimeSource* /*data*/, int /*provides*/, bool )
465{
466 paste(); // TODO use data, for DnD
467}
468
469void KWFormulaFrameSetEdit::selectAll()
470{
471 formulaView->slotSelectAll();
472}
473
474void KWFormulaFrameSetEdit::moveHome()
475{
476 formulaView->moveHome( KFormula::WordMovement );
477}
478void KWFormulaFrameSetEdit::moveEnd()
479{
480 formulaView->moveEnd( KFormula::WordMovement );
481}
482
483void KWFormulaFrameSetEdit::removeFormula()
484{
485 if ( formulaFrameSet()->isFloating() ) {
486 KWCanvas* canvas = m_canvas;
487
488 // This call will destroy us! We cannot use 'this' afterwards!
489 exitRight();
490
491 TQKeyEvent keyEvent( TQEvent::KeyPress, Key_Backspace, 0, 0 );
492 canvas->currentFrameSetEdit()->keyPressEvent( &keyEvent );
493 }
494}
495
496void KWFormulaFrameSetEdit::cursorChanged( bool visible, bool /*selecting*/ )
497{
498 if ( visible ) {
499 if ( m_currentFrame )
500 {
501 // Add the cursor position to the (zoomed) frame position
502 TQPoint nPoint = frameSet()->kWordDocument()->zoomPoint( m_currentFrame->topLeft() );
503 nPoint += formulaView->getCursorPoint();
504 // Apply viewmode conversion
505 TQPoint p = m_canvas->viewMode()->normalToView( nPoint );
506 m_canvas->ensureVisible( p.x(), p.y() );
507 }
508 }
509 formulaFrameSet()->setChanged();
510 m_canvas->repaintChanged( formulaFrameSet(), true );
511}
512
513void KWFormulaFrameSetEdit::slotLeaveFormula( KFormula::Container*,
514 KFormula::FormulaCursor* cursor,
515 int cmd )
516{
517 kdDebug() << k_funcinfo << endl;
518
519 if ( cursor == formulaView->getCursor() ) {
520 switch ( cmd ) {
521 case KFormula::Container::EXIT_LEFT:
522 exitLeft();
523 break;
524 case KFormula::Container::EXIT_RIGHT:
525 exitRight();
526 break;
527 case KFormula::Container::EXIT_ABOVE:
528 exitLeft();
529 break;
530 case KFormula::Container::EXIT_BELOW:
531 exitRight();
532 break;
533 case KFormula::Container::REMOVE_FORMULA:
534 removeFormula();
535 break;
536 }
537 }
538}
539
540#include "KWFormulaFrameSet.moc"
Class: KWCanvas This class is responsible for the rendering of the frames to the screen as well as th...
Definition KWCanvas.h:61
This object is created to edit a particular frameset in a particular view The view's canvas creates i...
bool exitLeft()
Called if the cursor tries to leave the frameset at its beginning.
bool exitRight()
Called if the cursor tries to leave the frameset at its end.
KWFrame * m_currentFrame
The Frameset-Edit implementation is responsible for updating that one (to the frame where the current...
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 deleteFrame(unsigned int num, bool remove=true, bool recalc=true)
Delete a frame from the set of frames this frameSet has.
virtual void load(TQDomElement &framesetElem, bool loadFrames=true)
load from XML - when loading
virtual void updateFrames(int flags=0xff)
Called when our frames change, or when another frameset's frames change.
void saveCommon(TQDomElement &parentElem, bool saveFrames)
save the common attributes for the frameset
KWFrame * frame(unsigned int _num) const
get a frame by number
TQString name() const
get/set frameset name. For tables in particular, this must be unique
Definition KWFrameSet.h:428
This class represents a single frame.
Definition KWFrame.h:68
Abstract base class for KWCanvas's view modes.
Definition KWViewMode.h:48