You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
koffice/lib/kformula/matrixelement.cpp

2693 lines
84 KiB

/* This file is part of the KDE project
Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <tqmemarray.h>
#include <tqpainter.h>
#include <tqptrlist.h>
#include <kdebug.h>
#include <tdelocale.h>
#include "MatrixDialog.h"
#include "elementvisitor.h"
#include "formulaelement.h"
#include "formulacursor.h"
#include "kformulacontainer.h"
#include "kformulacommand.h"
#include "matrixelement.h"
#include "sequenceelement.h"
#include "spaceelement.h"
KFORMULA_NAMESPACE_BEGIN
class MatrixSequenceElement : public SequenceElement {
typedef SequenceElement inherited;
public:
MatrixSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
virtual MatrixSequenceElement* clone() {
return new MatrixSequenceElement( *this );
}
/**
* This is called by the container to get a command depending on
* the current cursor position (this is how the element gets chosen)
* and the request.
*
* @returns the command that performs the requested action with
* the containers active cursor.
*/
virtual KCommand* buildCommand( Container*, Request* );
};
class KFCRemoveRow : public Command {
public:
KFCRemoveRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
~KFCRemoveRow();
virtual void execute();
virtual void unexecute();
protected:
MatrixElement* matrix;
uint rowPos;
uint colPos;
TQPtrList<MatrixSequenceElement>* row;
};
class KFCInsertRow : public KFCRemoveRow {
public:
KFCInsertRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
virtual void execute() { KFCRemoveRow::unexecute(); }
virtual void unexecute() { KFCRemoveRow::execute(); }
};
class KFCRemoveColumn : public Command {
public:
KFCRemoveColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
~KFCRemoveColumn();
virtual void execute();
virtual void unexecute();
protected:
MatrixElement* matrix;
uint rowPos;
uint colPos;
TQPtrList<MatrixSequenceElement>* column;
};
class KFCInsertColumn : public KFCRemoveColumn {
public:
KFCInsertColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c );
virtual void execute() { KFCRemoveColumn::unexecute(); }
virtual void unexecute() { KFCRemoveColumn::execute(); }
};
KCommand* MatrixSequenceElement::buildCommand( Container* container, Request* request )
{
FormulaCursor* cursor = container->activeCursor();
if ( cursor->isReadOnly() ) {
return 0;
}
switch ( *request ) {
case req_appendColumn:
case req_appendRow:
case req_insertColumn:
case req_removeColumn:
case req_insertRow:
case req_removeRow: {
MatrixElement* matrix = static_cast<MatrixElement*>( getParent() );
FormulaCursor* cursor = container->activeCursor();
for ( uint row = 0; row < matrix->getRows(); row++ ) {
for ( uint col = 0; col < matrix->getColumns(); col++ ) {
if ( matrix->getElement( row, col ) == cursor->getElement() ) {
switch ( *request ) {
case req_appendColumn:
return new KFCInsertColumn( i18n( "Append Column" ), container, matrix, row, matrix->getColumns() );
case req_appendRow:
return new KFCInsertRow( i18n( "Append Row" ), container, matrix, matrix->getRows(), col );
case req_insertColumn:
return new KFCInsertColumn( i18n( "Insert Column" ), container, matrix, row, col );
case req_removeColumn:
if ( matrix->getColumns() > 1 ) {
return new KFCRemoveColumn( i18n( "Remove Column" ), container, matrix, row, col );
}
break;
case req_insertRow:
return new KFCInsertRow( i18n( "Insert Row" ), container, matrix, row, col );
case req_removeRow:
if ( matrix->getRows() > 1 ) {
return new KFCRemoveRow( i18n( "Remove Row" ), container, matrix, row, col );
}
break;
default:
break;
}
}
}
}
kdWarning( DEBUGID ) << "MatrixSequenceElement::buildCommand: Sequence not found." << endl;
break;
}
default:
break;
}
return inherited::buildCommand( container, request );
}
KFCRemoveRow::KFCRemoveRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
: Command( name, document ), matrix( m ), rowPos( r ), colPos( c ), row( 0 )
{
}
KFCRemoveRow::~KFCRemoveRow()
{
delete row;
}
void KFCRemoveRow::execute()
{
FormulaCursor* cursor = getExecuteCursor();
row = matrix->content.at( rowPos );
FormulaElement* formula = matrix->formula();
for ( uint i = matrix->getColumns(); i > 0; i-- ) {
formula->elementRemoval( row->at( i-1 ) );
}
matrix->content.take( rowPos );
formula->changed();
if ( rowPos < matrix->getRows() ) {
matrix->getElement( rowPos, colPos )->goInside( cursor );
}
else {
matrix->getElement( rowPos-1, colPos )->goInside( cursor );
}
testDirty();
}
void KFCRemoveRow::unexecute()
{
matrix->content.insert( rowPos, row );
row = 0;
FormulaCursor* cursor = getExecuteCursor();
matrix->getElement( rowPos, colPos )->goInside( cursor );
matrix->formula()->changed();
testDirty();
}
KFCInsertRow::KFCInsertRow( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
: KFCRemoveRow( name, document, m, r, c )
{
row = new TQPtrList< MatrixSequenceElement >;
row->setAutoDelete( true );
for ( uint i = 0; i < matrix->getColumns(); i++ ) {
row->append( new MatrixSequenceElement( matrix ) );
}
}
KFCRemoveColumn::KFCRemoveColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
: Command( name, document ), matrix( m ), rowPos( r ), colPos( c )
{
column = new TQPtrList< MatrixSequenceElement >;
column->setAutoDelete( true );
}
KFCRemoveColumn::~KFCRemoveColumn()
{
delete column;
}
void KFCRemoveColumn::execute()
{
FormulaCursor* cursor = getExecuteCursor();
FormulaElement* formula = matrix->formula();
for ( uint i = 0; i < matrix->getRows(); i++ ) {
column->append( matrix->getElement( i, colPos ) );
formula->elementRemoval( column->at( i ) );
matrix->content.at( i )->take( colPos );
}
formula->changed();
if ( colPos < matrix->getColumns() ) {
matrix->getElement( rowPos, colPos )->goInside( cursor );
}
else {
matrix->getElement( rowPos, colPos-1 )->goInside( cursor );
}
testDirty();
}
void KFCRemoveColumn::unexecute()
{
for ( uint i = 0; i < matrix->getRows(); i++ ) {
matrix->content.at( i )->insert( colPos, column->take( 0 ) );
}
FormulaCursor* cursor = getExecuteCursor();
matrix->getElement( rowPos, colPos )->goInside( cursor );
matrix->formula()->changed();
testDirty();
}
KFCInsertColumn::KFCInsertColumn( const TQString& name, Container* document, MatrixElement* m, uint r, uint c )
: KFCRemoveColumn( name, document, m, r, c )
{
for ( uint i = 0; i < matrix->getRows(); i++ ) {
column->append( new MatrixSequenceElement( matrix ) );
}
}
MatrixElement::MatrixElement(uint rows, uint columns, BasicElement* parent)
: BasicElement(parent),
m_rowNumber( 0 ),
m_align( NoAlign ),
m_widthType( NoSize ),
m_frame( NoLine ),
m_frameHSpacing( NoSize ),
m_frameVSpacing( NoSize ),
m_side( NoSide ),
m_minLabelSpacingType( NoSize ),
m_customEqualRows( false ),
m_customEqualColumns( false ),
m_customDisplayStyle( false )
{
for (uint r = 0; r < rows; r++) {
TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
list->setAutoDelete(true);
for (uint c = 0; c < columns; c++) {
list->append(new MatrixSequenceElement(this));
}
content.append(list);
}
content.setAutoDelete(true);
}
MatrixElement::~MatrixElement()
{
}
MatrixElement::MatrixElement( const MatrixElement& other )
: BasicElement( other )
{
uint rows = other.getRows();
uint columns = other.getColumns();
TQPtrListIterator< TQPtrList< MatrixSequenceElement > > rowIter( other.content );
for (uint r = 0; r < rows; r++) {
++rowIter;
TQPtrListIterator< MatrixSequenceElement > colIter( *rowIter.current() );
TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
list->setAutoDelete(true);
for (uint c = 0; c < columns; c++) {
++colIter;
MatrixSequenceElement *mse =
//new MatrixSequenceElement( *( other.getElement( r, c ) ) );
new MatrixSequenceElement( *colIter.current() );
list->append( mse );
mse->setParent( this );
}
content.append(list);
}
content.setAutoDelete(true);
}
bool MatrixElement::accept( ElementVisitor* visitor )
{
return visitor->visit( this );
}
void MatrixElement::entered( SequenceElement* /*child*/ )
{
formula()->tell( i18n( "Matrix element" ) );
}
BasicElement* MatrixElement::goToPos( FormulaCursor* cursor, bool& handled,
const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
{
BasicElement* e = BasicElement::goToPos(cursor, handled, point, parentOrigin);
if (e != 0) {
LuPixelPoint myPos(parentOrigin.x() + getX(),
parentOrigin.y() + getY());
uint rows = getRows();
uint columns = getColumns();
for (uint r = 0; r < rows; r++) {
for (uint c = 0; c < columns; c++) {
BasicElement* element = getElement(r, c);
e = element->goToPos(cursor, handled, point, myPos);
if (e != 0) {
return e;
}
}
}
// We are in one of those gaps.
luPixel dx = point.x() - myPos.x();
luPixel dy = point.y() - myPos.y();
uint row = rows;
for (uint r = 0; r < rows; r++) {
BasicElement* element = getElement(r, 0);
if (element->getY() > dy) {
row = r;
break;
}
}
if (row == 0) {
BasicElement* element = getParent();
element->moveLeft(cursor, this);
handled = true;
return element;
}
row--;
uint column = columns;
for (uint c = 0; c < columns; c++) {
BasicElement* element = getElement(row, c);
if (element->getX() > dx) {
column = c;
break;
}
}
if (column == 0) {
BasicElement* element = getParent();
element->moveLeft(cursor, this);
handled = true;
return element;
}
column--;
// Rescan the rows with the actual colums required.
row = rows;
for (uint r = 0; r < rows; r++) {
BasicElement* element = getElement(r, column);
if (element->getY() > dy) {
row = r;
break;
}
}
if (row == 0) {
BasicElement* element = getParent();
element->moveLeft(cursor, this);
handled = true;
return element;
}
row--;
BasicElement* element = getElement(row, column);
element->moveLeft(cursor, this);
handled = true;
return element;
}
return 0;
}
// drawing
//
// Drawing depends on a context which knows the required properties like
// fonts, spaces and such.
// It is essential to calculate elements size with the same context
// before you draw.
/**
* Calculates our width and height and
* our children's parentPosition.
*/
void MatrixElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style )
{
TQMemArray<luPixel> toMidlines(getRows());
TQMemArray<luPixel> fromMidlines(getRows());
TQMemArray<luPixel> widths(getColumns());
toMidlines.fill(0);
fromMidlines.fill(0);
widths.fill(0);
uint rows = getRows();
uint columns = getColumns();
ContextStyle::TextStyle i_tstyle = context.convertTextStyleFraction(tstyle);
ContextStyle::IndexStyle i_istyle = context.convertIndexStyleUpper(istyle);
double factor = style.sizeFactor();
for (uint r = 0; r < rows; r++) {
TQPtrList< MatrixSequenceElement >* list = content.at(r);
for (uint c = 0; c < columns; c++) {
SequenceElement* element = list->at(c);
element->calcSizes( context, i_tstyle, i_istyle, style );
toMidlines[r] = TQMAX(toMidlines[r], element->axis( context, i_tstyle, factor ));
fromMidlines[r] = TQMAX(fromMidlines[r],
element->getHeight()-element->axis( context, i_tstyle, factor ));
widths[c] = TQMAX(widths[c], element->getWidth());
}
}
luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
luPixel yPos = 0;
for (uint r = 0; r < rows; r++) {
TQPtrList< MatrixSequenceElement >* list = content.at(r);
luPixel xPos = 0;
yPos += toMidlines[r];
for (uint c = 0; c < columns; c++) {
SequenceElement* element = list->at(c);
switch (context.getMatrixAlignment()) {
case ContextStyle::left:
element->setX(xPos);
break;
case ContextStyle::center:
element->setX(xPos + (widths[c] - element->getWidth())/2);
break;
case ContextStyle::right:
element->setX(xPos + widths[c] - element->getWidth());
break;
}
element->setY(yPos - element->axis( context, i_tstyle, factor ));
xPos += widths[c] + distX;
}
yPos += fromMidlines[r] + distY;
}
luPixel width = distX * (columns - 1);
luPixel height = distY * (rows - 1);
for (uint r = 0; r < rows; r++) height += toMidlines[r] + fromMidlines[r];
for (uint c = 0; c < columns; c++) width += widths[c];
setWidth(width);
setHeight(height);
if ((rows == 2) && (columns == 1)) {
setBaseline( getMainChild()->getHeight() + distY / 2 + context.axisHeight( tstyle, factor ) );
}
else {
setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
}
}
/**
* Draws the whole element including its children.
* The `parentOrigin' is the point this element's parent starts.
* We can use our parentPosition to get our own origin then.
*/
void MatrixElement::draw( TQPainter& painter, const LuPixelRect& rect,
const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style,
const LuPixelPoint& parentOrigin )
{
LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
//if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( rect ) )
// return;
uint rows = getRows();
uint columns = getColumns();
for (uint r = 0; r < rows; r++) {
for (uint c = 0; c < columns; c++) {
getElement(r, c)->draw(painter, rect, context,
context.convertTextStyleFraction(tstyle),
context.convertIndexStyleUpper(istyle),
style,
myPos);
}
}
// Debug
//painter.setPen(TQt::red);
//painter.drawRect(myPos.x(), myPos.y(), getWidth(), getHeight());
}
void MatrixElement::dispatchFontCommand( FontCommand* cmd )
{
uint rows = getRows();
uint columns = getColumns();
for (uint r = 0; r < rows; r++) {
for (uint c = 0; c < columns; c++) {
getElement(r, c)->dispatchFontCommand( cmd );
}
}
}
// navigation
//
// The elements are responsible to handle cursor movement themselves.
// To do this they need to know the direction the cursor moves and
// the element it comes from.
//
// The cursor might be in normal or in selection mode.
/**
* Enters this element while moving to the left starting inside
* the element `from'. Searches for a cursor position inside
* this element or to the left of it.
*/
void MatrixElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
{
if (cursor->isSelectionMode()) {
getParent()->moveLeft(cursor, this);
}
else {
if (from == getParent()) {
getElement(getRows()-1, getColumns()-1)->moveLeft(cursor, this);
}
else {
bool linear = cursor->getLinearMovement();
uint row = 0;
uint column = 0;
if (searchElement(from, row, column)) {
if (column > 0) {
getElement(row, column-1)->moveLeft(cursor, this);
}
else if (linear && (row > 0)) {
getElement(row-1, getColumns()-1)->moveLeft(cursor, this);
}
else {
getParent()->moveLeft(cursor, this);
}
}
else {
getParent()->moveLeft(cursor, this);
}
}
}
}
/**
* Enters this element while moving to the right starting inside
* the element `from'. Searches for a cursor position inside
* this element or to the right of it.
*/
void MatrixElement::moveRight(FormulaCursor* cursor, BasicElement* from)
{
if (cursor->isSelectionMode()) {
getParent()->moveRight(cursor, this);
}
else {
if (from == getParent()) {
getElement(0, 0)->moveRight(cursor, this);
}
else {
bool linear = cursor->getLinearMovement();
uint row = 0;
uint column = 0;
if (searchElement(from, row, column)) {
if (column < getColumns()-1) {
getElement(row, column+1)->moveRight(cursor, this);
}
else if (linear && (row < getRows()-1)) {
getElement(row+1, 0)->moveRight(cursor, this);
}
else {
getParent()->moveRight(cursor, this);
}
}
else {
getParent()->moveRight(cursor, this);
}
}
}
}
/**
* Enters this element while moving up starting inside
* the element `from'. Searches for a cursor position inside
* this element or above it.
*/
void MatrixElement::moveUp(FormulaCursor* cursor, BasicElement* from)
{
if (cursor->isSelectionMode()) {
getParent()->moveUp(cursor, this);
}
else {
if (from == getParent()) {
getElement(0, 0)->moveRight(cursor, this);
}
else {
uint row = 0;
uint column = 0;
if (searchElement(from, row, column)) {
if (row > 0) {
getElement(row-1, column)->moveRight(cursor, this);
}
else {
getParent()->moveUp(cursor, this);
}
}
else {
getParent()->moveUp(cursor, this);
}
}
}
}
/**
* Enters this element while moving down starting inside
* the element `from'. Searches for a cursor position inside
* this element or below it.
*/
void MatrixElement::moveDown(FormulaCursor* cursor, BasicElement* from)
{
if (cursor->isSelectionMode()) {
getParent()->moveDown(cursor, this);
}
else {
if (from == getParent()) {
getElement(0, 0)->moveRight(cursor, this);
}
else {
uint row = 0;
uint column = 0;
if (searchElement(from, row, column)) {
if (row < getRows()-1) {
getElement(row+1, column)->moveRight(cursor, this);
}
else {
getParent()->moveDown(cursor, this);
}
}
else {
getParent()->moveDown(cursor, this);
}
}
}
}
/**
* Sets the cursor inside this element to its start position.
* For most elements that is the main child.
*/
void MatrixElement::goInside(FormulaCursor* cursor)
{
getElement(0, 0)->goInside(cursor);
}
// If there is a main child we must provide the insert/remove semantics.
SequenceElement* MatrixElement::getMainChild()
{
return content.at(0)->at(0);
}
void MatrixElement::selectChild(FormulaCursor* cursor, BasicElement* child)
{
uint rows = getRows();
uint columns = getColumns();
for (uint r = 0; r < rows; r++) {
for (uint c = 0; c < columns; c++) {
if (child == getElement(r, c)) {
cursor->setTo(this, r*columns+c);
}
}
}
}
const MatrixSequenceElement* MatrixElement::getElement( uint row, uint column ) const
{
TQPtrListIterator< TQPtrList < MatrixSequenceElement > > rows( content );
rows += row;
if ( ! rows.current() )
return 0;
TQPtrListIterator< MatrixSequenceElement > cols ( *rows.current() );
cols += column;
return cols.current();
}
bool MatrixElement::searchElement(BasicElement* element, uint& row, uint& column)
{
uint rows = getRows();
uint columns = getColumns();
for (uint r = 0; r < rows; r++) {
for (uint c = 0; c < columns; c++) {
if (element == getElement(r, c)) {
row = r;
column = c;
return true;
}
}
}
return false;
}
/**
* Appends our attributes to the dom element.
*/
void MatrixElement::writeDom(TQDomElement element)
{
BasicElement::writeDom(element);
uint rows = getRows();
uint cols = getColumns();
element.setAttribute("ROWS", rows);
element.setAttribute("COLUMNS", cols);
TQDomDocument doc = element.ownerDocument();
for (uint r = 0; r < rows; r++) {
for (uint c = 0; c < cols; c++) {
TQDomElement tmp = getElement(r,c)->getElementDom(doc);
element.appendChild(tmp);
}
element.appendChild(doc.createComment("end of row"));
}
}
/**
* Reads our attributes from the element.
* Returns false if it failed.
*/
bool MatrixElement::readAttributesFromDom(TQDomElement element)
{
if (!BasicElement::readAttributesFromDom(element)) {
return false;
}
uint rows = 0;
TQString rowStr = element.attribute("ROWS");
if(!rowStr.isNull()) {
rows = rowStr.toInt();
}
if (rows == 0) {
kdWarning( DEBUGID ) << "Rows <= 0 in MatrixElement." << endl;
return false;
}
TQString columnStr = element.attribute("COLUMNS");
uint cols = 0;
if(!columnStr.isNull()) {
cols = columnStr.toInt();
}
if (cols == 0) {
kdWarning( DEBUGID ) << "Columns <= 0 in MatrixElement." << endl;
return false;
}
content.clear();
for (uint r = 0; r < rows; r++) {
TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
list->setAutoDelete(true);
content.append(list);
for (uint c = 0; c < cols; c++) {
MatrixSequenceElement* element = new MatrixSequenceElement(this);
list->append(element);
}
}
return true;
}
/**
* Reads our content from the node. Sets the node to the next node
* that needs to be read.
* Returns false if it failed.
*/
bool MatrixElement::readContentFromDom(TQDomNode& node)
{
if (!BasicElement::readContentFromDom(node)) {
return false;
}
uint rows = getRows();
uint cols = getColumns();
uint r = 0;
uint c = 0;
while ( !node.isNull() && r < rows ) {
if ( node.isElement() ) {
SequenceElement* element = getElement( r, c );
TQDomElement e = node.toElement();
if ( !element->buildFromDom( e ) ) {
return false;
}
c++;
if ( c == cols ) {
c = 0;
r++;
}
}
node = node.nextSibling();
}
return true;
}
bool MatrixElement::readAttributesFromMathMLDom( const TQDomElement& element )
{
if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
return false;
}
TQString alignStr = element.attribute( "align" ).lower();
if ( ! alignStr.isNull() ) {
if ( alignStr.find( "top" ) != -1 ) {
m_align = TopAlign;
}
else if ( alignStr.find( "bottom" ) != -1 ) {
m_align = BottomAlign;
}
else if ( alignStr.find( "center" ) != -1 ) {
m_align = CenterAlign;
}
else if ( alignStr.find( "baseline" ) != -1 ) {
m_align = BaselineAlign;
}
else if ( alignStr.find( "axis" ) != -1 ) {
m_align = AxisAlign;
}
int index = alignStr.findRev( ' ' );
if ( index != -1 ) {
m_rowNumber = alignStr.right( index + 1 ).toInt();
}
}
TQString rowalignStr = element.attribute( "rowalign" ).lower();
if ( ! rowalignStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', rowalignStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
if ( *it == "top" ) {
m_rowAlign.append( TopAlign );
}
else if ( *it == "bottom" ) {
m_rowAlign.append( BottomAlign );
}
else if ( *it == "center" ) {
m_rowAlign.append( CenterAlign );
}
else if ( *it == "baseline" ) {
m_rowAlign.append( BaselineAlign );
}
else if ( *it == "axis" ) {
m_rowAlign.append( AxisAlign );
}
}
}
TQString columnalignStr = element.attribute( "columnalign" ).lower();
if ( ! columnalignStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', columnalignStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
if ( *it == "left" ) {
m_columnAlign.append( LeftHorizontalAlign );
}
else if ( *it == "center" ) {
m_columnAlign.append( CenterHorizontalAlign );
}
else if ( *it == "right" ) {
m_columnAlign.append( RightHorizontalAlign );
}
}
}
TQString alignmentscopeStr = element.attribute( "alignmentscope" ).lower();
if ( ! alignmentscopeStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', alignmentscopeStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
if ( *it == "true" ) {
m_alignmentScope.append( true );
}
else if ( *it == "false" ) {
m_alignmentScope.append( false );
}
}
}
TQString columnwidthStr = element.attribute( "columnwidth" ).lower();
if ( columnwidthStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', columnwidthStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
SizeType type = NoSize;
double length;
if ( *it == "auto" ) {
type = AutoSize;
}
else if ( *it == "fit" ) {
type = FitSize;
}
else {
length = getSize( columnwidthStr, &type );
if ( type == NoSize ) {
type = getSpace( columnwidthStr );
}
}
if ( type != NoSize ) {
m_columnWidthType.append( type );
if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
m_columnWidth.append( length );
}
}
}
}
TQString widthStr = element.attribute( "width" ).lower();
if ( ! widthStr.isNull() ) {
if ( widthStr == "auto" ) {
m_widthType = AutoSize;
}
else {
m_width = getSize( widthStr, &m_widthType );
}
}
TQString rowspacingStr = element.attribute( "rowspacing" ).lower();
if ( ! rowspacingStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', rowspacingStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
SizeType type;
double length = getSize( *it, &type );
if ( type != NoSize ) {
m_rowSpacingType.append( type );
m_rowSpacing.append( length );
}
}
}
TQString columnspacingStr = element.attribute( "columnspacing" ).lower();
if ( ! columnspacingStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', columnspacingStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
SizeType type;
double length = getSize( *it, &type );
if ( type == NoSize ) {
type = getSpace( columnspacingStr );
}
if ( type != NoSize ) {
m_columnSpacingType.append( type );
if ( type == RelativeSize || type == AbsoluteSize || type == PixelSize ) {
m_columnSpacing.append( length );
}
}
}
}
TQString rowlinesStr = element.attribute( "rowlines" ).lower();
if ( ! rowlinesStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', rowlinesStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
if ( *it == "none" ) {
m_rowLines.append( NoneLine );
}
else if ( *it == "solid" ) {
m_rowLines.append( SolidLine );
}
else if ( *it == "dashed" ) {
m_rowLines.append( DashedLine );
}
}
}
TQString columnlinesStr = element.attribute( "columnlines" ).lower();
if ( ! columnlinesStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', columnlinesStr );
for ( TQStringList::iterator it = list.begin(); it != list.end(); it++ ) {
if ( *it == "none" ) {
m_columnLines.append( NoneLine );
}
else if ( *it == "solid" ) {
m_columnLines.append( SolidLine );
}
else if ( *it == "dashed" ) {
m_columnLines.append( DashedLine );
}
}
}
TQString frameStr = element.attribute( "frame" ).stripWhiteSpace().lower();
if ( ! frameStr.isNull() ) {
if ( frameStr == "none" ) {
m_frame = NoneLine;
}
else if ( frameStr == "solid" ) {
m_frame = SolidLine;
}
else if ( frameStr == "dashed" ) {
m_frame = DashedLine;
}
}
TQString framespacingStr = element.attribute( "framespacing" );
if ( ! framespacingStr.isNull() ) {
TQStringList list = TQStringList::split( ' ', framespacingStr );
m_frameHSpacing = getSize( list[0], &m_frameHSpacingType );
if ( m_frameHSpacingType == NoSize ) {
m_frameHSpacingType = getSpace( list[0] );
}
if ( list.count() > 1 ) {
m_frameVSpacing = getSize( list[1], &m_frameVSpacingType );
if ( m_frameVSpacingType == NoSize ) {
m_frameVSpacingType = getSpace( list[1] );
}
}
}
TQString equalrowsStr = element.attribute( "equalrows" ).stripWhiteSpace().lower();
if ( ! equalrowsStr.isNull() ) {
m_customEqualRows = true;
if ( equalrowsStr == "false" ) {
m_equalRows = false;
}
else {
m_equalRows = true;
}
}
TQString equalcolumnsStr = element.attribute( "equalcolumns" ).stripWhiteSpace().lower();
if ( ! equalcolumnsStr.isNull() ) {
m_customEqualColumns = true;
if ( equalcolumnsStr == "false" ) {
m_equalColumns = false;
}
else {
m_equalColumns = true;
}
}
TQString displaystyleStr = element.attribute( "displaystyle" ).stripWhiteSpace().lower();
if ( ! displaystyleStr.isNull() ) {
m_customDisplayStyle = true;
if ( displaystyleStr == "false" ) {
m_displayStyle = false;
}
else {
m_displayStyle = true;
}
}
TQString sideStr = element.attribute( "side" ).stripWhiteSpace().lower();
if ( ! sideStr.isNull() ) {
if ( sideStr == "left" ) {
m_side = LeftSide;
}
else if ( sideStr == "right" ) {
m_side = RightSide;
}
else if ( sideStr == "leftoverlap" ) {
m_side = LeftOverlapSide;
}
else if ( sideStr == "rightoverlap" ) {
m_side = RightOverlapSide;
}
}
TQString minlabelspacingStr = element.attribute( "minlabelspacing" ).stripWhiteSpace().lower();
if ( ! minlabelspacingStr.isNull() ) {
m_minLabelSpacing = getSize( minlabelspacingStr, &m_minLabelSpacingType );
if ( m_minLabelSpacingType == NoSize ) {
m_minLabelSpacingType = getSpace( minlabelspacingStr );
}
}
return true;
}
/**
* Reads our content from the MathML node. Sets the node to the next node
* that needs to be read. It is sometimes needed to read more than one node
* (e. g. for fence operators).
* Returns the number of nodes processed or -1 if it failed.
*/
int MatrixElement::readContentFromMathMLDom( TQDomNode& node )
{
// We have twice, since there may be empty elements and we need to know how
// many of them we have. So, first pass, get number of rows and columns
if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
return -1;
}
uint rows = 0;
uint cols = 0;
TQDomNode n = node;
while ( !n.isNull() ) {
if ( n.isElement() ) {
TQDomElement e = n.toElement();
if ( e.tagName().lower() == "mtr" || e.tagName().lower() == "mlabeledtr" )
{
rows++;
/* Determins the number of columns */
TQDomNode cellnode = e.firstChild();
int cc = 0;
while ( !cellnode.isNull() ) {
if ( cellnode.isElement() )
cc++;
cellnode = cellnode.nextSibling();
}
if ( cc > 0 && e.tagName().lower() == "mlabeledtr" )
cc--;
if ( cc > cols )
cols = cc;
}
}
n = n.nextSibling();
}
// Create elements
content.clear();
for (uint r = 0; r < rows; r++) {
TQPtrList< MatrixSequenceElement >* list = new TQPtrList< MatrixSequenceElement >;
list->setAutoDelete(true);
content.append(list);
for (uint c = 0; c < cols; c++) {
MatrixSequenceElement* element = new MatrixSequenceElement(this);
list->append(element);
}
}
// Second pass, read elements now
uint r = 0;
uint c = 0;
while ( !node.isNull() ) {
if ( node.isElement() ) {
TQDomElement e = node.toElement();
if ( e.tagName().lower() == "mtr" || e.tagName().lower() == "mlabeledtr" ) {
TQDomNode cellnode = e.firstChild();
if ( e.tagName().lower() == "mlabeledtr" ) {
while ( ! cellnode.isNull() && ! cellnode.isElement() )
cellnode = cellnode.nextSibling();
if ( ! cellnode.isNull() )
cellnode = cellnode.nextSibling();
}
while ( !cellnode.isNull() ) {
if ( cellnode.isElement() ) {
TQDomElement cellelement = cellnode.toElement();
if ( cellelement.tagName().lower() != "mtd" ) {
// TODO: Inferred mtd. Deprecated in MathML 2.0
kdWarning( DEBUGID ) << "Unsupported tag "
<< cellelement.tagName()
<< " inside matrix row\n";
}
else {
SequenceElement* element = getElement(r, c);
if ( element->buildFromMathMLDom( cellelement ) == -1 )
return -1;
c++;
}
}
cellnode = cellnode.nextSibling();
}
c = 0;
r++;
}
}
node = node.nextSibling();
}
return 1;
}
TQString MatrixElement::toLatex()
{
//All the border handling must be implemented here too
TQString matrix;
uint cols=getColumns();
uint rows=getRows();
matrix="\\begin{array}{ ";
for(uint i=0;i<cols;i++)
matrix+="c ";
matrix+="} ";
for (uint r = 0; r < rows; r++) {
for (uint c = 0; c < cols; c++) {
matrix+=getElement(r, c)->toLatex();
if( c < cols-1) matrix+=" & ";
}
if(r < rows-1 ) matrix+=" \\\\ ";
}
matrix+=" \\end{array}";
return matrix;
}
TQString MatrixElement::formulaString()
{
TQString matrix = "[";
uint cols=getColumns();
uint rows=getRows();
for (uint r = 0; r < rows; r++) {
matrix += "[";
for (uint c = 0; c < cols; c++) {
matrix+=getElement(r, c)->formulaString();
if ( c < cols-1 ) matrix+=", ";
}
matrix += "]";
if ( r < rows-1 ) matrix += ", ";
}
matrix += "]";
return matrix;
}
SequenceElement* MatrixElement::elementAt(uint row, uint column)
{
return getElement( row, column );
}
void MatrixElement::writeMathMLAttributes( TQDomElement& element ) const
{
TQString rownumber;
if ( m_rowNumber ) {
rownumber = TQString( " %1" ).arg( m_rowNumber );
}
switch ( m_align ) {
case TopAlign:
element.setAttribute( "align", "top" + rownumber );
break;
case BottomAlign:
element.setAttribute( "align", "bottom" + rownumber );
break;
case CenterAlign:
element.setAttribute( "align", "center" + rownumber );
break;
case BaselineAlign:
element.setAttribute( "align", "baseline" + rownumber );
break;
case AxisAlign:
element.setAttribute( "align", "axis" + rownumber );
break;
default:
break;
}
TQString rowalign;
for ( TQValueList<VerticalAlign >::const_iterator it = m_rowAlign.begin(); it != m_rowAlign.end(); it++ )
{
switch ( *it ) {
case TopAlign:
rowalign.append( "top " );
break;
case BottomAlign:
rowalign.append( "bottom " );
break;
case CenterAlign:
rowalign.append( "center " );
break;
case BaselineAlign:
rowalign.append( "baseline " );
break;
case AxisAlign:
rowalign.append( "axis " );
break;
default:
break;
}
}
if ( ! rowalign.isNull() ) {
element.setAttribute( "rowalign", rowalign.stripWhiteSpace() );
}
TQString columnalign;
for ( TQValueList<HorizontalAlign >::const_iterator it = m_columnAlign.begin(); it != m_columnAlign.end(); it++ )
{
switch ( *it ) {
case LeftHorizontalAlign:
rowalign.append( "left " );
break;
case CenterHorizontalAlign:
rowalign.append( "center " );
break;
case RightHorizontalAlign:
rowalign.append( "right " );
break;
default:
break;
}
}
if ( ! columnalign.isNull() ) {
element.setAttribute( "columnalign", columnalign.stripWhiteSpace() );
}
TQString alignmentscope;
for ( TQValueList< bool >::const_iterator it = m_alignmentScope.begin(); it != m_alignmentScope.end(); it++ )
{
if ( *it ) {
alignmentscope.append( "true " );
}
else {
alignmentscope.append( "false " );
}
}
if ( ! alignmentscope.isNull() ) {
element.setAttribute( "alignmentscope", alignmentscope.stripWhiteSpace() );
}
TQString columnwidth;
TQValueList< double >::const_iterator lengthIt = m_columnWidth.begin();
for ( TQValueList< SizeType >::const_iterator typeIt = m_columnWidthType.begin();
typeIt != m_columnWidthType.end(); typeIt ++ ) {
switch ( *typeIt ) {
case AutoSize:
columnwidth.append( "auto " );
break;
case FitSize:
columnwidth.append( "fit " );
break;
case AbsoluteSize:
columnwidth.append( TQString( "%1pt " ).arg( *lengthIt ) );
lengthIt++;
break;
case RelativeSize:
columnwidth.append( TQString( "%1% " ).arg( *lengthIt * 100.0 ) );
lengthIt++;
break;
case PixelSize:
columnwidth.append( TQString( "%1px " ).arg( *lengthIt ) );
lengthIt++;
break;
case NegativeVeryVeryThinMathSpace:
columnwidth.append( "negativeveryverythinmathspace " );
break;
case NegativeVeryThinMathSpace:
columnwidth.append( "negativeverythinmathspace " );
break;
case NegativeThinMathSpace:
columnwidth.append( "negativethinmathspace " );
break;
case NegativeMediumMathSpace:
columnwidth.append( "negativemediummathspace " );
break;
case NegativeThickMathSpace:
columnwidth.append( "negativethickmathspace " );
break;
case NegativeVeryThickMathSpace:
columnwidth.append( "negativeverythickmathspace " );
break;
case NegativeVeryVeryThickMathSpace:
columnwidth.append( "negativeveryverythickmathspace " );
break;
case VeryVeryThinMathSpace:
columnwidth.append( "veryverythinmathspace " );
break;
case VeryThinMathSpace:
columnwidth.append( "verythinmathspace " );
break;
case ThinMathSpace:
columnwidth.append( "thinmathspace " );
break;
case MediumMathSpace:
columnwidth.append( "mediummathspace " );
break;
case ThickMathSpace:
columnwidth.append( "thickmathspace " );
break;
case VeryThickMathSpace:
columnwidth.append( "verythickmathspace " );
break;
case VeryVeryThickMathSpace:
columnwidth.append( "veryverythickmathspace " );
break;
default:
break;
}
}
if ( ! columnwidth.isNull() ) {
element.setAttribute( "columnwidth", columnwidth.stripWhiteSpace() );
}
switch ( m_widthType ) {
case AutoSize:
element.setAttribute( "width", "auto" );
break;
case AbsoluteSize:
element.setAttribute( "width", TQString( "%1pt" ).arg( m_width ) );
break;
case RelativeSize:
element.setAttribute( "width", TQString( "%1% " ).arg( m_width * 100.0 ) );
break;
case PixelSize:
element.setAttribute( "width", TQString( "%1px " ).arg( m_width ) );
break;
default:
break;
}
TQString rowspacing;
lengthIt = m_rowSpacing.begin();
for ( TQValueList< SizeType >::const_iterator typeIt = m_rowSpacingType.begin();
typeIt != m_rowSpacingType.end(); typeIt++, lengthIt++ ) {
switch ( *typeIt ) {
case AbsoluteSize:
rowspacing.append( TQString( "%1pt " ).arg( *lengthIt ) );
break;
case RelativeSize:
rowspacing.append( TQString( "%1% " ).arg( *lengthIt * 100.0 ) );
break;
case PixelSize:
rowspacing.append( TQString( "%1px " ).arg( *lengthIt ) );
break;
default:
break;
}
}
if ( ! rowspacing.isNull() ) {
element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
}
TQString columnspacing;
lengthIt = m_columnSpacing.begin();
for ( TQValueList< SizeType >::const_iterator typeIt = m_columnSpacingType.begin();
typeIt != m_columnSpacingType.end(); typeIt++ ) {
switch ( *typeIt ) {
case AbsoluteSize:
columnspacing.append( TQString( "%1pt " ).arg( *lengthIt ) );
lengthIt++;
break;
case RelativeSize:
columnspacing.append( TQString( "%1% " ).arg( *lengthIt * 100.0 ) );
lengthIt++;
break;
case PixelSize:
columnspacing.append( TQString( "%1px " ).arg( *lengthIt ) );
lengthIt++;
break;
case NegativeVeryVeryThinMathSpace:
columnspacing.append( "negativeveryverythinmathspace " );
break;
case NegativeVeryThinMathSpace:
columnspacing.append( "negativeverythinmathspace " );
break;
case NegativeThinMathSpace:
columnspacing.append( "negativethinmathspace " );
break;
case NegativeMediumMathSpace:
columnspacing.append( "negativemediummathspace " );
break;
case NegativeThickMathSpace:
columnspacing.append( "negativethickmathspace " );
break;
case NegativeVeryThickMathSpace:
columnspacing.append( "negativeverythickmathspace " );
break;
case NegativeVeryVeryThickMathSpace:
columnspacing.append( "negativeveryverythickmathspace " );
break;
case VeryVeryThinMathSpace:
columnspacing.append( "veryverythinmathspace " );
break;
case VeryThinMathSpace:
columnspacing.append( "verythinmathspace " );
break;
case ThinMathSpace:
columnspacing.append( "thinmathspace " );
break;
case MediumMathSpace:
columnspacing.append( "mediummathspace " );
break;
case ThickMathSpace:
columnspacing.append( "thickmathspace " );
break;
case VeryThickMathSpace:
columnspacing.append( "verythickmathspace " );
break;
case VeryVeryThickMathSpace:
columnspacing.append( "veryverythickmathspace " );
break;
default:
break;
}
}
if ( ! rowspacing.isNull() ) {
element.setAttribute( "rowspacing", rowspacing.stripWhiteSpace() );
}
TQString rowlines;
for ( TQValueList< LineType >::const_iterator it = m_rowLines.begin(); it != m_rowLines.end(); it++ )
{
switch ( *it ) {
case NoneLine:
rowlines.append( "none " );
break;
case SolidLine:
rowlines.append( "solid " );
break;
case DashedLine:
rowlines.append( "dashed " );
break;
default:
break;
}
}
if ( ! rowlines.isNull() ) {
element.setAttribute( "rowlines", rowlines.stripWhiteSpace() );
}
TQString columnlines;
for ( TQValueList< LineType >::const_iterator it = m_columnLines.begin(); it != m_columnLines.end(); it++ )
{
switch ( *it ) {
case NoneLine:
columnlines.append( "none " );
break;
case SolidLine:
columnlines.append( "solid " );
break;
case DashedLine:
columnlines.append( "dashed " );
break;
default:
break;
}
}
if ( ! columnlines.isNull() ) {
element.setAttribute( "columnlines", columnlines.stripWhiteSpace() );
}
switch ( m_frame ) {
case NoneLine:
element.setAttribute( "frame", "none" );
break;
case SolidLine:
element.setAttribute( "frame", "solid" );
break;
case DashedLine:
element.setAttribute( "frame", "dashed" );
break;
default:
break;
}
TQString framespacing;
switch ( m_frameHSpacingType ) {
case AbsoluteSize:
framespacing.append( TQString( "%1pt " ).arg( m_frameHSpacing ) );
break;
case RelativeSize:
framespacing.append( TQString( "%1% " ).arg( m_frameHSpacing * 100.0 ) );
break;
case PixelSize:
framespacing.append( TQString( "%1px " ).arg( m_frameHSpacing ) );
break;
case NegativeVeryVeryThinMathSpace:
framespacing.append( "negativeveryverythinmathspace " );
break;
case NegativeVeryThinMathSpace:
framespacing.append( "negativeverythinmathspace " );
break;
case NegativeThinMathSpace:
framespacing.append( "negativethinmathspace " );
break;
case NegativeMediumMathSpace:
framespacing.append( "negativemediummathspace " );
break;
case NegativeThickMathSpace:
framespacing.append( "negativethickmathspace " );
break;
case NegativeVeryThickMathSpace:
framespacing.append( "negativeverythickmathspace " );
break;
case NegativeVeryVeryThickMathSpace:
framespacing.append( "negativeveryverythickmathspace " );
break;
case VeryVeryThinMathSpace:
framespacing.append( "veryverythinmathspace " );
break;
case VeryThinMathSpace:
framespacing.append( "verythinmathspace " );
break;
case ThinMathSpace:
framespacing.append( "thinmathspace " );
break;
case MediumMathSpace:
framespacing.append( "mediummathspace " );
break;
case ThickMathSpace:
framespacing.append( "thickmathspace " );
break;
case VeryThickMathSpace:
framespacing.append( "verythickmathspace " );
break;
case VeryVeryThickMathSpace:
framespacing.append( "veryverythickmathspace " );
break;
default:
break;
}
switch ( m_frameVSpacingType ) {
case AbsoluteSize:
framespacing.append( TQString( "%1pt " ).arg( m_frameVSpacing ) );
break;
case RelativeSize:
framespacing.append( TQString( "%1% " ).arg( m_frameVSpacing * 100.0 ) );
break;
case PixelSize:
framespacing.append( TQString( "%1px " ).arg( m_frameVSpacing ) );
break;
case NegativeVeryVeryThinMathSpace:
framespacing.append( "negativeveryverythinmathspace " );
break;
case NegativeVeryThinMathSpace:
framespacing.append( "negativeverythinmathspace " );
break;
case NegativeThinMathSpace:
framespacing.append( "negativethinmathspace " );
break;
case NegativeMediumMathSpace:
framespacing.append( "negativemediummathspace " );
break;
case NegativeThickMathSpace:
framespacing.append( "negativethickmathspace " );
break;
case NegativeVeryThickMathSpace:
framespacing.append( "negativeverythickmathspace " );
break;
case NegativeVeryVeryThickMathSpace:
framespacing.append( "negativeveryverythickmathspace " );
break;
case VeryVeryThinMathSpace:
framespacing.append( "veryverythinmathspace " );
break;
case VeryThinMathSpace:
framespacing.append( "verythinmathspace " );
break;
case ThinMathSpace:
framespacing.append( "thinmathspace " );
break;
case MediumMathSpace:
framespacing.append( "mediummathspace " );
break;
case ThickMathSpace:
framespacing.append( "thickmathspace " );
break;
case VeryThickMathSpace:
framespacing.append( "verythickmathspace " );
break;
case VeryVeryThickMathSpace:
framespacing.append( "veryverythickmathspace " );
break;
default:
break;
}
if ( ! framespacing.isNull() ) {
element.setAttribute( "framespacing", framespacing.stripWhiteSpace() );
}
if ( m_customEqualRows ) {
element.setAttribute( "equalrows", m_equalRows ? "true" : "false" );
}
if ( m_customEqualColumns ) {
element.setAttribute( "equalcolumns", m_equalColumns ? "true" : "false" );
}
if ( m_customDisplayStyle ) {
element.setAttribute( "displaystyle", m_displayStyle ? "true" : "false" );
}
switch ( m_side ) {
case LeftSide:
element.setAttribute( "side", "left" );
break;
case RightSide:
element.setAttribute( "side", "right" );
break;
case LeftOverlapSide:
element.setAttribute( "side", "leftoverlap" );
break;
case RightOverlapSide:
element.setAttribute( "side", "rightoverlap" );
break;
default:
break;
}
switch ( m_minLabelSpacingType ) {
case AbsoluteSize:
element.setAttribute( "minlabelspacing", TQString( "%1pt" ).arg( m_minLabelSpacing ) );
break;
case RelativeSize:
element.setAttribute( "minlabelspacing", TQString( "%1%" ).arg( m_minLabelSpacing * 100.0 ) );
break;
case PixelSize:
element.setAttribute( "minlabelspacing", TQString( "%1px" ).arg( m_minLabelSpacing ) );
break;
case NegativeVeryVeryThinMathSpace:
element.setAttribute( "minlabelspacing", "negativeveryverythinmathspace" );
break;
case NegativeVeryThinMathSpace:
element.setAttribute( "minlabelspacing", "negativeverythinmathspace" );
break;
case NegativeThinMathSpace:
element.setAttribute( "minlabelspacing", "negativethinmathspace" );
break;
case NegativeMediumMathSpace:
element.setAttribute( "minlabelspacing", "negativemediummathspace" );
break;
case NegativeThickMathSpace:
element.setAttribute( "minlabelspacing", "negativethickmathspace" );
break;
case NegativeVeryThickMathSpace:
element.setAttribute( "minlabelspacing", "negativeverythickmathspace" );
break;
case NegativeVeryVeryThickMathSpace:
element.setAttribute( "minlabelspacing", "negativeveryverythickmathspace" );
break;
case VeryVeryThinMathSpace:
element.setAttribute( "minlabelspacing", "veryverythinmathspace" );
break;
case VeryThinMathSpace:
element.setAttribute( "minlabelspacing", "verythinmathspace" );
break;
case ThinMathSpace:
element.setAttribute( "minlabelspacing", "thinmathspace" );
break;
case MediumMathSpace:
element.setAttribute( "minlabelspacing", "mediummathspace" );
break;
case ThickMathSpace:
element.setAttribute( "minlabelspacing", "thickmathspace" );
break;
case VeryThickMathSpace:
element.setAttribute( "minlabelspacing", "verythickmathspace" );
break;
case VeryVeryThickMathSpace:
element.setAttribute( "minlabelspacing", "veryverythickmathspace" );
break;
default:
break;
}
}
void MatrixElement::writeMathMLContent( TQDomDocument& doc,
TQDomElement& element,
bool oasisFormat ) const
{
TQDomElement row;
TQDomElement cell;
uint rows = getRows();
uint cols = getColumns();
for ( uint r = 0; r < rows; r++ )
{
row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
element.appendChild( row );
for ( uint c = 0; c < cols; c++ )
{
cell = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
row.appendChild( cell );
getElement(r,c)->writeMathML( doc, cell, oasisFormat );
}
}
}
//////////////////////////////////////////////////////////////////////////////
/**
* The lines behaviour is (a little) different from that
* of ordinary sequences.
*/
class MultilineSequenceElement : public SequenceElement {
typedef SequenceElement inherited;
public:
MultilineSequenceElement( BasicElement* parent = 0 );
virtual MultilineSequenceElement* clone() {
return new MultilineSequenceElement( *this );
}
virtual BasicElement* goToPos( FormulaCursor*, bool& handled,
const LuPixelPoint& point, const LuPixelPoint& parentOrigin );
/**
* Calculates our width and height and
* our children's parentPosition.
*/
virtual void calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style );
virtual void registerTab( BasicElement* tab );
/**
* This is called by the container to get a command depending on
* the current cursor position (this is how the element gets chosen)
* and the request.
*
* @returns the command that performs the requested action with
* the containers active cursor.
*/
virtual KCommand* buildCommand( Container*, Request* );
virtual KCommand* input( Container* container, TQKeyEvent* event );
virtual KCommand* input( Container* container, TQChar ch );
uint tabCount() const { return tabs.count(); }
BasicElement* tab( uint i ) { return tabs.at( i ); }
/// Change the width of tab i and move all elements after it.
void moveTabTo( uint i, luPixel pos );
/// Return the greatest tab number less than pos.
int tabBefore( uint pos );
/// Return the position of tab i.
int tabPos( uint i );
virtual void writeMathML( TQDomDocument& doc, TQDomNode& parent, bool oasisFormat = false ) const ;
private:
TQPtrList<BasicElement> tabs;
};
// Split the line at position pos.
class KFCNewLine : public Command {
public:
KFCNewLine( const TQString& name, Container* document,
MultilineSequenceElement* line, uint pos );
virtual ~KFCNewLine();
virtual void execute();
virtual void unexecute();
private:
MultilineSequenceElement* m_line;
MultilineSequenceElement* m_newline;
uint m_pos;
};
KFCNewLine::KFCNewLine( const TQString& name, Container* document,
MultilineSequenceElement* line, uint pos )
: Command( name, document ),
m_line( line ), m_pos( pos )
{
m_newline = new MultilineSequenceElement( m_line->getParent() );
}
KFCNewLine::~KFCNewLine()
{
delete m_newline;
}
void KFCNewLine::execute()
{
FormulaCursor* cursor = getExecuteCursor();
MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
int linePos = parent->content.find( m_line );
parent->content.insert( linePos+1, m_newline );
// If there are children to be moved.
if ( m_line->countChildren() > static_cast<int>( m_pos ) ) {
// Remove anything after position pos from the current line
m_line->selectAllChildren( cursor );
cursor->setMark( m_pos );
TQPtrList<BasicElement> elementList;
m_line->remove( cursor, elementList, beforeCursor );
// Insert the removed stuff into the new line
m_newline->goInside( cursor );
m_newline->insert( cursor, elementList, beforeCursor );
cursor->setPos( cursor->getMark() );
}
else {
m_newline->goInside( cursor );
}
// The command no longer owns the new line.
m_newline = 0;
// Tell that something changed
FormulaElement* formula = m_line->formula();
formula->changed();
testDirty();
}
void KFCNewLine::unexecute()
{
FormulaCursor* cursor = getExecuteCursor();
MultilineElement* parent = static_cast<MultilineElement*>( m_line->getParent() );
int linePos = parent->content.find( m_line );
// Now the command owns the new line again.
m_newline = parent->content.at( linePos+1 );
// Tell all cursors to leave this sequence
FormulaElement* formula = m_line->formula();
formula->elementRemoval( m_newline );
// If there are children to be moved.
if ( m_newline->countChildren() > 0 ) {
// Remove anything from the line to be deleted
m_newline->selectAllChildren( cursor );
TQPtrList<BasicElement> elementList;
m_newline->remove( cursor, elementList, beforeCursor );
// Insert the removed stuff into the previous line
m_line->moveEnd( cursor );
m_line->insert( cursor, elementList, beforeCursor );
cursor->setPos( cursor->getMark() );
}
else {
m_line->moveEnd( cursor );
}
parent->content.take( linePos+1 );
// Tell that something changed
formula->changed();
testDirty();
}
MultilineSequenceElement::MultilineSequenceElement( BasicElement* parent )
: SequenceElement( parent )
{
tabs.setAutoDelete( false );
}
BasicElement* MultilineSequenceElement::goToPos( FormulaCursor* cursor, bool& handled,
const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
{
//LuPixelPoint myPos(parentOrigin.x() + getX(),
// parentOrigin.y() + getY());
BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
if (e == 0) {
// If the mouse was behind this line put the cursor to the last position.
if ( ( point.x() > getX()+getWidth() ) &&
( point.y() >= getY() ) &&
( point.y() < getY()+getHeight() ) ) {
cursor->setTo(this, countChildren());
handled = true;
return this;
}
}
return e;
}
void MultilineSequenceElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style )
{
tabs.clear();
inherited::calcSizes( context, tstyle, istyle, style );
}
void MultilineSequenceElement::registerTab( BasicElement* tab )
{
tabs.append( tab );
}
KCommand* MultilineSequenceElement::buildCommand( Container* container, Request* request )
{
FormulaCursor* cursor = container->activeCursor();
if ( cursor->isReadOnly() ) {
return 0;
}
switch ( *request ) {
case req_remove: {
// Remove this line if its empty.
// Remove the formula if this line was the only one.
break;
}
case req_addNewline: {
FormulaCursor* cursor = container->activeCursor();
return new KFCNewLine( i18n( "Add Newline" ), container, this, cursor->getPos() );
}
case req_addTabMark: {
KFCReplace* command = new KFCReplace( i18n("Add Tabmark"), container );
SpaceElement* element = new SpaceElement( THIN, true );
command->addElement( element );
return command;
}
default:
break;
}
return inherited::buildCommand( container, request );
}
KCommand* MultilineSequenceElement::input( Container* container, TQKeyEvent* event )
{
int action = event->key();
//int state = event->state();
//MoveFlag flag = movementFlag(state);
switch ( action ) {
case TQt::Key_Enter:
case TQt::Key_Return: {
Request newline( req_addNewline );
return buildCommand( container, &newline );
}
case TQt::Key_Tab: {
Request r( req_addTabMark );
return buildCommand( container, &r );
}
}
return inherited::input( container, event );
}
KCommand* MultilineSequenceElement::input( Container* container, TQChar ch )
{
int latin1 = ch.latin1();
switch (latin1) {
case '&': {
Request r( req_addTabMark );
return buildCommand( container, &r );
}
}
return inherited::input( container, ch );
}
void MultilineSequenceElement::moveTabTo( uint i, luPixel pos )
{
BasicElement* marker = tab( i );
luPixel diff = pos - marker->getX();
marker->setWidth( marker->getWidth() + diff );
for ( int p = childPos( marker )+1; p < countChildren(); ++p ) {
BasicElement* child = getChild( p );
child->setX( child->getX() + diff );
}
setWidth( getWidth()+diff );
}
int MultilineSequenceElement::tabBefore( uint pos )
{
if ( tabs.isEmpty() ) {
return -1;
}
uint tabNum = 0;
for ( uint i=0; i<pos; ++i ) {
BasicElement* child = getChild( i );
if ( tabs.at( tabNum ) == child ) {
if ( tabNum+1 == tabs.count() ) {
return tabNum;
}
++tabNum;
}
}
return static_cast<int>( tabNum )-1;
}
int MultilineSequenceElement::tabPos( uint i )
{
if ( i < tabs.count() ) {
return childPos( tabs.at( i ) );
}
return -1;
}
void MultilineSequenceElement::writeMathML( TQDomDocument& doc,
TQDomNode& parent, bool oasisFormat ) const
{
// parent is required to be a <mtr> tag
TQDomElement tmp = doc.createElement( "TMP" );
inherited::writeMathML( doc, tmp, oasisFormat );
/* Now we re-parse the Dom tree, because of the TabMarkers
* that have no direct representation in MathML but mark the
* end of a <mtd> tag.
*/
TQDomElement mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
// The mrow, if it exists.
TQDomNode n = tmp.firstChild().firstChild();
while ( !n.isNull() ) {
// the illegal TabMarkers are children of the mrow, child of tmp.
if ( n.isElement() && n.toElement().tagName() == "TAB" ) {
parent.appendChild( mtd );
mtd = doc.createElement( oasisFormat ? "math:mtd" : "mtd" );
}
else {
mtd.appendChild( n.cloneNode() ); // cloneNode needed?
}
n = n.nextSibling();
}
parent.appendChild( mtd );
}
MultilineElement::MultilineElement( BasicElement* parent )
: BasicElement( parent )
{
content.setAutoDelete( true );
content.append( new MultilineSequenceElement( this ) );
}
MultilineElement::~MultilineElement()
{
}
MultilineElement::MultilineElement( const MultilineElement& other )
: BasicElement( other )
{
content.setAutoDelete( true );
uint count = other.content.count();
for (uint i = 0; i < count; i++) {
MultilineSequenceElement* line = content.at(i)->clone();
line->setParent( this );
content.append( line );
}
}
bool MultilineElement::accept( ElementVisitor* visitor )
{
return visitor->visit( this );
}
void MultilineElement::entered( SequenceElement* /*child*/ )
{
formula()->tell( i18n( "Multi line element" ) );
}
/**
* Returns the element the point is in.
*/
BasicElement* MultilineElement::goToPos( FormulaCursor* cursor, bool& handled,
const LuPixelPoint& point, const LuPixelPoint& parentOrigin )
{
BasicElement* e = inherited::goToPos(cursor, handled, point, parentOrigin);
if ( e != 0 ) {
LuPixelPoint myPos(parentOrigin.x() + getX(),
parentOrigin.y() + getY());
uint count = content.count();
for ( uint i = 0; i < count; ++i ) {
MultilineSequenceElement* line = content.at(i);
e = line->goToPos(cursor, handled, point, myPos);
if (e != 0) {
return e;
}
}
return this;
}
return 0;
}
void MultilineElement::goInside( FormulaCursor* cursor )
{
content.at( 0 )->goInside( cursor );
}
void MultilineElement::moveLeft( FormulaCursor* cursor, BasicElement* from )
{
// If you want to select more than one line you'll have to
// select the whole element.
if (cursor->isSelectionMode()) {
getParent()->moveLeft(cursor, this);
}
else {
// Coming from the parent (sequence) we go to
// the very last position
if (from == getParent()) {
content.at( content.count()-1 )->moveLeft(cursor, this);
}
else {
// Coming from one of the lines we go to the previous line
// or to the parent if there is none.
int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
if ( pos > -1 ) {
if ( pos > 0 ) {
content.at( pos-1 )->moveLeft( cursor, this );
}
else {
getParent()->moveLeft(cursor, this);
}
}
else {
kdDebug( DEBUGID ) << k_funcinfo << endl;
kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
}
}
}
}
void MultilineElement::moveRight( FormulaCursor* cursor, BasicElement* from )
{
if (cursor->isSelectionMode()) {
getParent()->moveRight(cursor, this);
}
else {
if (from == getParent()) {
content.at( 0 )->moveRight(cursor, this);
}
else {
int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
if ( pos > -1 ) {
uint upos = pos;
if ( upos < content.count() ) {
if ( upos < content.count()-1 ) {
content.at( upos+1 )->moveRight( cursor, this );
}
else {
getParent()->moveRight(cursor, this);
}
return;
}
}
kdDebug( DEBUGID ) << k_funcinfo << endl;
kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
}
}
}
void MultilineElement::moveUp( FormulaCursor* cursor, BasicElement* from )
{
// If you want to select more than one line you'll have to
// select the whole element.
if (cursor->isSelectionMode()) {
getParent()->moveLeft(cursor, this);
}
else {
// Coming from the parent (sequence) we go to
// the very last position
if (from == getParent()) {
content.at( content.count()-1 )->moveLeft(cursor, this);
}
else {
// Coming from one of the lines we go to the previous line
// or to the parent if there is none.
int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
if ( pos > -1 ) {
if ( pos > 0 ) {
//content.at( pos-1 )->moveLeft( cursor, this );
// This is rather hackish.
// But we know what elements we have here.
int cursorPos = cursor->getPos();
MultilineSequenceElement* current = content.at( pos );
MultilineSequenceElement* newLine = content.at( pos-1 );
int tabNum = current->tabBefore( cursorPos );
if ( tabNum > -1 ) {
int oldTabPos = current->tabPos( tabNum );
int newTabPos = newLine->tabPos( tabNum );
if ( newTabPos > -1 ) {
cursorPos += newTabPos-oldTabPos;
int nextNewTabPos = newLine->tabPos( tabNum+1 );
if ( nextNewTabPos > -1 ) {
cursorPos = TQMIN( cursorPos, nextNewTabPos );
}
}
else {
cursorPos = newLine->countChildren();
}
}
else {
int nextNewTabPos = newLine->tabPos( 0 );
if ( nextNewTabPos > -1 ) {
cursorPos = TQMIN( cursorPos, nextNewTabPos );
}
}
cursor->setTo( newLine,
TQMIN( cursorPos,
newLine->countChildren() ) );
}
else {
getParent()->moveLeft(cursor, this);
}
}
else {
kdDebug( DEBUGID ) << k_funcinfo << endl;
kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
}
}
}
}
void MultilineElement::moveDown( FormulaCursor* cursor, BasicElement* from )
{
if (cursor->isSelectionMode()) {
getParent()->moveRight(cursor, this);
}
else {
if (from == getParent()) {
content.at( 0 )->moveRight(cursor, this);
}
else {
int pos = content.find( static_cast<MultilineSequenceElement*>( from ) );
if ( pos > -1 ) {
uint upos = pos;
if ( upos < content.count() ) {
if ( upos < content.count()-1 ) {
//content.at( upos+1 )->moveRight( cursor, this );
// This is rather hackish.
// But we know what elements we have here.
int cursorPos = cursor->getPos();
MultilineSequenceElement* current = content.at( upos );
MultilineSequenceElement* newLine = content.at( upos+1 );
int tabNum = current->tabBefore( cursorPos );
if ( tabNum > -1 ) {
int oldTabPos = current->tabPos( tabNum );
int newTabPos = newLine->tabPos( tabNum );
if ( newTabPos > -1 ) {
cursorPos += newTabPos-oldTabPos;
int nextNewTabPos = newLine->tabPos( tabNum+1 );
if ( nextNewTabPos > -1 ) {
cursorPos = TQMIN( cursorPos, nextNewTabPos );
}
}
else {
cursorPos = newLine->countChildren();
}
}
else {
int nextNewTabPos = newLine->tabPos( 0 );
if ( nextNewTabPos > -1 ) {
cursorPos = TQMIN( cursorPos, nextNewTabPos );
}
}
cursor->setTo( newLine,
TQMIN( cursorPos,
newLine->countChildren() ) );
}
else {
getParent()->moveRight(cursor, this);
}
return;
}
}
kdDebug( DEBUGID ) << k_funcinfo << endl;
kdDebug( DEBUGID ) << "Serious confusion. Must never happen." << endl;
}
}
}
void MultilineElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style )
{
double factor = style.sizeFactor();
luPt mySize = context.getAdjustedSize( tstyle, factor );
TQFont font = context.getDefaultFont();
font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
TQFontMetrics fm( font );
luPixel leading = context.ptToLayoutUnitPt( fm.leading() );
luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
uint count = content.count();
luPixel height = -leading;
luPixel width = 0;
uint tabCount = 0;
for ( uint i = 0; i < count; ++i ) {
MultilineSequenceElement* line = content.at(i);
line->calcSizes( context, tstyle, istyle, style );
tabCount = TQMAX( tabCount, line->tabCount() );
height += leading;
line->setX( 0 );
line->setY( height );
height += line->getHeight() + distY;
width = TQMAX( line->getWidth(), width );
}
// calculate the tab positions
for ( uint t = 0; t < tabCount; ++t ) {
luPixel pos = 0;
for ( uint i = 0; i < count; ++i ) {
MultilineSequenceElement* line = content.at(i);
if ( t < line->tabCount() ) {
pos = TQMAX( pos, line->tab( t )->getX() );
}
else {
pos = TQMAX( pos, line->getWidth() );
}
}
for ( uint i = 0; i < count; ++i ) {
MultilineSequenceElement* line = content.at(i);
if ( t < line->tabCount() ) {
line->moveTabTo( t, pos );
width = TQMAX( width, line->getWidth() );
}
}
}
setHeight( height );
setWidth( width );
if ( count == 1 ) {
setBaseline( content.at( 0 )->getBaseline() );
}
else {
// There's always a first line. No formulas without lines.
setBaseline( height/2 + context.axisHeight( tstyle, factor ) );
}
}
void MultilineElement::draw( TQPainter& painter, const LuPixelRect& r,
const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style,
const LuPixelPoint& parentOrigin )
{
LuPixelPoint myPos( parentOrigin.x() + getX(), parentOrigin.y() + getY() );
uint count = content.count();
if ( context.edit() ) {
uint tabCount = 0;
painter.setPen( context.getHelpColor() );
for ( uint i = 0; i < count; ++i ) {
MultilineSequenceElement* line = content.at(i);
if ( tabCount < line->tabCount() ) {
for ( uint t = tabCount; t < line->tabCount(); ++t ) {
BasicElement* marker = line->tab( t );
painter.drawLine( context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
context.layoutUnitToPixelY( myPos.y() ),
context.layoutUnitToPixelX( myPos.x()+marker->getX() ),
context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
}
tabCount = line->tabCount();
}
}
}
for ( uint i = 0; i < count; ++i ) {
MultilineSequenceElement* line = content.at(i);
line->draw( painter, r, context, tstyle, istyle, style, myPos );
}
}
void MultilineElement::dispatchFontCommand( FontCommand* cmd )
{
uint count = content.count();
for ( uint i = 0; i < count; ++i ) {
MultilineSequenceElement* line = content.at(i);
line->dispatchFontCommand( cmd );
}
}
void MultilineElement::insert( FormulaCursor* cursor,
TQPtrList<BasicElement>& newChildren,
Direction direction )
{
MultilineSequenceElement* e = static_cast<MultilineSequenceElement*>(newChildren.take(0));
e->setParent(this);
content.insert( cursor->getPos(), e );
if (direction == beforeCursor) {
e->moveLeft(cursor, this);
}
else {
e->moveRight(cursor, this);
}
cursor->setSelection(false);
formula()->changed();
}
void MultilineElement::remove( FormulaCursor* cursor,
TQPtrList<BasicElement>& removedChildren,
Direction direction )
{
if ( content.count() == 1 ) { //&& ( cursor->getPos() == 0 ) ) {
getParent()->selectChild(cursor, this);
getParent()->remove(cursor, removedChildren, direction);
}
else {
MultilineSequenceElement* e = content.take( cursor->getPos() );
removedChildren.append( e );
formula()->elementRemoval( e );
//cursor->setTo( this, denominatorPos );
formula()->changed();
}
}
void MultilineElement::normalize( FormulaCursor* cursor, Direction direction )
{
int pos = cursor->getPos();
if ( ( cursor->getElement() == this ) &&
( pos > -1 ) && ( static_cast<unsigned>( pos ) <= content.count() ) ) {
switch ( direction ) {
case beforeCursor:
if ( pos > 0 ) {
content.at( pos-1 )->moveLeft( cursor, this );
break;
}
// no break! intended!
case afterCursor:
if ( static_cast<unsigned>( pos ) < content.count() ) {
content.at( pos )->moveRight( cursor, this );
}
else {
content.at( pos-1 )->moveLeft( cursor, this );
}
break;
}
}
else {
inherited::normalize( cursor, direction );
}
}
SequenceElement* MultilineElement::getMainChild()
{
return content.at( 0 );
}
void MultilineElement::selectChild(FormulaCursor* cursor, BasicElement* child)
{
int pos = content.find( dynamic_cast<MultilineSequenceElement*>( child ) );
if ( pos > -1 ) {
cursor->setTo( this, pos );
//content.at( pos )->moveRight( cursor, this );
}
}
/**
* Appends our attributes to the dom element.
*/
void MultilineElement::writeDom(TQDomElement element)
{
BasicElement::writeDom(element);
uint lineCount = content.count();
element.setAttribute( "LINES", lineCount );
TQDomDocument doc = element.ownerDocument();
for ( uint i = 0; i < lineCount; ++i ) {
TQDomElement tmp = content.at( i )->getElementDom(doc);
element.appendChild(tmp);
}
}
void MultilineElement::writeMathML( TQDomDocument& doc, TQDomNode& parent, bool oasisFormat ) const
{
TQDomElement de = doc.createElement( oasisFormat ? "math:mtable" : "mtable" );
TQDomElement row; TQDomElement cell;
for ( TQPtrListIterator < MultilineSequenceElement > it( content ); it.current(); ++it ) {
row = doc.createElement( oasisFormat ? "math:mtr" : "mtr" );
de.appendChild( row );
//cell = doc.createElement( "mtd" );
//row.appendChild( cell );
//content.at( i )->writeMathML( doc, cell );
it.current()->writeMathML( doc, row, oasisFormat );
}
parent.appendChild( de );
}
/**
* Reads our attributes from the element.
* Returns false if it failed.
*/
bool MultilineElement::readAttributesFromDom(TQDomElement element)
{
if (!BasicElement::readAttributesFromDom(element)) {
return false;
}
uint lineCount = 0;
TQString lineCountStr = element.attribute("LINES");
if(!lineCountStr.isNull()) {
lineCount = lineCountStr.toInt();
}
if (lineCount == 0) {
kdWarning( DEBUGID ) << "lineCount <= 0 in MultilineElement." << endl;
return false;
}
content.clear();
for ( uint i = 0; i < lineCount; ++i ) {
MultilineSequenceElement* element = new MultilineSequenceElement(this);
content.append(element);
}
return true;
}
/**
* Reads our content from the node. Sets the node to the next node
* that needs to be read.
* Returns false if it failed.
*/
bool MultilineElement::readContentFromDom(TQDomNode& node)
{
if (!BasicElement::readContentFromDom(node)) {
return false;
}
uint lineCount = content.count();
uint i = 0;
while ( !node.isNull() && i < lineCount ) {
if ( node.isElement() ) {
SequenceElement* element = content.at( i );
TQDomElement e = node.toElement();
if ( !element->buildFromDom( e ) ) {
return false;
}
++i;
}
node = node.nextSibling();
}
return true;
}
TQString MultilineElement::toLatex()
{
uint lineCount = content.count();
TQString muliline = "\\begin{split} ";
for ( uint i = 0; i < lineCount; ++i ) {
muliline += content.at( i )->toLatex();
muliline += " \\\\ ";
}
muliline += "\\end{split}";
return muliline;
}
// Does this make any sense at all?
TQString MultilineElement::formulaString()
{
uint lineCount = content.count();
TQString muliline = "";
for ( uint i = 0; i < lineCount; ++i ) {
muliline += content.at( i )->formulaString();
muliline += "\n";
}
//muliline += "";
return muliline;
}
KFORMULA_NAMESPACE_END