lib

kformulacontainer.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
3 Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqapplication.h>
22#include <tqdom.h>
23#include <tqevent.h>
24#include <tqfile.h>
25#include <tqpainter.h>
26#include <tqpixmap.h>
27#include <tqstring.h>
28#include <tqtextstream.h>
29
30#include <kdebug.h>
31#include <tdelocale.h>
32#include <kprinter.h>
33
34#include "KoGlobal.h"
35#include "bracketelement.h"
36#include "contextstyle.h"
37#include "formulacursor.h"
38#include "formulaelement.h"
39#include "fractionelement.h"
40#include "indexelement.h"
41#include "kformulacommand.h"
42#include "kformulacompatibility.h"
43#include "kformulacontainer.h"
44#include "kformuladocument.h"
45#include "kformulamathmlread.h"
46#include "kformulamimesource.h"
47#include "matrixelement.h"
48#include "rootelement.h"
49#include "sequenceelement.h"
50#include "symbolelement.h"
51#include "symboltable.h"
52#include "spaceelement.h"
53#include "textelement.h"
54
55#include <assert.h>
56
57KFORMULA_NAMESPACE_BEGIN
58using namespace std;
59
60
61struct Container::Container_Impl {
62
63 Container_Impl( Document* doc )
64 : dirty( true ), cursorMoved( false ), document( doc )
65 {
66 }
67
68 ~Container_Impl()
69 {
70 delete internCursor;
71 delete rootElement;
72 document = 0;
73 }
74
78 bool dirty;
79
83 bool cursorMoved;
84
88 FormulaElement* rootElement;
89
93 FormulaCursor* activeCursor;
94
98 FormulaCursor* internCursor;
99
103 Document* document;
104};
105
106
107FormulaElement* Container::rootElement() const { return impl->rootElement; }
108Document* Container::document() const { return impl->document; }
109
110Container::Container( Document* doc, int pos, bool registerMe )
111{
112 impl = new Container_Impl( doc );
113 impl->rootElement = 0;
114 if ( registerMe ) {
115 registerFormula( pos );
116 }
117}
118
119Container::~Container()
120{
121 unregisterFormula();
122 delete impl;
123 impl = 0;
124}
125
126
128{
129 assert( impl->rootElement == 0 );
130 impl->rootElement = createMainSequence();
131 impl->activeCursor = impl->internCursor = createCursor();
132 recalc();
133}
134
135
140
141
146
147
148KoCommandHistory* Container::getHistory() const
149{
150 return document()->getHistory();
151}
152
153
159{
160 emit elementWillVanish(child);
161}
162
168{
169 impl->dirty = true;
170}
171
173{
174 impl->cursorMoved = true;
175}
176
178{
179 emit leaveFormula( this, cursor, EXIT_LEFT );
180}
181
182void Container::moveOutRight( FormulaCursor* cursor )
183{
184 emit leaveFormula( this, cursor, EXIT_RIGHT );
185}
186
187void Container::moveOutAbove( FormulaCursor* cursor )
188{
189 emit leaveFormula( this, cursor, EXIT_ABOVE );
190}
191
192void Container::moveOutBelow( FormulaCursor* cursor )
193{
194 emit leaveFormula( this, cursor, EXIT_BELOW );
195}
196
197void Container::tell( const TQString& msg )
198{
199 emit statusMsg( msg );
200}
201
202void Container::removeFormula( FormulaCursor* cursor )
203{
204 emit leaveFormula( this, cursor, REMOVE_FORMULA );
205}
206
207
209{
210 document()->registerFormula( this, pos );
211}
212
213void Container::unregisterFormula()
214{
215 document()->unregisterFormula( this );
216}
217
218
219void Container::baseSizeChanged( int size, bool owned )
220{
221 if ( owned ) {
222 emit baseSizeChanged( size );
223 }
224 else {
225 const ContextStyle& context = document()->getContextStyle();
226 emit baseSizeChanged( context.baseSize() );
227 }
228}
229
231{
232 return impl->activeCursor;
233}
234
236{
237 return impl->activeCursor;
238}
239
240
246{
247 document()->activate(this);
248 if (cursor != 0) {
249 impl->activeCursor = cursor;
250 }
251 else {
252 *(impl->internCursor) = *(impl->activeCursor);
253 impl->activeCursor = impl->internCursor;
254 }
255}
256
257
258bool Container::hasValidCursor() const
259{
260 return (impl->activeCursor != 0) && !impl->activeCursor->isReadOnly();
261}
262
264{
265 if (impl->dirty) {
266 recalc();
267 }
268}
269
271{
272 impl->dirty = false;
273 ContextStyle& context = impl->document->getContextStyle();
274 rootElement()->calcSizes( context );
275
276 emit formulaChanged( context.layoutUnitToPixelX( rootElement()->getWidth() ),
277 context.layoutUnitToPixelY( rootElement()->getHeight() ) );
278 emit formulaChanged( context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) ),
279 context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) ) );
280 emit cursorMoved( activeCursor() );
281}
282
284{
285 return rootElement()->countChildren() == 0;
286}
287
288
289const SymbolTable& Container::getSymbolTable() const
290{
291 return document()->getSymbolTable();
292}
293
294
295void Container::draw( TQPainter& painter, const TQRect& r, const TQColorGroup& cg, bool edit )
296{
297 painter.fillRect( r, cg.base() );
298 draw( painter, r, edit );
299}
300
301
302void Container::draw( TQPainter& painter, const TQRect& r, bool edit )
303{
304 //ContextStyle& context = document()->getContextStyle( painter.device()->devType() == TQInternal::Printer );
305 ContextStyle& context = document()->getContextStyle( edit );
306 rootElement()->draw( painter, context.pixelToLayoutUnit( r ), context );
307}
308
309
310void Container::checkCursor()
311{
312 if ( impl->cursorMoved ) {
313 impl->cursorMoved = false;
314 emit cursorMoved( activeCursor() );
315 }
316}
317
318void Container::input( TQKeyEvent* event )
319{
320 //if ( !hasValidCursor() )
321 if ( impl->activeCursor == 0 ) {
322 return;
323 }
324 execute( activeCursor()->getElement()->input( this, event ) );
325 checkCursor();
326}
327
328
329void Container::performRequest( Request* request )
330{
331 if ( !hasValidCursor() )
332 return;
333 execute( activeCursor()->getElement()->buildCommand( this, request ) );
334 checkCursor();
335}
336
337
339{
340 if (!hasValidCursor())
341 return;
342 TQClipboard* clipboard = TQApplication::clipboard();
343 const TQMimeSource* source = clipboard->data();
344 if (source->provides( MimeSource::selectionMimeType() )) {
345 TQByteArray data = source->encodedData( MimeSource::selectionMimeType() );
346 TQDomDocument formula;
347 formula.setContent(data);
348 paste( formula, i18n("Paste") );
349 }
350}
351
352void Container::paste( const TQDomDocument& document, TQString desc )
353{
354 FormulaCursor* cursor = activeCursor();
355 TQPtrList<BasicElement> list;
356 list.setAutoDelete( true );
357 if ( cursor->buildElementsFromMathMLDom( document.documentElement(), list ) ) {
358 uint count = list.count();
359 // You must not execute an add command that adds nothing.
360 if (count > 0) {
361 KFCReplace* command = new KFCReplace( desc, this );
362 for (uint i = 0; i < count; i++) {
363 command->addElement(list.take(0));
364 }
365 execute(command);
366 }
367 }
368}
369
371{
372 // read-only cursors are fine for copying.
373 FormulaCursor* cursor = activeCursor();
374 if (cursor != 0) {
375 TQDomDocument formula = document()->createMathMLDomDocument();
376 cursor->copy( formula );
377 TQClipboard* clipboard = TQApplication::clipboard();
378 clipboard->setData(new MimeSource(document(), formula));
379 }
380}
381
383{
384 if (!hasValidCursor())
385 return;
386 FormulaCursor* cursor = activeCursor();
387 if (cursor->isSelection()) {
388 copy();
389 DirectedRemove r( req_remove, beforeCursor );
390 performRequest( &r );
391 }
392}
393
394
395void Container::emitErrorMsg( const TQString& msg )
396{
397 emit errorMsg( msg );
398}
399
400void Container::execute(KCommand* command)
401{
402 if ( command != 0 ) {
403 getHistory()->addCommand(command);
404 }
405}
406
407
409{
410 const ContextStyle& context = document()->getContextStyle();
411 return TQRect( context.layoutUnitToPixelX( rootElement()->getX() ),
412 context.layoutUnitToPixelY( rootElement()->getY() ),
413 context.layoutUnitToPixelX( rootElement()->getWidth() ),
414 context.layoutUnitToPixelY( rootElement()->getHeight() ) );
415}
416
418{
419 if ( impl->activeCursor != 0 ) {
420 const ContextStyle& context = document()->getContextStyle();
421 const LuPixelRect& cursorRect = impl->activeCursor->getCursorSize();
422 return TQRect( context.layoutUnitToPixelX( rootElement()->getX() ),
423 context.layoutUnitToPixelY( rootElement()->getY() ),
424 context.layoutUnitToPixelX( rootElement()->getWidth() ),
425 context.layoutUnitToPixelY( rootElement()->getHeight() ) ) |
426 TQRect( context.layoutUnitToPixelX( cursorRect.x() ),
427 context.layoutUnitToPixelY( cursorRect.y() ),
428 context.layoutUnitToPixelX( cursorRect.width() ),
429 context.layoutUnitToPixelY( cursorRect.height() ) );
430 }
431 return boundingRect();
432}
433
434double Container::width() const
435{
436 const ContextStyle& context = document()->getContextStyle();
437 return context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) );
438}
439
440double Container::height() const
441{
442 const ContextStyle& context = document()->getContextStyle();
443 return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) );
444}
445
447{
448 const ContextStyle& context = document()->getContextStyle();
449 //return context.layoutUnitToPixelY( rootElement()->getBaseline() );
450 return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getBaseline() ) );
451}
452
453void Container::moveTo( int x, int y )
454{
455 const ContextStyle& context = document()->getContextStyle();
456 rootElement()->setX( context.pixelToLayoutUnitX( x ) );
457 rootElement()->setY( context.pixelToLayoutUnitY( y ) );
458}
459
460int Container::fontSize() const
461{
462 if ( rootElement()->hasOwnBaseSize() ) {
463 return rootElement()->getBaseSize();
464 }
465 else {
466 const ContextStyle& context = document()->getContextStyle();
467 return tqRound( context.baseSize() );
468 }
469}
470
471void Container::setFontSize( int pointSize, bool /*forPrint*/ )
472{
473 if ( rootElement()->getBaseSize() != pointSize ) {
474 execute( new KFCChangeBaseSize( i18n( "Base Size Change" ), this, rootElement(), pointSize ) );
475 }
476}
477
478void Container::setFontSizeDirect( int pointSize )
479{
480 rootElement()->setBaseSize( pointSize );
481 recalc();
482}
483
485{
486 BasicElement *currentElement = activeCursor()->getElement();
487 if ( ( currentElement = currentElement->getParent() ) != 0 )
488 document()->wrapper()->enableMatrixActions( dynamic_cast<MatrixElement*>(currentElement) );
489 else
490 document()->wrapper()->enableMatrixActions( false );
491}
492
493void Container::save( TQDomElement &root )
494{
495 TQDomDocument ownerDoc = root.ownerDocument();
496 root.appendChild(rootElement()->getElementDom(ownerDoc));
497}
498
499
503bool Container::load( const TQDomElement &fe )
504{
505 if (!fe.isNull()) {
507 if (root->buildFromDom(fe)) {
508 delete impl->rootElement;
509 impl->rootElement = root;
511
512 recalc();
513 return true;
514 }
515 else {
516 delete root;
517 kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
518 }
519 }
520 else {
521 kdWarning( DEBUGID ) << "Empty element." << endl;
522 }
523 return false;
524}
525
526
527void Container::saveMathML( TQTextStream& stream, bool oasisFormat )
528{
529 TQDomDocument doc;
530 if ( !oasisFormat ) {
532 }
533 rootElement()->writeMathML( doc, doc, oasisFormat );
534 stream << doc;
535}
536
537bool Container::loadMathML( const TQDomDocument &doc, bool oasisFormat )
538{
539 return loadMathML( doc.documentElement(), oasisFormat );
540}
541
542/*
543bool Container::loadMathML( const TQDomElement &element, bool oasisFormat )
544{
545 const ContextStyle& context = document()->getContextStyle();
546 MathML2KFormula filter( element, context, oasisFormat );
547 filter.startConversion();
548 if (filter.m_error) {
549 return false;
550 }
551
552 if ( load( filter.getKFormulaDom().documentElement() ) ) {
553 getHistory()->clear();
554 return true;
555 }
556 return false;
557}
558*/
559
560bool Container::loadMathML( const TQDomElement &fe, bool /*oasisFormat*/ )
561{
562 kdDebug( DEBUGID ) << "loadMathML" << endl;
563 if (!fe.isNull()) {
565 if ( root->buildFromMathMLDom( fe ) != - 1) {
566 delete impl->rootElement;
567 impl->rootElement = root;
569
570 recalc();
571 return true;
572 }
573 else {
574 delete root;
575 kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
576 }
577 }
578 else {
579 kdWarning( DEBUGID ) << "Empty element." << endl;
580 }
581 return false;
582}
583
584
585void Container::print(KPrinter& printer)
586{
587 //printer.setFullPage(true);
588 TQPainter painter;
589 if (painter.begin(&printer)) {
590 rootElement()->draw( painter, LuPixelRect( rootElement()->getX(),
591 rootElement()->getY(),
592 rootElement()->getWidth(),
593 rootElement()->getHeight() ),
594 document()->getContextStyle( false ) );
595 }
596}
597
598TQImage Container::drawImage( int width, int height )
599{
600 ContextStyle& context = document()->getContextStyle( false );
601 TQRect rect(impl->rootElement->getX(), impl->rootElement->getY(),
602 impl->rootElement->getWidth(), impl->rootElement->getHeight());
603
604 int realWidth = context.layoutUnitToPixelX( impl->rootElement->getWidth() );
605 int realHeight = context.layoutUnitToPixelY( impl->rootElement->getHeight() );
606
607 double f = TQMAX( static_cast<double>( width )/static_cast<double>( realWidth ),
608 static_cast<double>( height )/static_cast<double>( realHeight ) );
609
610 int oldZoom = context.zoom();
611 context.setZoomAndResolution( tqRound( oldZoom*f ), KoGlobal::dpiX(), KoGlobal::dpiY() );
612
613 kdDebug( DEBUGID ) << "Container::drawImage "
614 << "(" << width << " " << height << ")"
615 << "(" << context.layoutUnitToPixelX( impl->rootElement->getWidth() )
616 << " " << context.layoutUnitToPixelY( impl->rootElement->getHeight() ) << ")"
617 << endl;
618
619 TQPixmap pm( context.layoutUnitToPixelX( impl->rootElement->getWidth() ),
620 context.layoutUnitToPixelY( impl->rootElement->getHeight() ) );
621 pm.fill();
622 TQPainter paint(&pm);
623 impl->rootElement->draw(paint, rect, context);
624 paint.end();
625 context.setZoomAndResolution( oldZoom, KoGlobal::dpiX(), KoGlobal::dpiY() );
626 //return pm.convertToImage().smoothScale( width, height );
627 return pm.convertToImage();
628}
629
631{
632 return rootElement()->toLatex();
633}
634
635TQString Container::formulaString()
636{
637 return rootElement()->formulaString();
638}
639
640KFORMULA_NAMESPACE_END
641
642using namespace KFormula;
643#include "kformulacontainer.moc"
Basis of every formula element.
int buildFromMathMLDom(TQDomElement element)
Set this element attribute, build children and call their builFromMathMLDom.
bool buildFromDom(TQDomElement element)
Set this element attribute, build children and call their buildFromDom.
bool loadMathML(const TQDomDocument &doc, bool oasisFormat=false)
Load function.
FormulaElement * rootElement() const
void setFontSize(int pointSize, bool forPrint=false)
Sets the base font size of this formula.
void registerFormula(int pos=-1)
Register and unregister this formula with its document.
void leaveFormula(Container *formula, FormulaCursor *cursor, int cmd)
The cursor wants to leave this formula.
void copy()
Copy the current selection to the clipboard.
FormulaCursor * createCursor()
Returns a new cursor.
void paste()
Insert data from the clipboard.
void initialize()
Needs to be called before anything else can be done with a newly created formula!
void cursorMoved(FormulaCursor *cursor)
The cursor has been moved but the formula hasn't been changed.
void errorMsg(const TQString &)
A message that describes an error.
void baseSizeChanged(int size, bool owned)
The base size changed.
void cursorHasMoved(FormulaCursor *)
Gets called when a request has the side effect of moving the cursor.
double baseline() const
virtual void recalc()
Recalc the formula.
void testDirty()
Recalcs the formula and emits the .
void formulaChanged(int width, int height)
The formula has changed and needs to be redrawn.
virtual Document * document() const
TQImage drawImage(int width, int height)
bool load(const TQDomElement &fe)
Loads a formula from the document.
virtual FormulaElement * createMainSequence()
Factory method.
TQString texString()
void setActiveCursor(FormulaCursor *cursor)
Sets the cursor that is to be used for any editing.
void save(TQDomElement &root)
Saves the data into the document.
void moveOutLeft(FormulaCursor *)
Inside the formula occurred an event that must be handled outside.
void cut()
Copy and remove.
void print(KPrinter &printer)
Prints the formula.
void updateMatrixActions()
If the cursor is in a matrix, the matrix actions will be enabled, otherwise disabled.
void statusMsg(const TQString &msg)
A message that might be a useful hint.
void changed()
Gets called when ever something changes and we need to recalc.
void input(TQKeyEvent *event)
General input.
void formulaLoaded(FormulaElement *)
Tells the cursors that we have just loaded a new formula.
void elementWillVanish(BasicElement *element)
The element is going to leave the formula with and all its children.
FormulaCursor * activeCursor()
void draw(TQPainter &painter, const TQRect &r, const TQColorGroup &cg, bool edit=false)
Draws the whole thing.
void moveTo(int x, int y)
Moves the formula to a new location.
void elementRemoval(BasicElement *child)
Gets called just before the child is removed from the element tree.
TQRect boundingRect() const
void saveMathML(TQTextStream &stream, bool oasisFormat=false)
Save formula as MathML.
Contains all the style information for the formela.
A document that can contain a lot of formulas (container).
KoCommandHistory * getHistory() const
void activate(Container *formula)
Sets a new formula.
virtual void unregisterFormula(Container *)
Removes a formula from this document.
ContextStyle & getContextStyle(bool edit=false)
TQDomDocument createMathMLDomDocument()
Create a MathML Dom Document, deprecates KFO Dom Document for internal layout TODO: Shouldn't this go...
const SymbolTable & getSymbolTable() const
virtual void registerFormula(Container *, int pos=-1)
Registers a new formula to be part of this document.
The selection.
bool isSelection() const
Returns wether there actually is a selection.
bool buildElementsFromMathMLDom(TQDomElement root, TQPtrList< BasicElement > &list)
Inserts the elements that could be read from the MathML dom into the list.
BasicElement * getElement()
The element we are in.
bool isReadOnly() const
void copy(TQDomDocument &doc)
Stores the currently selected elements inside a dom.
The main element.
virtual void calcSizes(const ContextStyle &context, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes &style)
Calculates our width and height and our children's parentPosition.
virtual TQString toLatex()
void draw(TQPainter &painter, const LuPixelRect &r, ContextStyle &context)
Draws the whole thing.
virtual void writeMathML(TQDomDocument &doc, TQDomNode &parent, bool oasisFormat=false) const
Same as above, just MathML.
void addElement(BasicElement *element)
Collects all elements that are to be added.
Removes the current selection and adds any new elements afterwards.
The command history stores a (user) configurable amount of Commands.
uint countChildren() const
The symbol table.
Definition symboltable.h:77