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/bracketelement.cc

1006 lines
32 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 <qptrlist.h>
#include <qpainter.h>
#include <qpen.h>
#include <qpointarray.h>
#include <kdebug.h>
#include <klocale.h>
#include "bracketelement.h"
#include "elementvisitor.h"
#include "fontstyle.h"
#include "formulacursor.h"
#include "formulaelement.h"
#include "sequenceelement.h"
KFORMULA_NAMESPACE_BEGIN
SingleContentElement::SingleContentElement(BasicElement* parent )
: BasicElement( parent )
{
content = new SequenceElement( this );
}
SingleContentElement::SingleContentElement( const SingleContentElement& other )
: BasicElement( other )
{
content = new SequenceElement( other.content );
content->setParent( this );
}
SingleContentElement::~SingleContentElement()
{
delete content;
}
QChar SingleContentElement::getCharacter() const
{
// This is meant to make the SingleContentElement text only.
// This "fixes" the parenthesis problem (parenthesis too large).
// I'm not sure if we really want this. There should be better ways.
if ( content->isTextOnly() ) {
return '\\';
}
return content->getCharacter();
}
BasicElement* SingleContentElement::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());
e = content->goToPos(cursor, handled, point, myPos);
if (e != 0) {
return e;
}
return this;
}
return 0;
}
void SingleContentElement::dispatchFontCommand( FontCommand* cmd )
{
content->dispatchFontCommand( cmd );
}
void SingleContentElement::moveLeft(FormulaCursor* cursor, BasicElement* from)
{
if (cursor->isSelectionMode()) {
getParent()->moveLeft(cursor, this);
}
else {
//bool linear = cursor->getLinearMovement();
if (from == getParent()) {
content->moveLeft(cursor, this);
}
else {
getParent()->moveLeft(cursor, this);
}
}
}
void SingleContentElement::moveRight(FormulaCursor* cursor, BasicElement* from)
{
if (cursor->isSelectionMode()) {
getParent()->moveRight(cursor, this);
}
else {
//bool linear = cursor->getLinearMovement();
if (from == getParent()) {
content->moveRight(cursor, this);
}
else {
getParent()->moveRight(cursor, this);
}
}
}
void SingleContentElement::moveUp(FormulaCursor* cursor, BasicElement* /*from*/)
{
getParent()->moveUp(cursor, this);
}
void SingleContentElement::moveDown(FormulaCursor* cursor, BasicElement* /*from*/)
{
getParent()->moveDown(cursor, this);
}
void SingleContentElement::remove( FormulaCursor* cursor,
QPtrList<BasicElement>& removedChildren,
Direction direction )
{
switch (cursor->getPos()) {
case contentPos:
BasicElement* parent = getParent();
parent->selectChild(cursor, this);
parent->remove(cursor, removedChildren, direction);
}
}
void SingleContentElement::normalize( FormulaCursor* cursor, Direction direction )
{
if (direction == beforeCursor) {
content->moveLeft(cursor, this);
}
else {
content->moveRight(cursor, this);
}
}
SequenceElement* SingleContentElement::getMainChild()
{
return content;
}
void SingleContentElement::selectChild(FormulaCursor* cursor, BasicElement* child)
{
if (child == content) {
cursor->setTo(this, contentPos);
}
}
void SingleContentElement::writeDom(QDomElement element)
{
BasicElement::writeDom(element);
QDomDocument doc = element.ownerDocument();
QDomElement con = doc.createElement("CONTENT");
con.appendChild(content->getElementDom(doc));
element.appendChild(con);
}
bool SingleContentElement::readContentFromDom(QDomNode& node)
{
if (!BasicElement::readContentFromDom(node)) {
return false;
}
if ( !buildChild( content, node, "CONTENT" ) ) {
kdWarning( DEBUGID ) << "Empty content in " << getTagName() << endl;
return false;
}
node = node.nextSibling();
return true;
}
int SingleContentElement::readContentFromMathMLDom( QDomNode& node )
{
if ( BasicElement::readContentFromMathMLDom( node ) == -1 ) {
return -1;
}
int nodeCounter = content->buildMathMLChild( node );
if ( nodeCounter == -1 ) {
kdWarning( DEBUGID) << "Empty content in SingleContentElement\n";
return -1;
}
return nodeCounter;
}
void SingleContentElement::writeMathMLContent( QDomDocument& doc, QDomElement& element, bool oasisFormat ) const
{
content->writeMathML( doc, element, oasisFormat );
}
BracketElement::BracketElement(SymbolType l, SymbolType r, BasicElement* parent)
: SingleContentElement(parent),
left( 0 ), right( 0 ),
leftType( l ), rightType( r ),
m_operator( false ), m_customLeft( false ), m_customRight( false )
{
}
BracketElement::~BracketElement()
{
delete left;
delete right;
}
BracketElement::BracketElement( const BracketElement& other )
: SingleContentElement( other ),
left( 0 ), right( 0 ),
leftType( other.leftType ), rightType( other.rightType ),
m_operator( other.m_operator ),
m_customLeft( other.m_customLeft ), m_customRight( other.m_customRight )
{
}
bool BracketElement::accept( ElementVisitor* visitor )
{
return visitor->visit( this );
}
void BracketElement::entered( SequenceElement* /*child*/ )
{
formula()->tell( i18n( "Delimited list" ) );
}
BasicElement* BracketElement::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());
e = getContent()->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();
if ((dx > getContent()->getX()+getContent()->getWidth()) ||
(dy > getContent()->getY()+getContent()->getHeight())) {
getContent()->moveEnd(cursor);
handled = true;
return getContent();
}
return this;
}
return 0;
}
/**
* Calculates our width and height and
* our children's parentPosition.
*/
void BracketElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style )
{
SequenceElement* content = getContent();
content->calcSizes( context, tstyle, istyle, style );
//if ( left == 0 ) {
delete left;
delete right;
left = context.fontStyle().createArtwork( leftType );
right = context.fontStyle().createArtwork( rightType );
//}
double factor = style.sizeFactor();
if (content->isTextOnly()) {
left->calcSizes(context, tstyle, factor);
right->calcSizes(context, tstyle, factor);
setBaseline(QMAX(content->getBaseline(),
QMAX(left->getBaseline(), right->getBaseline())));
content->setY(getBaseline() - content->getBaseline());
left ->setY(getBaseline() - left ->getBaseline());
right ->setY(getBaseline() - right ->getBaseline());
//setMidline(content->getY() + content->getMidline());
setHeight(QMAX(content->getY() + content->getHeight(),
QMAX(left ->getY() + left ->getHeight(),
right->getY() + right->getHeight())));
}
else {
//kdDebug( DEBUGID ) << "BracketElement::calcSizes " << content->axis( context, tstyle ) << " " << content->getHeight() << endl;
luPixel contentHeight = 2 * QMAX( content->axis( context, tstyle, factor ),
content->getHeight() - content->axis( context, tstyle, factor ) );
left->calcSizes( context, tstyle, factor, contentHeight );
right->calcSizes( context, tstyle, factor, contentHeight );
// height
setHeight(QMAX(contentHeight,
QMAX(left->getHeight(), right->getHeight())));
//setMidline(getHeight() / 2);
content->setY(getHeight() / 2 - content->axis( context, tstyle, factor ));
setBaseline(content->getBaseline() + content->getY());
if ( left->isNormalChar() ) {
left->setY(getBaseline() - left->getBaseline());
}
else {
left->setY((getHeight() - left->getHeight())/2);
}
if ( right->isNormalChar() ) {
right->setY(getBaseline() - right->getBaseline());
}
else {
right->setY((getHeight() - right->getHeight())/2);
}
// kdDebug() << "BracketElement::calcSizes" << endl
// << "getHeight(): " << getHeight() << endl
// << "left->getHeight(): " << left->getHeight() << endl
// << "right->getHeight(): " << right->getHeight() << endl
// << "left->getY(): " << left->getY() << endl
// << "right->getY(): " << right->getY() << endl
// << endl;
}
// width
setWidth(left->getWidth() + content->getWidth() + right->getWidth());
content->setX(left->getWidth());
right ->setX(left->getWidth()+content->getWidth());
}
/**
* 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 BracketElement::draw( QPainter& 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() );
//if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
// return;
SequenceElement* content = getContent();
content->draw(painter, r, context, tstyle, istyle, style, myPos);
if (content->isTextOnly()) {
left->draw(painter, r, context, tstyle, style, myPos);
right->draw(painter, r, context, tstyle, style, myPos);
}
else {
double factor = style.sizeFactor();
luPixel contentHeight = 2 * QMAX(content->axis( context, tstyle, factor ),
content->getHeight() - content->axis( context, tstyle, factor ));
left->draw(painter, r, context, tstyle, style, contentHeight, myPos);
right->draw(painter, r, context, tstyle, style, contentHeight, myPos);
}
// Debug
#if 0
painter.setBrush( Qt::NoBrush );
painter.setPen( Qt::red );
painter.drawRect( context.layoutUnitToPixelX( myPos.x()+left->getX() ),
context.layoutUnitToPixelY( myPos.y()+left->getY() ),
context.layoutUnitToPixelX( left->getWidth() ),
context.layoutUnitToPixelY( left->getHeight() ) );
painter.drawRect( context.layoutUnitToPixelX( myPos.x()+right->getX() ),
context.layoutUnitToPixelY( myPos.y()+right->getY() ),
context.layoutUnitToPixelX( right->getWidth() ),
context.layoutUnitToPixelY( right->getHeight() ) );
#endif
}
/**
* Appends our attributes to the dom element.
*/
void BracketElement::writeDom(QDomElement element)
{
SingleContentElement::writeDom(element);
element.setAttribute("LEFT", leftType);
element.setAttribute("RIGHT", rightType);
}
/**
* Reads our attributes from the element.
* Returns false if it failed.
*/
bool BracketElement::readAttributesFromDom(QDomElement element)
{
if (!BasicElement::readAttributesFromDom(element)) {
return false;
}
QString leftStr = element.attribute("LEFT");
if(!leftStr.isNull()) {
leftType = static_cast<SymbolType>(leftStr.toInt());
}
QString rightStr = element.attribute("RIGHT");
if(!rightStr.isNull()) {
rightType = static_cast<SymbolType>(rightStr.toInt());
}
return true;
}
/**
* Reads our attributes from the MathML element.
* Returns false if it failed.
*/
bool BracketElement::readAttributesFromMathMLDom(const QDomElement& element)
{
if ( !BasicElement::readAttributesFromMathMLDom( element ) ) {
return false;
}
if ( element.tagName().lower() == "mo" ) {
m_operator = true;
// TODO: parse attributes in section 3.2.5.2
}
else { // mfenced, see attributes in section 3.3.8.2
leftType = LeftRoundBracket;
rightType = RightRoundBracket;
QString openStr = element.attribute( "open" ).stripWhiteSpace();
if ( !openStr.isNull() ) {
m_customLeft = true;
if ( openStr == "[" )
leftType = LeftSquareBracket;
else if ( openStr == "]" )
leftType = RightSquareBracket;
else if ( openStr == "{" )
leftType = LeftCurlyBracket;
else if ( openStr == "}" )
leftType = RightCurlyBracket;
else if ( openStr == "<" )
leftType = LeftCornerBracket;
else if ( openStr == ">" )
leftType = RightCornerBracket;
else if ( openStr == "(" )
leftType = LeftRoundBracket;
else if ( openStr == ")" )
leftType = RightRoundBracket;
else if ( openStr == "/" )
leftType = SlashBracket;
else if ( openStr == "\\" )
leftType = BackSlashBracket;
else // TODO: Check for entity references
leftType = LeftRoundBracket;
}
QString closeStr = element.attribute( "close" ).stripWhiteSpace();
if ( !closeStr.isNull() ) {
m_customRight = true;
if ( closeStr == "[" )
rightType = LeftSquareBracket;
else if ( closeStr == "]" )
rightType = RightSquareBracket;
else if ( closeStr == "{" )
rightType = LeftCurlyBracket;
else if ( closeStr == "}" )
rightType = RightCurlyBracket;
else if ( closeStr == "<" )
rightType = LeftCornerBracket;
else if ( closeStr == ">" )
rightType = RightCornerBracket;
else if ( closeStr == "(" )
rightType = LeftRoundBracket;
else if ( closeStr == ")" )
rightType = RightRoundBracket;
else if ( closeStr == "/" )
rightType = SlashBracket;
else if ( closeStr == "\\" )
rightType = BackSlashBracket;
else // TODO: Check for entity references
rightType = LeftRoundBracket;
}
m_separators = element.attribute( "separators" ).simplifyWhiteSpace();
}
return true;
}
/**
* Reads our content from the MathML node. Sets the node to the next node
* that needs to be read.
* Returns false if it failed.
*/
int BracketElement::readContentFromMathMLDom(QDomNode& node)
{
bool empty = false;
int nodeCounter = 0;
if ( m_operator ) {
node = node.parentNode();
QDomNode open = node;
QDomNode parent = node.parentNode();
if ( ! operatorType( node, true ) )
return -1;
int nodeNum = searchOperator( node );
if ( nodeNum == -1 ) // Closing bracket not found
return -1;
if ( nodeNum == 0 ) { // Empty content
empty = true;
}
else if ( nodeNum == 1 ) {
do {
node = node.nextSibling();
nodeCounter++;
} while ( ! node.isElement() );
}
else { // More than two elements inside, infer a mrow
nodeCounter += nodeNum;
kdWarning() << "NodeNum: " << nodeNum << endl;
QDomDocument doc = node.ownerDocument();
QDomElement de = doc.createElement( "mrow" );
int i = 0;
do {
QDomNode n = node.nextSibling();
de.appendChild( node.toElement() );
node = n;
} while ( ++i < nodeNum );
parent.insertAfter( de, open );
node = de;
kdWarning() << doc.toString() << endl;
}
}
else {
// if it's a mfence tag, we need to convert to equivalent expanded form.
// See section 3.3.8
while ( ! node.isNull() && ! node.isElement() )
node = node.nextSibling();
QDomNode next = node.nextSibling();
while ( ! next.isNull() && ! next.isElement() )
next = next.nextSibling();
if ( ! next.isNull()) {
QDomDocument doc = node.ownerDocument();
QDomNode parent = node.parentNode();
QString ns = parent.prefix();
QDomElement de = doc.createElementNS( ns, "mrow" );
uint pos = 0;
while ( ! node.isNull() ) {
QDomNode no = node.nextSibling();
while ( ! no.isNull() && ! no.isElement() )
no = no.nextSibling();
de.appendChild( node.toElement() );
if ( ! no.isNull() && ( m_separators.isNull() || ! m_separators.isEmpty() ) ) {
QDomElement sep = doc.createElementNS( ns, "mo" );
de.appendChild( sep );
if ( m_separators.isNull() ) {
sep.appendChild( doc.createTextNode( "," ) );
}
else {
if ( m_separators.at( pos ).isSpace() ) {
pos++;
}
sep.appendChild( doc.createTextNode( QString ( m_separators.at( pos ) ) ) );
}
if ( pos < m_separators.length() - 1 ) {
pos++;
}
}
node = no;
}
parent.appendChild( de );
node = parent.firstChild();
while ( ! node.isElement() )
node = node.nextSibling();
}
}
if ( ! empty ) {
int contentNumber = inherited::readContentFromMathMLDom( node );
if ( contentNumber == -1 )
return -1;
nodeCounter += contentNumber;
for (int i = 0; i < contentNumber; i++ ) {
if ( node.isNull() ) {
return -1;
}
node = node.nextSibling();
}
}
if ( m_operator ) {
int operatorNumber = operatorType( node, false );
if ( operatorNumber == -1 ) {
return -1;
}
nodeCounter += operatorNumber;
}
kdDebug( DEBUGID ) << "Number of bracket nodes: " << nodeCounter << endl;
return nodeCounter;
}
QString BracketElement::toLatex()
{
QString ls,rs,cs;
cs=getContent()->toLatex();
ls="\\left"+latexString(leftType) + " ";
rs=" \\right"+latexString(rightType);
return ls+cs+rs;
}
QString BracketElement::latexString(char type)
{
switch (type) {
case ']':
return "]";
case '[':
return "[";
case '{':
return "\\{";
case '}':
return "\\}";
case '(':
return "(";
case ')':
return ")";
case '|':
return "|";
case '<':
return "\\langle";
case '>':
return "\\rangle";
case '/':
return "/";
case '\\':
return "\\backslash";
}
return ".";
}
QString BracketElement::formulaString()
{
return "(" + getContent()->formulaString() + ")";
}
int BracketElement::operatorType( QDomNode& node, bool open )
{
int counter = 1;
SymbolType* type = open ? &leftType : &rightType;
while ( ! node.isNull() && ! node.isElement() ) {
node = node.nextSibling();
counter++;
}
if ( node.isElement() ) {
QDomElement e = node.toElement();
QDomNode child = e.firstChild();
if ( child.isEntityReference() ) {
kdWarning() << "Entity Reference\n";
QString name = node.nodeName();
// TODO: To fully support these, SymbolType has to be extended,
// and better Unicode support is a must
// CloseCurlyDoubleQuote 0x201D
// CloseCurlyQoute 0x2019
// LeftCeiling 0x2308
// LeftDoubleBracket 0x301A
// LeftFloor 0x230A
// OpenCurlyDoubleQuote 0x201C
// OpenCurlyQuote 0x2018
// RightCeiling 0x2309
// RightDoubleBracket 0x301B
// RightFloor 0x230B
if ( name == "LeftAngleBracket" ) {
*type = LeftCornerBracket;
}
else if ( name == "RightAngleBracket" ) {
*type = RightCornerBracket;
}
else {
if ( open ) {
*type = LeftRoundBracket;
}
else
*type = RightRoundBracket;
}
}
else {
QString s = e.text();
if ( s.isNull() )
return -1;
*type = static_cast<SymbolType>( QString::number( s.at( 0 ).latin1() ).toInt() );
}
}
else {
return -1;
}
return counter;
}
int BracketElement::searchOperator( const QDomNode& node )
{
QDomNode n = node;
for ( int i = -2; ! n.isNull(); n = n.nextSibling() ) {
if ( n.isElement() ) {
i++;
QDomElement e = n.toElement();
if ( e.tagName().lower() == "mo" ) {
// Try to guess looking at attributes
QString form = e.attribute( "form" );
QString f;
if ( ! form.isNull() ) {
f = form.stripWhiteSpace().lower();
}
QString fence = e.attribute( "fence" );
if ( ! fence.isNull() ) {
if ( fence.stripWhiteSpace().lower() == "false" ) {
continue;
}
if ( ! f.isNull() ) {
if ( f == "postfix" ) {
return i;
}
else {
continue;
}
}
}
// Guess looking at contents
QDomNode child = e.firstChild();
QString name;
if ( child.isText() )
name = child.toText().data().stripWhiteSpace();
else if ( child.isEntityReference() )
name = child.nodeName();
else
continue;
if ( name == ")"
|| name == "]"
|| name == "}"
|| name == "CloseCurlyDoubleQuote"
|| name == "CloseCurlyQuote"
|| name == "RightAngleBracket"
|| name == "RightCeiling"
|| name == "RightDoubleBracket"
|| name == "RightFloor" ) {
if ( f.isNull() || f == "postfix" )
return i;
}
if ( name == "("
|| name == "["
|| name == "{"
|| name == "LeftAngleBracket"
|| name == "LeftCeiling"
|| name == "LeftDoubleBracket"
|| name == "LeftFloor"
|| name == "OpenCurlyQuote" ) {
if ( ! f.isNull() && f == "postfix" )
return i;
}
}
}
}
return -1;
}
void BracketElement::writeMathMLAttributes( QDomElement& element ) const
{
if ( left->getType() != LeftRoundBracket ||
right->getType() != RightRoundBracket )
{
element.setAttribute( "open", QString( QChar( leftType ) ) );
element.setAttribute( "close", QString( QChar( rightType ) ) );
}
if ( ! m_separators.isNull() ) {
element.setAttribute( "separators", m_separators );
}
}
OverlineElement::OverlineElement( BasicElement* parent )
: SingleContentElement( parent )
{
}
OverlineElement::~OverlineElement()
{
}
OverlineElement::OverlineElement( const OverlineElement& other )
: SingleContentElement( other )
{
}
bool OverlineElement::accept( ElementVisitor* visitor )
{
return visitor->visit( this );
}
void OverlineElement::entered( SequenceElement* /*child*/ )
{
formula()->tell( i18n( "Overline" ) );
}
void OverlineElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style )
{
SequenceElement* content = getContent();
content->calcSizes(context, tstyle,
context.convertIndexStyleLower(istyle), style );
//luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, style.sizeFactor() ) );
luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, style.sizeFactor() ) );
//luPixel unit = (content->getHeight() + distY)/ 3;
setWidth( content->getWidth() );
setHeight( content->getHeight() + distY );
content->setX( 0 );
content->setY( distY );
setBaseline(content->getBaseline() + content->getY());
}
void OverlineElement::draw( QPainter& 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() );
//if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
// return;
SequenceElement* content = getContent();
content->draw( painter, r, context, tstyle,
context.convertIndexStyleLower( istyle ), style, myPos );
luPixel x = myPos.x();
luPixel y = myPos.y();
//int distX = context.getDistanceX(tstyle);
double factor = style.sizeFactor();
luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
//luPixel unit = (content->getHeight() + distY)/ 3;
painter.setPen( QPen( context.getDefaultColor(),
context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
painter.drawLine( context.layoutUnitToPixelX( x ),
context.layoutUnitToPixelY( y+distY/3 ),
context.layoutUnitToPixelX( x+content->getWidth() ),
context.layoutUnitToPixelY( y+distY/3 ) );
}
QString OverlineElement::toLatex()
{
return "\\overline{" + getContent()->toLatex() + "}";
}
QString OverlineElement::formulaString()
{
return getContent()->formulaString();
}
void OverlineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
{
QDomElement de = doc.createElement( oasisFormat ? "math:mover" : "mover" );
SingleContentElement::writeMathML( doc, de, oasisFormat );
QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
// is this the right entity? Mozilla renders it correctly.
op.appendChild( doc.createEntityReference( "OverBar" ) );
de.appendChild( op );
parent.appendChild( de );
}
UnderlineElement::UnderlineElement( BasicElement* parent )
: SingleContentElement( parent )
{
}
UnderlineElement::~UnderlineElement()
{
}
UnderlineElement::UnderlineElement( const UnderlineElement& other )
: SingleContentElement( other )
{
}
bool UnderlineElement::accept( ElementVisitor* visitor )
{
return visitor->visit( this );
}
void UnderlineElement::entered( SequenceElement* /*child*/ )
{
formula()->tell( i18n( "Underline" ) );
}
void UnderlineElement::calcSizes( const ContextStyle& context,
ContextStyle::TextStyle tstyle,
ContextStyle::IndexStyle istyle,
StyleAttributes& style )
{
SequenceElement* content = getContent();
double factor = style.sizeFactor();
content->calcSizes(context, tstyle,
context.convertIndexStyleLower(istyle), style );
//luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle ) );
luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
//luPixel unit = (content->getHeight() + distY)/ 3;
setWidth( content->getWidth() );
setHeight( content->getHeight() + distY );
content->setX( 0 );
content->setY( 0 );
setBaseline(content->getBaseline() + content->getY());
}
void UnderlineElement::draw( QPainter& 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() );
//if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
// return;
SequenceElement* content = getContent();
content->draw( painter, r, context, tstyle,
context.convertIndexStyleLower( istyle ), style, myPos );
luPixel x = myPos.x();
luPixel y = myPos.y();
//int distX = context.getDistanceX(tstyle);
//luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle ) );
//luPixel unit = (content->getHeight() + distY)/ 3;
double factor = style.sizeFactor();
painter.setPen( QPen( context.getDefaultColor(),
context.layoutUnitToPixelY( context.getLineWidth( factor ) ) ) );
painter.drawLine( context.layoutUnitToPixelX( x ),
context.layoutUnitToPixelY( y+getHeight()-context.getLineWidth( factor ) ),
context.layoutUnitToPixelX( x+content->getWidth() ),
context.layoutUnitToPixelY( y+getHeight()-context.getLineWidth( factor ) ) );
}
QString UnderlineElement::toLatex()
{
return "\\underline{" + getContent()->toLatex() + "}";
}
QString UnderlineElement::formulaString()
{
return getContent()->formulaString();
}
void UnderlineElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
{
QDomElement de = doc.createElement( oasisFormat ? "math:munder" : "munder" );
SingleContentElement::writeMathML( doc, de, oasisFormat );
QDomElement op = doc.createElement( oasisFormat ? "math:mo" : "mo" );
// is this the right entity? Mozilla renders it correctly.
op.appendChild( doc.createEntityReference( "UnderBar" ) );
de.appendChild( op );
parent.appendChild( de );
}
KFORMULA_NAMESPACE_END