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.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 24 18:22:28 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003