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 m_rowNumber( 0 ),
00275 m_align( NoAlign ),
00276 m_widthType( NoSize ),
00277 m_frame( NoLine ),
00278 m_frameHSpacing( NoSize ),
00279 m_frameVSpacing( NoSize ),
00280 m_side( NoSide ),
00281 m_minLabelSpacingType( NoSize ),
00282 m_customEqualRows( false ),
00283 m_customEqualColumns( false ),
00284 m_customDisplayStyle( false )
00285 {
00286 for (uint r = 0; r < rows; r++) {
00287 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
00288 list->setAutoDelete(true);
00289 for (uint c = 0; c < columns; c++) {
00290 list->append(new MatrixSequenceElement(this));
00291 }
00292 content.append(list);
00293 }
00294 content.setAutoDelete(true);
00295 }
00296
00297 MatrixElement::~MatrixElement()
00298 {
00299 }
00300
00301
00302 MatrixElement::MatrixElement( const MatrixElement& other )
00303 : BasicElement( other )
00304 {
00305 uint rows = other.getRows();
00306 uint columns = other.getColumns();
00307
00308 QPtrListIterator< QPtrList< MatrixSequenceElement > > rowIter( other.content );
00309 for (uint r = 0; r < rows; r++) {
00310 ++rowIter;
00311 QPtrListIterator< MatrixSequenceElement > colIter( *rowIter.current() );
00312
00313 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
00314 list->setAutoDelete(true);
00315 for (uint c = 0; c < columns; c++) {
00316 ++colIter;
00317 MatrixSequenceElement *mse =
00318
00319 new MatrixSequenceElement( *colIter.current() );
00320 list->append( mse );
00321 mse->setParent( this );
00322 }
00323 content.append(list);
00324 }
00325 content.setAutoDelete(true);
00326 }
00327
00328
00329 bool MatrixElement::accept( ElementVisitor* visitor )
00330 {
00331 return visitor->visit( this );
00332 }
00333
00334
00335 void MatrixElement::entered( SequenceElement* )
00336 {
00337 formula()->tell( i18n( "Matrix element" ) );
00338 }
00339
00340
00341 BasicElement* MatrixElement::goToPos( FormulaCursor* cursor, bool& handled,
00342 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
00343 {
00344 BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
00345 if (e != 0) {
00346 LuPixelPoint myPos(parentOrigin.x() + getX(),
00347 parentOrigin.y() + getY());
00348
00349 uint rows = getRows();
00350 uint columns = getColumns();
00351
00352 for (uint r = 0; r < rows; r++) {
00353 for (uint c = 0; c < columns; c++) {
00354 BasicElement* element = getElement(r, c);
00355 e = element->goToPos(cursor, handled, point, myPos);
00356 if (e != 0) {
00357 return e;
00358 }
00359 }
00360 }
00361
00362
00363 luPixel dx = point.x() - myPos.x();
00364 luPixel dy = point.y() - myPos.y();
00365
00366 uint row = rows;
00367 for (uint r = 0; r < rows; r++) {
00368 BasicElement* element = getElement(r, 0);
00369 if (element->getY() > dy) {
00370 row = r;
00371 break;
00372 }
00373 }
00374 if (row == 0) {
00375 BasicElement* element = getParent();
00376 element->moveLeft(cursor, this);
00377 handled = true;
00378 return element;
00379 }
00380 row--;
00381
00382 uint column = columns;
00383 for (uint c = 0; c < columns; c++) {
00384 BasicElement* element = getElement(row, c);
00385 if (element->getX() > dx) {
00386 column = c;
00387 break;
00388 }
00389 }
00390 if (column == 0) {
00391 BasicElement* element = getParent();
00392 element->moveLeft(cursor, this);
00393 handled = true;
00394 return element;
00395 }
00396 column--;
00397
00398
00399 row = rows;
00400 for (uint r = 0; r < rows; r++) {
00401 BasicElement* element = getElement(r, column);
00402 if (element->getY() > dy) {
00403 row = r;
00404 break;
00405 }
00406 }
00407 if (row == 0) {
00408 BasicElement* element = getParent();
00409 element->moveLeft(cursor, this);
00410 handled = true;
00411 return element;
00412 }
00413 row--;
00414
00415 BasicElement* element = getElement(row, column);
00416 element->moveLeft(cursor, this);
00417 handled = true;
00418 return element;
00419 }
00420 return 0;
00421 }
00422
00423
00424
00425
00426
00427
00428
00429
00430
00435 void MatrixElement::calcSizes( const ContextStyle& context,
00436 ContextStyle::TextStyle tstyle,
00437 ContextStyle::IndexStyle istyle,
00438 StyleAttributes& style )
00439 {
00440 QMemArray<luPixel> toMidlines(getRows());
00441 QMemArray<luPixel> fromMidlines(getRows());
00442 QMemArray<luPixel> widths(getColumns());
00443
00444 toMidlines.fill(0);
00445 fromMidlines.fill(0);
00446 widths.fill(0);
00447
00448 uint rows = getRows();
00449 uint columns = getColumns();
00450
00451 ContextStyle::TextStyle i_tstyle = context.convertTextStyleFraction(tstyle);
00452 ContextStyle::IndexStyle i_istyle = context.convertIndexStyleUpper(istyle);
00453 double factor = style.sizeFactor();
00454
00455 for (uint r = 0; r < rows; r++) {
00456 QPtrList< MatrixSequenceElement >* list = content.at(r);
00457 for (uint c = 0; c < columns; c++) {
00458 SequenceElement* element = list->at(c);
00459 element->calcSizes( context, i_tstyle, i_istyle, style );
00460 toMidlines[r] = QMAX(toMidlines[r], element->axis( context, i_tstyle, factor ));
00461 fromMidlines[r] = QMAX(fromMidlines[r],
00462 element->getHeight()-element->axis( context, i_tstyle, factor ));
00463 widths[c] = QMAX(widths[c], element->getWidth());
00464 }
00465 }
00466
00467 luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
00468 luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
00469
00470 luPixel yPos = 0;
00471 for (uint r = 0; r < rows; r++) {
00472 QPtrList< MatrixSequenceElement >* list = content.at(r);
00473 luPixel xPos = 0;
00474 yPos += toMidlines[r];
00475 for (uint c = 0; c < columns; c++) {
00476 SequenceElement* element = list->at(c);
00477 switch (context.getMatrixAlignment()) {
00478 case ContextStyle::left:
00479 element->setX(xPos);
00480 break;
00481 case ContextStyle::center:
00482 element->setX(xPos + (widths[c] - element->getWidth())/2);
00483 break;
00484 case ContextStyle::right:
00485 element->setX(xPos + widths[c] - element->getWidth());
00486 break;
00487 }
00488 element->setY(yPos - element->axis( context, i_tstyle, factor ));
00489 xPos += widths[c] + distX;
00490 }
00491 yPos += fromMidlines[r] + distY;
00492 }
00493
00494 luPixel width = distX * (columns - 1);
00495 luPixel height = distY * (rows - 1);
00496
00497 for (uint r = 0; r < rows; r++) height += toMidlines[r] + fromMidlines[r];
00498 for (uint c = 0; c < columns; c++) width += widths[c];
00499
00500 setWidth(width);
00501 setHeight(height);
00502 if ((rows == 2) && (columns == 1)) {
00503 setBaseline( getMainChild()->getHeight() + distY / 2 + context.axisHeight( tstyle, factor ) );
00504 }
00505 else {
00506 setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
00507 }
00508 }
00509
00515 void MatrixElement::draw( QPainter& painter, const LuPixelRect& rect,
00516 const ContextStyle& context,
00517 ContextStyle::TextStyle tstyle,
00518 ContextStyle::IndexStyle istyle,
00519 StyleAttributes& style,
00520 const LuPixelPoint& parentOrigin )
00521 {
00522 LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
00523
00524
00525
00526 uint rows = getRows();
00527 uint columns = getColumns();
00528
00529 for (uint r = 0; r < rows; r++) {
00530 for (uint c = 0; c < columns; c++) {
00531 getElement(r, c)->draw(painter, rect, context,
00532 context.convertTextStyleFraction(tstyle),
00533 context.convertIndexStyleUpper(istyle),
00534 style,
00535 myPos);
00536 }
00537 }
00538
00539
00540
00541
00542 }
00543
00544
00545 void MatrixElement::dispatchFontCommand( FontCommand* cmd )
00546 {
00547 uint rows = getRows();
00548 uint columns = getColumns();
00549
00550 for (uint r = 0; r < rows; r++) {
00551 for (uint c = 0; c < columns; c++) {
00552 getElement(r, c)->dispatchFontCommand( cmd );
00553 }
00554 }
00555 }
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00571 void MatrixElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
00572 {
00573 if (cursor->isSelectionMode()) {
00574 getParent()->moveLeft(cursor, this);
00575 }
00576 else {
00577 if (from == getParent()) {
00578 getElement(getRows()-1, getColumns()-1)->moveLeft(cursor, this);
00579 }
00580 else {
00581 bool linear = cursor->getLinearMovement();
00582 uint row = 0;
00583 uint column = 0;
00584 if (searchElement(from, row, column)) {
00585 if (column > 0) {
00586 getElement(row, column-1)->moveLeft(cursor, this);
00587 }
00588 else if (linear && (row > 0)) {
00589 getElement(row-1, getColumns()-1)->moveLeft(cursor, this);
00590 }
00591 else {
00592 getParent()->moveLeft(cursor, this);
00593 }
00594 }
00595 else {
00596 getParent()->moveLeft(cursor, this);
00597 }
00598 }
00599 }
00600 }
00601
00607 void MatrixElement::moveRight(FormulaCursor* cursor, BasicElement* from)
00608 {
00609 if (cursor->isSelectionMode()) {
00610 getParent()->moveRight(cursor, this);
00611 }
00612 else {
00613 if (from == getParent()) {
00614 getElement(0, 0)->moveRight(cursor, this);
00615 }
00616 else {
00617 bool linear = cursor->getLinearMovement();
00618 uint row = 0;
00619 uint column = 0;
00620 if (searchElement(from, row, column)) {
00621 if (column < getColumns()-1) {
00622 getElement(row, column+1)->moveRight(cursor, this);
00623 }
00624 else if (linear && (row < getRows()-1)) {
00625 getElement(row+1, 0)->moveRight(cursor, this);
00626 }
00627 else {
00628 getParent()->moveRight(cursor, this);
00629 }
00630 }
00631 else {
00632 getParent()->moveRight(cursor, this);
00633 }
00634 }
00635 }
00636 }
00637
00643 void MatrixElement::moveUp(FormulaCursor* cursor, BasicElement* from)
00644 {
00645 if (cursor->isSelectionMode()) {
00646 getParent()->moveUp(cursor, this);
00647 }
00648 else {
00649 if (from == getParent()) {
00650 getElement(0, 0)->moveRight(cursor, this);
00651 }
00652 else {
00653 uint row = 0;
00654 uint column = 0;
00655 if (searchElement(from, row, column)) {
00656 if (row > 0) {
00657 getElement(row-1, column)->moveRight(cursor, this);
00658 }
00659 else {
00660 getParent()->moveUp(cursor, this);
00661 }
00662 }
00663 else {
00664 getParent()->moveUp(cursor, this);
00665 }
00666 }
00667 }
00668 }
00669
00675 void MatrixElement::moveDown(FormulaCursor* cursor, BasicElement* from)
00676 {
00677 if (cursor->isSelectionMode()) {
00678 getParent()->moveDown(cursor, this);
00679 }
00680 else {
00681 if (from == getParent()) {
00682 getElement(0, 0)->moveRight(cursor, this);
00683 }
00684 else {
00685 uint row = 0;
00686 uint column = 0;
00687 if (searchElement(from, row, column)) {
00688 if (row < getRows()-1) {
00689 getElement(row+1, column)->moveRight(cursor, this);
00690 }
00691 else {
00692 getParent()->moveDown(cursor, this);
00693 }
00694 }
00695 else {
00696 getParent()->moveDown(cursor, this);
00697 }
00698 }
00699 }
00700 }
00701
00706 void MatrixElement::goInside(FormulaCursor* cursor)
00707 {
00708 getElement(0, 0)->goInside(cursor);
00709 }
00710
00711
00712
00713 SequenceElement* MatrixElement::getMainChild()
00714 {
00715 return content.at(0)->at(0);
00716 }
00717
00718 void MatrixElement::selectChild(FormulaCursor* cursor, BasicElement* child)
00719 {
00720 uint rows = getRows();
00721 uint columns = getColumns();
00722 for (uint r = 0; r < rows; r++) {
00723 for (uint c = 0; c < columns; c++) {
00724 if (child == getElement(r, c)) {
00725 cursor->setTo(this, r*columns+c);
00726 }
00727 }
00728 }
00729 }
00730
00731 const MatrixSequenceElement* MatrixElement::getElement( uint row, uint column ) const
00732 {
00733 QPtrListIterator< QPtrList < MatrixSequenceElement > > rows( content );
00734 rows += row;
00735 if ( ! rows.current() )
00736 return 0;
00737
00738 QPtrListIterator< MatrixSequenceElement > cols ( *rows.current() );
00739 cols += column;
00740 return cols.current();
00741 }
00742
00743
00744 bool MatrixElement::searchElement(BasicElement* element, uint& row, uint& column)
00745 {
00746 uint rows = getRows();
00747 uint columns = getColumns();
00748 for (uint r = 0; r < rows; r++) {
00749 for (uint c = 0; c < columns; c++) {
00750 if (element == getElement(r, c)) {
00751 row = r;
00752 column = c;
00753 return true;
00754 }
00755 }
00756 }
00757 return false;
00758 }
00759
00760
00764 void MatrixElement::writeDom(QDomElement element)
00765 {
00766 BasicElement::writeDom(element);
00767
00768 uint rows = getRows();
00769 uint cols = getColumns();
00770
00771 element.setAttribute("ROWS", rows);
00772 element.setAttribute("COLUMNS", cols);
00773
00774 QDomDocument doc = element.ownerDocument();
00775
00776 for (uint r = 0; r < rows; r++) {
00777 for (uint c = 0; c < cols; c++) {
00778 QDomElement tmp = getElement(r,c)->getElementDom(doc);
00779 element.appendChild(tmp);
00780 }
00781 element.appendChild(doc.createComment("end of row"));
00782 }
00783 }
00784
00789 bool MatrixElement::readAttributesFromDom(QDomElement element)
00790 {
00791 if (!BasicElement::readAttributesFromDom(element)) {
00792 return false;
00793 }
00794 uint rows = 0;
00795 QString rowStr = element.attribute("ROWS");
00796 if(!rowStr.isNull()) {
00797 rows = rowStr.toInt();
00798 }
00799 if (rows == 0) {
00800 kdWarning( DEBUGID ) << "Rows <= 0 in MatrixElement." << endl;
00801 return false;
00802 }
00803
00804 QString columnStr = element.attribute("COLUMNS");
00805 uint cols = 0;
00806 if(!columnStr.isNull()) {
00807 cols = columnStr.toInt();
00808 }
00809 if (cols == 0) {
00810 kdWarning( DEBUGID ) << "Columns <= 0 in MatrixElement." << endl;
00811 return false;
00812 }
00813
00814 content.clear();
00815 for (uint r = 0; r < rows; r++) {
00816 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
00817 list->setAutoDelete(true);
00818 content.append(list);
00819 for (uint c = 0; c < cols; c++) {
00820 MatrixSequenceElement* element = new MatrixSequenceElement(this);
00821 list->append(element);
00822 }
00823 }
00824 return true;
00825 }
00826
00832 bool MatrixElement::readContentFromDom(QDomNode& node)
00833 {
00834 if (!BasicElement::readContentFromDom(node)) {
00835 return false;
00836 }
00837
00838 uint rows = getRows();
00839 uint cols = getColumns();
00840
00841 uint r = 0;
00842 uint c = 0;
00843 while ( !node.isNull() && r < rows ) {
00844 if ( node.isElement() ) {
00845 SequenceElement* element = getElement( r, c );
00846 QDomElement e = node.toElement();
00847 if ( !element->buildFromDom( e ) ) {
00848 return false;
00849 }
00850 c++;
00851 if ( c == cols ) {
00852 c = 0;
00853 r++;
00854 }
00855 }
00856 node = node.nextSibling();
00857 }
00858 return true;
00859 }
00860
00861 bool MatrixElement::readAttributesFromMathMLDom( const QDomElement& element )
00862 {
00863 if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
00864 return false;
00865 }
00866
00867 QString alignStr = element.attribute( "align" ).lower();
00868 if ( ! alignStr.isNull() ) {
00869 if ( alignStr.find( "top" ) != -1 ) {
00870 m_align = TopAlign;
00871 }
00872 else if ( alignStr.find( "bottom" ) != -1 ) {
00873 m_align = BottomAlign;
00874 }
00875 else if ( alignStr.find( "center" ) != -1 ) {
00876 m_align = CenterAlign;
00877 }
00878 else if ( alignStr.find( "baseline" ) != -1 ) {
00879 m_align = BaselineAlign;
00880 }
00881 else if ( alignStr.find( "axis" ) != -1 ) {
00882 m_align = AxisAlign;
00883 }
00884 int index = alignStr.findRev( ' ' );
00885 if ( index != -1 ) {
00886 m_rowNumber = alignStr.right( index + 1 ).toInt();
00887 }
00888 }
00889 QString rowalignStr = element.attribute( "rowalign" ).lower();
00890 if ( ! rowalignStr.isNull() ) {
00891 QStringList list = QStringList::split( ' ', rowalignStr );
00892 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
00893 if ( *it == "top" ) {
00894 m_rowAlign.append( TopAlign );
00895 }
00896 else if ( *it == "bottom" ) {
00897 m_rowAlign.append( BottomAlign );
00898 }
00899 else if ( *it == "center" ) {
00900 m_rowAlign.append( CenterAlign );
00901 }
00902 else if ( *it == "baseline" ) {
00903 m_rowAlign.append( BaselineAlign );
00904 }
00905 else if ( *it == "axis" ) {
00906 m_rowAlign.append( AxisAlign );
00907 }
00908 }
00909 }
00910 QString columnalignStr = element.attribute( "columnalign" ).lower();
00911 if ( ! columnalignStr.isNull() ) {
00912 QStringList list = QStringList::split( ' ', columnalignStr );
00913 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
00914 if ( *it == "left" ) {
00915 m_columnAlign.append( LeftHorizontalAlign );
00916 }
00917 else if ( *it == "center" ) {
00918 m_columnAlign.append( CenterHorizontalAlign );
00919 }
00920 else if ( *it == "right" ) {
00921 m_columnAlign.append( RightHorizontalAlign );
00922 }
00923 }
00924 }
00925 QString alignmentscopeStr = element.attribute( "alignmentscope" ).lower();
00926 if ( ! alignmentscopeStr.isNull() ) {
00927 QStringList list = QStringList::split( ' ', alignmentscopeStr );
00928 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
00929 if ( *it == "true" ) {
00930 m_alignmentScope.append( true );
00931 }
00932 else if ( *it == "false" ) {
00933 m_alignmentScope.append( false );
00934 }
00935 }
00936 }
00937 QString columnwidthStr = element.attribute( "columnwidth" ).lower();
00938 if ( columnwidthStr.isNull() ) {
00939 QStringList list = QStringList::split( ' ', columnwidthStr );
00940 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
00941 SizeType type = NoSize;
00942 double length;
00943 if ( *it == "auto" ) {
00944 type = AutoSize;
00945 }
00946 else if ( *it == "fit" ) {
00947 type = FitSize;
00948 }
00949 else {
00950 length = getSize( columnwidthStr, &type );
00951 if ( type == NoSize ) {
00952 type = getSpace( columnwidthStr );
00953 }
00954 }
00955 if ( type != NoSize ) {
00956 m_columnWidthType.append( type );
00957 if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
00958 m_columnWidth.append( length );
00959 }
00960 }
00961 }
00962 }
00963 QString widthStr = element.attribute( "width" ).lower();
00964 if ( ! widthStr.isNull() ) {
00965 if ( widthStr == "auto" ) {
00966 m_widthType = AutoSize;
00967 }
00968 else {
00969 m_width = getSize( widthStr, &m_widthType );
00970 }
00971 }
00972 QString rowspacingStr = element.attribute( "rowspacing" ).lower();
00973 if ( ! rowspacingStr.isNull() ) {
00974 QStringList list = QStringList::split( ' ', rowspacingStr );
00975 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
00976 SizeType type;
00977 double length = getSize( *it, &type );
00978 if ( type != NoSize ) {
00979 m_rowSpacingType.append( type );
00980 m_rowSpacing.append( length );
00981 }
00982 }
00983 }
00984 QString columnspacingStr = element.attribute( "columnspacing" ).lower();
00985 if ( ! columnspacingStr.isNull() ) {
00986 QStringList list = QStringList::split( ' ', columnspacingStr );
00987 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
00988 SizeType type;
00989 double length = getSize( *it, &type );
00990 if ( type == NoSize ) {
00991 type = getSpace( columnspacingStr );
00992 }
00993 if ( type != NoSize ) {
00994 m_columnSpacingType.append( type );
00995 if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
00996 m_columnSpacing.append( length );
00997 }
00998 }
00999 }
01000 }
01001 QString rowlinesStr = element.attribute( "rowlines" ).lower();
01002 if ( ! rowlinesStr.isNull() ) {
01003 QStringList list = QStringList::split( ' ', rowlinesStr );
01004 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
01005 if ( *it == "none" ) {
01006 m_rowLines.append( NoneLine );
01007 }
01008 else if ( *it == "solid" ) {
01009 m_rowLines.append( SolidLine );
01010 }
01011 else if ( *it == "dashed" ) {
01012 m_rowLines.append( DashedLine );
01013 }
01014 }
01015 }
01016 QString columnlinesStr = element.attribute( "columnlines" ).lower();
01017 if ( ! columnlinesStr.isNull() ) {
01018 QStringList list = QStringList::split( ' ', columnlinesStr );
01019 for ( QStringList::iterator it = list.begin(); it != list.end(); it++ ) {
01020 if ( *it == "none" ) {
01021 m_columnLines.append( NoneLine );
01022 }
01023 else if ( *it == "solid" ) {
01024 m_columnLines.append( SolidLine );
01025 }
01026 else if ( *it == "dashed" ) {
01027 m_columnLines.append( DashedLine );
01028 }
01029 }
01030 }
01031 QString frameStr = element.attribute( "frame" ).stripWhiteSpace().lower();
01032 if ( ! frameStr.isNull() ) {
01033 if ( frameStr == "none" ) {
01034 m_frame = NoneLine;
01035 }
01036 else if ( frameStr == "solid" ) {
01037 m_frame = SolidLine;
01038 }
01039 else if ( frameStr == "dashed" ) {
01040 m_frame = DashedLine;
01041 }
01042 }
01043 QString framespacingStr = element.attribute( "framespacing" );
01044 if ( ! framespacingStr.isNull() ) {
01045 QStringList list = QStringList::split( ' ', framespacingStr );
01046 m_frameHSpacing = getSize( list[0], &m_frameHSpacingType );
01047 if ( m_frameHSpacingType == NoSize ) {
01048 m_frameHSpacingType = getSpace( list[0] );
01049 }
01050 if ( list.count() > 1 ) {
01051 m_frameVSpacing = getSize( list[1], &m_frameVSpacingType );
01052 if ( m_frameVSpacingType == NoSize ) {
01053 m_frameVSpacingType = getSpace( list[1] );
01054 }
01055 }
01056 }
01057 QString equalrowsStr = element.attribute( "equalrows" ).stripWhiteSpace().lower();
01058 if ( ! equalrowsStr.isNull() ) {
01059 m_customEqualRows = true;
01060 if ( equalrowsStr == "false" ) {
01061 m_equalRows = false;
01062 }
01063 else {
01064 m_equalRows = true;
01065 }
01066 }
01067 QString equalcolumnsStr = element.attribute( "equalcolumns" ).stripWhiteSpace().lower();
01068 if ( ! equalcolumnsStr.isNull() ) {
01069 m_customEqualColumns = true;
01070 if ( equalcolumnsStr == "false" ) {
01071 m_equalColumns = false;
01072 }
01073 else {
01074 m_equalColumns = true;
01075 }
01076 }
01077 QString displaystyleStr = element.attribute( "displaystyle" ).stripWhiteSpace().lower();
01078 if ( ! displaystyleStr.isNull() ) {
01079 m_customDisplayStyle = true;
01080 if ( displaystyleStr == "false" ) {
01081 m_displayStyle = false;
01082 }
01083 else {
01084 m_displayStyle = true;
01085 }
01086 }
01087 QString sideStr = element.attribute( "side" ).stripWhiteSpace().lower();
01088 if ( ! sideStr.isNull() ) {
01089 if ( sideStr == "left" ) {
01090 m_side = LeftSide;
01091 }
01092 else if ( sideStr == "right" ) {
01093 m_side = RightSide;
01094 }
01095 else if ( sideStr == "leftoverlap" ) {
01096 m_side = LeftOverlapSide;
01097 }
01098 else if ( sideStr == "rightoverlap" ) {
01099 m_side = RightOverlapSide;
01100 }
01101 }
01102 QString minlabelspacingStr = element.attribute( "minlabelspacing" ).stripWhiteSpace().lower();
01103 if ( ! minlabelspacingStr.isNull() ) {
01104 m_minLabelSpacing = getSize( minlabelspacingStr, &m_minLabelSpacingType );
01105 if ( m_minLabelSpacingType == NoSize ) {
01106 m_minLabelSpacingType = getSpace( minlabelspacingStr );
01107 }
01108 }
01109 return true;
01110 }
01111
01118 int MatrixElement::readContentFromMathMLDom( QDomNode& node )
01119 {
01120
01121
01122
01123 if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
01124 return -1;
01125 }
01126
01127 uint rows = 0;
01128 uint cols = 0;
01129 QDomNode n = node;
01130 while ( !n.isNull() ) {
01131 if ( n.isElement() ) {
01132 QDomElement e = n.toElement();
01133 if ( e.tagName().lower() == "mtr")
01134 {
01135 rows++;
01136
01137
01138 QDomNode cellnode = e.firstChild();
01139 int cc = 0;
01140
01141 while ( !cellnode.isNull() ) {
01142 if ( cellnode.isElement() )
01143 cc++;
01144 cellnode = cellnode.nextSibling();
01145 }
01146 if ( cc > cols )
01147 cols = cc;
01148 }
01149 }
01150 n = n.nextSibling();
01151 }
01152
01153
01154 content.clear();
01155 for (uint r = 0; r < rows; r++) {
01156 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
01157 list->setAutoDelete(true);
01158 content.append(list);
01159 for (uint c = 0; c < cols; c++) {
01160 MatrixSequenceElement* element = new MatrixSequenceElement(this);
01161 list->append(element);
01162 }
01163 }
01164
01165
01166 uint r = 0;
01167 uint c = 0;
01168 while ( !node.isNull() ) {
01169 if ( node.isElement() ) {
01170 QDomElement e = node.toElement();
01171 if ( e.tagName().lower() == "mtr" ) {
01172 QDomNode cellnode = e.firstChild();
01173 while ( !cellnode.isNull() ) {
01174 if ( cellnode.isElement() ) {
01175 QDomElement cellelement = cellnode.toElement();
01176 if ( cellelement.tagName().lower() != "mtd" ) {
01177
01178 kdWarning( DEBUGID ) << "Unsupported tag "
01179 << cellelement.tagName()
01180 << " inside matrix row\n";
01181 }
01182 else {
01183 SequenceElement* element = getElement(r, c);
01184 if ( element->buildFromMathMLDom( cellelement ) == -1 )
01185 return -1;
01186 c++;
01187 }
01188 }
01189 cellnode = cellnode.nextSibling();
01190 }
01191 c = 0;
01192 r++;
01193 }
01194 }
01195 node = node.nextSibling();
01196 }
01197 return 1;
01198 }
01199
01200 QString MatrixElement::toLatex()
01201 {
01202
01203
01204 QString matrix;
01205 uint cols=getColumns();
01206 uint rows=getRows();
01207
01208 matrix="\\begin{array}{ ";
01209 for(uint i=0;i<cols;i++)
01210 matrix+="c ";
01211
01212 matrix+="} ";
01213
01214 for (uint r = 0; r < rows; r++) {
01215 for (uint c = 0; c < cols; c++) {
01216 matrix+=getElement(r, c)->toLatex();
01217 if( c < cols-1) matrix+=" & ";
01218 }
01219 if(r < rows-1 ) matrix+=" \\\\ ";
01220 }
01221
01222 matrix+=" \\end{array}";
01223
01224 return matrix;
01225 }
01226
01227 QString MatrixElement::formulaString()
01228 {
01229 QString matrix = "[";
01230 uint cols=getColumns();
01231 uint rows=getRows();
01232 for (uint r = 0; r < rows; r++) {
01233 matrix += "[";
01234 for (uint c = 0; c < cols; c++) {
01235 matrix+=getElement(r, c)->formulaString();
01236 if ( c < cols-1 ) matrix+=", ";
01237 }
01238 matrix += "]";
01239 if ( r < rows-1 ) matrix += ", ";
01240 }
01241 matrix += "]";
01242 return matrix;
01243 }
01244
01245
01246 SequenceElement* MatrixElement::elementAt(uint row, uint column)
01247 {
01248 return getElement( row, column );
01249 }
01250
01251 void MatrixElement::writeMathMLAttributes( QDomElement& element ) const
01252 {
01253 QString rownumber;
01254 if ( m_rowNumber ) {
01255 rownumber = QString( " %1" ).arg( m_rowNumber );
01256 }
01257 switch ( m_align ) {
01258 case TopAlign:
01259 element.setAttribute( "align", "top" + rownumber );
01260 break;
01261 case BottomAlign:
01262 element.setAttribute( "align", "bottom" + rownumber );
01263 break;
01264 case CenterAlign:
01265 element.setAttribute( "align", "center" + rownumber );
01266 break;
01267 case BaselineAlign:
01268 element.setAttribute( "align", "baseline" + rownumber );
01269 break;
01270 case AxisAlign:
01271 element.setAttribute( "align", "axis" + rownumber );
01272 break;
01273 default:
01274 break;
01275 }
01276 QString rowalign;
01277 for ( QValueList< VerticalAlign >::const_iterator it = m_rowAlign.begin(); it != m_rowAlign.end(); it++ )
01278 {
01279 switch ( *it ) {
01280 case TopAlign:
01281 rowalign.append( "top " );
01282 break;
01283 case BottomAlign:
01284 rowalign.append( "bottom " );
01285 break;
01286 case CenterAlign:
01287 rowalign.append( "center " );
01288 break;
01289 case BaselineAlign:
01290 rowalign.append( "baseline " );
01291 break;
01292 case AxisAlign:
01293 rowalign.append( "axis " );
01294 break;
01295 default:
01296 break;
01297 }
01298 }
01299 if ( ! rowalign.isNull() ) {
01300 element.setAttribute( "rowalign", rowalign.stripWhiteSpace() );
01301 }
01302 QString columnalign;
01303 for ( QValueList< HorizontalAlign >::const_iterator it = m_columnAlign.begin(); it != m_columnAlign.end(); it++ )
01304 {
01305 switch ( *it ) {
01306 case LeftHorizontalAlign:
01307 rowalign.append( "left " );
01308 break;
01309 case CenterHorizontalAlign:
01310 rowalign.append( "center " );
01311 break;
01312 case RightHorizontalAlign:
01313 rowalign.append( "right " );
01314 break;
01315 default:
01316 break;
01317 }
01318 }
01319 if ( ! columnalign.isNull() ) {
01320 element.setAttribute( "columnalign", columnalign.stripWhiteSpace() );
01321 }
01322 QString alignmentscope;
01323 for ( QValueList< bool >::const_iterator it = m_alignmentScope.begin(); it != m_alignmentScope.end(); it++ )
01324 {
01325 if ( *it ) {
01326 alignmentscope.append( "true " );
01327 }
01328 else {
01329 alignmentscope.append( "false " );
01330 }
01331 }
01332 if ( ! alignmentscope.isNull() ) {
01333 element.setAttribute( "alignmentscope", alignmentscope.stripWhiteSpace() );
01334 }
01335 QString columnwidth;
01336 QValueList< double >::const_iterator lengthIt = m_columnWidth.begin();
01337 for ( QValueList< SizeType >::const_iterator typeIt = m_columnWidthType.begin();
01338 typeIt != m_columnWidthType.end(); typeIt ++ ) {
01339 switch ( *typeIt ) {
01340 case AutoSize:
01341 columnwidth.append( "auto " );
01342 break;
01343 case FitSize:
01344 columnwidth.append( "fit " );
01345 break;
01346 case AbsoluteSize:
01347 columnwidth.append( QString( "%1pt " ).arg( *lengthIt ) );
01348 lengthIt++;
01349 break;
01350 case RelativeSize:
01351 columnwidth.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
01352 lengthIt++;
01353 break;
01354 case PixelSize:
01355 columnwidth.append( QString( "%1px " ).arg( *lengthIt ) );
01356 lengthIt++;
01357 break;
01358 case NegativeVeryVeryThinMathSpace:
01359 columnwidth.append( "negativeveryverythinmathspace " );
01360 break;
01361 case NegativeVeryThinMathSpace:
01362 columnwidth.append( "negativeverythinmathspace " );
01363 break;
01364 case NegativeThinMathSpace:
01365 columnwidth.append( "negativethinmathspace " );
01366 break;
01367 case NegativeMediumMathSpace:
01368 columnwidth.append( "negativemediummathspace " );
01369 break;
01370 case NegativeThickMathSpace:
01371 columnwidth.append( "negativethickmathspace " );
01372 break;
01373 case NegativeVeryThickMathSpace:
01374 columnwidth.append( "negativeverythickmathspace " );
01375 break;
01376 case NegativeVeryVeryThickMathSpace:
01377 columnwidth.append( "negativeveryverythickmathspace " );
01378 break;
01379 case VeryVeryThinMathSpace:
01380 columnwidth.append( "veryverythinmathspace " );
01381 break;
01382 case VeryThinMathSpace:
01383 columnwidth.append( "verythinmathspace " );
01384 break;
01385 case ThinMathSpace:
01386 columnwidth.append( "thinmathspace " );
01387 break;
01388 case MediumMathSpace:
01389 columnwidth.append( "mediummathspace " );
01390 break;
01391 case ThickMathSpace:
01392 columnwidth.append( "thickmathspace " );
01393 break;
01394 case VeryThickMathSpace:
01395 columnwidth.append( "verythickmathspace " );
01396 break;
01397 case VeryVeryThickMathSpace:
01398 columnwidth.append( "veryverythickmathspace " );
01399 break;
01400 default:
01401 break;
01402 }
01403 }
01404 if ( ! columnwidth.isNull() ) {
01405 element.setAttribute( "columnwidth", columnwidth.stripWhiteSpace() );
01406 }
01407 switch ( m_widthType ) {
01408 case AutoSize:
01409 element.setAttribute( "width", "auto" );
01410 break;
01411 case AbsoluteSize:
01412 element.setAttribute( "width", QString( "%1pt" ).arg( m_width ) );
01413 break;
01414 case RelativeSize:
01415 element.setAttribute( "width", QString( "%1% " ).arg( m_width * 100.0 ) );
01416 break;
01417 case PixelSize:
01418 element.setAttribute( "width", QString( "%1px " ).arg( m_width ) );
01419 break;
01420 default:
01421 break;
01422 }
01423 QString rowspacing;
01424 lengthIt = m_rowSpacing.begin();
01425 for ( QValueList< SizeType >::const_iterator typeIt = m_rowSpacingType.begin();
01426 typeIt != m_rowSpacingType.end(); typeIt++, lengthIt++ ) {
01427 switch ( *typeIt ) {
01428 case AbsoluteSize:
01429 rowspacing.append( QString( "%1pt " ).arg( *lengthIt ) );
01430 break;
01431 case RelativeSize:
01432 rowspacing.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
01433 break;
01434 case PixelSize:
01435 rowspacing.append( QString( "%1px " ).arg( *lengthIt ) );
01436 break;
01437 default:
01438 break;
01439 }
01440 }
01441 if ( ! rowspacing.isNull() ) {
01442 element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
01443 }
01444 QString columnspacing;
01445 lengthIt = m_columnSpacing.begin();
01446 for ( QValueList< SizeType >::const_iterator typeIt = m_columnSpacingType.begin();
01447 typeIt != m_columnSpacingType.end(); typeIt++ ) {
01448 switch ( *typeIt ) {
01449 case AbsoluteSize:
01450 columnspacing.append( QString( "%1pt " ).arg( *lengthIt ) );
01451 lengthIt++;
01452 break;
01453 case RelativeSize:
01454 columnspacing.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
01455 lengthIt++;
01456 break;
01457 case PixelSize:
01458 columnspacing.append( QString( "%1px " ).arg( *lengthIt ) );
01459 lengthIt++;
01460 break;
01461 case NegativeVeryVeryThinMathSpace:
01462 columnspacing.append( "negativeveryverythinmathspace " );
01463 break;
01464 case NegativeVeryThinMathSpace:
01465 columnspacing.append( "negativeverythinmathspace " );
01466 break;
01467 case NegativeThinMathSpace:
01468 columnspacing.append( "negativethinmathspace " );
01469 break;
01470 case NegativeMediumMathSpace:
01471 columnspacing.append( "negativemediummathspace " );
01472 break;
01473 case NegativeThickMathSpace:
01474 columnspacing.append( "negativethickmathspace " );
01475 break;
01476 case NegativeVeryThickMathSpace:
01477 columnspacing.append( "negativeverythickmathspace " );
01478 break;
01479 case NegativeVeryVeryThickMathSpace:
01480 columnspacing.append( "negativeveryverythickmathspace " );
01481 break;
01482 case VeryVeryThinMathSpace:
01483 columnspacing.append( "veryverythinmathspace " );
01484 break;
01485 case VeryThinMathSpace:
01486 columnspacing.append( "verythinmathspace " );
01487 break;
01488 case ThinMathSpace:
01489 columnspacing.append( "thinmathspace " );
01490 break;
01491 case MediumMathSpace:
01492 columnspacing.append( "mediummathspace " );
01493 break;
01494 case ThickMathSpace:
01495 columnspacing.append( "thickmathspace " );
01496 break;
01497 case VeryThickMathSpace:
01498 columnspacing.append( "verythickmathspace " );
01499 break;
01500 case VeryVeryThickMathSpace:
01501 columnspacing.append( "veryverythickmathspace " );
01502 break;
01503 default:
01504 break;
01505 }
01506 }
01507 if ( ! rowspacing.isNull() ) {
01508 element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
01509 }
01510 QString rowlines;
01511 for ( QValueList< LineType >::const_iterator it = m_rowLines.begin(); it != m_rowLines.end(); it++ )
01512 {
01513 switch ( *it ) {
01514 case NoneLine:
01515 rowlines.append( "none " );
01516 break;
01517 case SolidLine:
01518 rowlines.append( "solid " );
01519 break;
01520 case DashedLine:
01521 rowlines.append( "dashed " );
01522 break;
01523 default:
01524 break;
01525 }
01526 }
01527 if ( ! rowlines.isNull() ) {
01528 element.setAttribute( "rowlines", rowlines.stripWhiteSpace() );
01529 }
01530 QString columnlines;
01531 for ( QValueList< LineType >::const_iterator it = m_columnLines.begin(); it != m_columnLines.end(); it++ )
01532 {
01533 switch ( *it ) {
01534 case NoneLine:
01535 columnlines.append( "none " );
01536 break;
01537 case SolidLine:
01538 columnlines.append( "solid " );
01539 break;
01540 case DashedLine:
01541 columnlines.append( "dashed " );
01542 break;
01543 default:
01544 break;
01545 }
01546 }
01547 if ( ! columnlines.isNull() ) {
01548 element.setAttribute( "columnlines", columnlines.stripWhiteSpace() );
01549 }
01550 switch ( m_frame ) {
01551 case NoneLine:
01552 element.setAttribute( "frame", "none" );
01553 break;
01554 case SolidLine:
01555 element.setAttribute( "frame", "solid" );
01556 break;
01557 case DashedLine:
01558 element.setAttribute( "frame", "dashed" );
01559 break;
01560 default:
01561 break;
01562 }
01563 QString framespacing;
01564 switch ( m_frameHSpacingType ) {
01565 case AbsoluteSize:
01566 framespacing.append( QString( "%1pt " ).arg( m_frameHSpacing ) );
01567 break;
01568 case RelativeSize:
01569 framespacing.append( QString( "%1% " ).arg( m_frameHSpacing * 100.0 ) );
01570 break;
01571 case PixelSize:
01572 framespacing.append( QString( "%1px " ).arg( m_frameHSpacing ) );
01573 break;
01574 case NegativeVeryVeryThinMathSpace:
01575 framespacing.append( "negativeveryverythinmathspace " );
01576 break;
01577 case NegativeVeryThinMathSpace:
01578 framespacing.append( "negativeverythinmathspace " );
01579 break;
01580 case NegativeThinMathSpace:
01581 framespacing.append( "negativethinmathspace " );
01582 break;
01583 case NegativeMediumMathSpace:
01584 framespacing.append( "negativemediummathspace " );
01585 break;
01586 case NegativeThickMathSpace:
01587 framespacing.append( "negativethickmathspace " );
01588 break;
01589 case NegativeVeryThickMathSpace:
01590 framespacing.append( "negativeverythickmathspace " );
01591 break;
01592 case NegativeVeryVeryThickMathSpace:
01593 framespacing.append( "negativeveryverythickmathspace " );
01594 break;
01595 case VeryVeryThinMathSpace:
01596 framespacing.append( "veryverythinmathspace " );
01597 break;
01598 case VeryThinMathSpace:
01599 framespacing.append( "verythinmathspace " );
01600 break;
01601 case ThinMathSpace:
01602 framespacing.append( "thinmathspace " );
01603 break;
01604 case MediumMathSpace:
01605 framespacing.append( "mediummathspace " );
01606 break;
01607 case ThickMathSpace:
01608 framespacing.append( "thickmathspace " );
01609 break;
01610 case VeryThickMathSpace:
01611 framespacing.append( "verythickmathspace " );
01612 break;
01613 case VeryVeryThickMathSpace:
01614 framespacing.append( "veryverythickmathspace " );
01615 break;
01616 default:
01617 break;
01618 }
01619 switch ( m_frameVSpacingType ) {
01620 case AbsoluteSize:
01621 framespacing.append( QString( "%1pt " ).arg( m_frameVSpacing ) );
01622 break;
01623 case RelativeSize:
01624 framespacing.append( QString( "%1% " ).arg( m_frameVSpacing * 100.0 ) );
01625 break;
01626 case PixelSize:
01627 framespacing.append( QString( "%1px " ).arg( m_frameVSpacing ) );
01628 break;
01629 case NegativeVeryVeryThinMathSpace:
01630 framespacing.append( "negativeveryverythinmathspace " );
01631 break;
01632 case NegativeVeryThinMathSpace:
01633 framespacing.append( "negativeverythinmathspace " );
01634 break;
01635 case NegativeThinMathSpace:
01636 framespacing.append( "negativethinmathspace " );
01637 break;
01638 case NegativeMediumMathSpace:
01639 framespacing.append( "negativemediummathspace " );
01640 break;
01641 case NegativeThickMathSpace:
01642 framespacing.append( "negativethickmathspace " );
01643 break;
01644 case NegativeVeryThickMathSpace:
01645 framespacing.append( "negativeverythickmathspace " );
01646 break;
01647 case NegativeVeryVeryThickMathSpace:
01648 framespacing.append( "negativeveryverythickmathspace " );
01649 break;
01650 case VeryVeryThinMathSpace:
01651 framespacing.append( "veryverythinmathspace " );
01652 break;
01653 case VeryThinMathSpace:
01654 framespacing.append( "verythinmathspace " );
01655 break;
01656 case ThinMathSpace:
01657 framespacing.append( "thinmathspace " );
01658 break;
01659 case MediumMathSpace:
01660 framespacing.append( "mediummathspace " );
01661 break;
01662 case ThickMathSpace:
01663 framespacing.append( "thickmathspace " );
01664 break;
01665 case VeryThickMathSpace:
01666 framespacing.append( "verythickmathspace " );
01667 break;
01668 case VeryVeryThickMathSpace:
01669 framespacing.append( "veryverythickmathspace " );
01670 break;
01671 default:
01672 break;
01673 }
01674 if ( ! framespacing.isNull() ) {
01675 element.setAttribute( "framespacing", framespacing.stripWhiteSpace() );
01676 }
01677 if ( m_customEqualRows ) {
01678 element.setAttribute( "equalrows", m_equalRows ? "true" : "false" );
01679 }
01680 if ( m_customEqualColumns ) {
01681 element.setAttribute( "equalcolumns", m_equalColumns ? "true" : "false" );
01682 }
01683 if ( m_customDisplayStyle ) {
01684 element.setAttribute( "displaystyle", m_displayStyle ? "true" : "false" );
01685 }
01686 switch ( m_side ) {
01687 case LeftSide:
01688 element.setAttribute( "side", "left" );
01689 break;
01690 case RightSide:
01691 element.setAttribute( "side", "right" );
01692 break;
01693 case LeftOverlapSide:
01694 element.setAttribute( "side", "leftoverlap" );
01695 break;
01696 case RightOverlapSide:
01697 element.setAttribute( "side", "rightoverlap" );
01698 break;
01699 default:
01700 break;
01701 }
01702 switch ( m_minLabelSpacingType ) {
01703 case AbsoluteSize:
01704 element.setAttribute( "minlabelspacing", QString( "%1pt" ).arg( m_minLabelSpacing ) );
01705 break;
01706 case RelativeSize:
01707 element.setAttribute( "minlabelspacing", QString( "%1%" ).arg( m_minLabelSpacing * 100.0 ) );
01708 break;
01709 case PixelSize:
01710 element.setAttribute( "minlabelspacing", QString( "%1px" ).arg( m_minLabelSpacing ) );
01711 break;
01712 case NegativeVeryVeryThinMathSpace:
01713 element.setAttribute( "minlabelspacing", "negativeveryverythinmathspace" );
01714 break;
01715 case NegativeVeryThinMathSpace:
01716 element.setAttribute( "minlabelspacing", "negativeverythinmathspace" );
01717 break;
01718 case NegativeThinMathSpace:
01719 element.setAttribute( "minlabelspacing", "negativethinmathspace" );
01720 break;
01721 case NegativeMediumMathSpace:
01722 element.setAttribute( "minlabelspacing", "negativemediummathspace" );
01723 break;
01724 case NegativeThickMathSpace:
01725 element.setAttribute( "minlabelspacing", "negativethickmathspace" );
01726 break;
01727 case NegativeVeryThickMathSpace:
01728 element.setAttribute( "minlabelspacing", "negativeverythickmathspace" );
01729 break;
01730 case NegativeVeryVeryThickMathSpace:
01731 element.setAttribute( "minlabelspacing", "negativeveryverythickmathspace" );
01732 break;
01733 case VeryVeryThinMathSpace:
01734 element.setAttribute( "minlabelspacing", "veryverythinmathspace" );
01735 break;
01736 case VeryThinMathSpace:
01737 element.setAttribute( "minlabelspacing", "verythinmathspace" );
01738 break;
01739 case ThinMathSpace:
01740 element.setAttribute( "minlabelspacing", "thinmathspace" );
01741 break;
01742 case MediumMathSpace:
01743 element.setAttribute( "minlabelspacing", "mediummathspace" );
01744 break;
01745 case ThickMathSpace:
01746 element.setAttribute( "minlabelspacing", "thickmathspace" );
01747 break;
01748 case VeryThickMathSpace:
01749 element.setAttribute( "minlabelspacing", "verythickmathspace" );
01750 break;
01751 case VeryVeryThickMathSpace:
01752 element.setAttribute( "minlabelspacing", "veryverythickmathspace" );
01753 break;
01754 default:
01755 break;
01756 }
01757 }
01758
01759 void MatrixElement::writeMathMLContent( QDomDocument& doc,
01760 QDomElement& element,
01761 bool oasisFormat ) const
01762 {
01763 QDomElement row;
01764 QDomElement cell;
01765
01766 uint rows = getRows();
01767 uint cols = getColumns();
01768
01769 for ( uint r = 0; r < rows; r++ )
01770 {
01771 row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
01772 element.appendChild( row );
01773 for ( uint c = 0; c < cols; c++ )
01774 {
01775 cell = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
01776 row.appendChild( cell );
01777 getElement(r,c)->writeMathML( doc, cell, oasisFormat );
01778 }
01779 }
01780 }
01781
01782
01784
01785
01790 class MultilineSequenceElement : public SequenceElement {
01791 typedef SequenceElement inherited;
01792 public:
01793
01794 MultilineSequenceElement( BasicElement* parent = 0 );
01795
01796 virtual MultilineSequenceElement* clone() {
01797 return new MultilineSequenceElement( *this );
01798 }
01799
01800 virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
01801 const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
01802
01807 virtual void calcSizes( const ContextStyle& context,
01808 ContextStyle::TextStyle tstyle,
01809 ContextStyle::IndexStyle istyle,
01810 StyleAttributes& style );
01811
01812 virtual void registerTab( BasicElement* tab );
01813
01822 virtual KCommand* buildCommand( Container*, Request* );
01823
01824 virtual KCommand* input( Container* container, QKeyEvent* event );
01825
01826 virtual KCommand* input( Container* container, QChar ch );
01827
01828 uint tabCount() const { return tabs.count(); }
01829
01830 BasicElement* tab( uint i ) { return tabs.at( i ); }
01831
01833 void moveTabTo( uint i, luPixel pos );
01834
01836 int tabBefore( uint pos );
01837
01839 int tabPos( uint i );
01840
01841 virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
01842
01843 private:
01844
01845 QPtrList<BasicElement> tabs;
01846 };
01847
01848
01849
01850 class KFCNewLine : public Command {
01851 public:
01852 KFCNewLine( const QString& name, Container* document,
01853 MultilineSequenceElement* line, uint pos );
01854
01855 virtual ~KFCNewLine();
01856
01857 virtual void execute();
01858 virtual void unexecute();
01859
01860 private:
01861 MultilineSequenceElement* m_line;
01862 MultilineSequenceElement* m_newline;
01863 uint m_pos;
01864 };
01865
01866
01867 KFCNewLine::KFCNewLine( const QString& name, Container* document,
01868 MultilineSequenceElement* line, uint pos )
01869 : Command( name, document ),
01870 m_line( line ), m_pos( pos )
01871 {
01872 m_newline = new MultilineSequenceElement( m_line->getParent() );
01873 }
01874
01875
01876 KFCNewLine::~KFCNewLine()
01877 {
01878 delete m_newline;
01879 }
01880
01881
01882 void KFCNewLine::execute()
01883 {
01884 FormulaCursor* cursor = getExecuteCursor();
01885 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
01886 int linePos = parent->content.find( m_line );
01887 parent->content.insert( linePos+1, m_newline );
01888
01889
01890 if ( m_line->countChildren() > static_cast<int>( m_pos ) ) {
01891
01892
01893 m_line->selectAllChildren( cursor );
01894 cursor->setMark( m_pos );
01895 QPtrList<BasicElement> elementList;
01896 m_line->remove( cursor, elementList, beforeCursor );
01897
01898
01899 m_newline->goInside( cursor );
01900 m_newline->insert( cursor, elementList, beforeCursor );
01901 cursor->setPos( cursor->getMark() );
01902 }
01903 else {
01904 m_newline->goInside( cursor );
01905 }
01906
01907
01908 m_newline = 0;
01909
01910
01911 FormulaElement* formula = m_line->formula();
01912 formula->changed();
01913 testDirty();
01914 }
01915
01916
01917 void KFCNewLine::unexecute()
01918 {
01919 FormulaCursor* cursor = getExecuteCursor();
01920 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
01921 int linePos = parent->content.find( m_line );
01922
01923
01924 m_newline = parent->content.at( linePos+1 );
01925
01926
01927 FormulaElement* formula = m_line->formula();
01928 formula->elementRemoval( m_newline );
01929
01930
01931 if ( m_newline->countChildren() > 0 ) {
01932
01933
01934 m_newline->selectAllChildren( cursor );
01935 QPtrList<BasicElement> elementList;
01936 m_newline->remove( cursor, elementList, beforeCursor );
01937
01938
01939 m_line->moveEnd( cursor );
01940 m_line->insert( cursor, elementList, beforeCursor );
01941 cursor->setPos( cursor->getMark() );
01942 }
01943 else {
01944 m_line->moveEnd( cursor );
01945 }
01946 parent->content.take( linePos+1 );
01947
01948
01949 formula->changed();
01950 testDirty();
01951 }
01952
01953
01954 MultilineSequenceElement::MultilineSequenceElement( BasicElement* parent )
01955 : SequenceElement( parent )
01956 {
01957 tabs.setAutoDelete( false );
01958 }
01959
01960
01961 BasicElement* MultilineSequenceElement::goToPos( FormulaCursor* cursor, bool& handled,
01962 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
01963 {
01964
01965
01966 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
01967
01968 if (e == 0) {
01969
01970 if ( ( point.x() > getX()+getWidth() ) &&
01971 ( point.y() >= getY() ) &&
01972 ( point.y() < getY()+getHeight() ) ) {
01973 cursor->setTo(this, countChildren());
01974 handled = true;
01975 return this;
01976 }
01977 }
01978 return e;
01979 }
01980
01981
01982 void MultilineSequenceElement::calcSizes( const ContextStyle& context,
01983 ContextStyle::TextStyle tstyle,
01984 ContextStyle::IndexStyle istyle,
01985 StyleAttributes& style )
01986 {
01987 tabs.clear();
01988 inherited::calcSizes( context, tstyle, istyle, style );
01989 }
01990
01991
01992 void MultilineSequenceElement::registerTab( BasicElement* tab )
01993 {
01994 tabs.append( tab );
01995 }
01996
01997
01998 KCommand* MultilineSequenceElement::buildCommand( Container* container, Request* request )
01999 {
02000 FormulaCursor* cursor = container->activeCursor();
02001 if ( cursor->isReadOnly() ) {
02002 return 0;
02003 }
02004
02005 switch ( *request ) {
02006 case req_remove: {
02007
02008
02009 break;
02010 }
02011 case req_addNewline: {
02012 FormulaCursor* cursor = container->activeCursor();
02013 return new KFCNewLine( i18n( "Add Newline" ), container, this, cursor->getPos() );
02014 }
02015 case req_addTabMark: {
02016 KFCReplace* command = new KFCReplace( i18n("Add Tabmark"), container );
02017 SpaceElement* element = new SpaceElement( THIN, true );
02018 command->addElement( element );
02019 return command;
02020 }
02021 default:
02022 break;
02023 }
02024 return inherited::buildCommand( container, request );
02025 }
02026
02027
02028 KCommand* MultilineSequenceElement::input( Container* container, QKeyEvent* event )
02029 {
02030 int action = event->key();
02031
02032
02033
02034 switch ( action ) {
02035 case Qt::Key_Enter:
02036 case Qt::Key_Return: {
02037 Request newline( req_addNewline );
02038 return buildCommand( container, &newline );
02039 }
02040 case Qt::Key_Tab: {
02041 Request r( req_addTabMark );
02042 return buildCommand( container, &r );
02043 }
02044 }
02045 return inherited::input( container, event );
02046 }
02047
02048
02049 KCommand* MultilineSequenceElement::input( Container* container, QChar ch )
02050 {
02051 int latin1 = ch.latin1();
02052 switch (latin1) {
02053 case '&': {
02054 Request r( req_addTabMark );
02055 return buildCommand( container, &r );
02056 }
02057 }
02058 return inherited::input( container, ch );
02059 }
02060
02061
02062 void MultilineSequenceElement::moveTabTo( uint i, luPixel pos )
02063 {
02064 BasicElement* marker = tab( i );
02065 luPixel diff = pos - marker->getX();
02066 marker->setWidth( marker->getWidth() + diff );
02067
02068 for ( int p = childPos( marker )+1; p < countChildren(); ++p ) {
02069 BasicElement* child = getChild( p );
02070 child->setX( child->getX() + diff );
02071 }
02072
02073 setWidth( getWidth()+diff );
02074 }
02075
02076
02077 int MultilineSequenceElement::tabBefore( uint pos )
02078 {
02079 if ( tabs.isEmpty() ) {
02080 return -1;
02081 }
02082 uint tabNum = 0;
02083 for ( uint i=0; i<pos; ++i ) {
02084 BasicElement* child = getChild( i );
02085 if ( tabs.at( tabNum ) == child ) {
02086 if ( tabNum+1 == tabs.count() ) {
02087 return tabNum;
02088 }
02089 ++tabNum;
02090 }
02091 }
02092 return static_cast<int>( tabNum )-1;
02093 }
02094
02095
02096 int MultilineSequenceElement::tabPos( uint i )
02097 {
02098 if ( i < tabs.count() ) {
02099 return childPos( tabs.at( i ) );
02100 }
02101 return -1;
02102 }
02103
02104
02105 void MultilineSequenceElement::writeMathML( QDomDocument& doc,
02106 QDomNode& parent, bool oasisFormat ) const
02107 {
02108
02109
02110 QDomElement tmp = doc.createElement( "TMP" );
02111
02112 inherited::writeMathML( doc, tmp, oasisFormat );
02113
02114
02115
02116
02117
02118
02119 QDomElement mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
02120
02121
02122 QDomNode n = tmp.firstChild().firstChild();
02123 while ( !n.isNull() ) {
02124
02125 if ( n.isElement() && n.toElement().tagName() == "TAB" ) {
02126 parent.appendChild( mtd );
02127 mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
02128 }
02129 else {
02130 mtd.appendChild( n.cloneNode() );
02131 }
02132 n = n.nextSibling();
02133 }
02134
02135 parent.appendChild( mtd );
02136 }
02137
02138
02139 MultilineElement::MultilineElement( BasicElement* parent )
02140 : BasicElement( parent )
02141 {
02142 content.setAutoDelete( true );
02143 content.append( new MultilineSequenceElement( this ) );
02144 }
02145
02146 MultilineElement::~MultilineElement()
02147 {
02148 }
02149
02150 MultilineElement::MultilineElement( const MultilineElement& other )
02151 : BasicElement( other )
02152 {
02153 content.setAutoDelete( true );
02154 uint count = other.content.count();
02155 for (uint i = 0; i < count; i++) {
02156 MultilineSequenceElement* line = content.at(i)->clone();
02157 line->setParent( this );
02158 content.append( line );
02159 }
02160 }
02161
02162
02163 bool MultilineElement::accept( ElementVisitor* visitor )
02164 {
02165 return visitor->visit( this );
02166 }
02167
02168
02169 void MultilineElement::entered( SequenceElement* )
02170 {
02171 formula()->tell( i18n( "Multi line element" ) );
02172 }
02173
02174
02178 BasicElement* MultilineElement::goToPos( FormulaCursor* cursor, bool& handled,
02179 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
02180 {
02181 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
02182 if ( e != 0 ) {
02183 LuPixelPoint myPos(parentOrigin.x() + getX(),
02184 parentOrigin.y() + getY());
02185
02186 uint count = content.count();
02187 for ( uint i = 0; i < count; ++i ) {
02188 MultilineSequenceElement* line = content.at(i);
02189 e = line->goToPos(cursor, handled, point, myPos);
02190 if (e != 0) {
02191 return e;
02192 }
02193 }
02194 return this;
02195 }
02196 return 0;
02197 }
02198
02199 void MultilineElement::goInside( FormulaCursor* cursor )
02200 {
02201 content.at( 0 )->goInside( cursor );
02202 }
02203
02204 void MultilineElement::moveLeft( FormulaCursor* cursor, BasicElement* from )
02205 {
02206
02207
02208 if (cursor->isSelectionMode()) {
02209 getParent()->moveLeft(cursor, this);
02210 }
02211 else {
02212
02213
02214 if (from == getParent()) {
02215 content.at( content.count()-1 )->moveLeft(cursor, this);
02216 }
02217 else {
02218
02219
02220 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02221 if ( pos > -1 ) {
02222 if ( pos > 0 ) {
02223 content.at( pos-1 )->moveLeft( cursor, this );
02224 }
02225 else {
02226 getParent()->moveLeft(cursor, this);
02227 }
02228 }
02229 else {
02230 kdDebug( DEBUGID ) << k_funcinfo << endl;
02231 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02232 }
02233 }
02234 }
02235 }
02236
02237 void MultilineElement::moveRight( FormulaCursor* cursor, BasicElement* from )
02238 {
02239 if (cursor->isSelectionMode()) {
02240 getParent()->moveRight(cursor, this);
02241 }
02242 else {
02243 if (from == getParent()) {
02244 content.at( 0 )->moveRight(cursor, this);
02245 }
02246 else {
02247 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02248 if ( pos > -1 ) {
02249 uint upos = pos;
02250 if ( upos < content.count() ) {
02251 if ( upos < content.count()-1 ) {
02252 content.at( upos+1 )->moveRight( cursor, this );
02253 }
02254 else {
02255 getParent()->moveRight(cursor, this);
02256 }
02257 return;
02258 }
02259 }
02260 kdDebug( DEBUGID ) << k_funcinfo << endl;
02261 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02262 }
02263 }
02264 }
02265
02266 void MultilineElement::moveUp( FormulaCursor* cursor, BasicElement* from )
02267 {
02268
02269
02270 if (cursor->isSelectionMode()) {
02271 getParent()->moveLeft(cursor, this);
02272 }
02273 else {
02274
02275
02276 if (from == getParent()) {
02277 content.at( content.count()-1 )->moveLeft(cursor, this);
02278 }
02279 else {
02280
02281
02282 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02283 if ( pos > -1 ) {
02284 if ( pos > 0 ) {
02285
02286
02287
02288 int cursorPos = cursor->getPos();
02289 MultilineSequenceElement* current = content.at( pos );
02290 MultilineSequenceElement* newLine = content.at( pos-1 );
02291 int tabNum = current->tabBefore( cursorPos );
02292 if ( tabNum > -1 ) {
02293 int oldTabPos = current->tabPos( tabNum );
02294 int newTabPos = newLine->tabPos( tabNum );
02295 if ( newTabPos > -1 ) {
02296 cursorPos += newTabPos-oldTabPos;
02297 int nextNewTabPos = newLine->tabPos( tabNum+1 );
02298 if ( nextNewTabPos > -1 ) {
02299 cursorPos = QMIN( cursorPos, nextNewTabPos );
02300 }
02301 }
02302 else {
02303 cursorPos = newLine->countChildren();
02304 }
02305 }
02306 else {
02307 int nextNewTabPos = newLine->tabPos( 0 );
02308 if ( nextNewTabPos > -1 ) {
02309 cursorPos = QMIN( cursorPos, nextNewTabPos );
02310 }
02311 }
02312 cursor->setTo( newLine,
02313 QMIN( cursorPos,
02314 newLine->countChildren() ) );
02315 }
02316 else {
02317 getParent()->moveLeft(cursor, this);
02318 }
02319 }
02320 else {
02321 kdDebug( DEBUGID ) << k_funcinfo << endl;
02322 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02323 }
02324 }
02325 }
02326 }
02327
02328 void MultilineElement::moveDown( FormulaCursor* cursor, BasicElement* from )
02329 {
02330 if (cursor->isSelectionMode()) {
02331 getParent()->moveRight(cursor, this);
02332 }
02333 else {
02334 if (from == getParent()) {
02335 content.at( 0 )->moveRight(cursor, this);
02336 }
02337 else {
02338 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02339 if ( pos > -1 ) {
02340 uint upos = pos;
02341 if ( upos < content.count() ) {
02342 if ( upos < content.count()-1 ) {
02343
02344
02345
02346 int cursorPos = cursor->getPos();
02347 MultilineSequenceElement* current = content.at( upos );
02348 MultilineSequenceElement* newLine = content.at( upos+1 );
02349 int tabNum = current->tabBefore( cursorPos );
02350 if ( tabNum > -1 ) {
02351 int oldTabPos = current->tabPos( tabNum );
02352 int newTabPos = newLine->tabPos( tabNum );
02353 if ( newTabPos > -1 ) {
02354 cursorPos += newTabPos-oldTabPos;
02355 int nextNewTabPos = newLine->tabPos( tabNum+1 );
02356 if ( nextNewTabPos > -1 ) {
02357 cursorPos = QMIN( cursorPos, nextNewTabPos );
02358 }
02359 }
02360 else {
02361 cursorPos = newLine->countChildren();
02362 }
02363 }
02364 else {
02365 int nextNewTabPos = newLine->tabPos( 0 );
02366 if ( nextNewTabPos > -1 ) {
02367 cursorPos = QMIN( cursorPos, nextNewTabPos );
02368 }
02369 }
02370 cursor->setTo( newLine,
02371 QMIN( cursorPos,
02372 newLine->countChildren() ) );
02373 }
02374 else {
02375 getParent()->moveRight(cursor, this);
02376 }
02377 return;
02378 }
02379 }
02380 kdDebug( DEBUGID ) << k_funcinfo << endl;
02381 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02382 }
02383 }
02384 }
02385
02386
02387 void MultilineElement::calcSizes( const ContextStyle& context,
02388 ContextStyle::TextStyle tstyle,
02389 ContextStyle::IndexStyle istyle,
02390 StyleAttributes& style )
02391 {
02392 double factor = style.sizeFactor();
02393 luPt mySize = context.getAdjustedSize( tstyle, factor );
02394 QFont font = context.getDefaultFont();
02395 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
02396 QFontMetrics fm( font );
02397 luPixel leading = context.ptToLayoutUnitPt( fm.leading() );
02398 luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
02399
02400 uint count = content.count();
02401 luPixel height = -leading;
02402 luPixel width = 0;
02403 uint tabCount = 0;
02404 for ( uint i = 0; i < count; ++i ) {
02405 MultilineSequenceElement* line = content.at(i);
02406 line->calcSizes( context, tstyle, istyle, style );
02407 tabCount = QMAX( tabCount, line->tabCount() );
02408
02409 height += leading;
02410 line->setX( 0 );
02411 line->setY( height );
02412 height += line->getHeight() + distY;
02413 width = QMAX( line->getWidth(), width );
02414 }
02415
02416
02417 for ( uint t = 0; t < tabCount; ++t ) {
02418 luPixel pos = 0;
02419 for ( uint i = 0; i < count; ++i ) {
02420 MultilineSequenceElement* line = content.at(i);
02421 if ( t < line->tabCount() ) {
02422 pos = QMAX( pos, line->tab( t )->getX() );
02423 }
02424 else {
02425 pos = QMAX( pos, line->getWidth() );
02426 }
02427 }
02428 for ( uint i = 0; i < count; ++i ) {
02429 MultilineSequenceElement* line = content.at(i);
02430 if ( t < line->tabCount() ) {
02431 line->moveTabTo( t, pos );
02432 width = QMAX( width, line->getWidth() );
02433 }
02434 }
02435 }
02436
02437 setHeight( height );
02438 setWidth( width );
02439 if ( count == 1 ) {
02440 setBaseline( content.at( 0 )->getBaseline() );
02441 }
02442 else {
02443
02444 setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
02445 }
02446 }
02447
02448 void MultilineElement::draw( QPainter& painter, const LuPixelRect& r,
02449 const ContextStyle& context,
02450 ContextStyle::TextStyle tstyle,
02451 ContextStyle::IndexStyle istyle,
02452 StyleAttributes& style,
02453 const LuPixelPoint& parentOrigin )
02454 {
02455 LuPixelPoint myPos( parentOrigin.x() + getX(), parentOrigin.y() + getY() );
02456 uint count = content.count();
02457
02458 if ( context.edit() ) {
02459 uint tabCount = 0;
02460 painter.setPen( context.getHelpColor() );
02461 for ( uint i = 0; i < count; ++i ) {
02462 MultilineSequenceElement* line = content.at(i);
02463 if ( tabCount < line->tabCount() ) {
02464 for ( uint t = tabCount; t < line->tabCount(); ++t ) {
02465 BasicElement* marker = line->tab( t );
02466 painter.drawLine( context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
02467 context.layoutUnitToPixelY( myPos.y() ),
02468 context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
02469 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
02470 }
02471 tabCount = line->tabCount();
02472 }
02473 }
02474 }
02475
02476 for ( uint i = 0; i < count; ++i ) {
02477 MultilineSequenceElement* line = content.at(i);
02478 line->draw( painter, r, context, tstyle, istyle, style, myPos );
02479 }
02480 }
02481
02482
02483 void MultilineElement::dispatchFontCommand( FontCommand* cmd )
02484 {
02485 uint count = content.count();
02486 for ( uint i = 0; i < count; ++i ) {
02487 MultilineSequenceElement* line = content.at(i);
02488 line->dispatchFontCommand( cmd );
02489 }
02490 }
02491
02492 void MultilineElement::insert( FormulaCursor* cursor,
02493 QPtrList<BasicElement>& newChildren,
02494 Direction direction )
02495 {
02496 MultilineSequenceElement* e = static_cast<MultilineSequenceElement*>(newChildren.take(0));
02497 e->setParent(this);
02498 content.insert( cursor->getPos(), e );
02499
02500 if (direction == beforeCursor) {
02501 e->moveLeft(cursor, this);
02502 }
02503 else {
02504 e->moveRight(cursor, this);
02505 }
02506 cursor->setSelection(false);
02507 formula()->changed();
02508 }
02509
02510 void MultilineElement::remove( FormulaCursor* cursor,
02511 QPtrList<BasicElement>& removedChildren,
02512 Direction direction )
02513 {
02514 if ( content.count() == 1 ) {
02515 getParent()->selectChild(cursor, this);
02516 getParent()->remove(cursor, removedChildren, direction);
02517 }
02518 else {
02519 MultilineSequenceElement* e = content.take( cursor->getPos() );
02520 removedChildren.append( e );
02521 formula()->elementRemoval( e );
02522
02523 formula()->changed();
02524 }
02525 }
02526
02527 void MultilineElement::normalize( FormulaCursor* cursor, Direction direction )
02528 {
02529 int pos = cursor->getPos();
02530 if ( ( cursor->getElement() == this ) &&
02531 ( pos > -1 ) && ( static_cast<unsigned>( pos ) <= content.count() ) ) {
02532 switch ( direction ) {
02533 case beforeCursor:
02534 if ( pos > 0 ) {
02535 content.at( pos-1 )->moveLeft( cursor, this );
02536 break;
02537 }
02538
02539 case afterCursor:
02540 if ( static_cast<unsigned>( pos ) < content.count() ) {
02541 content.at( pos )->moveRight( cursor, this );
02542 }
02543 else {
02544 content.at( pos-1 )->moveLeft( cursor, this );
02545 }
02546 break;
02547 }
02548 }
02549 else {
02550 inherited::normalize( cursor, direction );
02551 }
02552 }
02553
02554 SequenceElement* MultilineElement::getMainChild()
02555 {
02556 return content.at( 0 );
02557 }
02558
02559 void MultilineElement::selectChild(FormulaCursor* cursor, BasicElement* child)
02560 {
02561 int pos = content.find( dynamic_cast<MultilineSequenceElement*>( child ) );
02562 if ( pos > -1 ) {
02563 cursor->setTo( this, pos );
02564
02565 }
02566 }
02567
02568
02572 void MultilineElement::writeDom(QDomElement element)
02573 {
02574 BasicElement::writeDom(element);
02575
02576 uint lineCount = content.count();
02577 element.setAttribute( "LINES", lineCount );
02578
02579 QDomDocument doc = element.ownerDocument();
02580 for ( uint i = 0; i < lineCount; ++i ) {
02581 QDomElement tmp = content.at( i )->getElementDom(doc);
02582 element.appendChild(tmp);
02583 }
02584 }
02585
02586 void MultilineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
02587 {
02588 QDomElement de = doc.createElement( oasisFormat ? "math:mtable" : "mtable" );
02589 QDomElement row; QDomElement cell;
02590
02591 for ( QPtrListIterator < MultilineSequenceElement > it( content ); it.current(); ++it ) {
02592 row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
02593 de.appendChild( row );
02594
02595
02596
02597
02598 it.current()->writeMathML( doc, row, oasisFormat );
02599 }
02600
02601 parent.appendChild( de );
02602 }
02603
02608 bool MultilineElement::readAttributesFromDom(QDomElement element)
02609 {
02610 if (!BasicElement::readAttributesFromDom(element)) {
02611 return false;
02612 }
02613 uint lineCount = 0;
02614 QString lineCountStr = element.attribute("LINES");
02615 if(!lineCountStr.isNull()) {
02616 lineCount = lineCountStr.toInt();
02617 }
02618 if (lineCount == 0) {
02619 kdWarning( DEBUGID ) << "lineCount <= 0 in MultilineElement." << endl;
02620 return false;
02621 }
02622
02623 content.clear();
02624 for ( uint i = 0; i < lineCount; ++i ) {
02625 MultilineSequenceElement* element = new MultilineSequenceElement(this);
02626 content.append(element);
02627 }
02628 return true;
02629 }
02630
02636 bool MultilineElement::readContentFromDom(QDomNode& node)
02637 {
02638 if (!BasicElement::readContentFromDom(node)) {
02639 return false;
02640 }
02641
02642 uint lineCount = content.count();
02643 uint i = 0;
02644 while ( !node.isNull() && i < lineCount ) {
02645 if ( node.isElement() ) {
02646 SequenceElement* element = content.at( i );
02647 QDomElement e = node.toElement();
02648 if ( !element->buildFromDom( e ) ) {
02649 return false;
02650 }
02651 ++i;
02652 }
02653 node = node.nextSibling();
02654 }
02655 return true;
02656 }
02657
02658 QString MultilineElement::toLatex()
02659 {
02660 uint lineCount = content.count();
02661 QString muliline = "\\begin{split} ";
02662 for ( uint i = 0; i < lineCount; ++i ) {
02663 muliline += content.at( i )->toLatex();
02664 muliline += " \\\\ ";
02665 }
02666 muliline += "\\end{split}";
02667 return muliline;
02668 }
02669
02670
02671 QString MultilineElement::formulaString()
02672 {
02673 uint lineCount = content.count();
02674 QString muliline = "";
02675 for ( uint i = 0; i < lineCount; ++i ) {
02676 muliline += content.at( i )->formulaString();
02677 muliline += "\n";
02678 }
02679
02680 return muliline;
02681 }
02682
02683
02684 KFORMULA_NAMESPACE_END