00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qmemarray.h>
00022 #include <qpainter.h>
00023 #include <qptrlist.h>
00024
00025 #include <kdebug.h>
00026 #include <klocale.h>
00027
00028 #include "MatrixDialog.h"
00029 #include "elementvisitor.h"
00030 #include "formulaelement.h"
00031 #include "formulacursor.h"
00032 #include "kformulacontainer.h"
00033 #include "kformulacommand.h"
00034 #include "matrixelement.h"
00035 #include "sequenceelement.h"
00036 #include "spaceelement.h"
00037
00038
00039 KFORMULA_NAMESPACE_BEGIN
00040
00041
00042 class MatrixSequenceElement : public SequenceElement {
00043 typedef SequenceElement inherited;
00044 public:
00045
00046 MatrixSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
00047 virtual MatrixSequenceElement* clone() {
00048 return new MatrixSequenceElement( *this );
00049 }
00050
00059 virtual KCommand* buildCommand( Container*, Request* );
00060 };
00061
00062
00063 class KFCRemoveRow : public Command {
00064 public:
00065 KFCRemoveRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
00066 ~KFCRemoveRow();
00067
00068 virtual void execute();
00069 virtual void unexecute();
00070
00071 protected:
00072 MatrixElement* matrix;
00073 uint rowPos;
00074 uint colPos;
00075
00076 QPtrList<MatrixSequenceElement>* row;
00077 };
00078
00079
00080 class KFCInsertRow : public KFCRemoveRow {
00081 public:
00082 KFCInsertRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
00083
00084 virtual void execute() { KFCRemoveRow::unexecute(); }
00085 virtual void unexecute() { KFCRemoveRow::execute(); }
00086 };
00087
00088
00089 class KFCRemoveColumn : public Command {
00090 public:
00091 KFCRemoveColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
00092 ~KFCRemoveColumn();
00093
00094 virtual void execute();
00095 virtual void unexecute();
00096
00097 protected:
00098 MatrixElement* matrix;
00099 uint rowPos;
00100 uint colPos;
00101
00102 QPtrList<MatrixSequenceElement>* column;
00103 };
00104
00105
00106 class KFCInsertColumn : public KFCRemoveColumn {
00107 public:
00108 KFCInsertColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c );
00109
00110 virtual void execute() { KFCRemoveColumn::unexecute(); }
00111 virtual void unexecute() { KFCRemoveColumn::execute(); }
00112 };
00113
00114
00115 KCommand* MatrixSequenceElement::buildCommand( Container* container, Request* request )
00116 {
00117 FormulaCursor* cursor = container->activeCursor();
00118 if ( cursor->isReadOnly() ) {
00119 return 0;
00120 }
00121
00122 switch ( *request ) {
00123 case req_appendColumn:
00124 case req_appendRow:
00125 case req_insertColumn:
00126 case req_removeColumn:
00127 case req_insertRow:
00128 case req_removeRow: {
00129 MatrixElement* matrix = static_cast<MatrixElement*>( getParent() );
00130 FormulaCursor* cursor = container->activeCursor();
00131 for ( uint row = 0; row < matrix->getRows(); row++ ) {
00132 for ( uint col = 0; col < matrix->getColumns(); col++ ) {
00133 if ( matrix->getElement( row, col ) == cursor->getElement() ) {
00134 switch ( *request ) {
00135 case req_appendColumn:
00136 return new KFCInsertColumn( i18n( "Append Column" ), container, matrix, row, matrix->getColumns() );
00137 case req_appendRow:
00138 return new KFCInsertRow( i18n( "Append Row" ), container, matrix, matrix->getRows(), col );
00139 case req_insertColumn:
00140 return new KFCInsertColumn( i18n( "Insert Column" ), container, matrix, row, col );
00141 case req_removeColumn:
00142 if ( matrix->getColumns() > 1 ) {
00143 return new KFCRemoveColumn( i18n( "Remove Column" ), container, matrix, row, col );
00144 }
00145 break;
00146 case req_insertRow:
00147 return new KFCInsertRow( i18n( "Insert Row" ), container, matrix, row, col );
00148 case req_removeRow:
00149 if ( matrix->getRows() > 1 ) {
00150 return new KFCRemoveRow( i18n( "Remove Row" ), container, matrix, row, col );
00151 }
00152 break;
00153 default:
00154 break;
00155 }
00156 }
00157 }
00158 }
00159 kdWarning( DEBUGID ) << "MatrixSequenceElement::buildCommand: Sequence not found." << endl;
00160 break;
00161 }
00162 default:
00163 break;
00164 }
00165 return inherited::buildCommand( container, request );
00166 }
00167
00168
00169 KFCRemoveRow::KFCRemoveRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
00170 : Command( name, document ), matrix( m ), rowPos( r ), colPos( c ), row( 0 )
00171 {
00172 }
00173
00174 KFCRemoveRow::~KFCRemoveRow()
00175 {
00176 delete row;
00177 }
00178
00179 void KFCRemoveRow::execute()
00180 {
00181 FormulaCursor* cursor = getExecuteCursor();
00182 row = matrix->content.at( rowPos );
00183 FormulaElement* formula = matrix->formula();
00184 for ( uint i = matrix->getColumns(); i > 0; i-- ) {
00185 formula->elementRemoval( row->at( i-1 ) );
00186 }
00187 matrix->content.take( rowPos );
00188 formula->changed();
00189 if ( rowPos < matrix->getRows() ) {
00190 matrix->getElement( rowPos, colPos )->goInside( cursor );
00191 }
00192 else {
00193 matrix->getElement( rowPos-1, colPos )->goInside( cursor );
00194 }
00195 testDirty();
00196 }
00197
00198 void KFCRemoveRow::unexecute()
00199 {
00200 matrix->content.insert( rowPos, row );
00201 row = 0;
00202 FormulaCursor* cursor = getExecuteCursor();
00203 matrix->getElement( rowPos, colPos )->goInside( cursor );
00204 matrix->formula()->changed();
00205 testDirty();
00206 }
00207
00208
00209 KFCInsertRow::KFCInsertRow( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
00210 : KFCRemoveRow( name, document, m, r, c )
00211 {
00212 row = new QPtrList< MatrixSequenceElement >;
00213 row->setAutoDelete( true );
00214 for ( uint i = 0; i < matrix->getColumns(); i++ ) {
00215 row->append( new MatrixSequenceElement( matrix ) );
00216 }
00217 }
00218
00219
00220 KFCRemoveColumn::KFCRemoveColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
00221 : Command( name, document ), matrix( m ), rowPos( r ), colPos( c )
00222 {
00223 column = new QPtrList< MatrixSequenceElement >;
00224 column->setAutoDelete( true );
00225 }
00226
00227 KFCRemoveColumn::~KFCRemoveColumn()
00228 {
00229 delete column;
00230 }
00231
00232 void KFCRemoveColumn::execute()
00233 {
00234 FormulaCursor* cursor = getExecuteCursor();
00235 FormulaElement* formula = matrix->formula();
00236 for ( uint i = 0; i < matrix->getRows(); i++ ) {
00237 column->append( matrix->getElement( i, colPos ) );
00238 formula->elementRemoval( column->at( i ) );
00239 matrix->content.at( i )->take( colPos );
00240 }
00241 formula->changed();
00242 if ( colPos < matrix->getColumns() ) {
00243 matrix->getElement( rowPos, colPos )->goInside( cursor );
00244 }
00245 else {
00246 matrix->getElement( rowPos, colPos-1 )->goInside( cursor );
00247 }
00248 testDirty();
00249 }
00250
00251 void KFCRemoveColumn::unexecute()
00252 {
00253 for ( uint i = 0; i < matrix->getRows(); i++ ) {
00254 matrix->content.at( i )->insert( colPos, column->take( 0 ) );
00255 }
00256 FormulaCursor* cursor = getExecuteCursor();
00257 matrix->getElement( rowPos, colPos )->goInside( cursor );
00258 matrix->formula()->changed();
00259 testDirty();
00260 }
00261
00262
00263 KFCInsertColumn::KFCInsertColumn( const QString& name, Container* document, MatrixElement* m, uint r, uint c )
00264 : KFCRemoveColumn( name, document, m, r, c )
00265 {
00266 for ( uint i = 0; i < matrix->getRows(); i++ ) {
00267 column->append( new MatrixSequenceElement( matrix ) );
00268 }
00269 }
00270
00271
00272 MatrixElement::MatrixElement(uint rows, uint columns, BasicElement* parent)
00273 : BasicElement(parent)
00274 {
00275 for (uint r = 0; r < rows; r++) {
00276 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
00277 list->setAutoDelete(true);
00278 for (uint c = 0; c < columns; c++) {
00279 list->append(new MatrixSequenceElement(this));
00280 }
00281 content.append(list);
00282 }
00283 content.setAutoDelete(true);
00284 }
00285
00286 MatrixElement::~MatrixElement()
00287 {
00288 }
00289
00290
00291 MatrixElement::MatrixElement( const MatrixElement& other )
00292 : BasicElement( other )
00293 {
00294 uint rows = other.getRows();
00295 uint columns = other.getColumns();
00296
00297 QPtrListIterator< QPtrList< MatrixSequenceElement > > rowIter( other.content );
00298 for (uint r = 0; r < rows; r++) {
00299 ++rowIter;
00300 QPtrListIterator< MatrixSequenceElement > colIter( *rowIter.current() );
00301
00302 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
00303 list->setAutoDelete(true);
00304 for (uint c = 0; c < columns; c++) {
00305 ++colIter;
00306 MatrixSequenceElement *mse =
00307
00308 new MatrixSequenceElement( *colIter.current() );
00309 list->append( mse );
00310 mse->setParent( this );
00311 }
00312 content.append(list);
00313 }
00314 content.setAutoDelete(true);
00315 }
00316
00317
00318 bool MatrixElement::accept( ElementVisitor* visitor )
00319 {
00320 return visitor->visit( this );
00321 }
00322
00323
00324 void MatrixElement::entered( SequenceElement* )
00325 {
00326 formula()->tell( i18n( "Matrix element" ) );
00327 }
00328
00329
00330 BasicElement* MatrixElement::goToPos( FormulaCursor* cursor, bool& handled,
00331 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00332 {
00333 BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00334 if (e != 0) {
00335 LuPixelPoint myPos(parentOrigin.x() + getX(),
00336 parentOrigin.y() + getY());
00337
00338 uint rows = getRows();
00339 uint columns = getColumns();
00340
00341 for (uint r = 0; r < rows; r++) {
00342 for (uint c = 0; c < columns; c++) {
00343 BasicElement* element = getElement(r, c);
00344 e = element->goToPos(cursor, handled, point, myPos);
00345 if (e != 0) {
00346 return e;
00347 }
00348 }
00349 }
00350
00351
00352 luPixel dx = point.x() - myPos.x();
00353 luPixel dy = point.y() - myPos.y();
00354
00355 uint row = rows;
00356 for (uint r = 0; r < rows; r++) {
00357 BasicElement* element = getElement(r, 0);
00358 if (element->getY() > dy) {
00359 row = r;
00360 break;
00361 }
00362 }
00363 if (row == 0) {
00364 BasicElement* element = getParent();
00365 element->moveLeft(cursor, this);
00366 handled = true;
00367 return element;
00368 }
00369 row--;
00370
00371 uint column = columns;
00372 for (uint c = 0; c < columns; c++) {
00373 BasicElement* element = getElement(row, c);
00374 if (element->getX() > dx) {
00375 column = c;
00376 break;
00377 }
00378 }
00379 if (column == 0) {
00380 BasicElement* element = getParent();
00381 element->moveLeft(cursor, this);
00382 handled = true;
00383 return element;
00384 }
00385 column--;
00386
00387
00388 row = rows;
00389 for (uint r = 0; r < rows; r++) {
00390 BasicElement* element = getElement(r, column);
00391 if (element->getY() > dy) {
00392 row = r;
00393 break;
00394 }
00395 }
00396 if (row == 0) {
00397 BasicElement* element = getParent();
00398 element->moveLeft(cursor, this);
00399 handled = true;
00400 return element;
00401 }
00402 row--;
00403
00404 BasicElement* element = getElement(row, column);
00405 element->moveLeft(cursor, this);
00406 handled = true;
00407 return element;
00408 }
00409 return 0;
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419
00424 void MatrixElement::calcSizes(const ContextStyle& style, ContextStyle::TextStyle tstyle, ContextStyle::IndexStyle istyle)
00425 {
00426 QMemArray<luPixel> toMidlines(getRows());
00427 QMemArray<luPixel> fromMidlines(getRows());
00428 QMemArray<luPixel> widths(getColumns());
00429
00430 toMidlines.fill(0);
00431 fromMidlines.fill(0);
00432 widths.fill(0);
00433
00434 uint rows = getRows();
00435 uint columns = getColumns();
00436
00437 ContextStyle::TextStyle i_tstyle = style.convertTextStyleFraction(tstyle);
00438 ContextStyle::IndexStyle i_istyle = style.convertIndexStyleUpper(istyle);
00439
00440 for (uint r = 0; r < rows; r++) {
00441 QPtrList< MatrixSequenceElement >* list = content.at(r);
00442 for (uint c = 0; c < columns; c++) {
00443 SequenceElement* element = list->at(c);
00444 element->calcSizes( style, i_tstyle, i_istyle );
00445 toMidlines[r] = QMAX(toMidlines[r], element->axis( style, i_tstyle ));
00446 fromMidlines[r] = QMAX(fromMidlines[r],
00447 element->getHeight()-element->axis( style, i_tstyle ));
00448 widths[c] = QMAX(widths[c], element->getWidth());
00449 }
00450 }
00451
00452 luPixel distX = style.ptToPixelX( style.getThinSpace( tstyle ) );
00453 luPixel distY = style.ptToPixelY( style.getThinSpace( tstyle ) );
00454
00455 luPixel yPos = 0;
00456 for (uint r = 0; r < rows; r++) {
00457 QPtrList< MatrixSequenceElement >* list = content.at(r);
00458 luPixel xPos = 0;
00459 yPos += toMidlines[r];
00460 for (uint c = 0; c < columns; c++) {
00461 SequenceElement* element = list->at(c);
00462 switch (style.getMatrixAlignment()) {
00463 case ContextStyle::left:
00464 element->setX(xPos);
00465 break;
00466 case ContextStyle::center:
00467 element->setX(xPos + (widths[c] - element->getWidth())/2);
00468 break;
00469 case ContextStyle::right:
00470 element->setX(xPos + widths[c] - element->getWidth());
00471 break;
00472 }
00473 element->setY(yPos - element->axis( style, i_tstyle ));
00474 xPos += widths[c] + distX;
00475 }
00476 yPos += fromMidlines[r] + distY;
00477 }
00478
00479 luPixel width = distX * (columns - 1);
00480 luPixel height = distY * (rows - 1);
00481
00482 for (uint r = 0; r < rows; r++) height += toMidlines[r] + fromMidlines[r];
00483 for (uint c = 0; c < columns; c++) width += widths[c];
00484
00485 setWidth(width);
00486 setHeight(height);
00487 if ((rows == 2) && (columns == 1)) {
00488 setBaseline( getMainChild()->getHeight() + distY / 2 + style.axisHeight( tstyle ) );
00489 }
00490 else {
00491 setBaseline( height/2 + style.axisHeight( tstyle ) );
00492 }
00493 }
00494
00500 void MatrixElement::draw( QPainter& painter, const LuPixelRect& rect,
00501 const ContextStyle& style,
00502 ContextStyle::TextStyle tstyle,
00503 ContextStyle::IndexStyle istyle,
00504 const LuPixelPoint& parentOrigin )
00505 {
00506 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00507
00508
00509
00510 uint rows = getRows();
00511 uint columns = getColumns();
00512
00513 for (uint r = 0; r < rows; r++) {
00514 for (uint c = 0; c < columns; c++) {
00515 getElement(r, c)->draw(painter, rect, style,
00516 style.convertTextStyleFraction(tstyle),
00517 style.convertIndexStyleUpper(istyle),
00518 myPos);
00519 }
00520 }
00521
00522
00523
00524
00525 }
00526
00527
00528 void MatrixElement::dispatchFontCommand( FontCommand* cmd )
00529 {
00530 uint rows = getRows();
00531 uint columns = getColumns();
00532
00533 for (uint r = 0; r < rows; r++) {
00534 for (uint c = 0; c < columns; c++) {
00535 getElement(r, c)->dispatchFontCommand( cmd );
00536 }
00537 }
00538 }
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00554 void MatrixElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
00555 {
00556 if (cursor->isSelectionMode()) {
00557 getParent()->moveLeft(cursor, this);
00558 }
00559 else {
00560 if (from == getParent()) {
00561 getElement(getRows()-1, getColumns()-1)->moveLeft(cursor, this);
00562 }
00563 else {
00564 bool linear = cursor->getLinearMovement();
00565 uint row = 0;
00566 uint column = 0;
00567 if (searchElement(from, row, column)) {
00568 if (column > 0) {
00569 getElement(row, column-1)->moveLeft(cursor, this);
00570 }
00571 else if (linear && (row > 0)) {
00572 getElement(row-1, getColumns()-1)->moveLeft(cursor, this);
00573 }
00574 else {
00575 getParent()->moveLeft(cursor, this);
00576 }
00577 }
00578 else {
00579 getParent()->moveLeft(cursor, this);
00580 }
00581 }
00582 }
00583 }
00584
00590 void MatrixElement::moveRight(FormulaCursor* cursor, BasicElement* from)
00591 {
00592 if (cursor->isSelectionMode()) {
00593 getParent()->moveRight(cursor, this);
00594 }
00595 else {
00596 if (from == getParent()) {
00597 getElement(0, 0)->moveRight(cursor, this);
00598 }
00599 else {
00600 bool linear = cursor->getLinearMovement();
00601 uint row = 0;
00602 uint column = 0;
00603 if (searchElement(from, row, column)) {
00604 if (column < getColumns()-1) {
00605 getElement(row, column+1)->moveRight(cursor, this);
00606 }
00607 else if (linear && (row < getRows()-1)) {
00608 getElement(row+1, 0)->moveRight(cursor, this);
00609 }
00610 else {
00611 getParent()->moveRight(cursor, this);
00612 }
00613 }
00614 else {
00615 getParent()->moveRight(cursor, this);
00616 }
00617 }
00618 }
00619 }
00620
00626 void MatrixElement::moveUp(FormulaCursor* cursor, BasicElement* from)
00627 {
00628 if (cursor->isSelectionMode()) {
00629 getParent()->moveUp(cursor, this);
00630 }
00631 else {
00632 if (from == getParent()) {
00633 getElement(0, 0)->moveRight(cursor, this);
00634 }
00635 else {
00636 uint row = 0;
00637 uint column = 0;
00638 if (searchElement(from, row, column)) {
00639 if (row > 0) {
00640 getElement(row-1, column)->moveRight(cursor, this);
00641 }
00642 else {
00643 getParent()->moveUp(cursor, this);
00644 }
00645 }
00646 else {
00647 getParent()->moveUp(cursor, this);
00648 }
00649 }
00650 }
00651 }
00652
00658 void MatrixElement::moveDown(FormulaCursor* cursor, BasicElement* from)
00659 {
00660 if (cursor->isSelectionMode()) {
00661 getParent()->moveDown(cursor, this);
00662 }
00663 else {
00664 if (from == getParent()) {
00665 getElement(0, 0)->moveRight(cursor, this);
00666 }
00667 else {
00668 uint row = 0;
00669 uint column = 0;
00670 if (searchElement(from, row, column)) {
00671 if (row < getRows()-1) {
00672 getElement(row+1, column)->moveRight(cursor, this);
00673 }
00674 else {
00675 getParent()->moveDown(cursor, this);
00676 }
00677 }
00678 else {
00679 getParent()->moveDown(cursor, this);
00680 }
00681 }
00682 }
00683 }
00684
00689 void MatrixElement::goInside(FormulaCursor* cursor)
00690 {
00691 getElement(0, 0)->goInside(cursor);
00692 }
00693
00694
00695
00696 SequenceElement* MatrixElement::getMainChild()
00697 {
00698 return content.at(0)->at(0);
00699 }
00700
00701 void MatrixElement::selectChild(FormulaCursor* cursor, BasicElement* child)
00702 {
00703 uint rows = getRows();
00704 uint columns = getColumns();
00705 for (uint r = 0; r < rows; r++) {
00706 for (uint c = 0; c < columns; c++) {
00707 if (child == getElement(r, c)) {
00708 cursor->setTo(this, r*columns+c);
00709 }
00710 }
00711 }
00712 }
00713
00714 bool MatrixElement::searchElement(BasicElement* element, uint& row, uint& column)
00715 {
00716 uint rows = getRows();
00717 uint columns = getColumns();
00718 for (uint r = 0; r < rows; r++) {
00719 for (uint c = 0; c < columns; c++) {
00720 if (element == getElement(r, c)) {
00721 row = r;
00722 column = c;
00723 return true;
00724 }
00725 }
00726 }
00727 return false;
00728 }
00729
00730
00734 void MatrixElement::writeDom(QDomElement element)
00735 {
00736 BasicElement::writeDom(element);
00737
00738 uint rows = getRows();
00739 uint cols = getColumns();
00740
00741 element.setAttribute("ROWS", rows);
00742 element.setAttribute("COLUMNS", cols);
00743
00744 QDomDocument doc = element.ownerDocument();
00745
00746 for (uint r = 0; r < rows; r++) {
00747 for (uint c = 0; c < cols; c++) {
00748 QDomElement tmp = getElement(r,c)->getElementDom(doc);
00749 element.appendChild(tmp);
00750 }
00751 element.appendChild(doc.createComment("end of row"));
00752 }
00753 }
00754
00759 bool MatrixElement::readAttributesFromDom(QDomElement element)
00760 {
00761 if (!BasicElement::readAttributesFromDom(element)) {
00762 return false;
00763 }
00764 uint rows = 0;
00765 QString rowStr = element.attribute("ROWS");
00766 if(!rowStr.isNull()) {
00767 rows = rowStr.toInt();
00768 }
00769 if (rows == 0) {
00770 kdWarning( DEBUGID ) << "Rows <= 0 in MatrixElement." << endl;
00771 return false;
00772 }
00773
00774 QString columnStr = element.attribute("COLUMNS");
00775 uint cols = 0;
00776 if(!columnStr.isNull()) {
00777 cols = columnStr.toInt();
00778 }
00779 if (cols == 0) {
00780 kdWarning( DEBUGID ) << "Columns <= 0 in MatrixElement." << endl;
00781 return false;
00782 }
00783
00784 content.clear();
00785 for (uint r = 0; r < rows; r++) {
00786 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
00787 list->setAutoDelete(true);
00788 content.append(list);
00789 for (uint c = 0; c < cols; c++) {
00790 MatrixSequenceElement* element = new MatrixSequenceElement(this);
00791 list->append(element);
00792 }
00793 }
00794 return true;
00795 }
00796
00802 bool MatrixElement::readContentFromDom(QDomNode& node)
00803 {
00804 if (!BasicElement::readContentFromDom(node)) {
00805 return false;
00806 }
00807
00808 uint rows = getRows();
00809 uint cols = getColumns();
00810
00811 uint r = 0;
00812 uint c = 0;
00813 while ( !node.isNull() && r < rows ) {
00814 if ( node.isElement() ) {
00815 SequenceElement* element = getElement( r, c );
00816 QDomElement e = node.toElement();
00817 if ( !element->buildFromDom( e ) ) {
00818 return false;
00819 }
00820 c++;
00821 if ( c == cols ) {
00822 c = 0;
00823 r++;
00824 }
00825 }
00826 node = node.nextSibling();
00827 }
00828 return true;
00829 }
00830
00831 QString MatrixElement::toLatex()
00832 {
00833
00834
00835 QString matrix;
00836 uint cols=getColumns();
00837 uint rows=getRows();
00838
00839 matrix="\\begin{array}{ ";
00840 for(uint i=0;i<cols;i++)
00841 matrix+="c ";
00842
00843 matrix+="}";
00844
00845 for (uint r = 0; r < rows; r++) {
00846 for (uint c = 0; c < cols; c++) {
00847 matrix+=getElement(r, c)->toLatex();
00848 if( c < cols-1) matrix+=" & ";
00849 }
00850 if(r < rows-1 ) matrix+=" \\\\ ";
00851 }
00852
00853 matrix+="\\end{array}";
00854
00855 return matrix;
00856 }
00857
00858 QString MatrixElement::formulaString()
00859 {
00860 QString matrix = "[";
00861 uint cols=getColumns();
00862 uint rows=getRows();
00863 for (uint r = 0; r < rows; r++) {
00864 matrix += "[";
00865 for (uint c = 0; c < cols; c++) {
00866 matrix+=getElement(r, c)->formulaString();
00867 if ( c < cols-1 ) matrix+=", ";
00868 }
00869 matrix += "]";
00870 if ( r < rows-1 ) matrix += ", ";
00871 }
00872 matrix += "]";
00873 return matrix;
00874 }
00875
00876
00877 SequenceElement* MatrixElement::elementAt(uint row, uint column)
00878 {
00879 return getElement( row, column );
00880 }
00881
00882
00883 void MatrixElement::writeMathML( QDomDocument doc, QDomNode parent )
00884 {
00885 QDomElement de = doc.createElement( "mtable" );
00886 QDomElement row;
00887 QDomElement cell;
00888
00889 uint rows = getRows();
00890 uint cols = getColumns();
00891
00892 for ( uint r = 0; r < rows; r++ )
00893 {
00894 row = doc.createElement( "mtr" );
00895 de.appendChild( row );
00896 for ( uint c = 0; c < cols; c++ )
00897 {
00898 cell = doc.createElement( "mtd" );
00899 row.appendChild( cell );
00900 getElement(r,c)->writeMathML( doc, cell );
00901 }
00902 }
00903
00904 parent.appendChild( de );
00905 }
00906
00907
00909
00910
00915 class MultilineSequenceElement : public SequenceElement {
00916 typedef SequenceElement inherited;
00917 public:
00918
00919 MultilineSequenceElement( BasicElement* parent = 0 );
00920
00921 virtual MultilineSequenceElement* clone() {
00922 return new MultilineSequenceElement( *this );
00923 }
00924
00925 virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
00926 const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
00927
00932 virtual void calcSizes( const ContextStyle& context,
00933 ContextStyle::TextStyle tstyle,
00934 ContextStyle::IndexStyle istyle );
00935
00936 virtual void registerTab( BasicElement* tab );
00937
00946 virtual KCommand* buildCommand( Container*, Request* );
00947
00948 virtual KCommand* input( Container* container, QKeyEvent* event );
00949
00950 virtual KCommand* input( Container* container, QChar ch );
00951
00952 uint tabCount() const { return tabs.count(); }
00953
00954 BasicElement* tab( uint i ) { return tabs.at( i ); }
00955
00957 void moveTabTo( uint i, luPixel pos );
00958
00960 int tabBefore( uint pos );
00961
00963 int tabPos( uint i );
00964
00965 virtual void writeMathML( QDomDocument doc, QDomNode parent );
00966
00967 private:
00968
00969 QPtrList<BasicElement> tabs;
00970 };
00971
00972
00973
00974 class KFCNewLine : public Command {
00975 public:
00976 KFCNewLine( const QString& name, Container* document,
00977 MultilineSequenceElement* line, uint pos );
00978
00979 virtual ~KFCNewLine();
00980
00981 virtual void execute();
00982 virtual void unexecute();
00983
00984 private:
00985 MultilineSequenceElement* m_line;
00986 MultilineSequenceElement* m_newline;
00987 uint m_pos;
00988 };
00989
00990
00991 KFCNewLine::KFCNewLine( const QString& name, Container* document,
00992 MultilineSequenceElement* line, uint pos )
00993 : Command( name, document ),
00994 m_line( line ), m_pos( pos )
00995 {
00996 m_newline = new MultilineSequenceElement( m_line->getParent() );
00997 }
00998
00999
01000 KFCNewLine::~KFCNewLine()
01001 {
01002 delete m_newline;
01003 }
01004
01005
01006 void KFCNewLine::execute()
01007 {
01008 FormulaCursor* cursor = getExecuteCursor();
01009 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
01010 int linePos = parent->content.find( m_line );
01011 parent->content.insert( linePos+1, m_newline );
01012
01013
01014 if ( m_line->countChildren() > static_cast<int>( m_pos ) ) {
01015
01016
01017 m_line->selectAllChildren( cursor );
01018 cursor->setMark( m_pos );
01019 QPtrList<BasicElement> elementList;
01020 m_line->remove( cursor, elementList, beforeCursor );
01021
01022
01023 m_newline->goInside( cursor );
01024 m_newline->insert( cursor, elementList, beforeCursor );
01025 cursor->setPos( cursor->getMark() );
01026 }
01027 else {
01028 m_newline->goInside( cursor );
01029 }
01030
01031
01032 m_newline = 0;
01033
01034
01035 FormulaElement* formula = m_line->formula();
01036 formula->changed();
01037 testDirty();
01038 }
01039
01040
01041 void KFCNewLine::unexecute()
01042 {
01043 FormulaCursor* cursor = getExecuteCursor();
01044 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
01045 int linePos = parent->content.find( m_line );
01046
01047
01048 m_newline = parent->content.at( linePos+1 );
01049
01050
01051 FormulaElement* formula = m_line->formula();
01052 formula->elementRemoval( m_newline );
01053
01054
01055 if ( m_newline->countChildren() > 0 ) {
01056
01057
01058 m_newline->selectAllChildren( cursor );
01059 QPtrList<BasicElement> elementList;
01060 m_newline->remove( cursor, elementList, beforeCursor );
01061
01062
01063 m_line->moveEnd( cursor );
01064 m_line->insert( cursor, elementList, beforeCursor );
01065 cursor->setPos( cursor->getMark() );
01066 }
01067 else {
01068 m_line->moveEnd( cursor );
01069 }
01070 parent->content.take( linePos+1 );
01071
01072
01073 formula->changed();
01074 testDirty();
01075 }
01076
01077
01078 MultilineSequenceElement::MultilineSequenceElement( BasicElement* parent )
01079 : SequenceElement( parent )
01080 {
01081 tabs.setAutoDelete( false );
01082 }
01083
01084
01085 BasicElement* MultilineSequenceElement::goToPos( FormulaCursor* cursor, bool& handled,
01086 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
01087 {
01088
01089
01090 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
01091
01092 if (e == 0) {
01093
01094 if ( ( point.x() > getX()+getWidth() ) &&
01095 ( point.y() >= getY() ) &&
01096 ( point.y() < getY()+getHeight() ) ) {
01097 cursor->setTo(this, countChildren());
01098 handled = true;
01099 return this;
01100 }
01101 }
01102 return e;
01103 }
01104
01105
01106 void MultilineSequenceElement::calcSizes( const ContextStyle& context,
01107 ContextStyle::TextStyle tstyle,
01108 ContextStyle::IndexStyle istyle )
01109 {
01110 tabs.clear();
01111 inherited::calcSizes( context, tstyle, istyle );
01112 }
01113
01114
01115 void MultilineSequenceElement::registerTab( BasicElement* tab )
01116 {
01117 tabs.append( tab );
01118 }
01119
01120
01121 KCommand* MultilineSequenceElement::buildCommand( Container* container, Request* request )
01122 {
01123 FormulaCursor* cursor = container->activeCursor();
01124 if ( cursor->isReadOnly() ) {
01125 return 0;
01126 }
01127
01128 switch ( *request ) {
01129 case req_remove: {
01130
01131
01132 break;
01133 }
01134 case req_addNewline: {
01135 FormulaCursor* cursor = container->activeCursor();
01136 return new KFCNewLine( i18n( "Add Newline" ), container, this, cursor->getPos() );
01137 }
01138 case req_addTabMark: {
01139 KFCReplace* command = new KFCReplace( i18n("Add Tabmark"), container );
01140 SpaceElement* element = new SpaceElement( THIN, true );
01141 command->addElement( element );
01142 return command;
01143 }
01144 default:
01145 break;
01146 }
01147 return inherited::buildCommand( container, request );
01148 }
01149
01150
01151 KCommand* MultilineSequenceElement::input( Container* container, QKeyEvent* event )
01152 {
01153 int action = event->key();
01154
01155
01156
01157 switch ( action ) {
01158 case Qt::Key_Enter:
01159 case Qt::Key_Return: {
01160 Request newline( req_addNewline );
01161 return buildCommand( container, &newline );
01162 }
01163 case Qt::Key_Tab: {
01164 Request r( req_addTabMark );
01165 return buildCommand( container, &r );
01166 }
01167 }
01168 return inherited::input( container, event );
01169 }
01170
01171
01172 KCommand* MultilineSequenceElement::input( Container* container, QChar ch )
01173 {
01174 int latin1 = ch.latin1();
01175 switch (latin1) {
01176 case '&': {
01177 Request r( req_addTabMark );
01178 return buildCommand( container, &r );
01179 }
01180 }
01181 return inherited::input( container, ch );
01182 }
01183
01184
01185 void MultilineSequenceElement::moveTabTo( uint i, luPixel pos )
01186 {
01187 BasicElement* marker = tab( i );
01188 luPixel diff = pos - marker->getX();
01189 marker->setWidth( marker->getWidth() + diff );
01190
01191 for ( int p = childPos( marker )+1; p < countChildren(); ++p ) {
01192 BasicElement* child = getChild( p );
01193 child->setX( child->getX() + diff );
01194 }
01195
01196 setWidth( getWidth()+diff );
01197 }
01198
01199
01200 int MultilineSequenceElement::tabBefore( uint pos )
01201 {
01202 if ( tabs.isEmpty() ) {
01203 return -1;
01204 }
01205 uint tabNum = 0;
01206 for ( uint i=0; i<pos; ++i ) {
01207 BasicElement* child = getChild( i );
01208 if ( tabs.at( tabNum ) == child ) {
01209 if ( tabNum+1 == tabs.count() ) {
01210 return tabNum;
01211 }
01212 ++tabNum;
01213 }
01214 }
01215 return static_cast<int>( tabNum )-1;
01216 }
01217
01218
01219 int MultilineSequenceElement::tabPos( uint i )
01220 {
01221 if ( i < tabs.count() ) {
01222 return childPos( tabs.at( i ) );
01223 }
01224 return -1;
01225 }
01226
01227
01228 void MultilineSequenceElement::writeMathML( QDomDocument doc,
01229 QDomNode parent )
01230 {
01231
01232
01233 QDomElement tmp = doc.createElement( "TMP" );
01234
01235 inherited::writeMathML( doc, tmp );
01236
01237
01238
01239
01240
01241
01242 QDomElement mtd = doc.createElement( "mtd" );
01243
01244
01245 QDomNode n = tmp.firstChild().firstChild();
01246 while ( !n.isNull() ) {
01247
01248 if ( n.isElement() && n.toElement().tagName() == "TAB" ) {
01249 parent.appendChild( mtd );
01250 mtd = doc.createElement( "mtd" );
01251 }
01252 else {
01253 mtd.appendChild( n.cloneNode() );
01254 }
01255 n = n.nextSibling();
01256 }
01257
01258 parent.appendChild( mtd );
01259 }
01260
01261
01262 MultilineElement::MultilineElement( BasicElement* parent )
01263 : BasicElement( parent )
01264 {
01265 content.setAutoDelete( true );
01266 content.append( new MultilineSequenceElement( this ) );
01267 }
01268
01269 MultilineElement::~MultilineElement()
01270 {
01271 }
01272
01273 MultilineElement::MultilineElement( const MultilineElement& other )
01274 : BasicElement( other )
01275 {
01276 content.setAutoDelete( true );
01277 uint count = other.content.count();
01278 for (uint i = 0; i < count; i++) {
01279 MultilineSequenceElement* line = content.at(i)->clone();
01280 line->setParent( this );
01281 content.append( line );
01282 }
01283 }
01284
01285
01286 bool MultilineElement::accept( ElementVisitor* visitor )
01287 {
01288 return visitor->visit( this );
01289 }
01290
01291
01292 void MultilineElement::entered( SequenceElement* )
01293 {
01294 formula()->tell( i18n( "Multi line element" ) );
01295 }
01296
01297
01301 BasicElement* MultilineElement::goToPos( FormulaCursor* cursor, bool& handled,
01302 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
01303 {
01304 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
01305 if ( e != 0 ) {
01306 LuPixelPoint myPos(parentOrigin.x() + getX(),
01307 parentOrigin.y() + getY());
01308
01309 uint count = content.count();
01310 for ( uint i = 0; i < count; ++i ) {
01311 MultilineSequenceElement* line = content.at(i);
01312 e = line->goToPos(cursor, handled, point, myPos);
01313 if (e != 0) {
01314 return e;
01315 }
01316 }
01317 return this;
01318 }
01319 return 0;
01320 }
01321
01322 void MultilineElement::goInside( FormulaCursor* cursor )
01323 {
01324 content.at( 0 )->goInside( cursor );
01325 }
01326
01327 void MultilineElement::moveLeft( FormulaCursor* cursor, BasicElement* from )
01328 {
01329
01330
01331 if (cursor->isSelectionMode()) {
01332 getParent()->moveLeft(cursor, this);
01333 }
01334 else {
01335
01336
01337 if (from == getParent()) {
01338 content.at( content.count()-1 )->moveLeft(cursor, this);
01339 }
01340 else {
01341
01342
01343 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
01344 if ( pos > -1 ) {
01345 if ( pos > 0 ) {
01346 content.at( pos-1 )->moveLeft( cursor, this );
01347 }
01348 else {
01349 getParent()->moveLeft(cursor, this);
01350 }
01351 }
01352 else {
01353 kdDebug( DEBUGID ) << k_funcinfo << endl;
01354 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
01355 }
01356 }
01357 }
01358 }
01359
01360 void MultilineElement::moveRight( FormulaCursor* cursor, BasicElement* from )
01361 {
01362 if (cursor->isSelectionMode()) {
01363 getParent()->moveRight(cursor, this);
01364 }
01365 else {
01366 if (from == getParent()) {
01367 content.at( 0 )->moveRight(cursor, this);
01368 }
01369 else {
01370 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
01371 if ( pos > -1 ) {
01372 uint upos = pos;
01373 if ( upos < content.count() ) {
01374 if ( upos < content.count()-1 ) {
01375 content.at( upos+1 )->moveRight( cursor, this );
01376 }
01377 else {
01378 getParent()->moveRight(cursor, this);
01379 }
01380 return;
01381 }
01382 }
01383 kdDebug( DEBUGID ) << k_funcinfo << endl;
01384 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
01385 }
01386 }
01387 }
01388
01389 void MultilineElement::moveUp( FormulaCursor* cursor, BasicElement* from )
01390 {
01391
01392
01393 if (cursor->isSelectionMode()) {
01394 getParent()->moveLeft(cursor, this);
01395 }
01396 else {
01397
01398
01399 if (from == getParent()) {
01400 content.at( content.count()-1 )->moveLeft(cursor, this);
01401 }
01402 else {
01403
01404
01405 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
01406 if ( pos > -1 ) {
01407 if ( pos > 0 ) {
01408
01409
01410
01411 int cursorPos = cursor->getPos();
01412 MultilineSequenceElement* current = content.at( pos );
01413 MultilineSequenceElement* newLine = content.at( pos-1 );
01414 int tabNum = current->tabBefore( cursorPos );
01415 if ( tabNum > -1 ) {
01416 int oldTabPos = current->tabPos( tabNum );
01417 int newTabPos = newLine->tabPos( tabNum );
01418 if ( newTabPos > -1 ) {
01419 cursorPos += newTabPos-oldTabPos;
01420 int nextNewTabPos = newLine->tabPos( tabNum+1 );
01421 if ( nextNewTabPos > -1 ) {
01422 cursorPos = QMIN( cursorPos, nextNewTabPos );
01423 }
01424 }
01425 else {
01426 cursorPos = newLine->countChildren();
01427 }
01428 }
01429 else {
01430 int nextNewTabPos = newLine->tabPos( 0 );
01431 if ( nextNewTabPos > -1 ) {
01432 cursorPos = QMIN( cursorPos, nextNewTabPos );
01433 }
01434 }
01435 cursor->setTo( newLine,
01436 QMIN( cursorPos,
01437 newLine->countChildren() ) );
01438 }
01439 else {
01440 getParent()->moveLeft(cursor, this);
01441 }
01442 }
01443 else {
01444 kdDebug( DEBUGID ) << k_funcinfo << endl;
01445 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
01446 }
01447 }
01448 }
01449 }
01450
01451 void MultilineElement::moveDown( FormulaCursor* cursor, BasicElement* from )
01452 {
01453 if (cursor->isSelectionMode()) {
01454 getParent()->moveRight(cursor, this);
01455 }
01456 else {
01457 if (from == getParent()) {
01458 content.at( 0 )->moveRight(cursor, this);
01459 }
01460 else {
01461 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
01462 if ( pos > -1 ) {
01463 uint upos = pos;
01464 if ( upos < content.count() ) {
01465 if ( upos < content.count()-1 ) {
01466
01467
01468
01469 int cursorPos = cursor->getPos();
01470 MultilineSequenceElement* current = content.at( upos );
01471 MultilineSequenceElement* newLine = content.at( upos+1 );
01472 int tabNum = current->tabBefore( cursorPos );
01473 if ( tabNum > -1 ) {
01474 int oldTabPos = current->tabPos( tabNum );
01475 int newTabPos = newLine->tabPos( tabNum );
01476 if ( newTabPos > -1 ) {
01477 cursorPos += newTabPos-oldTabPos;
01478 int nextNewTabPos = newLine->tabPos( tabNum+1 );
01479 if ( nextNewTabPos > -1 ) {
01480 cursorPos = QMIN( cursorPos, nextNewTabPos );
01481 }
01482 }
01483 else {
01484 cursorPos = newLine->countChildren();
01485 }
01486 }
01487 else {
01488 int nextNewTabPos = newLine->tabPos( 0 );
01489 if ( nextNewTabPos > -1 ) {
01490 cursorPos = QMIN( cursorPos, nextNewTabPos );
01491 }
01492 }
01493 cursor->setTo( newLine,
01494 QMIN( cursorPos,
01495 newLine->countChildren() ) );
01496 }
01497 else {
01498 getParent()->moveRight(cursor, this);
01499 }
01500 return;
01501 }
01502 }
01503 kdDebug( DEBUGID ) << k_funcinfo << endl;
01504 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
01505 }
01506 }
01507 }
01508
01509
01510 void MultilineElement::calcSizes( const ContextStyle& context,
01511 ContextStyle::TextStyle tstyle,
01512 ContextStyle::IndexStyle istyle )
01513 {
01514 luPt mySize = context.getAdjustedSize( tstyle );
01515 QFont font = context.getDefaultFont();
01516 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
01517 QFontMetrics fm( font );
01518 luPixel leading = context.ptToLayoutUnitPt( fm.leading() );
01519 luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle ) );
01520
01521 uint count = content.count();
01522 luPixel height = -leading;
01523 luPixel width = 0;
01524 uint tabCount = 0;
01525 for ( uint i = 0; i < count; ++i ) {
01526 MultilineSequenceElement* line = content.at(i);
01527 line->calcSizes( context, tstyle, istyle );
01528 tabCount = QMAX( tabCount, line->tabCount() );
01529
01530 height += leading;
01531 line->setX( 0 );
01532 line->setY( height );
01533 height += line->getHeight() + distY;
01534 width = QMAX( line->getWidth(), width );
01535 }
01536
01537
01538 for ( uint t = 0; t < tabCount; ++t ) {
01539 luPixel pos = 0;
01540 for ( uint i = 0; i < count; ++i ) {
01541 MultilineSequenceElement* line = content.at(i);
01542 if ( t < line->tabCount() ) {
01543 pos = QMAX( pos, line->tab( t )->getX() );
01544 }
01545 else {
01546 pos = QMAX( pos, line->getWidth() );
01547 }
01548 }
01549 for ( uint i = 0; i < count; ++i ) {
01550 MultilineSequenceElement* line = content.at(i);
01551 if ( t < line->tabCount() ) {
01552 line->moveTabTo( t, pos );
01553 width = QMAX( width, line->getWidth() );
01554 }
01555 }
01556 }
01557
01558 setHeight( height );
01559 setWidth( width );
01560 if ( count == 1 ) {
01561 setBaseline( content.at( 0 )->getBaseline() );
01562 }
01563 else {
01564
01565 setBaseline( height/2 + context.axisHeight( tstyle ) );
01566 }
01567 }
01568
01569 void MultilineElement::draw( QPainter& painter, const LuPixelRect& r,
01570 const ContextStyle& context,
01571 ContextStyle::TextStyle tstyle,
01572 ContextStyle::IndexStyle istyle,
01573 const LuPixelPoint& parentOrigin )
01574 {
01575 LuPixelPoint myPos( parentOrigin.x() + getX(), parentOrigin.y() + getY() );
01576 uint count = content.count();
01577
01578 if ( context.edit() ) {
01579 uint tabCount = 0;
01580 painter.setPen( context.getHelpColor() );
01581 for ( uint i = 0; i < count; ++i ) {
01582 MultilineSequenceElement* line = content.at(i);
01583 if ( tabCount < line->tabCount() ) {
01584 for ( uint t = tabCount; t < line->tabCount(); ++t ) {
01585 BasicElement* marker = line->tab( t );
01586 painter.drawLine( context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
01587 context.layoutUnitToPixelY( myPos.y() ),
01588 context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
01589 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
01590 }
01591 tabCount = line->tabCount();
01592 }
01593 }
01594 }
01595
01596 for ( uint i = 0; i < count; ++i ) {
01597 MultilineSequenceElement* line = content.at(i);
01598 line->draw( painter, r, context, tstyle, istyle, myPos );
01599 }
01600 }
01601
01602
01603 void MultilineElement::dispatchFontCommand( FontCommand* cmd )
01604 {
01605 uint count = content.count();
01606 for ( uint i = 0; i < count; ++i ) {
01607 MultilineSequenceElement* line = content.at(i);
01608 line->dispatchFontCommand( cmd );
01609 }
01610 }
01611
01612 void MultilineElement::insert( FormulaCursor* cursor,
01613 QPtrList<BasicElement>& newChildren,
01614 Direction direction )
01615 {
01616 MultilineSequenceElement* e = static_cast<MultilineSequenceElement*>(newChildren.take(0));
01617 e->setParent(this);
01618 content.insert( cursor->getPos(), e );
01619
01620 if (direction == beforeCursor) {
01621 e->moveLeft(cursor, this);
01622 }
01623 else {
01624 e->moveRight(cursor, this);
01625 }
01626 cursor->setSelection(false);
01627 formula()->changed();
01628 }
01629
01630 void MultilineElement::remove( FormulaCursor* cursor,
01631 QPtrList<BasicElement>& removedChildren,
01632 Direction direction )
01633 {
01634 if ( content.count() == 1 ) {
01635 getParent()->selectChild(cursor, this);
01636 getParent()->remove(cursor, removedChildren, direction);
01637 }
01638 else {
01639 MultilineSequenceElement* e = content.take( cursor->getPos() );
01640 removedChildren.append( e );
01641 formula()->elementRemoval( e );
01642
01643 formula()->changed();
01644 }
01645 }
01646
01647 void MultilineElement::normalize( FormulaCursor* cursor, Direction direction )
01648 {
01649 int pos = cursor->getPos();
01650 if ( ( cursor->getElement() == this ) &&
01651 ( pos > -1 ) && ( static_cast<unsigned>( pos ) <= content.count() ) ) {
01652 switch ( direction ) {
01653 case beforeCursor:
01654 if ( pos > 0 ) {
01655 content.at( pos-1 )->moveLeft( cursor, this );
01656 break;
01657 }
01658
01659 case afterCursor:
01660 if ( static_cast<unsigned>( pos ) < content.count() ) {
01661 content.at( pos )->moveRight( cursor, this );
01662 }
01663 else {
01664 content.at( pos-1 )->moveLeft( cursor, this );
01665 }
01666 break;
01667 }
01668 }
01669 else {
01670 inherited::normalize( cursor, direction );
01671 }
01672 }
01673
01674 SequenceElement* MultilineElement::getMainChild()
01675 {
01676 return content.at( 0 );
01677 }
01678
01679 void MultilineElement::selectChild(FormulaCursor* cursor, BasicElement* child)
01680 {
01681 int pos = content.find( dynamic_cast<MultilineSequenceElement*>( child ) );
01682 if ( pos > -1 ) {
01683 cursor->setTo( this, pos );
01684
01685 }
01686 }
01687
01688
01692 void MultilineElement::writeDom(QDomElement element)
01693 {
01694 BasicElement::writeDom(element);
01695
01696 uint lineCount = content.count();
01697 element.setAttribute( "LINES", lineCount );
01698
01699 QDomDocument doc = element.ownerDocument();
01700 for ( uint i = 0; i < lineCount; ++i ) {
01701 QDomElement tmp = content.at( i )->getElementDom(doc);
01702 element.appendChild(tmp);
01703 }
01704 }
01705
01706 void MultilineElement::writeMathML( QDomDocument doc, QDomNode parent )
01707 {
01708 QDomElement de = doc.createElement( "mtable" );
01709 QDomElement row; QDomElement cell;
01710
01711 for ( uint i = 0; i < content.count(); ++i ) {
01712 row = doc.createElement( "mtr" );
01713 de.appendChild( row );
01714
01715
01716
01717
01718 content.at( i )->writeMathML( doc, row );
01719 }
01720
01721 parent.appendChild( de );
01722 }
01723
01728 bool MultilineElement::readAttributesFromDom(QDomElement element)
01729 {
01730 if (!BasicElement::readAttributesFromDom(element)) {
01731 return false;
01732 }
01733 uint lineCount = 0;
01734 QString lineCountStr = element.attribute("LINES");
01735 if(!lineCountStr.isNull()) {
01736 lineCount = lineCountStr.toInt();
01737 }
01738 if (lineCount == 0) {
01739 kdWarning( DEBUGID ) << "lineCount <= 0 in MultilineElement." << endl;
01740 return false;
01741 }
01742
01743 content.clear();
01744 for ( uint i = 0; i < lineCount; ++i ) {
01745 MultilineSequenceElement* element = new MultilineSequenceElement(this);
01746 content.append(element);
01747 }
01748 return true;
01749 }
01750
01756 bool MultilineElement::readContentFromDom(QDomNode& node)
01757 {
01758 if (!BasicElement::readContentFromDom(node)) {
01759 return false;
01760 }
01761
01762 uint lineCount = content.count();
01763 uint i = 0;
01764 while ( !node.isNull() && i < lineCount ) {
01765 if ( node.isElement() ) {
01766 SequenceElement* element = content.at( i );
01767 QDomElement e = node.toElement();
01768 if ( !element->buildFromDom( e ) ) {
01769 return false;
01770 }
01771 ++i;
01772 }
01773 node = node.nextSibling();
01774 }
01775 return true;
01776 }
01777
01778 QString MultilineElement::toLatex()
01779 {
01780 uint lineCount = content.count();
01781 QString muliline = "\\begin{split} ";
01782 for ( uint i = 0; i < lineCount; ++i ) {
01783 muliline += content.at( i )->toLatex();
01784 muliline += " \\\\ ";
01785 }
01786 muliline += "\\end{split}";
01787 return muliline;
01788 }
01789
01790
01791 QString MultilineElement::formulaString()
01792 {
01793 uint lineCount = content.count();
01794 QString muliline = "";
01795 for ( uint i = 0; i < lineCount; ++i ) {
01796 muliline += content.at( i )->formulaString();
01797 muliline += "\n";
01798 }
01799
01800 return muliline;
01801 }
01802
01803
01804 KFORMULA_NAMESPACE_END