lib Library API Documentation

matrixelement.cc

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