lib

formulacursor.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 <tqpainter.h>
22
23#include <kdebug.h>
24#include <assert.h>
25
26#include "formulacursor.h"
27#include "formulaelement.h"
28#include "indexelement.h"
29#include "matrixelement.h"
30#include "rootelement.h"
31#include "sequenceelement.h"
32#include "symbolelement.h"
33#include "textelement.h"
34
35KFORMULA_NAMESPACE_BEGIN
36
38 : selectionFlag(false), linearMovement(false),
39 hasChangedFlag(true), readOnly(false)
40{
41 //setTo(element, 0);
42 element->goInside( this );
43}
44
45void FormulaCursor::setTo(BasicElement* element, uint cursor, int mark)
46{
47 hasChangedFlag = true;
48 current = element;
49 cursorPos = cursor;
50 if ((mark == -1) && selectionFlag) {
51 return;
52 }
53 if (mark != -1) {
54 setSelection(true);
55 }
56 markPos = mark;
57}
58
59
60void FormulaCursor::setPos(uint pos)
61{
62 hasChangedFlag = true;
63 cursorPos = pos;
64}
65
66void FormulaCursor::setMark(int mark)
67{
68 hasChangedFlag = true;
69 markPos = mark;
70}
71
72void FormulaCursor::calcCursorSize( const ContextStyle& context, bool smallCursor )
73{
74 // We only draw the cursor if its normalized.
75 SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
76
77 if (sequence != 0) {
78 sequence->calcCursorSize( context, this, smallCursor );
79 }
80}
81
82void FormulaCursor::draw( TQPainter& painter, const ContextStyle& context,
83 StyleAttributes& style, bool smallCursor, bool activeCursor )
84{
85 //if (readOnly && !isSelection())
86 //return;
87
88 // We only draw the cursor if its normalized.
89 SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
90
91 if (sequence != 0) {
92 sequence->drawCursor( painter, context, style, this, smallCursor, activeCursor );
93 }
94}
95
96
97void FormulaCursor::handleSelectState(int flag)
98{
99 if (flag & SelectMovement) {
100 if (!isSelection()) {
101 setMark(getPos());
102 setSelection(true);
103 }
104 }
105 else {
106 setSelection(false);
107 }
108}
109
110void FormulaCursor::moveLeft(int flag)
111{
112 BasicElement* element = getElement();
113 handleSelectState(flag);
114 if (flag & WordMovement) {
115 SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
116 if (sequence != 0) {
117 sequence->moveWordLeft(this);
118 }
119 else {
120 element->moveHome(this);
121 }
122 }
123 else {
124 element->moveLeft(this, element);
125 }
126}
127
128void FormulaCursor::moveRight(int flag)
129{
130 BasicElement* element = getElement();
131 handleSelectState(flag);
132 if (flag & WordMovement) {
133 SequenceElement* sequence = dynamic_cast<SequenceElement*>(current);
134 if (sequence != 0) {
135 sequence->moveWordRight(this);
136 }
137 else {
138 element->moveEnd(this);
139 }
140 }
141 else {
142 element->moveRight(this, element);
143 }
144}
145
146void FormulaCursor::moveUp(int flag)
147{
148 BasicElement* element = getElement();
149 handleSelectState(flag);
150 element->moveUp(this, element);
151}
152
153void FormulaCursor::moveDown(int flag)
154{
155 BasicElement* element = getElement();
156 handleSelectState(flag);
157 element->moveDown(this, element);
158}
159
160void FormulaCursor::moveHome(int flag)
161{
162 BasicElement* element = getElement();
163 handleSelectState(flag);
164 if (flag & WordMovement) {
165 element->formula()->moveHome(this);
166 }
167 else {
168 element->moveHome(this);
169 }
170}
171
172void FormulaCursor::moveEnd(int flag)
173{
174 BasicElement* element = getElement();
175 handleSelectState(flag);
176 if (flag & WordMovement) {
177 element->formula()->moveEnd(this);
178 }
179 else {
180 element->moveEnd(this);
181 }
182}
183
185{
186 return ( getElement() == getElement()->formula() ) && ( getPos() == 0 );
187}
188
190{
191 return ( getElement() == getElement()->formula() ) &&
192 ( getPos() == normal()->countChildren() );
193}
194
195void FormulaCursor::mousePress( const LuPixelPoint& pos, int flag )
196{
197 FormulaElement* formula = getElement()->formula();
198 formula->goToPos( this, pos );
199 if (flag & SelectMovement) {
200 setSelection(true);
201 if (getMark() == -1) {
202 setMark(getPos());
203 }
204 }
205 else {
206 setSelection(false);
207 setMark(getPos());
208 }
209}
210
211void FormulaCursor::mouseMove( const LuPixelPoint& point, int )
212{
213 setSelection(true);
214 BasicElement* element = getElement();
215 int mark = getMark();
216
217 FormulaElement* formula = getElement()->formula();
218 formula->goToPos( this, point );
219 BasicElement* newElement = getElement();
220 int pos = getPos();
221
222 BasicElement* posChild = 0;
223 BasicElement* markChild = 0;
224 while (element != newElement) {
225 posChild = newElement;
226 newElement = newElement->getParent();
227 if (newElement == 0) {
228 posChild = 0;
229 newElement = getElement();
230 markChild = element;
231 element = element->getParent();
232 }
233 }
234
235 if (dynamic_cast<SequenceElement*>(element) == 0) {
236 element = element->getParent();
237 element->selectChild(this, newElement);
238 }
239 else {
240 if (posChild != 0) {
241 element->selectChild(this, posChild);
242 pos = getPos();
243 }
244 if (markChild != 0) {
245 element->selectChild(this, markChild);
246 mark = getMark();
247 }
248 if (pos == mark) {
249 if ((posChild == 0) && (markChild != 0)) {
250 mark++;
251 }
252 else if ((posChild != 0) && (markChild == 0)) {
253 mark--;
254 }
255 }
256 else if (pos < mark) {
257 if (posChild != 0) {
258 pos--;
259 }
260 }
261 setTo(element, pos, mark);
262 }
263}
264
265void FormulaCursor::mouseRelease( const LuPixelPoint&, int )
266{
267 //mouseSelectionFlag = false;
268}
269
270
275{
276 element->goInside(this);
277}
278
279
286void FormulaCursor::normalize(Direction direction)
287{
288 BasicElement* element = getElement();
289 element->normalize(this, direction);
290}
291
292
297void FormulaCursor::insert(BasicElement* child, Direction direction)
298{
299 TQPtrList<BasicElement> list;
300 list.append(child);
301 insert(list, direction);
302}
303
304void FormulaCursor::insert(TQPtrList<BasicElement>& children,
305 Direction direction)
306{
307 assert( !isReadOnly() );
308 BasicElement* element = getElement();
309 element->insert(this, children, direction);
310}
311
312
318void FormulaCursor::remove(TQPtrList<BasicElement>& children,
319 Direction direction)
320{
321 assert( !isReadOnly() );
322 SequenceElement* sequence = normal();
323 if (sequence != 0) {
324
325 // If there is no child to remove in the sequence
326 // remove the sequence instead.
327 if (sequence->countChildren() == 0) {
328 BasicElement* parent = sequence->getParent();
329 if (parent != 0) {
330 parent->selectChild(this, sequence);
331 parent->remove(this, children, direction);
332 return;
333 }
334 }
335 else {
336 sequence->remove(this, children, direction);
337 }
338 }
339}
340
341
347 Direction direction)
348{
349 assert( !isReadOnly() );
350 TQPtrList<BasicElement> list;
351 // we suppres deletion here to get an error if something
352 // was left in the list.
353 //list.setAutoDelete(true);
354
355 //remove(list, direction);
356 if (isSelection()) {
357 getElement()->remove(this, list, direction);
358 }
359
360 insert(element, direction);
361 SequenceElement* mainChild = element->getMainChild();
362 if (mainChild != 0) {
363 mainChild->goInside(this);
364 insert(list);
365 /*
366 BasicElement* parent = element->getParent();
367 if (direction == beforeCursor) {
368 parent->moveRight(this, element);
369 }
370 else {
371 parent->moveLeft(this, element);
372 }
373 */
374 element->selectChild(this, mainChild);
375 }
376}
377
378
384{
385 assert( !isReadOnly() );
386 TQPtrList<BasicElement> childrenList;
387 TQPtrList<BasicElement> list;
388 BasicElement* element = getElement();
389 SequenceElement* mainChild = element->getMainChild();
390 if ((mainChild != 0) && (mainChild->countChildren() > 0)) {
391 mainChild->selectAllChildren(this);
392 remove(childrenList);
393 }
394 element->getParent()->selectChild(this, element);
395 setSelection(false);
396 remove(list);
397 insert(childrenList, direction);
398 if (list.count() > 0) {
399 return list.take(0);
400 }
401 return 0;
402}
403
404
413{
414 assert( !isReadOnly() );
415 BasicElement* parent = getElement()->getParent();
416 if (parent != 0) {
417 if (getElement() == parent->getMainChild()) {
418 parent->selectChild(this, getElement());
419 return replaceByMainChildContent(direction);
420 }
421 }
422 return 0;
423}
424
425
431{
432 BasicElement* element = getElement();
433 return element->isSenseless();
434}
435
436
444BasicElement* FormulaCursor::getActiveChild(Direction direction)
445{
446 return getElement()->getChild(this, direction);
447}
448
449BasicElement* FormulaCursor::getSelectedChild()
450{
451 if (isSelection()) {
452 if ((getSelectionEnd() - getSelectionStart()) > 1) {
453 return 0;
454 }
455 return getActiveChild((getPos() > getMark()) ?
456 beforeCursor :
457 afterCursor);
458 }
459 else {
460 return getActiveChild(beforeCursor);
461 }
462}
463
464
466{
467 if ( !isSelection() && getPos() > 0 ) {
468 setSelection( true );
469 setMark( getPos() - 1 );
470 }
471}
472
473
478bool FormulaCursor::pointsAfterMainChild(BasicElement* element)
479{
480 if (element != 0) {
481 SequenceElement* mainChild = element->getMainChild();
482 return (getElement() == mainChild) &&
483 ((mainChild->countChildren() == getPos()) || (0 == getPos()));
484 }
485 return false;
486}
487
488
494{
495 IndexElement* element = dynamic_cast<IndexElement*>(getSelectedChild());
496
497 if ((element == 0) && !isSelection()) {
498 element = dynamic_cast<IndexElement*>(getElement()->getParent());
499 if (!pointsAfterMainChild(element)) {
500 return 0;
501 }
502 }
503 return element;
504}
505
506
512{
513 RootElement* element = dynamic_cast<RootElement*>(getSelectedChild());
514
515 if ((element == 0) && !isSelection()) {
516 element = dynamic_cast<RootElement*>(getElement()->getParent());
517 if (!pointsAfterMainChild(element)) {
518 return 0;
519 }
520 }
521 return element;
522}
523
524
530{
531 SymbolElement* element = dynamic_cast<SymbolElement*>(getSelectedChild());
532
533 if ((element == 0) && !isSelection()) {
534 element = dynamic_cast<SymbolElement*>(getElement()->getParent());
535 if (!pointsAfterMainChild(element)) {
536 return 0;
537 }
538 }
539 return element;
540}
541
547{
548 NameSequence* element = dynamic_cast<NameSequence*>( getSelectedChild() );
549
550 if ( ( element == 0 ) && !isSelection() ) {
551 element = dynamic_cast<NameSequence*>( getElement() );
552 if ( !pointsAfterMainChild( element ) ) {
553 return 0;
554 }
555 }
556 return element;
557}
558
563{
564 return dynamic_cast<TextElement*>(getSelectedChild());
565}
566
567
569{
570 MatrixElement* element = dynamic_cast<MatrixElement*>(getSelectedChild());
571
572 if ( ( element != 0 ) && !isSelection() ) {
573 normal()->selectChild( this, element );
574 }
575// if ((element == 0) && !isSelection()) {
576// element = dynamic_cast<MatrixElement*>(getElement()->getParent());
577// if (!pointsAfterMainChild(element)) {
578// return 0;
579// }
580// }
581 return element;
582}
583
588{
589 BasicElement* child = getElement();
590 if (element && child == element->getParent()) {
591 child->childWillVanish(this, element);
592 return;
593 }
594 while (child != 0) {
595 if (child == element) {
596 // This is meant to catch all cursors that did not
597 // cause the deletion.
598 child->getParent()->moveLeft(this, child);
599 setSelection(false);
600 hasChangedFlag = true;
601 return;
602 }
603 child = child->getParent();
604 }
605}
606
607
612{
613 //current = rootElement;
614 //setPos(0);
615 rootElement->goInside( this );
616 setMark(-1);
617 setSelection(false);
618}
619
620
622{
623 if ( readOnly ) {
624 return true;
625 }
626 const SequenceElement* sequence = normal();
627 if ( sequence != 0 ) {
628 bool ro = sequence->readOnly( this );
629 //kdDebug() << k_funcinfo << "readOnly=" << ro << endl;
630 return ro;
631 }
632 return false;
633}
634
635
639void FormulaCursor::copy( TQDomDocument& doc )
640{
641 if (isSelection()) {
642 SequenceElement* sequence = normal();
643 if (sequence != 0) {
644 TQDomElement root = doc.createElementNS( "http://www.w3.org/1998/Math/MathML",
645 "math" );
646 doc.appendChild( root );
647 TQDomElement de = doc.createElement( "mrow" );
648 root.appendChild( de );
649 sequence->getChildrenMathMLDom(doc, de, getSelectionStart(), getSelectionEnd());
650 }
651 else {
652 // This must never happen.
653 tqFatal("A not normalized cursor is selecting.");
654 }
655 }
656}
657
662bool FormulaCursor::buildElementsFromDom( TQDomElement root, TQPtrList<BasicElement>& list )
663{
664 assert( !isReadOnly() );
665 SequenceElement* sequence = normal();
666 if (sequence != 0) {
667 TQDomElement e = root.firstChild().toElement();
668 if (sequence->buildChildrenFromDom(list, e.firstChild())) {
669 return true;
670 }
671 }
672 return false;
673}
674
679bool FormulaCursor::buildElementsFromMathMLDom( TQDomElement root, TQPtrList<BasicElement>& list )
680{
681 assert( !isReadOnly() );
682 SequenceElement* sequence = normal();
683 if (sequence != 0) {
684 TQDomElement e = root.firstChild().toElement();
685 if (sequence->buildChildrenFromMathMLDom(list, e.firstChild())) {
686 return true;
687 }
688 }
689 return false;
690}
691
697{
698 return new CursorData(current, cursorPos, markPos,
699 selectionFlag, linearMovement, readOnly);
700}
701
702
703// Keep in sync with 'setCursorData'
704FormulaCursor& FormulaCursor::operator= (const FormulaCursor& other)
705{
706 current = other.current;
707 cursorPos = other.cursorPos;
708 markPos = other.markPos;
709 selectionFlag = other.selectionFlag;
710 linearMovement = other.linearMovement;
711 readOnly = other.readOnly;
712 hasChangedFlag = true;
713 return *this;
714}
715
716
722{
723 current = data->current;
724 cursorPos = data->cursorPos;
725 markPos = data->markPos;
726 selectionFlag = data->selectionFlag;
727 linearMovement = data->linearMovement;
728 readOnly = data->readOnly;
729 hasChangedFlag = true;
730}
731
732
736SequenceElement* FormulaCursor::normal()
737{
738 return dynamic_cast<SequenceElement*>(current);
739}
740
742{
743 return dynamic_cast<SequenceElement*>(current);
744}
745
746KFORMULA_NAMESPACE_END
Basis of every formula element.
virtual FormulaElement * formula()
Provide fast access to the rootElement for each child.
virtual void remove(FormulaCursor *, TQPtrList< BasicElement > &, Direction)
Removes all selected children and returns them.
virtual void moveHome(FormulaCursor *)
Enters this element while moving to the left starting inside the element `from'.
virtual BasicElement * getChild(FormulaCursor *, Direction=beforeCursor)
Returns the child at the cursor.
virtual void selectChild(FormulaCursor *, BasicElement *)
Sets the cursor to select the child.
virtual void goInside(FormulaCursor *cursor)
Sets the cursor inside this element to its start position.
virtual void normalize(FormulaCursor *, Direction)
Moves the cursor to a normal place where new elements might be inserted.
virtual SequenceElement * getMainChild()
Removes the child.
virtual bool isSenseless()
Returns wether the element has no more useful children (except its main child) and should therefore b...
virtual void insert(FormulaCursor *, TQPtrList< BasicElement > &, Direction)
Inserts all new children at the cursor position.
virtual void childWillVanish(FormulaCursor *, BasicElement *)
Moves the cursor away from the given child.
virtual void moveEnd(FormulaCursor *)
Moves the cursor to the last position in this sequence.
Contains all the style information for the formela.
A black box that is supposed to contain everything which is needed to describe a cursor.
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.
IndexElement * getActiveIndexElement()
Returns the IndexElement the cursor is on or 0 if there is non.
NameSequence * getActiveNameSequence()
SequenceElement * normal()
Returns the sequence the cursor is in if we are normal.
void normalize(Direction direction=beforeCursor)
Moves the cursor to a normal position.
void insert(BasicElement *, Direction=beforeCursor)
Inserts the child at the current position.
SymbolElement * getActiveSymbolElement()
Returns the SymbolElement the cursor is on or 0 if there is non.
void selectActiveElement()
Selects the element the cursor points to (stands after) if there is such an element and if there is n...
void replaceSelectionWith(BasicElement *, Direction=beforeCursor)
Replaces the current selection with the supplied element.
void setCursorData(CursorData *data)
Sets the cursor to where the CursorData points to.
FormulaCursor(FormulaElement *element)
Creates a cursor and puts is at the beginning of the formula.
void setSelection(bool selection)
Sets the selection mode.
CursorData * getCursorData()
Creates a new CursorData object that describes the cursor.
RootElement * getActiveRootElement()
Returns the RootElement the cursor is on or 0 if there is non.
bool isEnd() const
BasicElement * replaceByMainChildContent(Direction=beforeCursor)
Replaces the element the cursor points to with its main child's content.
BasicElement * removeEnclosingElement(Direction=beforeCursor)
Trys to find the element we are the main child of and replace it with our content.
void calcCursorSize(const ContextStyle &context, bool smallCursor)
Calculates the size of the cursor.
void goInsideElement(BasicElement *element)
Moves the cursor inside the element.
void elementWillVanish(BasicElement *element)
The element is going to leave the formula with and all its children.
void setTo(BasicElement *element, uint cursor, int mark=-1)
Sets the cursor to a new position.
bool buildElementsFromDom(TQDomElement root, TQPtrList< BasicElement > &list)
Inserts the elements that could be read from the dom into the list.
bool elementIsSenseless()
Returns wether the element the cursor points to should be replaced.
BasicElement * getElement()
The element we are in.
MatrixElement * getActiveMatrixElement()
TextElement * getActiveTextElement()
bool isHome() const
bool isReadOnly() const
void remove(TQPtrList< BasicElement > &, Direction=beforeCursor)
Removes the current selected children and returns them.
void draw(TQPainter &, const ContextStyle &context, StyleAttributes &style, bool smallCursor, bool activeCursor)
Draws the cursor at its current position.
void formulaLoaded(FormulaElement *rootElement)
A new formula has been loaded.
void copy(TQDomDocument &doc)
Stores the currently selected elements inside a dom.
The main element.
BasicElement * goToPos(FormulaCursor *, const LuPixelPoint &point)
Returns the element the point is in.
The element with up to four indexes in the four corners.
The sequence thats a name.
A nice graphical root.
Definition rootelement.h:35
The element that contains a number of children.
uint countChildren() const
void selectAllChildren(FormulaCursor *cursor)
Selects all children.
void getChildrenMathMLDom(TQDomDocument &doc, TQDomNode &elem, uint from, uint to)
Stores the given childrens MathML dom in the element.
virtual void moveWordLeft(FormulaCursor *cursor)
Enters this element while moving to the left starting inside the element `from'.
virtual void moveEnd(FormulaCursor *cursor)
Moves the cursor to the last position in this sequence.
virtual void remove(FormulaCursor *, TQPtrList< BasicElement > &, Direction)
Removes all selected children and returns them.
virtual void drawCursor(TQPainter &painter, const ContextStyle &context, StyleAttributes &style, FormulaCursor *cursor, bool smallCursor, bool activeCursor)
If the cursor is inside a sequence it needs to be drawn.
virtual void moveWordRight(FormulaCursor *cursor)
Moves to the end of this word or if we are there already to the end of the next.
virtual void goInside(FormulaCursor *cursor)
Sets the cursor inside this element to its start position.
virtual void selectChild(FormulaCursor *cursor, BasicElement *child)
Sets the cursor to select the child.
virtual bool readOnly(const FormulaCursor *) const
bool buildChildrenFromDom(TQPtrList< BasicElement > &list, TQDomNode n)
Builds elements from the given node and its siblings and puts them into the list.
virtual void moveHome(FormulaCursor *cursor)
Enters this element while moving up starting inside the element `from'.
A symbol is simply a piece of art.
An element that represents one char.
Definition textelement.h:37