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" || e.tagName().lower() == "mlabeledtr" )
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 > 0 && e.tagName().lower() == "mlabeledtr" )
01147 cc--;
01148 if ( cc > cols )
01149 cols = cc;
01150 }
01151 }
01152 n = n.nextSibling();
01153 }
01154
01155
01156 content.clear();
01157 for (uint r = 0; r < rows; r++) {
01158 QPtrList< MatrixSequenceElement >* list = new QPtrList< MatrixSequenceElement >;
01159 list->setAutoDelete(true);
01160 content.append(list);
01161 for (uint c = 0; c < cols; c++) {
01162 MatrixSequenceElement* element = new MatrixSequenceElement(this);
01163 list->append(element);
01164 }
01165 }
01166
01167
01168 uint r = 0;
01169 uint c = 0;
01170 while ( !node.isNull() ) {
01171 if ( node.isElement() ) {
01172 QDomElement e = node.toElement();
01173 if ( e.tagName().lower() == "mtr" || e.tagName().lower() == "mlabeledtr" ) {
01174 QDomNode cellnode = e.firstChild();
01175 if ( e.tagName().lower() == "mlabeledtr" ) {
01176 while ( ! cellnode.isNull() && ! cellnode.isElement() )
01177 cellnode = cellnode.nextSibling();
01178 if ( ! cellnode.isNull() )
01179 cellnode = cellnode.nextSibling();
01180 }
01181 while ( !cellnode.isNull() ) {
01182 if ( cellnode.isElement() ) {
01183 QDomElement cellelement = cellnode.toElement();
01184 if ( cellelement.tagName().lower() != "mtd" ) {
01185
01186 kdWarning( DEBUGID ) << "Unsupported tag "
01187 << cellelement.tagName()
01188 << " inside matrix row\n";
01189 }
01190 else {
01191 SequenceElement* element = getElement(r, c);
01192 if ( element->buildFromMathMLDom( cellelement ) == -1 )
01193 return -1;
01194 c++;
01195 }
01196 }
01197 cellnode = cellnode.nextSibling();
01198 }
01199 c = 0;
01200 r++;
01201 }
01202 }
01203 node = node.nextSibling();
01204 }
01205 return 1;
01206 }
01207
01208 QString MatrixElement::toLatex()
01209 {
01210
01211
01212 QString matrix;
01213 uint cols=getColumns();
01214 uint rows=getRows();
01215
01216 matrix="\\begin{array}{ ";
01217 for(uint i=0;i<cols;i++)
01218 matrix+="c ";
01219
01220 matrix+="} ";
01221
01222 for (uint r = 0; r < rows; r++) {
01223 for (uint c = 0; c < cols; c++) {
01224 matrix+=getElement(r, c)->toLatex();
01225 if( c < cols-1) matrix+=" & ";
01226 }
01227 if(r < rows-1 ) matrix+=" \\\\ ";
01228 }
01229
01230 matrix+=" \\end{array}";
01231
01232 return matrix;
01233 }
01234
01235 QString MatrixElement::formulaString()
01236 {
01237 QString matrix = "[";
01238 uint cols=getColumns();
01239 uint rows=getRows();
01240 for (uint r = 0; r < rows; r++) {
01241 matrix += "[";
01242 for (uint c = 0; c < cols; c++) {
01243 matrix+=getElement(r, c)->formulaString();
01244 if ( c < cols-1 ) matrix+=", ";
01245 }
01246 matrix += "]";
01247 if ( r < rows-1 ) matrix += ", ";
01248 }
01249 matrix += "]";
01250 return matrix;
01251 }
01252
01253
01254 SequenceElement* MatrixElement::elementAt(uint row, uint column)
01255 {
01256 return getElement( row, column );
01257 }
01258
01259 void MatrixElement::writeMathMLAttributes( QDomElement& element ) const
01260 {
01261 QString rownumber;
01262 if ( m_rowNumber ) {
01263 rownumber = QString( " %1" ).arg( m_rowNumber );
01264 }
01265 switch ( m_align ) {
01266 case TopAlign:
01267 element.setAttribute( "align", "top" + rownumber );
01268 break;
01269 case BottomAlign:
01270 element.setAttribute( "align", "bottom" + rownumber );
01271 break;
01272 case CenterAlign:
01273 element.setAttribute( "align", "center" + rownumber );
01274 break;
01275 case BaselineAlign:
01276 element.setAttribute( "align", "baseline" + rownumber );
01277 break;
01278 case AxisAlign:
01279 element.setAttribute( "align", "axis" + rownumber );
01280 break;
01281 default:
01282 break;
01283 }
01284 QString rowalign;
01285 for ( QValueList< VerticalAlign >::const_iterator it = m_rowAlign.begin(); it != m_rowAlign.end(); it++ )
01286 {
01287 switch ( *it ) {
01288 case TopAlign:
01289 rowalign.append( "top " );
01290 break;
01291 case BottomAlign:
01292 rowalign.append( "bottom " );
01293 break;
01294 case CenterAlign:
01295 rowalign.append( "center " );
01296 break;
01297 case BaselineAlign:
01298 rowalign.append( "baseline " );
01299 break;
01300 case AxisAlign:
01301 rowalign.append( "axis " );
01302 break;
01303 default:
01304 break;
01305 }
01306 }
01307 if ( ! rowalign.isNull() ) {
01308 element.setAttribute( "rowalign", rowalign.stripWhiteSpace() );
01309 }
01310 QString columnalign;
01311 for ( QValueList< HorizontalAlign >::const_iterator it = m_columnAlign.begin(); it != m_columnAlign.end(); it++ )
01312 {
01313 switch ( *it ) {
01314 case LeftHorizontalAlign:
01315 rowalign.append( "left " );
01316 break;
01317 case CenterHorizontalAlign:
01318 rowalign.append( "center " );
01319 break;
01320 case RightHorizontalAlign:
01321 rowalign.append( "right " );
01322 break;
01323 default:
01324 break;
01325 }
01326 }
01327 if ( ! columnalign.isNull() ) {
01328 element.setAttribute( "columnalign", columnalign.stripWhiteSpace() );
01329 }
01330 QString alignmentscope;
01331 for ( QValueList< bool >::const_iterator it = m_alignmentScope.begin(); it != m_alignmentScope.end(); it++ )
01332 {
01333 if ( *it ) {
01334 alignmentscope.append( "true " );
01335 }
01336 else {
01337 alignmentscope.append( "false " );
01338 }
01339 }
01340 if ( ! alignmentscope.isNull() ) {
01341 element.setAttribute( "alignmentscope", alignmentscope.stripWhiteSpace() );
01342 }
01343 QString columnwidth;
01344 QValueList< double >::const_iterator lengthIt = m_columnWidth.begin();
01345 for ( QValueList< SizeType >::const_iterator typeIt = m_columnWidthType.begin();
01346 typeIt != m_columnWidthType.end(); typeIt ++ ) {
01347 switch ( *typeIt ) {
01348 case AutoSize:
01349 columnwidth.append( "auto " );
01350 break;
01351 case FitSize:
01352 columnwidth.append( "fit " );
01353 break;
01354 case AbsoluteSize:
01355 columnwidth.append( QString( "%1pt " ).arg( *lengthIt ) );
01356 lengthIt++;
01357 break;
01358 case RelativeSize:
01359 columnwidth.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
01360 lengthIt++;
01361 break;
01362 case PixelSize:
01363 columnwidth.append( QString( "%1px " ).arg( *lengthIt ) );
01364 lengthIt++;
01365 break;
01366 case NegativeVeryVeryThinMathSpace:
01367 columnwidth.append( "negativeveryverythinmathspace " );
01368 break;
01369 case NegativeVeryThinMathSpace:
01370 columnwidth.append( "negativeverythinmathspace " );
01371 break;
01372 case NegativeThinMathSpace:
01373 columnwidth.append( "negativethinmathspace " );
01374 break;
01375 case NegativeMediumMathSpace:
01376 columnwidth.append( "negativemediummathspace " );
01377 break;
01378 case NegativeThickMathSpace:
01379 columnwidth.append( "negativethickmathspace " );
01380 break;
01381 case NegativeVeryThickMathSpace:
01382 columnwidth.append( "negativeverythickmathspace " );
01383 break;
01384 case NegativeVeryVeryThickMathSpace:
01385 columnwidth.append( "negativeveryverythickmathspace " );
01386 break;
01387 case VeryVeryThinMathSpace:
01388 columnwidth.append( "veryverythinmathspace " );
01389 break;
01390 case VeryThinMathSpace:
01391 columnwidth.append( "verythinmathspace " );
01392 break;
01393 case ThinMathSpace:
01394 columnwidth.append( "thinmathspace " );
01395 break;
01396 case MediumMathSpace:
01397 columnwidth.append( "mediummathspace " );
01398 break;
01399 case ThickMathSpace:
01400 columnwidth.append( "thickmathspace " );
01401 break;
01402 case VeryThickMathSpace:
01403 columnwidth.append( "verythickmathspace " );
01404 break;
01405 case VeryVeryThickMathSpace:
01406 columnwidth.append( "veryverythickmathspace " );
01407 break;
01408 default:
01409 break;
01410 }
01411 }
01412 if ( ! columnwidth.isNull() ) {
01413 element.setAttribute( "columnwidth", columnwidth.stripWhiteSpace() );
01414 }
01415 switch ( m_widthType ) {
01416 case AutoSize:
01417 element.setAttribute( "width", "auto" );
01418 break;
01419 case AbsoluteSize:
01420 element.setAttribute( "width", QString( "%1pt" ).arg( m_width ) );
01421 break;
01422 case RelativeSize:
01423 element.setAttribute( "width", QString( "%1% " ).arg( m_width * 100.0 ) );
01424 break;
01425 case PixelSize:
01426 element.setAttribute( "width", QString( "%1px " ).arg( m_width ) );
01427 break;
01428 default:
01429 break;
01430 }
01431 QString rowspacing;
01432 lengthIt = m_rowSpacing.begin();
01433 for ( QValueList< SizeType >::const_iterator typeIt = m_rowSpacingType.begin();
01434 typeIt != m_rowSpacingType.end(); typeIt++, lengthIt++ ) {
01435 switch ( *typeIt ) {
01436 case AbsoluteSize:
01437 rowspacing.append( QString( "%1pt " ).arg( *lengthIt ) );
01438 break;
01439 case RelativeSize:
01440 rowspacing.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
01441 break;
01442 case PixelSize:
01443 rowspacing.append( QString( "%1px " ).arg( *lengthIt ) );
01444 break;
01445 default:
01446 break;
01447 }
01448 }
01449 if ( ! rowspacing.isNull() ) {
01450 element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
01451 }
01452 QString columnspacing;
01453 lengthIt = m_columnSpacing.begin();
01454 for ( QValueList< SizeType >::const_iterator typeIt = m_columnSpacingType.begin();
01455 typeIt != m_columnSpacingType.end(); typeIt++ ) {
01456 switch ( *typeIt ) {
01457 case AbsoluteSize:
01458 columnspacing.append( QString( "%1pt " ).arg( *lengthIt ) );
01459 lengthIt++;
01460 break;
01461 case RelativeSize:
01462 columnspacing.append( QString( "%1% " ).arg( *lengthIt * 100.0 ) );
01463 lengthIt++;
01464 break;
01465 case PixelSize:
01466 columnspacing.append( QString( "%1px " ).arg( *lengthIt ) );
01467 lengthIt++;
01468 break;
01469 case NegativeVeryVeryThinMathSpace:
01470 columnspacing.append( "negativeveryverythinmathspace " );
01471 break;
01472 case NegativeVeryThinMathSpace:
01473 columnspacing.append( "negativeverythinmathspace " );
01474 break;
01475 case NegativeThinMathSpace:
01476 columnspacing.append( "negativethinmathspace " );
01477 break;
01478 case NegativeMediumMathSpace:
01479 columnspacing.append( "negativemediummathspace " );
01480 break;
01481 case NegativeThickMathSpace:
01482 columnspacing.append( "negativethickmathspace " );
01483 break;
01484 case NegativeVeryThickMathSpace:
01485 columnspacing.append( "negativeverythickmathspace " );
01486 break;
01487 case NegativeVeryVeryThickMathSpace:
01488 columnspacing.append( "negativeveryverythickmathspace " );
01489 break;
01490 case VeryVeryThinMathSpace:
01491 columnspacing.append( "veryverythinmathspace " );
01492 break;
01493 case VeryThinMathSpace:
01494 columnspacing.append( "verythinmathspace " );
01495 break;
01496 case ThinMathSpace:
01497 columnspacing.append( "thinmathspace " );
01498 break;
01499 case MediumMathSpace:
01500 columnspacing.append( "mediummathspace " );
01501 break;
01502 case ThickMathSpace:
01503 columnspacing.append( "thickmathspace " );
01504 break;
01505 case VeryThickMathSpace:
01506 columnspacing.append( "verythickmathspace " );
01507 break;
01508 case VeryVeryThickMathSpace:
01509 columnspacing.append( "veryverythickmathspace " );
01510 break;
01511 default:
01512 break;
01513 }
01514 }
01515 if ( ! rowspacing.isNull() ) {
01516 element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
01517 }
01518 QString rowlines;
01519 for ( QValueList< LineType >::const_iterator it = m_rowLines.begin(); it != m_rowLines.end(); it++ )
01520 {
01521 switch ( *it ) {
01522 case NoneLine:
01523 rowlines.append( "none " );
01524 break;
01525 case SolidLine:
01526 rowlines.append( "solid " );
01527 break;
01528 case DashedLine:
01529 rowlines.append( "dashed " );
01530 break;
01531 default:
01532 break;
01533 }
01534 }
01535 if ( ! rowlines.isNull() ) {
01536 element.setAttribute( "rowlines", rowlines.stripWhiteSpace() );
01537 }
01538 QString columnlines;
01539 for ( QValueList< LineType >::const_iterator it = m_columnLines.begin(); it != m_columnLines.end(); it++ )
01540 {
01541 switch ( *it ) {
01542 case NoneLine:
01543 columnlines.append( "none " );
01544 break;
01545 case SolidLine:
01546 columnlines.append( "solid " );
01547 break;
01548 case DashedLine:
01549 columnlines.append( "dashed " );
01550 break;
01551 default:
01552 break;
01553 }
01554 }
01555 if ( ! columnlines.isNull() ) {
01556 element.setAttribute( "columnlines", columnlines.stripWhiteSpace() );
01557 }
01558 switch ( m_frame ) {
01559 case NoneLine:
01560 element.setAttribute( "frame", "none" );
01561 break;
01562 case SolidLine:
01563 element.setAttribute( "frame", "solid" );
01564 break;
01565 case DashedLine:
01566 element.setAttribute( "frame", "dashed" );
01567 break;
01568 default:
01569 break;
01570 }
01571 QString framespacing;
01572 switch ( m_frameHSpacingType ) {
01573 case AbsoluteSize:
01574 framespacing.append( QString( "%1pt " ).arg( m_frameHSpacing ) );
01575 break;
01576 case RelativeSize:
01577 framespacing.append( QString( "%1% " ).arg( m_frameHSpacing * 100.0 ) );
01578 break;
01579 case PixelSize:
01580 framespacing.append( QString( "%1px " ).arg( m_frameHSpacing ) );
01581 break;
01582 case NegativeVeryVeryThinMathSpace:
01583 framespacing.append( "negativeveryverythinmathspace " );
01584 break;
01585 case NegativeVeryThinMathSpace:
01586 framespacing.append( "negativeverythinmathspace " );
01587 break;
01588 case NegativeThinMathSpace:
01589 framespacing.append( "negativethinmathspace " );
01590 break;
01591 case NegativeMediumMathSpace:
01592 framespacing.append( "negativemediummathspace " );
01593 break;
01594 case NegativeThickMathSpace:
01595 framespacing.append( "negativethickmathspace " );
01596 break;
01597 case NegativeVeryThickMathSpace:
01598 framespacing.append( "negativeverythickmathspace " );
01599 break;
01600 case NegativeVeryVeryThickMathSpace:
01601 framespacing.append( "negativeveryverythickmathspace " );
01602 break;
01603 case VeryVeryThinMathSpace:
01604 framespacing.append( "veryverythinmathspace " );
01605 break;
01606 case VeryThinMathSpace:
01607 framespacing.append( "verythinmathspace " );
01608 break;
01609 case ThinMathSpace:
01610 framespacing.append( "thinmathspace " );
01611 break;
01612 case MediumMathSpace:
01613 framespacing.append( "mediummathspace " );
01614 break;
01615 case ThickMathSpace:
01616 framespacing.append( "thickmathspace " );
01617 break;
01618 case VeryThickMathSpace:
01619 framespacing.append( "verythickmathspace " );
01620 break;
01621 case VeryVeryThickMathSpace:
01622 framespacing.append( "veryverythickmathspace " );
01623 break;
01624 default:
01625 break;
01626 }
01627 switch ( m_frameVSpacingType ) {
01628 case AbsoluteSize:
01629 framespacing.append( QString( "%1pt " ).arg( m_frameVSpacing ) );
01630 break;
01631 case RelativeSize:
01632 framespacing.append( QString( "%1% " ).arg( m_frameVSpacing * 100.0 ) );
01633 break;
01634 case PixelSize:
01635 framespacing.append( QString( "%1px " ).arg( m_frameVSpacing ) );
01636 break;
01637 case NegativeVeryVeryThinMathSpace:
01638 framespacing.append( "negativeveryverythinmathspace " );
01639 break;
01640 case NegativeVeryThinMathSpace:
01641 framespacing.append( "negativeverythinmathspace " );
01642 break;
01643 case NegativeThinMathSpace:
01644 framespacing.append( "negativethinmathspace " );
01645 break;
01646 case NegativeMediumMathSpace:
01647 framespacing.append( "negativemediummathspace " );
01648 break;
01649 case NegativeThickMathSpace:
01650 framespacing.append( "negativethickmathspace " );
01651 break;
01652 case NegativeVeryThickMathSpace:
01653 framespacing.append( "negativeverythickmathspace " );
01654 break;
01655 case NegativeVeryVeryThickMathSpace:
01656 framespacing.append( "negativeveryverythickmathspace " );
01657 break;
01658 case VeryVeryThinMathSpace:
01659 framespacing.append( "veryverythinmathspace " );
01660 break;
01661 case VeryThinMathSpace:
01662 framespacing.append( "verythinmathspace " );
01663 break;
01664 case ThinMathSpace:
01665 framespacing.append( "thinmathspace " );
01666 break;
01667 case MediumMathSpace:
01668 framespacing.append( "mediummathspace " );
01669 break;
01670 case ThickMathSpace:
01671 framespacing.append( "thickmathspace " );
01672 break;
01673 case VeryThickMathSpace:
01674 framespacing.append( "verythickmathspace " );
01675 break;
01676 case VeryVeryThickMathSpace:
01677 framespacing.append( "veryverythickmathspace " );
01678 break;
01679 default:
01680 break;
01681 }
01682 if ( ! framespacing.isNull() ) {
01683 element.setAttribute( "framespacing", framespacing.stripWhiteSpace() );
01684 }
01685 if ( m_customEqualRows ) {
01686 element.setAttribute( "equalrows", m_equalRows ? "true" : "false" );
01687 }
01688 if ( m_customEqualColumns ) {
01689 element.setAttribute( "equalcolumns", m_equalColumns ? "true" : "false" );
01690 }
01691 if ( m_customDisplayStyle ) {
01692 element.setAttribute( "displaystyle", m_displayStyle ? "true" : "false" );
01693 }
01694 switch ( m_side ) {
01695 case LeftSide:
01696 element.setAttribute( "side", "left" );
01697 break;
01698 case RightSide:
01699 element.setAttribute( "side", "right" );
01700 break;
01701 case LeftOverlapSide:
01702 element.setAttribute( "side", "leftoverlap" );
01703 break;
01704 case RightOverlapSide:
01705 element.setAttribute( "side", "rightoverlap" );
01706 break;
01707 default:
01708 break;
01709 }
01710 switch ( m_minLabelSpacingType ) {
01711 case AbsoluteSize:
01712 element.setAttribute( "minlabelspacing", QString( "%1pt" ).arg( m_minLabelSpacing ) );
01713 break;
01714 case RelativeSize:
01715 element.setAttribute( "minlabelspacing", QString( "%1%" ).arg( m_minLabelSpacing * 100.0 ) );
01716 break;
01717 case PixelSize:
01718 element.setAttribute( "minlabelspacing", QString( "%1px" ).arg( m_minLabelSpacing ) );
01719 break;
01720 case NegativeVeryVeryThinMathSpace:
01721 element.setAttribute( "minlabelspacing", "negativeveryverythinmathspace" );
01722 break;
01723 case NegativeVeryThinMathSpace:
01724 element.setAttribute( "minlabelspacing", "negativeverythinmathspace" );
01725 break;
01726 case NegativeThinMathSpace:
01727 element.setAttribute( "minlabelspacing", "negativethinmathspace" );
01728 break;
01729 case NegativeMediumMathSpace:
01730 element.setAttribute( "minlabelspacing", "negativemediummathspace" );
01731 break;
01732 case NegativeThickMathSpace:
01733 element.setAttribute( "minlabelspacing", "negativethickmathspace" );
01734 break;
01735 case NegativeVeryThickMathSpace:
01736 element.setAttribute( "minlabelspacing", "negativeverythickmathspace" );
01737 break;
01738 case NegativeVeryVeryThickMathSpace:
01739 element.setAttribute( "minlabelspacing", "negativeveryverythickmathspace" );
01740 break;
01741 case VeryVeryThinMathSpace:
01742 element.setAttribute( "minlabelspacing", "veryverythinmathspace" );
01743 break;
01744 case VeryThinMathSpace:
01745 element.setAttribute( "minlabelspacing", "verythinmathspace" );
01746 break;
01747 case ThinMathSpace:
01748 element.setAttribute( "minlabelspacing", "thinmathspace" );
01749 break;
01750 case MediumMathSpace:
01751 element.setAttribute( "minlabelspacing", "mediummathspace" );
01752 break;
01753 case ThickMathSpace:
01754 element.setAttribute( "minlabelspacing", "thickmathspace" );
01755 break;
01756 case VeryThickMathSpace:
01757 element.setAttribute( "minlabelspacing", "verythickmathspace" );
01758 break;
01759 case VeryVeryThickMathSpace:
01760 element.setAttribute( "minlabelspacing", "veryverythickmathspace" );
01761 break;
01762 default:
01763 break;
01764 }
01765 }
01766
01767 void MatrixElement::writeMathMLContent( QDomDocument& doc,
01768 QDomElement& element,
01769 bool oasisFormat ) const
01770 {
01771 QDomElement row;
01772 QDomElement cell;
01773
01774 uint rows = getRows();
01775 uint cols = getColumns();
01776
01777 for ( uint r = 0; r < rows; r++ )
01778 {
01779 row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
01780 element.appendChild( row );
01781 for ( uint c = 0; c < cols; c++ )
01782 {
01783 cell = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
01784 row.appendChild( cell );
01785 getElement(r,c)->writeMathML( doc, cell, oasisFormat );
01786 }
01787 }
01788 }
01789
01790
01792
01793
01798 class MultilineSequenceElement : public SequenceElement {
01799 typedef SequenceElement inherited;
01800 public:
01801
01802 MultilineSequenceElement( BasicElement* parent = 0 );
01803
01804 virtual MultilineSequenceElement* clone() {
01805 return new MultilineSequenceElement( *this );
01806 }
01807
01808 virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
01809 const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
01810
01815 virtual void calcSizes( const ContextStyle& context,
01816 ContextStyle::TextStyle tstyle,
01817 ContextStyle::IndexStyle istyle,
01818 StyleAttributes& style );
01819
01820 virtual void registerTab( BasicElement* tab );
01821
01830 virtual KCommand* buildCommand( Container*, Request* );
01831
01832 virtual KCommand* input( Container* container, QKeyEvent* event );
01833
01834 virtual KCommand* input( Container* container, QChar ch );
01835
01836 uint tabCount() const { return tabs.count(); }
01837
01838 BasicElement* tab( uint i ) { return tabs.at( i ); }
01839
01841 void moveTabTo( uint i, luPixel pos );
01842
01844 int tabBefore( uint pos );
01845
01847 int tabPos( uint i );
01848
01849 virtual void writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat = false ) const ;
01850
01851 private:
01852
01853 QPtrList<BasicElement> tabs;
01854 };
01855
01856
01857
01858 class KFCNewLine : public Command {
01859 public:
01860 KFCNewLine( const QString& name, Container* document,
01861 MultilineSequenceElement* line, uint pos );
01862
01863 virtual ~KFCNewLine();
01864
01865 virtual void execute();
01866 virtual void unexecute();
01867
01868 private:
01869 MultilineSequenceElement* m_line;
01870 MultilineSequenceElement* m_newline;
01871 uint m_pos;
01872 };
01873
01874
01875 KFCNewLine::KFCNewLine( const QString& name, Container* document,
01876 MultilineSequenceElement* line, uint pos )
01877 : Command( name, document ),
01878 m_line( line ), m_pos( pos )
01879 {
01880 m_newline = new MultilineSequenceElement( m_line->getParent() );
01881 }
01882
01883
01884 KFCNewLine::~KFCNewLine()
01885 {
01886 delete m_newline;
01887 }
01888
01889
01890 void KFCNewLine::execute()
01891 {
01892 FormulaCursor* cursor = getExecuteCursor();
01893 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
01894 int linePos = parent->content.find( m_line );
01895 parent->content.insert( linePos+1, m_newline );
01896
01897
01898 if ( m_line->countChildren() > static_cast<int>( m_pos ) ) {
01899
01900
01901 m_line->selectAllChildren( cursor );
01902 cursor->setMark( m_pos );
01903 QPtrList<BasicElement> elementList;
01904 m_line->remove( cursor, elementList, beforeCursor );
01905
01906
01907 m_newline->goInside( cursor );
01908 m_newline->insert( cursor, elementList, beforeCursor );
01909 cursor->setPos( cursor->getMark() );
01910 }
01911 else {
01912 m_newline->goInside( cursor );
01913 }
01914
01915
01916 m_newline = 0;
01917
01918
01919 FormulaElement* formula = m_line->formula();
01920 formula->changed();
01921 testDirty();
01922 }
01923
01924
01925 void KFCNewLine::unexecute()
01926 {
01927 FormulaCursor* cursor = getExecuteCursor();
01928 MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
01929 int linePos = parent->content.find( m_line );
01930
01931
01932 m_newline = parent->content.at( linePos+1 );
01933
01934
01935 FormulaElement* formula = m_line->formula();
01936 formula->elementRemoval( m_newline );
01937
01938
01939 if ( m_newline->countChildren() > 0 ) {
01940
01941
01942 m_newline->selectAllChildren( cursor );
01943 QPtrList<BasicElement> elementList;
01944 m_newline->remove( cursor, elementList, beforeCursor );
01945
01946
01947 m_line->moveEnd( cursor );
01948 m_line->insert( cursor, elementList, beforeCursor );
01949 cursor->setPos( cursor->getMark() );
01950 }
01951 else {
01952 m_line->moveEnd( cursor );
01953 }
01954 parent->content.take( linePos+1 );
01955
01956
01957 formula->changed();
01958 testDirty();
01959 }
01960
01961
01962 MultilineSequenceElement::MultilineSequenceElement( BasicElement* parent )
01963 : SequenceElement( parent )
01964 {
01965 tabs.setAutoDelete( false );
01966 }
01967
01968
01969 BasicElement* MultilineSequenceElement::goToPos( FormulaCursor* cursor, bool& handled,
01970 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
01971 {
01972
01973
01974 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
01975
01976 if (e == 0) {
01977
01978 if ( ( point.x() > getX()+getWidth() ) &&
01979 ( point.y() >= getY() ) &&
01980 ( point.y() < getY()+getHeight() ) ) {
01981 cursor->setTo(this, countChildren());
01982 handled = true;
01983 return this;
01984 }
01985 }
01986 return e;
01987 }
01988
01989
01990 void MultilineSequenceElement::calcSizes( const ContextStyle& context,
01991 ContextStyle::TextStyle tstyle,
01992 ContextStyle::IndexStyle istyle,
01993 StyleAttributes& style )
01994 {
01995 tabs.clear();
01996 inherited::calcSizes( context, tstyle, istyle, style );
01997 }
01998
01999
02000 void MultilineSequenceElement::registerTab( BasicElement* tab )
02001 {
02002 tabs.append( tab );
02003 }
02004
02005
02006 KCommand* MultilineSequenceElement::buildCommand( Container* container, Request* request )
02007 {
02008 FormulaCursor* cursor = container->activeCursor();
02009 if ( cursor->isReadOnly() ) {
02010 return 0;
02011 }
02012
02013 switch ( *request ) {
02014 case req_remove: {
02015
02016
02017 break;
02018 }
02019 case req_addNewline: {
02020 FormulaCursor* cursor = container->activeCursor();
02021 return new KFCNewLine( i18n( "Add Newline" ), container, this, cursor->getPos() );
02022 }
02023 case req_addTabMark: {
02024 KFCReplace* command = new KFCReplace( i18n("Add Tabmark"), container );
02025 SpaceElement* element = new SpaceElement( THIN, true );
02026 command->addElement( element );
02027 return command;
02028 }
02029 default:
02030 break;
02031 }
02032 return inherited::buildCommand( container, request );
02033 }
02034
02035
02036 KCommand* MultilineSequenceElement::input( Container* container, QKeyEvent* event )
02037 {
02038 int action = event->key();
02039
02040
02041
02042 switch ( action ) {
02043 case Qt::Key_Enter:
02044 case Qt::Key_Return: {
02045 Request newline( req_addNewline );
02046 return buildCommand( container, &newline );
02047 }
02048 case Qt::Key_Tab: {
02049 Request r( req_addTabMark );
02050 return buildCommand( container, &r );
02051 }
02052 }
02053 return inherited::input( container, event );
02054 }
02055
02056
02057 KCommand* MultilineSequenceElement::input( Container* container, QChar ch )
02058 {
02059 int latin1 = ch.latin1();
02060 switch (latin1) {
02061 case '&': {
02062 Request r( req_addTabMark );
02063 return buildCommand( container, &r );
02064 }
02065 }
02066 return inherited::input( container, ch );
02067 }
02068
02069
02070 void MultilineSequenceElement::moveTabTo( uint i, luPixel pos )
02071 {
02072 BasicElement* marker = tab( i );
02073 luPixel diff = pos - marker->getX();
02074 marker->setWidth( marker->getWidth() + diff );
02075
02076 for ( int p = childPos( marker )+1; p < countChildren(); ++p ) {
02077 BasicElement* child = getChild( p );
02078 child->setX( child->getX() + diff );
02079 }
02080
02081 setWidth( getWidth()+diff );
02082 }
02083
02084
02085 int MultilineSequenceElement::tabBefore( uint pos )
02086 {
02087 if ( tabs.isEmpty() ) {
02088 return -1;
02089 }
02090 uint tabNum = 0;
02091 for ( uint i=0; i<pos; ++i ) {
02092 BasicElement* child = getChild( i );
02093 if ( tabs.at( tabNum ) == child ) {
02094 if ( tabNum+1 == tabs.count() ) {
02095 return tabNum;
02096 }
02097 ++tabNum;
02098 }
02099 }
02100 return static_cast<int>( tabNum )-1;
02101 }
02102
02103
02104 int MultilineSequenceElement::tabPos( uint i )
02105 {
02106 if ( i < tabs.count() ) {
02107 return childPos( tabs.at( i ) );
02108 }
02109 return -1;
02110 }
02111
02112
02113 void MultilineSequenceElement::writeMathML( QDomDocument& doc,
02114 QDomNode& parent, bool oasisFormat ) const
02115 {
02116
02117
02118 QDomElement tmp = doc.createElement( "TMP" );
02119
02120 inherited::writeMathML( doc, tmp, oasisFormat );
02121
02122
02123
02124
02125
02126
02127 QDomElement mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
02128
02129
02130 QDomNode n = tmp.firstChild().firstChild();
02131 while ( !n.isNull() ) {
02132
02133 if ( n.isElement() && n.toElement().tagName() == "TAB" ) {
02134 parent.appendChild( mtd );
02135 mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
02136 }
02137 else {
02138 mtd.appendChild( n.cloneNode() );
02139 }
02140 n = n.nextSibling();
02141 }
02142
02143 parent.appendChild( mtd );
02144 }
02145
02146
02147 MultilineElement::MultilineElement( BasicElement* parent )
02148 : BasicElement( parent )
02149 {
02150 content.setAutoDelete( true );
02151 content.append( new MultilineSequenceElement( this ) );
02152 }
02153
02154 MultilineElement::~MultilineElement()
02155 {
02156 }
02157
02158 MultilineElement::MultilineElement( const MultilineElement& other )
02159 : BasicElement( other )
02160 {
02161 content.setAutoDelete( true );
02162 uint count = other.content.count();
02163 for (uint i = 0; i < count; i++) {
02164 MultilineSequenceElement* line = content.at(i)->clone();
02165 line->setParent( this );
02166 content.append( line );
02167 }
02168 }
02169
02170
02171 bool MultilineElement::accept( ElementVisitor* visitor )
02172 {
02173 return visitor->visit( this );
02174 }
02175
02176
02177 void MultilineElement::entered( SequenceElement* )
02178 {
02179 formula()->tell( i18n( "Multi line element" ) );
02180 }
02181
02182
02186 BasicElement* MultilineElement::goToPos( FormulaCursor* cursor, bool& handled,
02187 const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
02188 {
02189 BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
02190 if ( e != 0 ) {
02191 LuPixelPoint myPos(parentOrigin.x() + getX(),
02192 parentOrigin.y() + getY());
02193
02194 uint count = content.count();
02195 for ( uint i = 0; i < count; ++i ) {
02196 MultilineSequenceElement* line = content.at(i);
02197 e = line->goToPos(cursor, handled, point, myPos);
02198 if (e != 0) {
02199 return e;
02200 }
02201 }
02202 return this;
02203 }
02204 return 0;
02205 }
02206
02207 void MultilineElement::goInside( FormulaCursor* cursor )
02208 {
02209 content.at( 0 )->goInside( cursor );
02210 }
02211
02212 void MultilineElement::moveLeft( FormulaCursor* cursor, BasicElement* from )
02213 {
02214
02215
02216 if (cursor->isSelectionMode()) {
02217 getParent()->moveLeft(cursor, this);
02218 }
02219 else {
02220
02221
02222 if (from == getParent()) {
02223 content.at( content.count()-1 )->moveLeft(cursor, this);
02224 }
02225 else {
02226
02227
02228 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02229 if ( pos > -1 ) {
02230 if ( pos > 0 ) {
02231 content.at( pos-1 )->moveLeft( cursor, this );
02232 }
02233 else {
02234 getParent()->moveLeft(cursor, this);
02235 }
02236 }
02237 else {
02238 kdDebug( DEBUGID ) << k_funcinfo << endl;
02239 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02240 }
02241 }
02242 }
02243 }
02244
02245 void MultilineElement::moveRight( FormulaCursor* cursor, BasicElement* from )
02246 {
02247 if (cursor->isSelectionMode()) {
02248 getParent()->moveRight(cursor, this);
02249 }
02250 else {
02251 if (from == getParent()) {
02252 content.at( 0 )->moveRight(cursor, this);
02253 }
02254 else {
02255 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02256 if ( pos > -1 ) {
02257 uint upos = pos;
02258 if ( upos < content.count() ) {
02259 if ( upos < content.count()-1 ) {
02260 content.at( upos+1 )->moveRight( cursor, this );
02261 }
02262 else {
02263 getParent()->moveRight(cursor, this);
02264 }
02265 return;
02266 }
02267 }
02268 kdDebug( DEBUGID ) << k_funcinfo << endl;
02269 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02270 }
02271 }
02272 }
02273
02274 void MultilineElement::moveUp( FormulaCursor* cursor, BasicElement* from )
02275 {
02276
02277
02278 if (cursor->isSelectionMode()) {
02279 getParent()->moveLeft(cursor, this);
02280 }
02281 else {
02282
02283
02284 if (from == getParent()) {
02285 content.at( content.count()-1 )->moveLeft(cursor, this);
02286 }
02287 else {
02288
02289
02290 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02291 if ( pos > -1 ) {
02292 if ( pos > 0 ) {
02293
02294
02295
02296 int cursorPos = cursor->getPos();
02297 MultilineSequenceElement* current = content.at( pos );
02298 MultilineSequenceElement* newLine = content.at( pos-1 );
02299 int tabNum = current->tabBefore( cursorPos );
02300 if ( tabNum > -1 ) {
02301 int oldTabPos = current->tabPos( tabNum );
02302 int newTabPos = newLine->tabPos( tabNum );
02303 if ( newTabPos > -1 ) {
02304 cursorPos += newTabPos-oldTabPos;
02305 int nextNewTabPos = newLine->tabPos( tabNum+1 );
02306 if ( nextNewTabPos > -1 ) {
02307 cursorPos = QMIN( cursorPos, nextNewTabPos );
02308 }
02309 }
02310 else {
02311 cursorPos = newLine->countChildren();
02312 }
02313 }
02314 else {
02315 int nextNewTabPos = newLine->tabPos( 0 );
02316 if ( nextNewTabPos > -1 ) {
02317 cursorPos = QMIN( cursorPos, nextNewTabPos );
02318 }
02319 }
02320 cursor->setTo( newLine,
02321 QMIN( cursorPos,
02322 newLine->countChildren() ) );
02323 }
02324 else {
02325 getParent()->moveLeft(cursor, this);
02326 }
02327 }
02328 else {
02329 kdDebug( DEBUGID ) << k_funcinfo << endl;
02330 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02331 }
02332 }
02333 }
02334 }
02335
02336 void MultilineElement::moveDown( FormulaCursor* cursor, BasicElement* from )
02337 {
02338 if (cursor->isSelectionMode()) {
02339 getParent()->moveRight(cursor, this);
02340 }
02341 else {
02342 if (from == getParent()) {
02343 content.at( 0 )->moveRight(cursor, this);
02344 }
02345 else {
02346 int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
02347 if ( pos > -1 ) {
02348 uint upos = pos;
02349 if ( upos < content.count() ) {
02350 if ( upos < content.count()-1 ) {
02351
02352
02353
02354 int cursorPos = cursor->getPos();
02355 MultilineSequenceElement* current = content.at( upos );
02356 MultilineSequenceElement* newLine = content.at( upos+1 );
02357 int tabNum = current->tabBefore( cursorPos );
02358 if ( tabNum > -1 ) {
02359 int oldTabPos = current->tabPos( tabNum );
02360 int newTabPos = newLine->tabPos( tabNum );
02361 if ( newTabPos > -1 ) {
02362 cursorPos += newTabPos-oldTabPos;
02363 int nextNewTabPos = newLine->tabPos( tabNum+1 );
02364 if ( nextNewTabPos > -1 ) {
02365 cursorPos = QMIN( cursorPos, nextNewTabPos );
02366 }
02367 }
02368 else {
02369 cursorPos = newLine->countChildren();
02370 }
02371 }
02372 else {
02373 int nextNewTabPos = newLine->tabPos( 0 );
02374 if ( nextNewTabPos > -1 ) {
02375 cursorPos = QMIN( cursorPos, nextNewTabPos );
02376 }
02377 }
02378 cursor->setTo( newLine,
02379 QMIN( cursorPos,
02380 newLine->countChildren() ) );
02381 }
02382 else {
02383 getParent()->moveRight(cursor, this);
02384 }
02385 return;
02386 }
02387 }
02388 kdDebug( DEBUGID ) << k_funcinfo << endl;
02389 kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
02390 }
02391 }
02392 }
02393
02394
02395 void MultilineElement::calcSizes( const ContextStyle& context,
02396 ContextStyle::TextStyle tstyle,
02397 ContextStyle::IndexStyle istyle,
02398 StyleAttributes& style )
02399 {
02400 double factor = style.sizeFactor();
02401 luPt mySize = context.getAdjustedSize( tstyle, factor );
02402 QFont font = context.getDefaultFont();
02403 font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
02404 QFontMetrics fm( font );
02405 luPixel leading = context.ptToLayoutUnitPt( fm.leading() );
02406 luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
02407
02408 uint count = content.count();
02409 luPixel height = -leading;
02410 luPixel width = 0;
02411 uint tabCount = 0;
02412 for ( uint i = 0; i < count; ++i ) {
02413 MultilineSequenceElement* line = content.at(i);
02414 line->calcSizes( context, tstyle, istyle, style );
02415 tabCount = QMAX( tabCount, line->tabCount() );
02416
02417 height += leading;
02418 line->setX( 0 );
02419 line->setY( height );
02420 height += line->getHeight() + distY;
02421 width = QMAX( line->getWidth(), width );
02422 }
02423
02424
02425 for ( uint t = 0; t < tabCount; ++t ) {
02426 luPixel pos = 0;
02427 for ( uint i = 0; i < count; ++i ) {
02428 MultilineSequenceElement* line = content.at(i);
02429 if ( t < line->tabCount() ) {
02430 pos = QMAX( pos, line->tab( t )->getX() );
02431 }
02432 else {
02433 pos = QMAX( pos, line->getWidth() );
02434 }
02435 }
02436 for ( uint i = 0; i < count; ++i ) {
02437 MultilineSequenceElement* line = content.at(i);
02438 if ( t < line->tabCount() ) {
02439 line->moveTabTo( t, pos );
02440 width = QMAX( width, line->getWidth() );
02441 }
02442 }
02443 }
02444
02445 setHeight( height );
02446 setWidth( width );
02447 if ( count == 1 ) {
02448 setBaseline( content.at( 0 )->getBaseline() );
02449 }
02450 else {
02451
02452 setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
02453 }
02454 }
02455
02456 void MultilineElement::draw( QPainter& painter, const LuPixelRect& r,
02457 const ContextStyle& context,
02458 ContextStyle::TextStyle tstyle,
02459 ContextStyle::IndexStyle istyle,
02460 StyleAttributes& style,
02461 const LuPixelPoint& parentOrigin )
02462 {
02463 LuPixelPoint myPos( parentOrigin.x() + getX(), parentOrigin.y() + getY() );
02464 uint count = content.count();
02465
02466 if ( context.edit() ) {
02467 uint tabCount = 0;
02468 painter.setPen( context.getHelpColor() );
02469 for ( uint i = 0; i < count; ++i ) {
02470 MultilineSequenceElement* line = content.at(i);
02471 if ( tabCount < line->tabCount() ) {
02472 for ( uint t = tabCount; t < line->tabCount(); ++t ) {
02473 BasicElement* marker = line->tab( t );
02474 painter.drawLine( context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
02475 context.layoutUnitToPixelY( myPos.y() ),
02476 context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
02477 context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
02478 }
02479 tabCount = line->tabCount();
02480 }
02481 }
02482 }
02483
02484 for ( uint i = 0; i < count; ++i ) {
02485 MultilineSequenceElement* line = content.at(i);
02486 line->draw( painter, r, context, tstyle, istyle, style, myPos );
02487 }
02488 }
02489
02490
02491 void MultilineElement::dispatchFontCommand( FontCommand* cmd )
02492 {
02493 uint count = content.count();
02494 for ( uint i = 0; i < count; ++i ) {
02495 MultilineSequenceElement* line = content.at(i);
02496 line->dispatchFontCommand( cmd );
02497 }
02498 }
02499
02500 void MultilineElement::insert( FormulaCursor* cursor,
02501 QPtrList<BasicElement>& newChildren,
02502 Direction direction )
02503 {
02504 MultilineSequenceElement* e = static_cast<MultilineSequenceElement*>(newChildren.take(0));
02505 e->setParent(this);
02506 content.insert( cursor->getPos(), e );
02507
02508 if (direction == beforeCursor) {
02509 e->moveLeft(cursor, this);
02510 }
02511 else {
02512 e->moveRight(cursor, this);
02513 }
02514 cursor->setSelection(false);
02515 formula()->changed();
02516 }
02517
02518 void MultilineElement::remove( FormulaCursor* cursor,
02519 QPtrList<BasicElement>& removedChildren,
02520 Direction direction )
02521 {
02522 if ( content.count() == 1 ) {
02523 getParent()->selectChild(cursor, this);
02524 getParent()->remove(cursor, removedChildren, direction);
02525 }
02526 else {
02527 MultilineSequenceElement* e = content.take( cursor->getPos() );
02528 removedChildren.append( e );
02529 formula()->elementRemoval( e );
02530
02531 formula()->changed();
02532 }
02533 }
02534
02535 void MultilineElement::normalize( FormulaCursor* cursor, Direction direction )
02536 {
02537 int pos = cursor->getPos();
02538 if ( ( cursor->getElement() == this ) &&
02539 ( pos > -1 ) && ( static_cast<unsigned>( pos ) <= content.count() ) ) {
02540 switch ( direction ) {
02541 case beforeCursor:
02542 if ( pos > 0 ) {
02543 content.at( pos-1 )->moveLeft( cursor, this );
02544 break;
02545 }
02546
02547 case afterCursor:
02548 if ( static_cast<unsigned>( pos ) < content.count() ) {
02549 content.at( pos )->moveRight( cursor, this );
02550 }
02551 else {
02552 content.at( pos-1 )->moveLeft( cursor, this );
02553 }
02554 break;
02555 }
02556 }
02557 else {
02558 inherited::normalize( cursor, direction );
02559 }
02560 }
02561
02562 SequenceElement* MultilineElement::getMainChild()
02563 {
02564 return content.at( 0 );
02565 }
02566
02567 void MultilineElement::selectChild(FormulaCursor* cursor, BasicElement* child)
02568 {
02569 int pos = content.find( dynamic_cast<MultilineSequenceElement*>( child ) );
02570 if ( pos > -1 ) {
02571 cursor->setTo( this, pos );
02572
02573 }
02574 }
02575
02576
02580 void MultilineElement::writeDom(QDomElement element)
02581 {
02582 BasicElement::writeDom(element);
02583
02584 uint lineCount = content.count();
02585 element.setAttribute( "LINES", lineCount );
02586
02587 QDomDocument doc = element.ownerDocument();
02588 for ( uint i = 0; i < lineCount; ++i ) {
02589 QDomElement tmp = content.at( i )->getElementDom(doc);
02590 element.appendChild(tmp);
02591 }
02592 }
02593
02594 void MultilineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
02595 {
02596 QDomElement de = doc.createElement( oasisFormat ? "math:mtable" : "mtable" );
02597 QDomElement row; QDomElement cell;
02598
02599 for ( QPtrListIterator < MultilineSequenceElement > it( content ); it.current(); ++it ) {
02600 row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
02601 de.appendChild( row );
02602
02603
02604
02605
02606 it.current()->writeMathML( doc, row, oasisFormat );
02607 }
02608
02609 parent.appendChild( de );
02610 }
02611
02616 bool MultilineElement::readAttributesFromDom(QDomElement element)
02617 {
02618 if (!BasicElement::readAttributesFromDom(element)) {
02619 return false;
02620 }
02621 uint lineCount = 0;
02622 QString lineCountStr = element.attribute("LINES");
02623 if(!lineCountStr.isNull()) {
02624 lineCount = lineCountStr.toInt();
02625 }
02626 if (lineCount == 0) {
02627 kdWarning( DEBUGID ) << "lineCount <= 0 in MultilineElement." << endl;
02628 return false;
02629 }
02630
02631 content.clear();
02632 for ( uint i = 0; i < lineCount; ++i ) {
02633 MultilineSequenceElement* element = new MultilineSequenceElement(this);
02634 content.append(element);
02635 }
02636 return true;
02637 }
02638
02644 bool MultilineElement::readContentFromDom(QDomNode& node)
02645 {
02646 if (!BasicElement::readContentFromDom(node)) {
02647 return false;
02648 }
02649
02650 uint lineCount = content.count();
02651 uint i = 0;
02652 while ( !node.isNull() && i < lineCount ) {
02653 if ( node.isElement() ) {
02654 SequenceElement* element = content.at( i );
02655 QDomElement e = node.toElement();
02656 if ( !element->buildFromDom( e ) ) {
02657 return false;
02658 }
02659 ++i;
02660 }
02661 node = node.nextSibling();
02662 }
02663 return true;
02664 }
02665
02666 QString MultilineElement::toLatex()
02667 {
02668 uint lineCount = content.count();
02669 QString muliline = "\\begin{split} ";
02670 for ( uint i = 0; i < lineCount; ++i ) {
02671 muliline += content.at( i )->toLatex();
02672 muliline += " \\\\ ";
02673 }
02674 muliline += "\\end{split}";
02675 return muliline;
02676 }
02677
02678
02679 QString MultilineElement::formulaString()
02680 {
02681 uint lineCount = content.count();
02682 QString muliline = "";
02683 for ( uint i = 0; i < lineCount; ++i ) {
02684 muliline += content.at( i )->formulaString();
02685 muliline += "\n";
02686 }
02687
02688 return muliline;
02689 }
02690
02691
02692 KFORMULA_NAMESPACE_END