lib

matrixelement.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 <tqmemarray.h>
22#include <tqpainter.h>
23#include <tqptrlist.h>
24
25#include <kdebug.h>
26#include <tdelocale.h>
27
28#include "MatrixDialog.h"
29#include "elementvisitor.h"
30#include "formulaelement.h"
31#include "formulacursor.h"
32#include "kformulacontainer.h"
33#include "kformulacommand.h"
34#include "matrixelement.h"
35#include "sequenceelement.h"
36#include "spaceelement.h"
37
38
39KFORMULA_NAMESPACE_BEGIN
40
41
42class MatrixSequenceElement : public SequenceElement {
43 typedef SequenceElement inherited;
44public:
45
46 MatrixSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
47 virtual MatrixSequenceElement* clone() {
48 return new MatrixSequenceElement( *this );
49 }
50
59 virtual KCommand* buildCommand( Container*, Request* );
60};
61
62
63class KFCRemoveRow : public Command {
64public:
65 KFCRemoveRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
66 ~KFCRemoveRow();
67
68 virtual void execute();
69 virtual void unexecute();
70
71protected:
72 MatrixElement* matrix;
73 uint rowPos;
74 uint colPos;
75
76 TQPtrList<MatrixSequenceElement>* row;
77};
78
79
80class KFCInsertRow : public KFCRemoveRow {
81public:
82 KFCInsertRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
83
84 virtual void execute() { KFCRemoveRow::unexecute(); }
85 virtual void unexecute() { KFCRemoveRow::execute(); }
86};
87
88
89class KFCRemoveColumn : public Command {
90public:
91 KFCRemoveColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
92 ~KFCRemoveColumn();
93
94 virtual void execute();
95 virtual void unexecute();
96
97protected:
98 MatrixElement* matrix;
99 uint rowPos;
100 uint colPos;
101
102 TQPtrList<MatrixSequenceElement>* column;
103};
104
105
106class KFCInsertColumn : public KFCRemoveColumn {
107public:
108 KFCInsertColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
109
110 virtual void execute() { KFCRemoveColumn::unexecute(); }
111 virtual void unexecute() { KFCRemoveColumn::execute(); }
112};
113
114
115KCommand* MatrixSequenceElement::buildCommand( Container* container, Request* request )
116{
117 FormulaCursor* cursor = container->activeCursor();
118 if ( cursor->isReadOnly() ) {
119 return 0;
120 }
121
122 switch ( *request ) {
123 case req_appendColumn:
124 case req_appendRow:
125 case req_insertColumn:
126 case req_removeColumn:
127 case req_insertRow:
128 case req_removeRow: {
129 MatrixElement* matrix = static_cast<MatrixElement*>( getParent() );
130 FormulaCursor* cursor = container->activeCursor();
131 for ( uint row = 0; row < matrix->getRows(); row++ ) {
132 for ( uint col = 0; col < matrix->getColumns(); col++ ) {
133 if ( matrix->getElement( row, col ) == cursor->getElement() ) {
134 switch ( *request ) {
135 case req_appendColumn:
136 return new KFCInsertColumn( i18n( "Append Column" ), container, matrix, row, matrix->getColumns() );
137 case req_appendRow:
138 return new KFCInsertRow( i18n( "Append Row" ), container, matrix, matrix->getRows(), col );
139 case req_insertColumn:
140 return new KFCInsertColumn( i18n( "Insert Column" ), container, matrix, row, col );
141 case req_removeColumn:
142 if ( matrix->getColumns() > 1 ) {
143 return new KFCRemoveColumn( i18n( "Remove Column" ), container, matrix, row, col );
144 }
145 break;
146 case req_insertRow:
147 return new KFCInsertRow( i18n( "Insert Row" ), container, matrix, row, col );
148 case req_removeRow:
149 if ( matrix->getRows() > 1 ) {
150 return new KFCRemoveRow( i18n( "Remove Row" ), container, matrix, row, col );
151 }
152 break;
153 default:
154 break;
155 }
156 }
157 }
158 }
159 kdWarning( DEBUGID ) << "MatrixSequenceElement::buildCommand: Sequence not found." << endl;
160 break;
161 }
162 default:
163 break;
164 }
165 return inherited::buildCommand( container, request );
166}
167
168
169KFCRemoveRow::KFCRemoveRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
170 : Command( name, document ), matrix( m ), rowPos( r ), colPos( c ), row( 0 )
171{
172}
173
174KFCRemoveRow::~KFCRemoveRow()
175{
176 delete row;
177}
178
180{
181 FormulaCursor* cursor = getExecuteCursor();
182 row = matrix->content.at( rowPos );
183 FormulaElement* formula = matrix->formula();
184 for ( uint i = matrix->getColumns(); i > 0; i-- ) {
185 formula->elementRemoval( row->at( i-1 ) );
186 }
187 matrix->content.take( rowPos );
188 formula->changed();
189 if ( rowPos < matrix->getRows() ) {
190 matrix->getElement( rowPos, colPos )->goInside( cursor );
191 }
192 else {
193 matrix->getElement( rowPos-1, colPos )->goInside( cursor );
194 }
195 testDirty();
196}
197
199{
200 matrix->content.insert( rowPos, row );
201 row = 0;
202 FormulaCursor* cursor = getExecuteCursor();
203 matrix->getElement( rowPos, colPos )->goInside( cursor );
204 matrix->formula()->changed();
205 testDirty();
206}
207
208
209KFCInsertRow::KFCInsertRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
210 : KFCRemoveRow( name, document, m, r, c )
211{
212 row = new TQPtrList< MatrixSequenceElement >;
213 row->setAutoDelete( true );
214 for ( uint i = 0; i < matrix->getColumns(); i++ ) {
215 row->append( new MatrixSequenceElement( matrix ) );
216 }
217}
218
219
220KFCRemoveColumn::KFCRemoveColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
221 : Command( name, document ), matrix( m ), rowPos( r ), colPos( c )
222{
223 column = new TQPtrList< MatrixSequenceElement >;
224 column->setAutoDelete( true );
225}
226
227KFCRemoveColumn::~KFCRemoveColumn()
228{
229 delete column;
230}
231
233{
234 FormulaCursor* cursor = getExecuteCursor();
235 FormulaElement* formula = matrix->formula();
236 for ( uint i = 0; i < matrix->getRows(); i++ ) {
237 column->append( matrix->getElement( i, colPos ) );
238 formula->elementRemoval( column->at( i ) );
239 matrix->content.at( i )->take( colPos );
240 }
241 formula->changed();
242 if ( colPos < matrix->getColumns() ) {
243 matrix->getElement( rowPos, colPos )->goInside( cursor );
244 }
245 else {
246 matrix->getElement( rowPos, colPos-1 )->goInside( cursor );
247 }
248 testDirty();
249}
250
252{
253 for ( uint i = 0; i < matrix->getRows(); i++ ) {
254 matrix->content.at( i )->insert( colPos, column->take( 0 ) );
255 }
256 FormulaCursor* cursor = getExecuteCursor();
257 matrix->getElement( rowPos, colPos )->goInside( cursor );
258 matrix->formula()->changed();
259 testDirty();
260}
261
262
263KFCInsertColumn::KFCInsertColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
264 : KFCRemoveColumn( name, document, m, r, c )
265{
266 for ( uint i = 0; i < matrix->getRows(); i++ ) {
267 column->append( new MatrixSequenceElement( matrix ) );
268 }
269}
270
271
272MatrixElement::MatrixElement(uint rows, uint columns, BasicElement* parent)
273 : BasicElement(parent),
274 m_rowNumber( 0 ),
275 m_align( NoAlign ),
276 m_widthType( NoSize ),
277 m_frame( NoLine ),
278 m_frameHSpacing( NoSize ),
279 m_frameVSpacing( NoSize ),
280 m_side( NoSide ),
281 m_minLabelSpacingType( NoSize ),
282 m_customEqualRows( false ),
283 m_customEqualColumns( false ),
284 m_customDisplayStyle( false )
285{
286 for (uint r = 0; r < rows; r++) {
287 TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
288 list->setAutoDelete(true);
289 for (uint c = 0; c < columns; c++) {
290 list->append(new MatrixSequenceElement(this));
291 }
292 content.append(list);
293 }
294 content.setAutoDelete(true);
295}
296
297MatrixElement::~MatrixElement()
298{
299}
300
301
302MatrixElement::MatrixElement( const MatrixElement& other )
303 : BasicElement( other )
304{
305 uint rows = other.getRows();
306 uint columns = other.getColumns();
307
308 TQPtrListIterator< TQPtrList< MatrixSequenceElement > > rowIter( other.content );
309 for (uint r = 0; r < rows; r++) {
310 ++rowIter;
311 TQPtrListIterator< MatrixSequenceElement > colIter( *rowIter.current() );
312
313 TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
314 list->setAutoDelete(true);
315 for (uint c = 0; c < columns; c++) {
316 ++colIter;
317 MatrixSequenceElement *mse =
318 //new MatrixSequenceElement( *( other.getElement( r, c ) ) );
319 new MatrixSequenceElement( *colIter.current() );
320 list->append( mse );
321 mse->setParent( this );
322 }
323 content.append(list);
324 }
325 content.setAutoDelete(true);
326}
327
328
330{
331 return visitor->visit( this );
332}
333
334
335void MatrixElement::entered( SequenceElement* /*child*/ )
336{
337 formula()->tell( i18n( "Matrix element" ) );
338}
339
340
341BasicElement* MatrixElement::goToPos( FormulaCursor* cursor, bool& handled,
342 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
343{
344 BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
345 if (e != 0) {
346 LuPixelPoint myPos(parentOrigin.x() + getX(),
347 parentOrigin.y() + getY());
348
349 uint rows = getRows();
350 uint columns = getColumns();
351
352 for (uint r = 0; r < rows; r++) {
353 for (uint c = 0; c < columns; c++) {
354 BasicElement* element = getElement(r, c);
355 e = element->goToPos(cursor, handled, point, myPos);
356 if (e != 0) {
357 return e;
358 }
359 }
360 }
361
362 // We are in one of those gaps.
363 luPixel dx = point.x() - myPos.x();
364 luPixel dy = point.y() - myPos.y();
365
366 uint row = rows;
367 for (uint r = 0; r < rows; r++) {
368 BasicElement* element = getElement(r, 0);
369 if (element->getY() > dy) {
370 row = r;
371 break;
372 }
373 }
374 if (row == 0) {
375 BasicElement* element = getParent();
376 element->moveLeft(cursor, this);
377 handled = true;
378 return element;
379 }
380 row--;
381
382 uint column = columns;
383 for (uint c = 0; c < columns; c++) {
384 BasicElement* element = getElement(row, c);
385 if (element->getX() > dx) {
386 column = c;
387 break;
388 }
389 }
390 if (column == 0) {
391 BasicElement* element = getParent();
392 element->moveLeft(cursor, this);
393 handled = true;
394 return element;
395 }
396 column--;
397
398 // Rescan the rows with the actual colums required.
399 row = rows;
400 for (uint r = 0; r < rows; r++) {
401 BasicElement* element = getElement(r, column);
402 if (element->getY() > dy) {
403 row = r;
404 break;
405 }
406 }
407 if (row == 0) {
408 BasicElement* element = getParent();
409 element->moveLeft(cursor, this);
410 handled = true;
411 return element;
412 }
413 row--;
414
415 BasicElement* element = getElement(row, column);
416 element->moveLeft(cursor, this);
417 handled = true;
418 return element;
419 }
420 return 0;
421}
422
423
424// drawing
425//
426// Drawing depends on a context which knows the required properties like
427// fonts, spaces and such.
428// It is essential to calculate elements size with the same context
429// before you draw.
430
437 ContextStyle::IndexStyle istyle,
438 StyleAttributes& style )
439{
440 TQMemArray<luPixel> toMidlines(getRows());
441 TQMemArray<luPixel> fromMidlines(getRows());
442 TQMemArray<luPixel> widths(getColumns());
443
444 toMidlines.fill(0);
445 fromMidlines.fill(0);
446 widths.fill(0);
447
448 uint rows = getRows();
449 uint columns = getColumns();
450
451 ContextStyle::TextStyle i_tstyle = context.convertTextStyleFraction(tstyle);
452 ContextStyle::IndexStyle i_istyle = context.convertIndexStyleUpper(istyle);
453 double factor = style.sizeFactor();
454
455 for (uint r = 0; r < rows; r++) {
456 TQPtrList< MatrixSequenceElement >* list = content.at(r);
457 for (uint c = 0; c < columns; c++) {
458 SequenceElement* element = list->at(c);
459 element->calcSizes( context, i_tstyle, i_istyle, style );
460 toMidlines[r] = TQMAX(toMidlines[r], element->axis( context, i_tstyle, factor ));
461 fromMidlines[r] = TQMAX(fromMidlines[r],
462 element->getHeight()-element->axis( context, i_tstyle, factor ));
463 widths[c] = TQMAX(widths[c], element->getWidth());
464 }
465 }
466
467 luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
468 luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
469
470 luPixel yPos = 0;
471 for (uint r = 0; r < rows; r++) {
472 TQPtrList< MatrixSequenceElement >* list = content.at(r);
473 luPixel xPos = 0;
474 yPos += toMidlines[r];
475 for (uint c = 0; c < columns; c++) {
476 SequenceElement* element = list->at(c);
477 switch (context.getMatrixAlignment()) {
478 case ContextStyle::left:
479 element->setX(xPos);
480 break;
481 case ContextStyle::center:
482 element->setX(xPos + (widths[c] - element->getWidth())/2);
483 break;
484 case ContextStyle::right:
485 element->setX(xPos + widths[c] - element->getWidth());
486 break;
487 }
488 element->setY(yPos - element->axis( context, i_tstyle, factor ));
489 xPos += widths[c] + distX;
490 }
491 yPos += fromMidlines[r] + distY;
492 }
493
494 luPixel width = distX * (columns - 1);
495 luPixel height = distY * (rows - 1);
496
497 for (uint r = 0; r < rows; r++) height += toMidlines[r] + fromMidlines[r];
498 for (uint c = 0; c < columns; c++) width += widths[c];
499
500 setWidth(width);
501 setHeight(height);
502 if ((rows == 2) && (columns == 1)) {
503 setBaseline( getMainChild()->getHeight() + distY / 2 + context.axisHeight( tstyle, factor ) );
504 }
505 else {
506 setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
507 }
508}
509
515void MatrixElement::draw( TQPainter& painter, const LuPixelRect& rect,
516 const ContextStyle& context,
518 ContextStyle::IndexStyle istyle,
519 StyleAttributes& style,
520 const LuPixelPoint& parentOrigin )
521{
522 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
523 //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( rect ) )
524 // return;
525
526 uint rows = getRows();
527 uint columns = getColumns();
528
529 for (uint r = 0; r < rows; r++) {
530 for (uint c = 0; c < columns; c++) {
531 getElement(r, c)->draw(painter, rect, context,
532 context.convertTextStyleFraction(tstyle),
533 context.convertIndexStyleUpper(istyle),
534 style,
535 myPos);
536 }
537 }
538
539 // Debug
540 //painter.setPen(TQt::red);
541 //painter.drawRect(myPos.x(), myPos.y(), getWidth(), getHeight());
542}
543
544
546{
547 uint rows = getRows();
548 uint columns = getColumns();
549
550 for (uint r = 0; r < rows; r++) {
551 for (uint c = 0; c < columns; c++) {
552 getElement(r, c)->dispatchFontCommand( cmd );
553 }
554 }
555}
556
557
558// navigation
559//
560// The elements are responsible to handle cursor movement themselves.
561// To do this they need to know the direction the cursor moves and
562// the element it comes from.
563//
564// The cursor might be in normal or in selection mode.
565
571void MatrixElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
572{
573 if (cursor->isSelectionMode()) {
574 getParent()->moveLeft(cursor, this);
575 }
576 else {
577 if (from == getParent()) {
578 getElement(getRows()-1, getColumns()-1)->moveLeft(cursor, this);
579 }
580 else {
581 bool linear = cursor->getLinearMovement();
582 uint row = 0;
583 uint column = 0;
584 if (searchElement(from, row, column)) {
585 if (column > 0) {
586 getElement(row, column-1)->moveLeft(cursor, this);
587 }
588 else if (linear && (row > 0)) {
589 getElement(row-1, getColumns()-1)->moveLeft(cursor, this);
590 }
591 else {
592 getParent()->moveLeft(cursor, this);
593 }
594 }
595 else {
596 getParent()->moveLeft(cursor, this);
597 }
598 }
599 }
600}
601
607void MatrixElement::moveRight(FormulaCursor* cursor, BasicElement* from)
608{
609 if (cursor->isSelectionMode()) {
610 getParent()->moveRight(cursor, this);
611 }
612 else {
613 if (from == getParent()) {
614 getElement(0, 0)->moveRight(cursor, this);
615 }
616 else {
617 bool linear = cursor->getLinearMovement();
618 uint row = 0;
619 uint column = 0;
620 if (searchElement(from, row, column)) {
621 if (column < getColumns()-1) {
622 getElement(row, column+1)->moveRight(cursor, this);
623 }
624 else if (linear && (row < getRows()-1)) {
625 getElement(row+1, 0)->moveRight(cursor, this);
626 }
627 else {
628 getParent()->moveRight(cursor, this);
629 }
630 }
631 else {
632 getParent()->moveRight(cursor, this);
633 }
634 }
635 }
636}
637
643void MatrixElement::moveUp(FormulaCursor* cursor, BasicElement* from)
644{
645 if (cursor->isSelectionMode()) {
646 getParent()->moveUp(cursor, this);
647 }
648 else {
649 if (from == getParent()) {
650 getElement(0, 0)->moveRight(cursor, this);
651 }
652 else {
653 uint row = 0;
654 uint column = 0;
655 if (searchElement(from, row, column)) {
656 if (row > 0) {
657 getElement(row-1, column)->moveRight(cursor, this);
658 }
659 else {
660 getParent()->moveUp(cursor, this);
661 }
662 }
663 else {
664 getParent()->moveUp(cursor, this);
665 }
666 }
667 }
668}
669
675void MatrixElement::moveDown(FormulaCursor* cursor, BasicElement* from)
676{
677 if (cursor->isSelectionMode()) {
678 getParent()->moveDown(cursor, this);
679 }
680 else {
681 if (from == getParent()) {
682 getElement(0, 0)->moveRight(cursor, this);
683 }
684 else {
685 uint row = 0;
686 uint column = 0;
687 if (searchElement(from, row, column)) {
688 if (row < getRows()-1) {
689 getElement(row+1, column)->moveRight(cursor, this);
690 }
691 else {
692 getParent()->moveDown(cursor, this);
693 }
694 }
695 else {
696 getParent()->moveDown(cursor, this);
697 }
698 }
699 }
700}
701
707{
708 getElement(0, 0)->goInside(cursor);
709}
710
711
712// If there is a main child we must provide the insert/remove semantics.
714{
715 return content.at(0)->at(0);
716}
717
718void MatrixElement::selectChild(FormulaCursor* cursor, BasicElement* child)
719{
720 uint rows = getRows();
721 uint columns = getColumns();
722 for (uint r = 0; r < rows; r++) {
723 for (uint c = 0; c < columns; c++) {
724 if (child == getElement(r, c)) {
725 cursor->setTo(this, r*columns+c);
726 }
727 }
728 }
729}
730
731const MatrixSequenceElement* MatrixElement::getElement( uint row, uint column ) const
732{
733 TQPtrListIterator< TQPtrList < MatrixSequenceElement > > rows( content );
734 rows += row;
735 if ( ! rows.current() )
736 return 0;
737
738 TQPtrListIterator< MatrixSequenceElement > cols ( *rows.current() );
739 cols += column;
740 return cols.current();
741}
742
743
744bool MatrixElement::searchElement(BasicElement* element, uint& row, uint& column)
745{
746 uint rows = getRows();
747 uint columns = getColumns();
748 for (uint r = 0; r < rows; r++) {
749 for (uint c = 0; c < columns; c++) {
750 if (element == getElement(r, c)) {
751 row = r;
752 column = c;
753 return true;
754 }
755 }
756 }
757 return false;
758}
759
760
764void MatrixElement::writeDom(TQDomElement element)
765{
766 BasicElement::writeDom(element);
767
768 uint rows = getRows();
769 uint cols = getColumns();
770
771 element.setAttribute("ROWS", rows);
772 element.setAttribute("COLUMNS", cols);
773
774 TQDomDocument doc = element.ownerDocument();
775
776 for (uint r = 0; r < rows; r++) {
777 for (uint c = 0; c < cols; c++) {
778 TQDomElement tmp = getElement(r,c)->getElementDom(doc);
779 element.appendChild(tmp);
780 }
781 element.appendChild(doc.createComment("end of row"));
782 }
783}
784
789bool MatrixElement::readAttributesFromDom(TQDomElement element)
790{
792 return false;
793 }
794 uint rows = 0;
795 TQString rowStr = element.attribute("ROWS");
796 if(!rowStr.isNull()) {
797 rows = rowStr.toInt();
798 }
799 if (rows == 0) {
800 kdWarning( DEBUGID ) << "Rows <= 0 in MatrixElement." << endl;
801 return false;
802 }
803
804 TQString columnStr = element.attribute("COLUMNS");
805 uint cols = 0;
806 if(!columnStr.isNull()) {
807 cols = columnStr.toInt();
808 }
809 if (cols == 0) {
810 kdWarning( DEBUGID ) << "Columns <= 0 in MatrixElement." << endl;
811 return false;
812 }
813
814 content.clear();
815 for (uint r = 0; r < rows; r++) {
816 TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
817 list->setAutoDelete(true);
818 content.append(list);
819 for (uint c = 0; c < cols; c++) {
820 MatrixSequenceElement* element = new MatrixSequenceElement(this);
821 list->append(element);
822 }
823 }
824 return true;
825}
826
833{
835 return false;
836 }
837
838 uint rows = getRows();
839 uint cols = getColumns();
840
841 uint r = 0;
842 uint c = 0;
843 while ( !node.isNull() && r < rows ) {
844 if ( node.isElement() ) {
845 SequenceElement* element = getElement( r, c );
846 TQDomElement e = node.toElement();
847 if ( !element->buildFromDom( e ) ) {
848 return false;
849 }
850 c++;
851 if ( c == cols ) {
852 c = 0;
853 r++;
854 }
855 }
856 node = node.nextSibling();
857 }
858 return true;
859}
860
861bool MatrixElement::readAttributesFromMathMLDom( const TQDomElement& element )
862{
864 return false;
865 }
866
867 TQString alignStr = element.attribute( "align" ).lower();
868 if ( ! alignStr.isNull() ) {
869 if ( alignStr.find( "top" ) != -1 ) {
870 m_align = TopAlign;
871 }
872 else if ( alignStr.find( "bottom" ) != -1 ) {
873 m_align = BottomAlign;
874 }
875 else if ( alignStr.find( "center" ) != -1 ) {
876 m_align = CenterAlign;
877 }
878 else if ( alignStr.find( "baseline" ) != -1 ) {
879 m_align = BaselineAlign;
880 }
881 else if ( alignStr.find( "axis" ) != -1 ) {
882 m_align = AxisAlign;
883 }
884 int index = alignStr.findRev( ' ' );
885 if ( index != -1 ) {
886 m_rowNumber = alignStr.right( index + 1 ).toInt();
887 }
888 }
889 TQString rowalignStr = element.attribute( "rowalign" ).lower();
890 if ( ! rowalignStr.isNull() ) {
891 TQStringList list = TQStringList::split( ' ', rowalignStr );
892 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
893 if ( *it == "top" ) {
894 m_rowAlign.append( TopAlign );
895 }
896 else if ( *it == "bottom" ) {
897 m_rowAlign.append( BottomAlign );
898 }
899 else if ( *it == "center" ) {
900 m_rowAlign.append( CenterAlign );
901 }
902 else if ( *it == "baseline" ) {
903 m_rowAlign.append( BaselineAlign );
904 }
905 else if ( *it == "axis" ) {
906 m_rowAlign.append( AxisAlign );
907 }
908 }
909 }
910 TQString columnalignStr = element.attribute( "columnalign" ).lower();
911 if ( ! columnalignStr.isNull() ) {
912 TQStringList list = TQStringList::split( ' ', columnalignStr );
913 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
914 if ( *it == "left" ) {
915 m_columnAlign.append( LeftHorizontalAlign );
916 }
917 else if ( *it == "center" ) {
918 m_columnAlign.append( CenterHorizontalAlign );
919 }
920 else if ( *it == "right" ) {
921 m_columnAlign.append( RightHorizontalAlign );
922 }
923 }
924 }
925 TQString alignmentscopeStr = element.attribute( "alignmentscope" ).lower();
926 if ( ! alignmentscopeStr.isNull() ) {
927 TQStringList list = TQStringList::split( ' ', alignmentscopeStr );
928 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
929 if ( *it == "true" ) {
930 m_alignmentScope.append( true );
931 }
932 else if ( *it == "false" ) {
933 m_alignmentScope.append( false );
934 }
935 }
936 }
937 TQString columnwidthStr = element.attribute( "columnwidth" ).lower();
938 if ( columnwidthStr.isNull() ) {
939 TQStringList list = TQStringList::split( ' ', columnwidthStr );
940 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
941 SizeType type = NoSize;
942 double length;
943 if ( *it == "auto" ) {
944 type = AutoSize;
945 }
946 else if ( *it == "fit" ) {
947 type = FitSize;
948 }
949 else {
950 length = getSize( columnwidthStr, &type );
951 if ( type == NoSize ) {
952 type = getSpace( columnwidthStr );
953 }
954 }
955 if ( type != NoSize ) {
956 m_columnWidthType.append( type );
957 if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
958 m_columnWidth.append( length );
959 }
960 }
961 }
962 }
963 TQString widthStr = element.attribute( "width" ).lower();
964 if ( ! widthStr.isNull() ) {
965 if ( widthStr == "auto" ) {
966 m_widthType = AutoSize;
967 }
968 else {
969 m_width = getSize( widthStr, &m_widthType );
970 }
971 }
972 TQString rowspacingStr = element.attribute( "rowspacing" ).lower();
973 if ( ! rowspacingStr.isNull() ) {
974 TQStringList list = TQStringList::split( ' ', rowspacingStr );
975 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
976 SizeType type;
977 double length = getSize( *it, &type );
978 if ( type != NoSize ) {
979 m_rowSpacingType.append( type );
980 m_rowSpacing.append( length );
981 }
982 }
983 }
984 TQString columnspacingStr = element.attribute( "columnspacing" ).lower();
985 if ( ! columnspacingStr.isNull() ) {
986 TQStringList list = TQStringList::split( ' ', columnspacingStr );
987 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
988 SizeType type;
989 double length = getSize( *it, &type );
990 if ( type == NoSize ) {
991 type = getSpace( columnspacingStr );
992 }
993 if ( type != NoSize ) {
994 m_columnSpacingType.append( type );
995 if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
996 m_columnSpacing.append( length );
997 }
998 }
999 }
1000 }
1001 TQString rowlinesStr = element.attribute( "rowlines" ).lower();
1002 if ( ! rowlinesStr.isNull() ) {
1003 TQStringList list = TQStringList::split( ' ', rowlinesStr );
1004 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
1005 if ( *it == "none" ) {
1006 m_rowLines.append( NoneLine );
1007 }
1008 else if ( *it == "solid" ) {
1009 m_rowLines.append( SolidLine );
1010 }
1011 else if ( *it == "dashed" ) {
1012 m_rowLines.append( DashedLine );
1013 }
1014 }
1015 }
1016 TQString columnlinesStr = element.attribute( "columnlines" ).lower();
1017 if ( ! columnlinesStr.isNull() ) {
1018 TQStringList list = TQStringList::split( ' ', columnlinesStr );
1019 for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
1020 if ( *it == "none" ) {
1021 m_columnLines.append( NoneLine );
1022 }
1023 else if ( *it == "solid" ) {
1024 m_columnLines.append( SolidLine );
1025 }
1026 else if ( *it == "dashed" ) {
1027 m_columnLines.append( DashedLine );
1028 }
1029 }
1030 }
1031 TQString frameStr = element.attribute( "frame" ).stripWhiteSpace().lower();
1032 if ( ! frameStr.isNull() ) {
1033 if ( frameStr == "none" ) {
1034 m_frame = NoneLine;
1035 }
1036 else if ( frameStr == "solid" ) {
1037 m_frame = SolidLine;
1038 }
1039 else if ( frameStr == "dashed" ) {
1040 m_frame = DashedLine;
1041 }
1042 }
1043 TQString framespacingStr = element.attribute( "framespacing" );
1044 if ( ! framespacingStr.isNull() ) {
1045 TQStringList list = TQStringList::split( ' ', framespacingStr );
1046 m_frameHSpacing = getSize( list[0], &m_frameHSpacingType );
1047 if ( m_frameHSpacingType == NoSize ) {
1048 m_frameHSpacingType = getSpace( list[0] );
1049 }
1050 if ( list.count() > 1 ) {
1051 m_frameVSpacing = getSize( list[1], &m_frameVSpacingType );
1052 if ( m_frameVSpacingType == NoSize ) {
1053 m_frameVSpacingType = getSpace( list[1] );
1054 }
1055 }
1056 }
1057 TQString equalrowsStr = element.attribute( "equalrows" ).stripWhiteSpace().lower();
1058 if ( ! equalrowsStr.isNull() ) {
1059 m_customEqualRows = true;
1060 if ( equalrowsStr == "false" ) {
1061 m_equalRows = false;
1062 }
1063 else {
1064 m_equalRows = true;
1065 }
1066 }
1067 TQString equalcolumnsStr = element.attribute( "equalcolumns" ).stripWhiteSpace().lower();
1068 if ( ! equalcolumnsStr.isNull() ) {
1069 m_customEqualColumns = true;
1070 if ( equalcolumnsStr == "false" ) {
1071 m_equalColumns = false;
1072 }
1073 else {
1074 m_equalColumns = true;
1075 }
1076 }
1077 TQString displaystyleStr = element.attribute( "displaystyle" ).stripWhiteSpace().lower();
1078 if ( ! displaystyleStr.isNull() ) {
1079 m_customDisplayStyle = true;
1080 if ( displaystyleStr == "false" ) {
1081 m_displayStyle = false;
1082 }
1083 else {
1084 m_displayStyle = true;
1085 }
1086 }
1087 TQString sideStr = element.attribute( "side" ).stripWhiteSpace().lower();
1088 if ( ! sideStr.isNull() ) {
1089 if ( sideStr == "left" ) {
1090 m_side = LeftSide;
1091 }
1092 else if ( sideStr == "right" ) {
1093 m_side = RightSide;
1094 }
1095 else if ( sideStr == "leftoverlap" ) {
1096 m_side = LeftOverlapSide;
1097 }
1098 else if ( sideStr == "rightoverlap" ) {
1099 m_side = RightOverlapSide;
1100 }
1101 }
1102 TQString minlabelspacingStr = element.attribute( "minlabelspacing" ).stripWhiteSpace().lower();
1103 if ( ! minlabelspacingStr.isNull() ) {
1104 m_minLabelSpacing = getSize( minlabelspacingStr, &m_minLabelSpacingType );
1105 if ( m_minLabelSpacingType == NoSize ) {
1106 m_minLabelSpacingType = getSpace( minlabelspacingStr );
1107 }
1108 }
1109 return true;
1110}
1111
1119{
1120 // We have twice, since there may be empty elements and we need to know how
1121 // many of them we have. So, first pass, get number of rows and columns
1122
1123 if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
1124 return -1;
1125 }
1126
1127 uint rows = 0;
1128 uint cols = 0;
1129 TQDomNode n = node;
1130 while ( !n.isNull() ) {
1131 if ( n.isElement() ) {
1132 TQDomElement e = n.toElement();
1133 if ( e.tagName().lower() == "mtr" || e.tagName().lower() == "mlabeledtr" )
1134 {
1135 rows++;
1136
1137 /* Determins the number of columns */
1138 TQDomNode cellnode = e.firstChild();
1139 int cc = 0;
1140
1141 while ( !cellnode.isNull() ) {
1142 if ( cellnode.isElement() )
1143 cc++;
1144 cellnode = cellnode.nextSibling();
1145 }
1146 if ( cc > 0 && e.tagName().lower() == "mlabeledtr" )
1147 cc--;
1148 if ( cc > cols )
1149 cols = cc;
1150 }
1151 }
1152 n = n.nextSibling();
1153 }
1154
1155 // Create elements
1156 content.clear();
1157 for (uint r = 0; r < rows; r++) {
1158 TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
1159 list->setAutoDelete(true);
1160 content.append(list);
1161 for (uint c = 0; c < cols; c++) {
1162 MatrixSequenceElement* element = new MatrixSequenceElement(this);
1163 list->append(element);
1164 }
1165 }
1166
1167 // Second pass, read elements now
1168 uint r = 0;
1169 uint c = 0;
1170 while ( !node.isNull() ) {
1171 if ( node.isElement() ) {
1172 TQDomElement e = node.toElement();
1173 if ( e.tagName().lower() == "mtr" || e.tagName().lower() == "mlabeledtr" ) {
1174 TQDomNode cellnode = e.firstChild();
1175 if ( e.tagName().lower() == "mlabeledtr" ) {
1176 while ( ! cellnode.isNull() && ! cellnode.isElement() )
1177 cellnode = cellnode.nextSibling();
1178 if ( ! cellnode.isNull() )
1179 cellnode = cellnode.nextSibling();
1180 }
1181 while ( !cellnode.isNull() ) {
1182 if ( cellnode.isElement() ) {
1183 TQDomElement cellelement = cellnode.toElement();
1184 if ( cellelement.tagName().lower() != "mtd" ) {
1185 // TODO: Inferred mtd. Deprecated in MathML 2.0
1186 kdWarning( DEBUGID ) << "Unsupported tag "
1187 << cellelement.tagName()
1188 << " inside matrix row\n";
1189 }
1190 else {
1191 SequenceElement* element = getElement(r, c);
1192 if ( element->buildFromMathMLDom( cellelement ) == -1 )
1193 return -1;
1194 c++;
1195 }
1196 }
1197 cellnode = cellnode.nextSibling();
1198 }
1199 c = 0;
1200 r++;
1201 }
1202 }
1203 node = node.nextSibling();
1204 }
1205 return 1;
1206}
1207
1209{
1210 //All the border handling must be implemented here too
1211
1212 TQString matrix;
1213 uint cols=getColumns();
1214 uint rows=getRows();
1215
1216 matrix="\\begin{array}{ ";
1217 for(uint i=0;i<cols;i++)
1218 matrix+="c ";
1219
1220 matrix+="} ";
1221
1222 for (uint r = 0; r < rows; r++) {
1223 for (uint c = 0; c < cols; c++) {
1224 matrix+=getElement(r, c)->toLatex();
1225 if( c < cols-1) matrix+=" & ";
1226 }
1227 if(r < rows-1 ) matrix+=" \\\\ ";
1228 }
1229
1230 matrix+=" \\end{array}";
1231
1232 return matrix;
1233}
1234
1235TQString MatrixElement::formulaString()
1236{
1237 TQString matrix = "[";
1238 uint cols=getColumns();
1239 uint rows=getRows();
1240 for (uint r = 0; r < rows; r++) {
1241 matrix += "[";
1242 for (uint c = 0; c < cols; c++) {
1243 matrix+=getElement(r, c)->formulaString();
1244 if ( c < cols-1 ) matrix+=", ";
1245 }
1246 matrix += "]";
1247 if ( r < rows-1 ) matrix += ", ";
1248 }
1249 matrix += "]";
1250 return matrix;
1251}
1252
1253
1254SequenceElement* MatrixElement::elementAt(uint row, uint column)
1255{
1256 return getElement( row, column );
1257}
1258
1259void MatrixElement::writeMathMLAttributes( TQDomElement& element ) const
1260{
1261 TQString rownumber;
1262 if ( m_rowNumber ) {
1263 rownumber = TQString( " %1" ).arg( m_rowNumber );
1264 }
1265 switch ( m_align ) {
1266 case TopAlign:
1267 element.setAttribute( "align", "top" + rownumber );
1268 break;
1269 case BottomAlign:
1270 element.setAttribute( "align", "bottom" + rownumber );
1271 break;
1272 case CenterAlign:
1273 element.setAttribute( "align", "center" + rownumber );
1274 break;
1275 case BaselineAlign:
1276 element.setAttribute( "align", "baseline" + rownumber );
1277 break;
1278 case AxisAlign:
1279 element.setAttribute( "align", "axis" + rownumber );
1280 break;
1281 default:
1282 break;
1283 }
1284 TQString rowalign;
1285 for ( TQValueList<VerticalAlign >::const_iterator it = m_rowAlign.begin(); it != m_rowAlign.end(); it++ )
1286 {
1287 switch ( *it ) {
1288 case TopAlign:
1289 rowalign.append( "top " );
1290 break;
1291 case BottomAlign:
1292 rowalign.append( "bottom " );
1293 break;
1294 case CenterAlign:
1295 rowalign.append( "center " );
1296 break;
1297 case BaselineAlign:
1298 rowalign.append( "baseline " );
1299 break;
1300 case AxisAlign:
1301 rowalign.append( "axis " );
1302 break;
1303 default:
1304 break;
1305 }
1306 }
1307 if ( ! rowalign.isNull() ) {
1308 element.setAttribute( "rowalign", rowalign.stripWhiteSpace() );
1309 }
1310 TQString columnalign;
1311 for ( TQValueList<HorizontalAlign >::const_iterator it = m_columnAlign.begin(); it != m_columnAlign.end(); it++ )
1312 {
1313 switch ( *it ) {
1314 case LeftHorizontalAlign:
1315 rowalign.append( "left " );
1316 break;
1317 case CenterHorizontalAlign:
1318 rowalign.append( "center " );
1319 break;
1320 case RightHorizontalAlign:
1321 rowalign.append( "right " );
1322 break;
1323 default:
1324 break;
1325 }
1326 }
1327 if ( ! columnalign.isNull() ) {
1328 element.setAttribute( "columnalign", columnalign.stripWhiteSpace() );
1329 }
1330 TQString alignmentscope;
1331 for ( TQValueList< bool >::const_iterator it = m_alignmentScope.begin(); it != m_alignmentScope.end(); it++ )
1332 {
1333 if ( *it ) {
1334 alignmentscope.append( "true " );
1335 }
1336 else {
1337 alignmentscope.append( "false " );
1338 }
1339 }
1340 if ( ! alignmentscope.isNull() ) {
1341 element.setAttribute( "alignmentscope", alignmentscope.stripWhiteSpace() );
1342 }
1343 TQString columnwidth;
1344 TQValueList< double >::const_iterator lengthIt = m_columnWidth.begin();
1345 for ( TQValueList< SizeType >::const_iterator typeIt = m_columnWidthType.begin();
1346 typeIt != m_columnWidthType.end(); typeIt ++ ) {
1347 switch ( *typeIt ) {
1348 case AutoSize:
1349 columnwidth.append( "auto " );
1350 break;
1351 case FitSize:
1352 columnwidth.append( "fit " );
1353 break;
1354 case AbsoluteSize:
1355 columnwidth.append( TQString( "%1pt " ).arg( *lengthIt ) );
1356 lengthIt++;
1357 break;
1358 case RelativeSize:
1359 columnwidth.append( TQString( "%1% " ).arg( *lengthIt * 100.0 ) );
1360 lengthIt++;
1361 break;
1362 case PixelSize:
1363 columnwidth.append( TQString( "%1px " ).arg( *lengthIt ) );
1364 lengthIt++;
1365 break;
1366 case NegativeVeryVeryThinMathSpace:
1367 columnwidth.append( "negativeveryverythinmathspace " );
1368 break;
1369 case NegativeVeryThinMathSpace:
1370 columnwidth.append( "negativeverythinmathspace " );
1371 break;
1372 case NegativeThinMathSpace:
1373 columnwidth.append( "negativethinmathspace " );
1374 break;
1375 case NegativeMediumMathSpace:
1376 columnwidth.append( "negativemediummathspace " );
1377 break;
1378 case NegativeThickMathSpace:
1379 columnwidth.append( "negativethickmathspace " );
1380 break;
1381 case NegativeVeryThickMathSpace:
1382 columnwidth.append( "negativeverythickmathspace " );
1383 break;
1384 case NegativeVeryVeryThickMathSpace:
1385 columnwidth.append( "negativeveryverythickmathspace " );
1386 break;
1387 case VeryVeryThinMathSpace:
1388 columnwidth.append( "veryverythinmathspace " );
1389 break;
1390 case VeryThinMathSpace:
1391 columnwidth.append( "verythinmathspace " );
1392 break;
1393 case ThinMathSpace:
1394 columnwidth.append( "thinmathspace " );
1395 break;
1396 case MediumMathSpace:
1397 columnwidth.append( "mediummathspace " );
1398 break;
1399 case ThickMathSpace:
1400 columnwidth.append( "thickmathspace " );
1401 break;
1402 case VeryThickMathSpace:
1403 columnwidth.append( "verythickmathspace " );
1404 break;
1405 case VeryVeryThickMathSpace:
1406 columnwidth.append( "veryverythickmathspace " );
1407 break;
1408 default:
1409 break;
1410 }
1411 }
1412 if ( ! columnwidth.isNull() ) {
1413 element.setAttribute( "columnwidth", columnwidth.stripWhiteSpace() );
1414 }
1415 switch ( m_widthType ) {
1416 case AutoSize:
1417 element.setAttribute( "width", "auto" );
1418 break;
1419 case AbsoluteSize:
1420 element.setAttribute( "width", TQString( "%1pt" ).arg( m_width ) );
1421 break;
1422 case RelativeSize:
1423 element.setAttribute( "width", TQString( "%1% " ).arg( m_width * 100.0 ) );
1424 break;
1425 case PixelSize:
1426 element.setAttribute( "width", TQString( "%1px " ).arg( m_width ) );
1427 break;
1428 default:
1429 break;
1430 }
1431 TQString rowspacing;
1432 lengthIt = m_rowSpacing.begin();
1433 for ( TQValueList< SizeType >::const_iterator typeIt = m_rowSpacingType.begin();
1434 typeIt != m_rowSpacingType.end(); typeIt++, lengthIt++ ) {
1435 switch ( *typeIt ) {
1436 case AbsoluteSize:
1437 rowspacing.append( TQString( "%1pt " ).arg( *lengthIt ) );
1438 break;
1439 case RelativeSize:
1440 rowspacing.append( TQString( "%1% " ).arg( *lengthIt * 100.0 ) );
1441 break;
1442 case PixelSize:
1443 rowspacing.append( TQString( "%1px " ).arg( *lengthIt ) );
1444 break;
1445 default:
1446 break;
1447 }
1448 }
1449 if ( ! rowspacing.isNull() ) {
1450 element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
1451 }
1452 TQString columnspacing;
1453 lengthIt = m_columnSpacing.begin();
1454 for ( TQValueList< SizeType >::const_iterator typeIt = m_columnSpacingType.begin();
1455 typeIt != m_columnSpacingType.end(); typeIt++ ) {
1456 switch ( *typeIt ) {
1457 case AbsoluteSize:
1458 columnspacing.append( TQString( "%1pt " ).arg( *lengthIt ) );
1459 lengthIt++;
1460 break;
1461 case RelativeSize:
1462 columnspacing.append( TQString( "%1% " ).arg( *lengthIt * 100.0 ) );
1463 lengthIt++;
1464 break;
1465 case PixelSize:
1466 columnspacing.append( TQString( "%1px " ).arg( *lengthIt ) );
1467 lengthIt++;
1468 break;
1469 case NegativeVeryVeryThinMathSpace:
1470 columnspacing.append( "negativeveryverythinmathspace " );
1471 break;
1472 case NegativeVeryThinMathSpace:
1473 columnspacing.append( "negativeverythinmathspace " );
1474 break;
1475 case NegativeThinMathSpace:
1476 columnspacing.append( "negativethinmathspace " );
1477 break;
1478 case NegativeMediumMathSpace:
1479 columnspacing.append( "negativemediummathspace " );
1480 break;
1481 case NegativeThickMathSpace:
1482 columnspacing.append( "negativethickmathspace " );
1483 break;
1484 case NegativeVeryThickMathSpace:
1485 columnspacing.append( "negativeverythickmathspace " );
1486 break;
1487 case NegativeVeryVeryThickMathSpace:
1488 columnspacing.append( "negativeveryverythickmathspace " );
1489 break;
1490 case VeryVeryThinMathSpace:
1491 columnspacing.append( "veryverythinmathspace " );
1492 break;
1493 case VeryThinMathSpace:
1494 columnspacing.append( "verythinmathspace " );
1495 break;
1496 case ThinMathSpace:
1497 columnspacing.append( "thinmathspace " );
1498 break;
1499 case MediumMathSpace:
1500 columnspacing.append( "mediummathspace " );
1501 break;
1502 case ThickMathSpace:
1503 columnspacing.append( "thickmathspace " );
1504 break;
1505 case VeryThickMathSpace:
1506 columnspacing.append( "verythickmathspace " );
1507 break;
1508 case VeryVeryThickMathSpace:
1509 columnspacing.append( "veryverythickmathspace " );
1510 break;
1511 default:
1512 break;
1513 }
1514 }
1515 if ( ! rowspacing.isNull() ) {
1516 element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
1517 }
1518 TQString rowlines;
1519 for ( TQValueList< LineType >::const_iterator it = m_rowLines.begin(); it != m_rowLines.end(); it++ )
1520 {
1521 switch ( *it ) {
1522 case NoneLine:
1523 rowlines.append( "none " );
1524 break;
1525 case SolidLine:
1526 rowlines.append( "solid " );
1527 break;
1528 case DashedLine:
1529 rowlines.append( "dashed " );
1530 break;
1531 default:
1532 break;
1533 }
1534 }
1535 if ( ! rowlines.isNull() ) {
1536 element.setAttribute( "rowlines", rowlines.stripWhiteSpace() );
1537 }
1538 TQString columnlines;
1539 for ( TQValueList< LineType >::const_iterator it = m_columnLines.begin(); it != m_columnLines.end(); it++ )
1540 {
1541 switch ( *it ) {
1542 case NoneLine:
1543 columnlines.append( "none " );
1544 break;
1545 case SolidLine:
1546 columnlines.append( "solid " );
1547 break;
1548 case DashedLine:
1549 columnlines.append( "dashed " );
1550 break;
1551 default:
1552 break;
1553 }
1554 }
1555 if ( ! columnlines.isNull() ) {
1556 element.setAttribute( "columnlines", columnlines.stripWhiteSpace() );
1557 }
1558 switch ( m_frame ) {
1559 case NoneLine:
1560 element.setAttribute( "frame", "none" );
1561 break;
1562 case SolidLine:
1563 element.setAttribute( "frame", "solid" );
1564 break;
1565 case DashedLine:
1566 element.setAttribute( "frame", "dashed" );
1567 break;
1568 default:
1569 break;
1570 }
1571 TQString framespacing;
1572 switch ( m_frameHSpacingType ) {
1573 case AbsoluteSize:
1574 framespacing.append( TQString( "%1pt " ).arg( m_frameHSpacing ) );
1575 break;
1576 case RelativeSize:
1577 framespacing.append( TQString( "%1% " ).arg( m_frameHSpacing * 100.0 ) );
1578 break;
1579 case PixelSize:
1580 framespacing.append( TQString( "%1px " ).arg( m_frameHSpacing ) );
1581 break;
1582 case NegativeVeryVeryThinMathSpace:
1583 framespacing.append( "negativeveryverythinmathspace " );
1584 break;
1585 case NegativeVeryThinMathSpace:
1586 framespacing.append( "negativeverythinmathspace " );
1587 break;
1588 case NegativeThinMathSpace:
1589 framespacing.append( "negativethinmathspace " );
1590 break;
1591 case NegativeMediumMathSpace:
1592 framespacing.append( "negativemediummathspace " );
1593 break;
1594 case NegativeThickMathSpace:
1595 framespacing.append( "negativethickmathspace " );
1596 break;
1597 case NegativeVeryThickMathSpace:
1598 framespacing.append( "negativeverythickmathspace " );
1599 break;
1600 case NegativeVeryVeryThickMathSpace:
1601 framespacing.append( "negativeveryverythickmathspace " );
1602 break;
1603 case VeryVeryThinMathSpace:
1604 framespacing.append( "veryverythinmathspace " );
1605 break;
1606 case VeryThinMathSpace:
1607 framespacing.append( "verythinmathspace " );
1608 break;
1609 case ThinMathSpace:
1610 framespacing.append( "thinmathspace " );
1611 break;
1612 case MediumMathSpace:
1613 framespacing.append( "mediummathspace " );
1614 break;
1615 case ThickMathSpace:
1616 framespacing.append( "thickmathspace " );
1617 break;
1618 case VeryThickMathSpace:
1619 framespacing.append( "verythickmathspace " );
1620 break;
1621 case VeryVeryThickMathSpace:
1622 framespacing.append( "veryverythickmathspace " );
1623 break;
1624 default:
1625 break;
1626 }
1627 switch ( m_frameVSpacingType ) {
1628 case AbsoluteSize:
1629 framespacing.append( TQString( "%1pt " ).arg( m_frameVSpacing ) );
1630 break;
1631 case RelativeSize:
1632 framespacing.append( TQString( "%1% " ).arg( m_frameVSpacing * 100.0 ) );
1633 break;
1634 case PixelSize:
1635 framespacing.append( TQString( "%1px " ).arg( m_frameVSpacing ) );
1636 break;
1637 case NegativeVeryVeryThinMathSpace:
1638 framespacing.append( "negativeveryverythinmathspace " );
1639 break;
1640 case NegativeVeryThinMathSpace:
1641 framespacing.append( "negativeverythinmathspace " );
1642 break;
1643 case NegativeThinMathSpace:
1644 framespacing.append( "negativethinmathspace " );
1645 break;
1646 case NegativeMediumMathSpace:
1647 framespacing.append( "negativemediummathspace " );
1648 break;
1649 case NegativeThickMathSpace:
1650 framespacing.append( "negativethickmathspace " );
1651 break;
1652 case NegativeVeryThickMathSpace:
1653 framespacing.append( "negativeverythickmathspace " );
1654 break;
1655 case NegativeVeryVeryThickMathSpace:
1656 framespacing.append( "negativeveryverythickmathspace " );
1657 break;
1658 case VeryVeryThinMathSpace:
1659 framespacing.append( "veryverythinmathspace " );
1660 break;
1661 case VeryThinMathSpace:
1662 framespacing.append( "verythinmathspace " );
1663 break;
1664 case ThinMathSpace:
1665 framespacing.append( "thinmathspace " );
1666 break;
1667 case MediumMathSpace:
1668 framespacing.append( "mediummathspace " );
1669 break;
1670 case ThickMathSpace:
1671 framespacing.append( "thickmathspace " );
1672 break;
1673 case VeryThickMathSpace:
1674 framespacing.append( "verythickmathspace " );
1675 break;
1676 case VeryVeryThickMathSpace:
1677 framespacing.append( "veryverythickmathspace " );
1678 break;
1679 default:
1680 break;
1681 }
1682 if ( ! framespacing.isNull() ) {
1683 element.setAttribute( "framespacing", framespacing.stripWhiteSpace() );
1684 }
1685 if ( m_customEqualRows ) {
1686 element.setAttribute( "equalrows", m_equalRows ? "true" : "false" );
1687 }
1688 if ( m_customEqualColumns ) {
1689 element.setAttribute( "equalcolumns", m_equalColumns ? "true" : "false" );
1690 }
1691 if ( m_customDisplayStyle ) {
1692 element.setAttribute( "displaystyle", m_displayStyle ? "true" : "false" );
1693 }
1694 switch ( m_side ) {
1695 case LeftSide:
1696 element.setAttribute( "side", "left" );
1697 break;
1698 case RightSide:
1699 element.setAttribute( "side", "right" );
1700 break;
1701 case LeftOverlapSide:
1702 element.setAttribute( "side", "leftoverlap" );
1703 break;
1704 case RightOverlapSide:
1705 element.setAttribute( "side", "rightoverlap" );
1706 break;
1707 default:
1708 break;
1709 }
1710 switch ( m_minLabelSpacingType ) {
1711 case AbsoluteSize:
1712 element.setAttribute( "minlabelspacing", TQString( "%1pt" ).arg( m_minLabelSpacing ) );
1713 break;
1714 case RelativeSize:
1715 element.setAttribute( "minlabelspacing", TQString( "%1%" ).arg( m_minLabelSpacing * 100.0 ) );
1716 break;
1717 case PixelSize:
1718 element.setAttribute( "minlabelspacing", TQString( "%1px" ).arg( m_minLabelSpacing ) );
1719 break;
1720 case NegativeVeryVeryThinMathSpace:
1721 element.setAttribute( "minlabelspacing", "negativeveryverythinmathspace" );
1722 break;
1723 case NegativeVeryThinMathSpace:
1724 element.setAttribute( "minlabelspacing", "negativeverythinmathspace" );
1725 break;
1726 case NegativeThinMathSpace:
1727 element.setAttribute( "minlabelspacing", "negativethinmathspace" );
1728 break;
1729 case NegativeMediumMathSpace:
1730 element.setAttribute( "minlabelspacing", "negativemediummathspace" );
1731 break;
1732 case NegativeThickMathSpace:
1733 element.setAttribute( "minlabelspacing", "negativethickmathspace" );
1734 break;
1735 case NegativeVeryThickMathSpace:
1736 element.setAttribute( "minlabelspacing", "negativeverythickmathspace" );
1737 break;
1738 case NegativeVeryVeryThickMathSpace:
1739 element.setAttribute( "minlabelspacing", "negativeveryverythickmathspace" );
1740 break;
1741 case VeryVeryThinMathSpace:
1742 element.setAttribute( "minlabelspacing", "veryverythinmathspace" );
1743 break;
1744 case VeryThinMathSpace:
1745 element.setAttribute( "minlabelspacing", "verythinmathspace" );
1746 break;
1747 case ThinMathSpace:
1748 element.setAttribute( "minlabelspacing", "thinmathspace" );
1749 break;
1750 case MediumMathSpace:
1751 element.setAttribute( "minlabelspacing", "mediummathspace" );
1752 break;
1753 case ThickMathSpace:
1754 element.setAttribute( "minlabelspacing", "thickmathspace" );
1755 break;
1756 case VeryThickMathSpace:
1757 element.setAttribute( "minlabelspacing", "verythickmathspace" );
1758 break;
1759 case VeryVeryThickMathSpace:
1760 element.setAttribute( "minlabelspacing", "veryverythickmathspace" );
1761 break;
1762 default:
1763 break;
1764 }
1765}
1766
1767void MatrixElement::writeMathMLContent( TQDomDocument& doc,
1768 TQDomElement& element,
1769 bool oasisFormat ) const
1770{
1771 TQDomElement row;
1772 TQDomElement cell;
1773
1774 uint rows = getRows();
1775 uint cols = getColumns();
1776
1777 for ( uint r = 0; r < rows; r++ )
1778 {
1779 row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
1780 element.appendChild( row );
1781 for ( uint c = 0; c < cols; c++ )
1782 {
1783 cell = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
1784 row.appendChild( cell );
1785 getElement(r,c)->writeMathML( doc, cell, oasisFormat );
1786 }
1787 }
1788}
1789
1790
1792
1793
1798class MultilineSequenceElement : public SequenceElement {
1799 typedef SequenceElement inherited;
1800public:
1801
1802 MultilineSequenceElement( BasicElement* parent = 0 );
1803
1804 virtual MultilineSequenceElement* clone() {
1805 return new MultilineSequenceElement( *this );
1806 }
1807
1808 virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
1809 const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
1810
1815 virtual void calcSizes( const ContextStyle& context,
1817 ContextStyle::IndexStyle istyle,
1818 StyleAttributes& style );
1819
1820 virtual void registerTab( BasicElement* tab );
1821
1830 virtual KCommand* buildCommand( Container*, Request* );
1831
1832 virtual KCommand* input( Container* container, TQKeyEvent* event );
1833
1834 virtual KCommand* input( Container* container, TQChar ch );
1835
1836 uint tabCount() const { return tabs.count(); }
1837
1838 BasicElement* tab( uint i ) { return tabs.at( i ); }
1839
1841 void moveTabTo( uint i, luPixel pos );
1842
1844 int tabBefore( uint pos );
1845
1847 int tabPos( uint i );
1848
1849 virtual void writeMathML( TQDomDocument& doc, TQDomNode& parent, bool oasisFormat = false ) const ;
1850
1851private:
1852
1853 TQPtrList<BasicElement> tabs;
1854};
1855
1856
1857// Split the line at position pos.
1858class KFCNewLine : public Command {
1859public:
1860 KFCNewLine( const TQString& name, Container* document,
1861 MultilineSequenceElement* line, uint pos );
1862
1863 virtual ~KFCNewLine();
1864
1865 virtual void execute();
1866 virtual void unexecute();
1867
1868private:
1869 MultilineSequenceElement* m_line;
1870 MultilineSequenceElement* m_newline;
1871 uint m_pos;
1872};
1873
1874
1875KFCNewLine::KFCNewLine( const TQString& name, Container* document,
1876 MultilineSequenceElement* line, uint pos )
1877 : Command( name, document ),
1878 m_line( line ), m_pos( pos )
1879{
1880 m_newline = new MultilineSequenceElement( m_line->getParent() );
1881}
1882
1883
1884KFCNewLine::~KFCNewLine()
1885{
1886 delete m_newline;
1887}
1888
1889
1891{
1892 FormulaCursor* cursor = getExecuteCursor();
1893 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
1894 int linePos = parent->content.find( m_line );
1895 parent->content.insert( linePos+1, m_newline );
1896
1897 // If there are children to be moved.
1898 if ( m_line->countChildren() > static_cast<int>( m_pos ) ) {
1899
1900 // Remove anything after position pos from the current line
1901 m_line->selectAllChildren( cursor );
1902 cursor->setMark( m_pos );
1903 TQPtrList<BasicElement> elementList;
1904 m_line->remove( cursor, elementList, beforeCursor );
1905
1906 // Insert the removed stuff into the new line
1907 m_newline->goInside( cursor );
1908 m_newline->insert( cursor, elementList, beforeCursor );
1909 cursor->setPos( cursor->getMark() );
1910 }
1911 else {
1912 m_newline->goInside( cursor );
1913 }
1914
1915 // The command no longer owns the new line.
1916 m_newline = 0;
1917
1918 // Tell that something changed
1919 FormulaElement* formula = m_line->formula();
1920 formula->changed();
1921 testDirty();
1922}
1923
1924
1926{
1927 FormulaCursor* cursor = getExecuteCursor();
1928 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
1929 int linePos = parent->content.find( m_line );
1930
1931 // Now the command owns the new line again.
1932 m_newline = parent->content.at( linePos+1 );
1933
1934 // Tell all cursors to leave this sequence
1935 FormulaElement* formula = m_line->formula();
1936 formula->elementRemoval( m_newline );
1937
1938 // If there are children to be moved.
1939 if ( m_newline->countChildren() > 0 ) {
1940
1941 // Remove anything from the line to be deleted
1942 m_newline->selectAllChildren( cursor );
1943 TQPtrList<BasicElement> elementList;
1944 m_newline->remove( cursor, elementList, beforeCursor );
1945
1946 // Insert the removed stuff into the previous line
1947 m_line->moveEnd( cursor );
1948 m_line->insert( cursor, elementList, beforeCursor );
1949 cursor->setPos( cursor->getMark() );
1950 }
1951 else {
1952 m_line->moveEnd( cursor );
1953 }
1954 parent->content.take( linePos+1 );
1955
1956 // Tell that something changed
1957 formula->changed();
1958 testDirty();
1959}
1960
1961
1962MultilineSequenceElement::MultilineSequenceElement( BasicElement* parent )
1963 : SequenceElement( parent )
1964{
1965 tabs.setAutoDelete( false );
1966}
1967
1968
1969BasicElement* MultilineSequenceElement::goToPos( FormulaCursor* cursor, bool& handled,
1970 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
1971{
1972 //LuPixelPoint myPos(parentOrigin.x() + getX(),
1973 // parentOrigin.y() + getY());
1974 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
1975
1976 if (e == 0) {
1977 // If the mouse was behind this line put the cursor to the last position.
1978 if ( ( point.x() > getX()+getWidth() ) &&
1979 ( point.y() >= getY() ) &&
1980 ( point.y() < getY()+getHeight() ) ) {
1981 cursor->setTo(this, countChildren());
1982 handled = true;
1983 return this;
1984 }
1985 }
1986 return e;
1987}
1988
1989
1990void MultilineSequenceElement::calcSizes( const ContextStyle& context,
1992 ContextStyle::IndexStyle istyle,
1993 StyleAttributes& style )
1994{
1995 tabs.clear();
1996 inherited::calcSizes( context, tstyle, istyle, style );
1997}
1998
1999
2000void MultilineSequenceElement::registerTab( BasicElement* tab )
2001{
2002 tabs.append( tab );
2003}
2004
2005
2006KCommand* MultilineSequenceElement::buildCommand( Container* container, Request* request )
2007{
2008 FormulaCursor* cursor = container->activeCursor();
2009 if ( cursor->isReadOnly() ) {
2010 return 0;
2011 }
2012
2013 switch ( *request ) {
2014 case req_remove: {
2015 // Remove this line if its empty.
2016 // Remove the formula if this line was the only one.
2017 break;
2018 }
2019 case req_addNewline: {
2020 FormulaCursor* cursor = container->activeCursor();
2021 return new KFCNewLine( i18n( "Add Newline" ), container, this, cursor->getPos() );
2022 }
2023 case req_addTabMark: {
2024 KFCReplace* command = new KFCReplace( i18n("Add Tabmark"), container );
2025 SpaceElement* element = new SpaceElement( THIN, true );
2026 command->addElement( element );
2027 return command;
2028 }
2029 default:
2030 break;
2031 }
2032 return inherited::buildCommand( container, request );
2033}
2034
2035
2036KCommand* MultilineSequenceElement::input( Container* container, TQKeyEvent* event )
2037{
2038 int action = event->key();
2039 //int state = event->state();
2040 //MoveFlag flag = movementFlag(state);
2041
2042 switch ( action ) {
2043 case TQt::Key_Enter:
2044 case TQt::Key_Return: {
2045 Request newline( req_addNewline );
2046 return buildCommand( container, &newline );
2047 }
2048 case TQt::Key_Tab: {
2049 Request r( req_addTabMark );
2050 return buildCommand( container, &r );
2051 }
2052 }
2053 return inherited::input( container, event );
2054}
2055
2056
2057KCommand* MultilineSequenceElement::input( Container* container, TQChar ch )
2058{
2059 int latin1 = ch.latin1();
2060 switch (latin1) {
2061 case '&': {
2062 Request r( req_addTabMark );
2063 return buildCommand( container, &r );
2064 }
2065 }
2066 return inherited::input( container, ch );
2067}
2068
2069
2070void MultilineSequenceElement::moveTabTo( uint i, luPixel pos )
2071{
2072 BasicElement* marker = tab( i );
2073 luPixel diff = pos - marker->getX();
2074 marker->setWidth( marker->getWidth() + diff );
2075
2076 for ( int p = childPos( marker )+1; p < countChildren(); ++p ) {
2077 BasicElement* child = getChild( p );
2078 child->setX( child->getX() + diff );
2079 }
2080
2081 setWidth( getWidth()+diff );
2082}
2083
2084
2085int MultilineSequenceElement::tabBefore( uint pos )
2086{
2087 if ( tabs.isEmpty() ) {
2088 return -1;
2089 }
2090 uint tabNum = 0;
2091 for ( uint i=0; i<pos; ++i ) {
2092 BasicElement* child = getChild( i );
2093 if ( tabs.at( tabNum ) == child ) {
2094 if ( tabNum+1 == tabs.count() ) {
2095 return tabNum;
2096 }
2097 ++tabNum;
2098 }
2099 }
2100 return static_cast<int>( tabNum )-1;
2101}
2102
2103
2104int MultilineSequenceElement::tabPos( uint i )
2105{
2106 if ( i < tabs.count() ) {
2107 return childPos( tabs.at( i ) );
2108 }
2109 return -1;
2110}
2111
2112
2113void MultilineSequenceElement::writeMathML( TQDomDocument& doc,
2114 TQDomNode& parent, bool oasisFormat ) const
2115{
2116 // parent is required to be a <mtr> tag
2117
2118 TQDomElement tmp = doc.createElement( "TMP" );
2119
2120 inherited::writeMathML( doc, tmp, oasisFormat );
2121
2122 /* Now we re-parse the Dom tree, because of the TabMarkers
2123 * that have no direct representation in MathML but mark the
2124 * end of a <mtd> tag.
2125 */
2126
2127 TQDomElement mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
2128
2129 // The mrow, if it exists.
2130 TQDomNode n = tmp.firstChild().firstChild();
2131 while ( !n.isNull() ) {
2132 // the illegal TabMarkers are children of the mrow, child of tmp.
2133 if ( n.isElement() && n.toElement().tagName() == "TAB" ) {
2134 parent.appendChild( mtd );
2135 mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
2136 }
2137 else {
2138 mtd.appendChild( n.cloneNode() ); // cloneNode needed?
2139 }
2140 n = n.nextSibling();
2141 }
2142
2143 parent.appendChild( mtd );
2144}
2145
2146
2148 : BasicElement( parent )
2149{
2150 content.setAutoDelete( true );
2151 content.append( new MultilineSequenceElement( this ) );
2152}
2153
2154MultilineElement::~MultilineElement()
2155{
2156}
2157
2159 : BasicElement( other )
2160{
2161 content.setAutoDelete( true );
2162 uint count = other.content.count();
2163 for (uint i = 0; i < count; i++) {
2164 MultilineSequenceElement* line = content.at(i)->clone();
2165 line->setParent( this );
2166 content.append( line );
2167 }
2168}
2169
2170
2172{
2173 return visitor->visit( this );
2174}
2175
2176
2177void MultilineElement::entered( SequenceElement* /*child*/ )
2178{
2179 formula()->tell( i18n( "Multi line element" ) );
2180}
2181
2182
2186BasicElement* MultilineElement::goToPos( FormulaCursor* cursor, bool& handled,
2187 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
2188{
2189 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
2190 if ( e != 0 ) {
2191 LuPixelPoint myPos(parentOrigin.x() + getX(),
2192 parentOrigin.y() + getY());
2193
2194 uint count = content.count();
2195 for ( uint i = 0; i < count; ++i ) {
2196 MultilineSequenceElement* line = content.at(i);
2197 e = line->goToPos(cursor, handled, point, myPos);
2198 if (e != 0) {
2199 return e;
2200 }
2201 }
2202 return this;
2203 }
2204 return 0;
2205}
2206
2208{
2209 content.at( 0 )->goInside( cursor );
2210}
2211
2212void MultilineElement::moveLeft( FormulaCursor* cursor, BasicElement* from )
2213{
2214 // If you want to select more than one line you'll have to
2215 // select the whole element.
2216 if (cursor->isSelectionMode()) {
2217 getParent()->moveLeft(cursor, this);
2218 }
2219 else {
2220 // Coming from the parent (sequence) we go to
2221 // the very last position
2222 if (from == getParent()) {
2223 content.at( content.count()-1 )->moveLeft(cursor, this);
2224 }
2225 else {
2226 // Coming from one of the lines we go to the previous line
2227 // or to the parent if there is none.
2228 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
2229 if ( pos > -1 ) {
2230 if ( pos > 0 ) {
2231 content.at( pos-1 )->moveLeft( cursor, this );
2232 }
2233 else {
2234 getParent()->moveLeft(cursor, this);
2235 }
2236 }
2237 else {
2238 kdDebug( DEBUGID ) << k_funcinfo << endl;
2239 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
2240 }
2241 }
2242 }
2243}
2244
2245void MultilineElement::moveRight( FormulaCursor* cursor, BasicElement* from )
2246{
2247 if (cursor->isSelectionMode()) {
2248 getParent()->moveRight(cursor, this);
2249 }
2250 else {
2251 if (from == getParent()) {
2252 content.at( 0 )->moveRight(cursor, this);
2253 }
2254 else {
2255 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
2256 if ( pos > -1 ) {
2257 uint upos = pos;
2258 if ( upos < content.count() ) {
2259 if ( upos < content.count()-1 ) {
2260 content.at( upos+1 )->moveRight( cursor, this );
2261 }
2262 else {
2263 getParent()->moveRight(cursor, this);
2264 }
2265 return;
2266 }
2267 }
2268 kdDebug( DEBUGID ) << k_funcinfo << endl;
2269 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
2270 }
2271 }
2272}
2273
2274void MultilineElement::moveUp( FormulaCursor* cursor, BasicElement* from )
2275{
2276 // If you want to select more than one line you'll have to
2277 // select the whole element.
2278 if (cursor->isSelectionMode()) {
2279 getParent()->moveLeft(cursor, this);
2280 }
2281 else {
2282 // Coming from the parent (sequence) we go to
2283 // the very last position
2284 if (from == getParent()) {
2285 content.at( content.count()-1 )->moveLeft(cursor, this);
2286 }
2287 else {
2288 // Coming from one of the lines we go to the previous line
2289 // or to the parent if there is none.
2290 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
2291 if ( pos > -1 ) {
2292 if ( pos > 0 ) {
2293 //content.at( pos-1 )->moveLeft( cursor, this );
2294 // This is rather hackish.
2295 // But we know what elements we have here.
2296 int cursorPos = cursor->getPos();
2297 MultilineSequenceElement* current = content.at( pos );
2298 MultilineSequenceElement* newLine = content.at( pos-1 );
2299 int tabNum = current->tabBefore( cursorPos );
2300 if ( tabNum > -1 ) {
2301 int oldTabPos = current->tabPos( tabNum );
2302 int newTabPos = newLine->tabPos( tabNum );
2303 if ( newTabPos > -1 ) {
2304 cursorPos += newTabPos-oldTabPos;
2305 int nextNewTabPos = newLine->tabPos( tabNum+1 );
2306 if ( nextNewTabPos > -1 ) {
2307 cursorPos = TQMIN( cursorPos, nextNewTabPos );
2308 }
2309 }
2310 else {
2311 cursorPos = newLine->countChildren();
2312 }
2313 }
2314 else {
2315 int nextNewTabPos = newLine->tabPos( 0 );
2316 if ( nextNewTabPos > -1 ) {
2317 cursorPos = TQMIN( cursorPos, nextNewTabPos );
2318 }
2319 }
2320 cursor->setTo( newLine,
2321 TQMIN( cursorPos,
2322 newLine->countChildren() ) );
2323 }
2324 else {
2325 getParent()->moveLeft(cursor, this);
2326 }
2327 }
2328 else {
2329 kdDebug( DEBUGID ) << k_funcinfo << endl;
2330 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
2331 }
2332 }
2333 }
2334}
2335
2336void MultilineElement::moveDown( FormulaCursor* cursor, BasicElement* from )
2337{
2338 if (cursor->isSelectionMode()) {
2339 getParent()->moveRight(cursor, this);
2340 }
2341 else {
2342 if (from == getParent()) {
2343 content.at( 0 )->moveRight(cursor, this);
2344 }
2345 else {
2346 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
2347 if ( pos > -1 ) {
2348 uint upos = pos;
2349 if ( upos < content.count() ) {
2350 if ( upos < content.count()-1 ) {
2351 //content.at( upos+1 )->moveRight( cursor, this );
2352 // This is rather hackish.
2353 // But we know what elements we have here.
2354 int cursorPos = cursor->getPos();
2355 MultilineSequenceElement* current = content.at( upos );
2356 MultilineSequenceElement* newLine = content.at( upos+1 );
2357 int tabNum = current->tabBefore( cursorPos );
2358 if ( tabNum > -1 ) {
2359 int oldTabPos = current->tabPos( tabNum );
2360 int newTabPos = newLine->tabPos( tabNum );
2361 if ( newTabPos > -1 ) {
2362 cursorPos += newTabPos-oldTabPos;
2363 int nextNewTabPos = newLine->tabPos( tabNum+1 );
2364 if ( nextNewTabPos > -1 ) {
2365 cursorPos = TQMIN( cursorPos, nextNewTabPos );
2366 }
2367 }
2368 else {
2369 cursorPos = newLine->countChildren();
2370 }
2371 }
2372 else {
2373 int nextNewTabPos = newLine->tabPos( 0 );
2374 if ( nextNewTabPos > -1 ) {
2375 cursorPos = TQMIN( cursorPos, nextNewTabPos );
2376 }
2377 }
2378 cursor->setTo( newLine,
2379 TQMIN( cursorPos,
2380 newLine->countChildren() ) );
2381 }
2382 else {
2383 getParent()->moveRight(cursor, this);
2384 }
2385 return;
2386 }
2387 }
2388 kdDebug( DEBUGID ) << k_funcinfo << endl;
2389 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
2390 }
2391 }
2392}
2393
2394
2397 ContextStyle::IndexStyle istyle,
2398 StyleAttributes& style )
2399{
2400 double factor = style.sizeFactor();
2401 luPt mySize = context.getAdjustedSize( tstyle, factor );
2402 TQFont font = context.getDefaultFont();
2403 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
2404 TQFontMetrics fm( font );
2405 luPixel leading = context.ptToLayoutUnitPt( fm.leading() );
2406 luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
2407
2408 uint count = content.count();
2409 luPixel height = -leading;
2410 luPixel width = 0;
2411 uint tabCount = 0;
2412 for ( uint i = 0; i < count; ++i ) {
2413 MultilineSequenceElement* line = content.at(i);
2414 line->calcSizes( context, tstyle, istyle, style );
2415 tabCount = TQMAX( tabCount, line->tabCount() );
2416
2417 height += leading;
2418 line->setX( 0 );
2419 line->setY( height );
2420 height += line->getHeight() + distY;
2421 width = TQMAX( line->getWidth(), width );
2422 }
2423
2424 // calculate the tab positions
2425 for ( uint t = 0; t < tabCount; ++t ) {
2426 luPixel pos = 0;
2427 for ( uint i = 0; i < count; ++i ) {
2428 MultilineSequenceElement* line = content.at(i);
2429 if ( t < line->tabCount() ) {
2430 pos = TQMAX( pos, line->tab( t )->getX() );
2431 }
2432 else {
2433 pos = TQMAX( pos, line->getWidth() );
2434 }
2435 }
2436 for ( uint i = 0; i < count; ++i ) {
2437 MultilineSequenceElement* line = content.at(i);
2438 if ( t < line->tabCount() ) {
2439 line->moveTabTo( t, pos );
2440 width = TQMAX( width, line->getWidth() );
2441 }
2442 }
2443 }
2444
2445 setHeight( height );
2446 setWidth( width );
2447 if ( count == 1 ) {
2448 setBaseline( content.at( 0 )->getBaseline() );
2449 }
2450 else {
2451 // There's always a first line. No formulas without lines.
2452 setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
2453 }
2454}
2455
2456void MultilineElement::draw( TQPainter& painter, const LuPixelRect& r,
2457 const ContextStyle& context,
2459 ContextStyle::IndexStyle istyle,
2460 StyleAttributes& style,
2461 const LuPixelPoint& parentOrigin )
2462{
2463 LuPixelPoint myPos( parentOrigin.x() + getX(), parentOrigin.y() + getY() );
2464 uint count = content.count();
2465
2466 if ( context.edit() ) {
2467 uint tabCount = 0;
2468 painter.setPen( context.getHelpColor() );
2469 for ( uint i = 0; i < count; ++i ) {
2470 MultilineSequenceElement* line = content.at(i);
2471 if ( tabCount < line->tabCount() ) {
2472 for ( uint t = tabCount; t < line->tabCount(); ++t ) {
2473 BasicElement* marker = line->tab( t );
2474 painter.drawLine( context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
2475 context.layoutUnitToPixelY( myPos.y() ),
2476 context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
2477 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
2478 }
2479 tabCount = line->tabCount();
2480 }
2481 }
2482 }
2483
2484 for ( uint i = 0; i < count; ++i ) {
2485 MultilineSequenceElement* line = content.at(i);
2486 line->draw( painter, r, context, tstyle, istyle, style, myPos );
2487 }
2488}
2489
2490
2492{
2493 uint count = content.count();
2494 for ( uint i = 0; i < count; ++i ) {
2495 MultilineSequenceElement* line = content.at(i);
2496 line->dispatchFontCommand( cmd );
2497 }
2498}
2499
2501 TQPtrList<BasicElement>& newChildren,
2502 Direction direction )
2503{
2504 MultilineSequenceElement* e = static_cast<MultilineSequenceElement*>(newChildren.take(0));
2505 e->setParent(this);
2506 content.insert( cursor->getPos(), e );
2507
2508 if (direction == beforeCursor) {
2509 e->moveLeft(cursor, this);
2510 }
2511 else {
2512 e->moveRight(cursor, this);
2513 }
2514 cursor->setSelection(false);
2515 formula()->changed();
2516}
2517
2519 TQPtrList<BasicElement>& removedChildren,
2520 Direction direction )
2521{
2522 if ( content.count() == 1 ) { //&& ( cursor->getPos() == 0 ) ) {
2523 getParent()->selectChild(cursor, this);
2524 getParent()->remove(cursor, removedChildren, direction);
2525 }
2526 else {
2527 MultilineSequenceElement* e = content.take( cursor->getPos() );
2528 removedChildren.append( e );
2529 formula()->elementRemoval( e );
2530 //cursor->setTo( this, denominatorPos );
2531 formula()->changed();
2532 }
2533}
2534
2535void MultilineElement::normalize( FormulaCursor* cursor, Direction direction )
2536{
2537 int pos = cursor->getPos();
2538 if ( ( cursor->getElement() == this ) &&
2539 ( pos > -1 ) && ( static_cast<unsigned>( pos ) <= content.count() ) ) {
2540 switch ( direction ) {
2541 case beforeCursor:
2542 if ( pos > 0 ) {
2543 content.at( pos-1 )->moveLeft( cursor, this );
2544 break;
2545 }
2546 // no break! intended!
2547 case afterCursor:
2548 if ( static_cast<unsigned>( pos ) < content.count() ) {
2549 content.at( pos )->moveRight( cursor, this );
2550 }
2551 else {
2552 content.at( pos-1 )->moveLeft( cursor, this );
2553 }
2554 break;
2555 }
2556 }
2557 else {
2558 inherited::normalize( cursor, direction );
2559 }
2560}
2561
2563{
2564 return content.at( 0 );
2565}
2566
2567void MultilineElement::selectChild(FormulaCursor* cursor, BasicElement* child)
2568{
2569 int pos = content.find( dynamic_cast<MultilineSequenceElement*>( child ) );
2570 if ( pos > -1 ) {
2571 cursor->setTo( this, pos );
2572 //content.at( pos )->moveRight( cursor, this );
2573 }
2574}
2575
2576
2580void MultilineElement::writeDom(TQDomElement element)
2581{
2582 BasicElement::writeDom(element);
2583
2584 uint lineCount = content.count();
2585 element.setAttribute( "LINES", lineCount );
2586
2587 TQDomDocument doc = element.ownerDocument();
2588 for ( uint i = 0; i < lineCount; ++i ) {
2589 TQDomElement tmp = content.at( i )->getElementDom(doc);
2590 element.appendChild(tmp);
2591 }
2592}
2593
2594void MultilineElement::writeMathML( TQDomDocument& doc, TQDomNode& parent, bool oasisFormat ) const
2595{
2596 TQDomElement de = doc.createElement( oasisFormat ? "math:mtable" : "mtable" );
2597 TQDomElement row; TQDomElement cell;
2598
2599 for ( TQPtrListIterator < MultilineSequenceElement > it( content ); it.current(); ++it ) {
2600 row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
2601 de.appendChild( row );
2602 //cell = doc.createElement( "mtd" );
2603 //row.appendChild( cell );
2604
2605 //content.at( i )->writeMathML( doc, cell );
2606 it.current()->writeMathML( doc, row, oasisFormat );
2607 }
2608
2609 parent.appendChild( de );
2610}
2611
2617{
2619 return false;
2620 }
2621 uint lineCount = 0;
2622 TQString lineCountStr = element.attribute("LINES");
2623 if(!lineCountStr.isNull()) {
2624 lineCount = lineCountStr.toInt();
2625 }
2626 if (lineCount == 0) {
2627 kdWarning( DEBUGID ) << "lineCount <= 0 in MultilineElement." << endl;
2628 return false;
2629 }
2630
2631 content.clear();
2632 for ( uint i = 0; i < lineCount; ++i ) {
2633 MultilineSequenceElement* element = new MultilineSequenceElement(this);
2634 content.append(element);
2635 }
2636 return true;
2637}
2638
2645{
2647 return false;
2648 }
2649
2650 uint lineCount = content.count();
2651 uint i = 0;
2652 while ( !node.isNull() && i < lineCount ) {
2653 if ( node.isElement() ) {
2654 SequenceElement* element = content.at( i );
2655 TQDomElement e = node.toElement();
2656 if ( !element->buildFromDom( e ) ) {
2657 return false;
2658 }
2659 ++i;
2660 }
2661 node = node.nextSibling();
2662 }
2663 return true;
2664}
2665
2667{
2668 uint lineCount = content.count();
2669 TQString muliline = "\\begin{split} ";
2670 for ( uint i = 0; i < lineCount; ++i ) {
2671 muliline += content.at( i )->toLatex();
2672 muliline += " \\\\ ";
2673 }
2674 muliline += "\\end{split}";
2675 return muliline;
2676}
2677
2678// Does this make any sense at all?
2679TQString MultilineElement::formulaString()
2680{
2681 uint lineCount = content.count();
2682 TQString muliline = "";
2683 for ( uint i = 0; i < lineCount; ++i ) {
2684 muliline += content.at( i )->formulaString();
2685 muliline += "\n";
2686 }
2687 //muliline += "";
2688 return muliline;
2689}
2690
2691
2692KFORMULA_NAMESPACE_END
Basis of every formula element.
virtual FormulaElement * formula()
Provide fast access to the rootElement for each child.
virtual bool readAttributesFromMathMLDom(const TQDomElement &element)
Reads our attributes from the MathML element.
virtual bool readContentFromDom(TQDomNode &node)
Reads our content from the node.
virtual int readContentFromMathMLDom(TQDomNode &node)
Reads our content from the MathML node.
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.
virtual void normalize(FormulaCursor *, Direction)
Moves the cursor to a normal place where new elements might be inserted.
virtual bool readAttributesFromDom(TQDomElement element)
Reads our attributes from the element.
virtual BasicElement * goToPos(FormulaCursor *, bool &handled, const LuPixelPoint &point, const LuPixelPoint &parentOrigin)
Sets the cursor and returns the element the point is in.
double getSize(const TQString &str, SizeType *st)
Utility function that sets the size type and returns the size value from a MathML attribute string wi...
virtual void writeDom(TQDomElement element)
Appends our attributes to the dom element.
virtual void writeMathML(TQDomDocument &doc, TQDomNode &parent, bool oasisFormat=false) const
Same as above, just MathML.
The document.
FormulaCursor * activeCursor()
Contains all the style information for the formela.
TextStyle
Textstyles like in TeX.
Base for all font commands that act on the current selection.
The selection.
void setSelection(bool selection)
Sets the selection mode.
bool isSelectionMode() const
Returns wether we are in selection mode.
void setTo(BasicElement *element, uint cursor, int mark=-1)
Sets the cursor to a new position.
BasicElement * getElement()
The element we are in.
bool isReadOnly() const
void elementRemoval(BasicElement *child)
Gets called just before the child is removed from the element tree.
void tell(const TQString &msg)
Tell the user something has happened.
virtual void changed()
Gets called whenever something changes and we need to recalc.
virtual FormulaElement * formula()
Provide fast access to the rootElement for each child.
virtual TQString name() const=0
virtual void unexecute()=0
virtual void execute()=0
void addElement(BasicElement *element)
Collects all elements that are to be added.
virtual int readContentFromMathMLDom(TQDomNode &node)
Reads our content from the MathML node.
virtual void entered(SequenceElement *child)
The cursor has entered one of our child sequences.
virtual void selectChild(FormulaCursor *, BasicElement *)
Inserts all new children at the cursor position.
virtual void writeDom(TQDomElement element)
Appends our attributes to the dom element.
virtual TQString toLatex()
Moves the cursor away from the given child.
virtual bool readAttributesFromDom(TQDomElement element)
Reads our attributes from the element.
virtual void calcSizes(const ContextStyle &cstyle, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes &style)
Calculates our width and height and our children's parentPosition.
virtual SequenceElement * getMainChild()
We define the Main Child of a matrix to be the first row/column.
virtual bool readAttributesFromMathMLDom(const TQDomElement &element)
Reads our attributes from the MathML element.
virtual bool readContentFromDom(TQDomNode &node)
Reads our content from the node.
virtual BasicElement * goToPos(FormulaCursor *, bool &handled, const LuPixelPoint &point, const LuPixelPoint &parentOrigin)
Sets the cursor and returns the element the point is in.
virtual bool accept(ElementVisitor *visitor)
Visit this element.
virtual void dispatchFontCommand(FontCommand *cmd)
Draws the whole element including its children.
virtual void goInside(FormulaCursor *cursor)
Enters this element while moving to the left starting inside the element `from'.
Any number of lines.
virtual void entered(SequenceElement *child)
The cursor has entered one of our child sequences.
virtual void writeDom(TQDomElement element)
Appends our attributes to the dom element.
virtual void writeMathML(TQDomDocument &doc, TQDomNode &parent, bool oasisFormat=false) const
Same as above, just MathML.
virtual void insert(FormulaCursor *, TQPtrList< BasicElement > &, Direction)
Inserts all new children at the cursor position.
BasicElement * goToPos(FormulaCursor *cursor, bool &handled, const LuPixelPoint &point, const LuPixelPoint &parentOrigin)
Returns the element the point is in.
virtual void remove(FormulaCursor *, TQPtrList< BasicElement > &, Direction)
Removes all selected children and returns them.
virtual void goInside(FormulaCursor *cursor)
Sets the cursor inside this element to its start position.
virtual void calcSizes(const ContextStyle &cstyle, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes &style)
Enters this element while moving to the left starting inside the element `from'.
virtual bool readContentFromDom(TQDomNode &node)
Reads our content from the node.
virtual bool accept(ElementVisitor *visitor)
Visit this element.
virtual void normalize(FormulaCursor *, Direction)
Moves the cursor to a normal place where new elements might be inserted.
virtual void selectChild(FormulaCursor *cursor, BasicElement *child)
Sets the cursor to select the child.
virtual void dispatchFontCommand(FontCommand *cmd)
Draws the whole element including its children.
virtual SequenceElement * getMainChild()
Removes the child.
virtual bool readAttributesFromDom(TQDomElement element)
Reads our attributes from the element.
MultilineElement(BasicElement *parent=0)
The container this FormulaElement belongs to must not be 0, except you really know what you are doing...
virtual TQString toLatex()
The element that contains a number of children.
virtual KCommand * input(Container *container, TQChar ch)
Parses the input.
uint countChildren() const
virtual KCommand * buildCommand(Container *, Request *)
This is called by the container to get a command depending on the current cursor position (this is ho...
virtual BasicElement * getChild(FormulaCursor *, Direction=beforeCursor)
Returns the child at the cursor.
virtual void dispatchFontCommand(FontCommand *cmd)
Draws the whole element including its children.
virtual void calcSizes(const ContextStyle &cstyle, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle, StyleAttributes &style)
Calculates our width and height and our children's parentPosition.
virtual BasicElement * goToPos(FormulaCursor *, bool &handled, const LuPixelPoint &point, const LuPixelPoint &parentOrigin)
Sets the cursor and returns the element the point is in.
TDEAction * action(StdAction act_enum, const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0L)
const char * name(StdAction id)