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...
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.
void deleteFrame(KWFrame *frm, 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
void saveCommon(TQDomElement &parentElem, bool saveFrames)
save the common attributes for the frameset
This class represents a single frame.
Definition KWFrame.h:68
void startOasisFrame(KoXmlWriter &xmlWriter, KoGenStyles &mainStyles, const TQString &name, const TQString &lastFrameName=TQString()) const
Write out a draw:frame element and its style.
Definition KWFrame.cpp:544
Abstract base class for KWCanvas's view modes.
Definition KWViewMode.h:48