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.
907 lines
25 KiB
907 lines
25 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 <qpainter.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include "elementvisitor.h"
|
|
#include "formulacursor.h"
|
|
#include "formulaelement.h"
|
|
#include "kformulacommand.h"
|
|
#include "sequenceelement.h"
|
|
#include "symbolelement.h"
|
|
|
|
KFORMULA_NAMESPACE_BEGIN
|
|
|
|
|
|
class SymbolSequenceElement : public SequenceElement {
|
|
typedef SequenceElement inherited;
|
|
public:
|
|
|
|
SymbolSequenceElement( BasicElement* parent = 0 ) : SequenceElement( parent ) {}
|
|
|
|
/**
|
|
* 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* );
|
|
};
|
|
|
|
|
|
KCommand* SymbolSequenceElement::buildCommand( Container* container, Request* request )
|
|
{
|
|
FormulaCursor* cursor = container->activeCursor();
|
|
if ( cursor->isReadOnly() ) {
|
|
return 0;
|
|
}
|
|
|
|
switch ( *request ) {
|
|
case req_addIndex: {
|
|
FormulaCursor* cursor = container->activeCursor();
|
|
if ( cursor->isSelection() ||
|
|
( cursor->getPos() > 0 && cursor->getPos() < countChildren() ) ) {
|
|
break;
|
|
}
|
|
IndexRequest* ir = static_cast<IndexRequest*>( request );
|
|
if ( ( ir->index() == upperMiddlePos ) || ( ir->index() == lowerMiddlePos ) ) {
|
|
SymbolElement* element = static_cast<SymbolElement*>( getParent() );
|
|
ElementIndexPtr index = element->getIndex( ir->index() );
|
|
if ( !index->hasIndex() ) {
|
|
KFCAddGenericIndex* command = new KFCAddGenericIndex( container, index );
|
|
return command;
|
|
}
|
|
else {
|
|
index->moveToIndex( cursor, afterCursor );
|
|
cursor->setSelection( false );
|
|
formula()->cursorHasMoved( cursor );
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
return inherited::buildCommand( container, request );
|
|
}
|
|
|
|
|
|
SymbolElement::SymbolElement(SymbolType type, BasicElement* parent)
|
|
: BasicElement(parent), symbol( 0 ), symbolType( type )
|
|
{
|
|
content = new SymbolSequenceElement( this );
|
|
upper = 0;
|
|
lower = 0;
|
|
}
|
|
|
|
SymbolElement::~SymbolElement()
|
|
{
|
|
delete lower;
|
|
delete upper;
|
|
delete content;
|
|
delete symbol;
|
|
}
|
|
|
|
|
|
SymbolElement::SymbolElement( const SymbolElement& other )
|
|
: BasicElement( other ), symbol( 0 ), symbolType( other.symbolType )
|
|
{
|
|
content = new SymbolSequenceElement( *dynamic_cast<SymbolSequenceElement*>( other.content ) );
|
|
content->setParent( this );
|
|
|
|
if ( other.upper ) {
|
|
upper = new SequenceElement( *( other.upper ) );
|
|
upper->setParent( this );
|
|
}
|
|
else {
|
|
upper = 0;
|
|
}
|
|
if ( other.lower ) {
|
|
lower = new SequenceElement( *( other.lower ) );
|
|
lower->setParent( this );
|
|
}
|
|
else {
|
|
lower = 0;
|
|
}
|
|
}
|
|
|
|
|
|
bool SymbolElement::accept( ElementVisitor* visitor )
|
|
{
|
|
return visitor->visit( this );
|
|
}
|
|
|
|
|
|
BasicElement* SymbolElement::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;
|
|
}
|
|
if (hasLower()) {
|
|
e = lower->goToPos(cursor, handled, point, myPos);
|
|
if (e != 0) {
|
|
return e;
|
|
}
|
|
}
|
|
if (hasUpper()) {
|
|
e = upper->goToPos(cursor, handled, point, myPos);
|
|
if (e != 0) {
|
|
return e;
|
|
}
|
|
}
|
|
|
|
// the positions after the indexes.
|
|
luPixel dx = point.x() - myPos.x();
|
|
luPixel dy = point.y() - myPos.y();
|
|
if (dy < symbol->getY()) {
|
|
if (hasUpper() && (dx > upper->getX())) {
|
|
upper->moveLeft(cursor, this);
|
|
handled = true;
|
|
return upper;
|
|
}
|
|
}
|
|
else if (dy > symbol->getY()+symbol->getHeight()) {
|
|
if (hasLower() && (dx > lower->getX())) {
|
|
lower->moveLeft(cursor, this);
|
|
handled = true;
|
|
return lower;
|
|
}
|
|
}
|
|
|
|
// Have the cursor jump behind the integral.
|
|
if ( ( dx < symbol->getX()+symbol->getWidth() ) &&
|
|
( dx > symbol->getX()+symbol->getWidth()/2 ) ) {
|
|
content->moveRight( cursor, this );
|
|
handled = true;
|
|
return content;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* Calculates our width and height and
|
|
* our children's parentPosition.
|
|
*/
|
|
void SymbolElement::calcSizes( const ContextStyle& context,
|
|
ContextStyle::TextStyle tstyle,
|
|
ContextStyle::IndexStyle istyle,
|
|
StyleAttributes& style )
|
|
{
|
|
double factor = style.sizeFactor();
|
|
luPt mySize = context.getAdjustedSize( tstyle, factor );
|
|
luPixel distX = context.ptToPixelX( context.getThinSpace( tstyle, factor ) );
|
|
luPixel distY = context.ptToPixelY( context.getThinSpace( tstyle, factor ) );
|
|
|
|
//if ( symbol == 0 ) {
|
|
delete symbol;
|
|
symbol = context.fontStyle().createArtwork( symbolType );
|
|
//}
|
|
|
|
symbol->calcSizes(context, tstyle, factor, mySize);
|
|
content->calcSizes( context, tstyle, istyle, style );
|
|
|
|
//symbol->scale(((double)parentSize)/symbol->getHeight()*2);
|
|
|
|
luPixel upperWidth = 0;
|
|
luPixel upperHeight = 0;
|
|
if (hasUpper()) {
|
|
upper->calcSizes( context, context.convertTextStyleIndex( tstyle ),
|
|
context.convertIndexStyleUpper( istyle ), style );
|
|
upperWidth = upper->getWidth();
|
|
upperHeight = upper->getHeight() + distY;
|
|
}
|
|
|
|
luPixel lowerWidth = 0;
|
|
luPixel lowerHeight = 0;
|
|
if (hasLower()) {
|
|
lower->calcSizes( context, context.convertTextStyleIndex( tstyle ),
|
|
context.convertIndexStyleLower( istyle ), style );
|
|
lowerWidth = lower->getWidth();
|
|
lowerHeight = lower->getHeight() + distY;
|
|
}
|
|
|
|
// widths
|
|
luPixel xOffset = QMAX(symbol->getWidth(), QMAX(upperWidth, lowerWidth));
|
|
if (context.getCenterSymbol()) {
|
|
symbol->setX((xOffset - symbol->getWidth()) / 2);
|
|
}
|
|
else {
|
|
symbol->setX(xOffset - symbol->getWidth());
|
|
}
|
|
// ???
|
|
content->setX(xOffset +
|
|
static_cast<luPixel>( symbol->slant()*symbol->getHeight()/2 ) +
|
|
distX/2);
|
|
|
|
setWidth(QMAX(content->getX() + content->getWidth(),
|
|
QMAX(upperWidth, lowerWidth)));
|
|
|
|
// heights
|
|
//int toMidline = QMAX(content->getHeight() / 2,
|
|
luPixel toMidline = QMAX(content->axis( context, tstyle, factor ),
|
|
upperHeight + symbol->getHeight()/2);
|
|
//int fromMidline = QMAX(content->getHeight() / 2,
|
|
luPixel fromMidline = QMAX(content->getHeight() - content->axis( context, tstyle, factor ),
|
|
lowerHeight + symbol->getHeight()/2);
|
|
setHeight(toMidline + fromMidline);
|
|
//setMidline(toMidline);
|
|
|
|
symbol->setY(toMidline - symbol->getHeight()/2);
|
|
//content->setY(toMidline - content->getHeight()/2);
|
|
content->setY(toMidline - content->axis( context, tstyle, factor ));
|
|
|
|
if (hasUpper()) {
|
|
luPixel slant =
|
|
static_cast<luPixel>( symbol->slant()*( symbol->getHeight()+distY ) );
|
|
if (context.getCenterSymbol()) {
|
|
upper->setX((xOffset - upperWidth) / 2 + slant );
|
|
}
|
|
else {
|
|
if (upperWidth < symbol->getWidth()) {
|
|
upper->setX(symbol->getX() +
|
|
(symbol->getWidth() - upperWidth) / 2 + slant );
|
|
}
|
|
else {
|
|
upper->setX(xOffset - upperWidth);
|
|
}
|
|
}
|
|
upper->setY(toMidline - upperHeight - symbol->getHeight()/2);
|
|
}
|
|
if (hasLower()) {
|
|
luPixel slant = static_cast<luPixel>( -symbol->slant()*distY );
|
|
if (context.getCenterSymbol()) {
|
|
lower->setX((xOffset - lowerWidth) / 2 + slant);
|
|
}
|
|
else {
|
|
if (lowerWidth < symbol->getWidth()) {
|
|
lower->setX(symbol->getX() +
|
|
(symbol->getWidth() - lowerWidth) / 2 + slant );
|
|
}
|
|
else {
|
|
lower->setX(xOffset - lowerWidth);
|
|
}
|
|
}
|
|
lower->setY(toMidline + symbol->getHeight()/2 + distY);
|
|
}
|
|
setBaseline(content->getBaseline() + content->getY());
|
|
}
|
|
|
|
/**
|
|
* 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 SymbolElement::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;
|
|
|
|
luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
|
|
symbol->draw( painter, r, context, tstyle, style, mySize, myPos );
|
|
content->draw( painter, r, context, tstyle, istyle, style, myPos );
|
|
if ( hasUpper() ) {
|
|
upper->draw( painter, r, context, context.convertTextStyleIndex( tstyle ),
|
|
context.convertIndexStyleUpper( istyle ), style, myPos );
|
|
}
|
|
if ( hasLower() ) {
|
|
lower->draw( painter, r, context, context.convertTextStyleIndex( tstyle ),
|
|
context.convertIndexStyleLower( istyle ), style, myPos );
|
|
}
|
|
|
|
// Debug
|
|
#if 0
|
|
painter.setBrush(Qt::NoBrush);
|
|
painter.setPen(Qt::red);
|
|
// painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
|
|
// context.layoutUnitToPixelY( myPos.y() ),
|
|
// context.layoutUnitToPixelX( getWidth() ),
|
|
// context.layoutUnitToPixelY( getHeight() ) );
|
|
painter.drawRect( context.layoutUnitToPixelX( myPos.x()+symbol->getX() ),
|
|
context.layoutUnitToPixelY( myPos.y()+symbol->getY() ),
|
|
context.layoutUnitToPixelX( symbol->getWidth() ),
|
|
context.layoutUnitToPixelY( symbol->getHeight() ) );
|
|
painter.setPen(Qt::green);
|
|
painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
|
|
context.layoutUnitToPixelY( myPos.y()+axis(context, tstyle) ),
|
|
context.layoutUnitToPixelX( myPos.x()+getWidth() ),
|
|
context.layoutUnitToPixelY( myPos.y()+axis(context, tstyle) ) );
|
|
#endif
|
|
}
|
|
|
|
|
|
void SymbolElement::dispatchFontCommand( FontCommand* cmd )
|
|
{
|
|
content->dispatchFontCommand( cmd );
|
|
if ( hasUpper() ) {
|
|
upper->dispatchFontCommand( cmd );
|
|
}
|
|
if ( hasLower() ) {
|
|
lower->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 SymbolElement::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 if (from == content) {
|
|
if (linear && hasLower()) {
|
|
lower->moveLeft(cursor, this);
|
|
}
|
|
else if (linear && hasUpper()) {
|
|
upper->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
getParent()->moveLeft(cursor, this);
|
|
}
|
|
}
|
|
else if (from == lower) {
|
|
if (linear && hasUpper()) {
|
|
upper->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
getParent()->moveLeft(cursor, this);
|
|
}
|
|
}
|
|
else if (from == upper) {
|
|
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 SymbolElement::moveRight(FormulaCursor* cursor, BasicElement* from)
|
|
{
|
|
if (cursor->isSelectionMode()) {
|
|
getParent()->moveRight(cursor, this);
|
|
}
|
|
else {
|
|
bool linear = cursor->getLinearMovement();
|
|
if (from == getParent()) {
|
|
if (linear && hasUpper()) {
|
|
upper->moveRight(cursor, this);
|
|
}
|
|
else if (linear && hasLower()) {
|
|
lower->moveRight(cursor, this);
|
|
}
|
|
else {
|
|
content->moveRight(cursor, this);
|
|
}
|
|
}
|
|
else if (from == upper) {
|
|
if (linear && hasLower()) {
|
|
lower->moveRight(cursor, this);
|
|
}
|
|
else {
|
|
content->moveRight(cursor, this);
|
|
}
|
|
}
|
|
else if (from == lower) {
|
|
content->moveRight(cursor, this);
|
|
}
|
|
else if (from == content) {
|
|
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 SymbolElement::moveUp(FormulaCursor* cursor, BasicElement* from)
|
|
{
|
|
if (cursor->isSelectionMode()) {
|
|
getParent()->moveUp(cursor, this);
|
|
}
|
|
else {
|
|
if (from == content) {
|
|
if (hasUpper()) {
|
|
upper->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
getParent()->moveUp(cursor, this);
|
|
}
|
|
}
|
|
else if (from == upper) {
|
|
getParent()->moveUp(cursor, this);
|
|
}
|
|
else if ((from == getParent()) || (from == lower)) {
|
|
content->moveRight(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 SymbolElement::moveDown(FormulaCursor* cursor, BasicElement* from)
|
|
{
|
|
if (cursor->isSelectionMode()) {
|
|
getParent()->moveDown(cursor, this);
|
|
}
|
|
else {
|
|
if (from == content) {
|
|
if (hasLower()) {
|
|
lower->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
getParent()->moveDown(cursor, this);
|
|
}
|
|
}
|
|
else if (from == lower) {
|
|
getParent()->moveDown(cursor, this);
|
|
}
|
|
else if ((from == getParent()) || (from == upper)) {
|
|
content->moveRight(cursor, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
// children
|
|
|
|
// main child
|
|
//
|
|
// If an element has children one has to become the main one.
|
|
|
|
// void SymbolElement::setMainChild(SequenceElement* child)
|
|
// {
|
|
// formula()->elementRemoval(content);
|
|
// content = child;
|
|
// content->setParent(this);
|
|
// formula()->changed();
|
|
// }
|
|
|
|
|
|
/**
|
|
* Inserts all new children at the cursor position. Places the
|
|
* cursor according to the direction.
|
|
*
|
|
* You only can insert one index at a time. So the list must contain
|
|
* exactly on SequenceElement. And the index you want to insert
|
|
* must not exist already.
|
|
*
|
|
* The list will be emptied but stays the property of the caller.
|
|
*/
|
|
void SymbolElement::insert(FormulaCursor* cursor,
|
|
QPtrList<BasicElement>& newChildren,
|
|
Direction direction)
|
|
{
|
|
SequenceElement* index = static_cast<SequenceElement*>(newChildren.take(0));
|
|
index->setParent(this);
|
|
|
|
switch (cursor->getPos()) {
|
|
case upperMiddlePos:
|
|
upper = index;
|
|
break;
|
|
case lowerMiddlePos:
|
|
lower = index;
|
|
break;
|
|
default:
|
|
// this is an error!
|
|
return;
|
|
}
|
|
|
|
if (direction == beforeCursor) {
|
|
index->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
index->moveRight(cursor, this);
|
|
}
|
|
cursor->setSelection(false);
|
|
formula()->changed();
|
|
}
|
|
|
|
/**
|
|
* Removes all selected children and returns them. Places the
|
|
* cursor to where the children have been.
|
|
*
|
|
* The cursor has to be inside one of our indexes which is supposed
|
|
* to be empty. The index will be removed and the cursor will
|
|
* be placed to the removed index so it can be inserted again.
|
|
* This methode is called by SequenceElement::remove only.
|
|
*
|
|
* The ownership of the list is passed to the caller.
|
|
*/
|
|
void SymbolElement::remove(FormulaCursor* cursor,
|
|
QPtrList<BasicElement>& removedChildren,
|
|
Direction direction)
|
|
{
|
|
int pos = cursor->getPos();
|
|
switch (pos) {
|
|
case upperMiddlePos:
|
|
removedChildren.append(upper);
|
|
formula()->elementRemoval(upper);
|
|
upper = 0;
|
|
setToUpper(cursor);
|
|
break;
|
|
case lowerMiddlePos:
|
|
removedChildren.append(lower);
|
|
formula()->elementRemoval(lower);
|
|
lower = 0;
|
|
setToLower(cursor);
|
|
break;
|
|
case contentPos: {
|
|
BasicElement* parent = getParent();
|
|
parent->selectChild(cursor, this);
|
|
parent->remove(cursor, removedChildren, direction);
|
|
break;
|
|
}
|
|
}
|
|
formula()->changed();
|
|
}
|
|
|
|
/**
|
|
* Moves the cursor to a normal place where new elements
|
|
* might be inserted.
|
|
*/
|
|
void SymbolElement::normalize(FormulaCursor* cursor, Direction direction)
|
|
{
|
|
if (direction == beforeCursor) {
|
|
content->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
content->moveRight(cursor, this);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the child at the cursor.
|
|
*/
|
|
BasicElement* SymbolElement::getChild(FormulaCursor* cursor, Direction)
|
|
{
|
|
int pos = cursor->getPos();
|
|
switch (pos) {
|
|
case contentPos:
|
|
return content;
|
|
case upperMiddlePos:
|
|
return upper;
|
|
case lowerMiddlePos:
|
|
return lower;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Sets the cursor to select the child. The mark is placed before,
|
|
* the position behind it.
|
|
*/
|
|
void SymbolElement::selectChild(FormulaCursor* cursor, BasicElement* child)
|
|
{
|
|
if (child == content) {
|
|
setToContent(cursor);
|
|
}
|
|
else if (child == upper) {
|
|
setToUpper(cursor);
|
|
}
|
|
else if (child == lower) {
|
|
setToLower(cursor);
|
|
}
|
|
}
|
|
|
|
void SymbolElement::setToUpper(FormulaCursor* cursor)
|
|
{
|
|
cursor->setTo(this, upperMiddlePos);
|
|
}
|
|
|
|
void SymbolElement::setToLower(FormulaCursor* cursor)
|
|
{
|
|
cursor->setTo(this, lowerMiddlePos);
|
|
}
|
|
|
|
/**
|
|
* Sets the cursor to point to the place where the content is.
|
|
* There always is a content so this is not a useful place.
|
|
* No insertion or removal will succeed as long as the cursor is
|
|
* there.
|
|
*/
|
|
void SymbolElement::setToContent(FormulaCursor* cursor)
|
|
{
|
|
cursor->setTo(this, contentPos);
|
|
}
|
|
|
|
|
|
void SymbolElement::moveToUpper(FormulaCursor* cursor, Direction direction)
|
|
{
|
|
if (hasUpper()) {
|
|
if (direction == beforeCursor) {
|
|
upper->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
upper->moveRight(cursor, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
void SymbolElement::moveToLower(FormulaCursor* cursor, Direction direction)
|
|
{
|
|
if (hasLower()) {
|
|
if (direction == beforeCursor) {
|
|
lower->moveLeft(cursor, this);
|
|
}
|
|
else {
|
|
lower->moveRight(cursor, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ElementIndexPtr SymbolElement::getIndex( int position )
|
|
{
|
|
switch ( position ) {
|
|
case lowerMiddlePos:
|
|
return getLowerIndex();
|
|
case upperMiddlePos:
|
|
return getUpperIndex();
|
|
}
|
|
return getUpperIndex();
|
|
}
|
|
|
|
|
|
/**
|
|
* Appends our attributes to the dom element.
|
|
*/
|
|
void SymbolElement::writeDom(QDomElement element)
|
|
{
|
|
BasicElement::writeDom(element);
|
|
|
|
element.setAttribute("TYPE", symbolType);
|
|
|
|
QDomDocument doc = element.ownerDocument();
|
|
|
|
QDomElement con = doc.createElement("CONTENT");
|
|
con.appendChild(content->getElementDom(doc));
|
|
element.appendChild(con);
|
|
|
|
if(hasLower()) {
|
|
QDomElement ind = doc.createElement("LOWER");
|
|
ind.appendChild(lower->getElementDom(doc));
|
|
element.appendChild(ind);
|
|
}
|
|
if(hasUpper()) {
|
|
QDomElement ind = doc.createElement("UPPER");
|
|
ind.appendChild(upper->getElementDom(doc));
|
|
element.appendChild(ind);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reads our attributes from the element.
|
|
* Returns false if it failed.
|
|
*/
|
|
bool SymbolElement::readAttributesFromDom(QDomElement element)
|
|
{
|
|
if (!BasicElement::readAttributesFromDom(element)) {
|
|
return false;
|
|
}
|
|
|
|
QString typeStr = element.attribute("TYPE");
|
|
if(!typeStr.isNull()) {
|
|
symbolType = static_cast<SymbolType>(typeStr.toInt());
|
|
}
|
|
|
|
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 SymbolElement::readContentFromDom(QDomNode& node)
|
|
{
|
|
if (!BasicElement::readContentFromDom(node)) {
|
|
return false;
|
|
}
|
|
|
|
if ( !buildChild( content, node, "CONTENT" ) ) {
|
|
kdWarning( DEBUGID ) << "Empty content in SymbolElement." << endl;
|
|
return false;
|
|
}
|
|
node = node.nextSibling();
|
|
|
|
bool lowerRead = false;
|
|
bool upperRead = false;
|
|
|
|
while (!node.isNull() && !(upperRead && lowerRead)) {
|
|
|
|
if (!lowerRead && (node.nodeName().upper() == "LOWER")) {
|
|
lowerRead = buildChild( lower=new SequenceElement( this ), node, "LOWER" );
|
|
if ( !lowerRead ) return false;
|
|
}
|
|
|
|
if (!upperRead && (node.nodeName().upper() == "UPPER")) {
|
|
upperRead = buildChild( upper=new SequenceElement( this ), node, "UPPER" );
|
|
if ( !upperRead ) return false;
|
|
}
|
|
|
|
node = node.nextSibling();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
QString SymbolElement::toLatex()
|
|
{
|
|
QString sym;
|
|
|
|
switch(symbolType) {
|
|
|
|
case 1001:
|
|
sym="\\int";
|
|
break;
|
|
case 1002:
|
|
sym="\\sum";
|
|
break;
|
|
case 1003:
|
|
sym="\\prod";
|
|
break;
|
|
|
|
default:
|
|
sym=" ";
|
|
|
|
}
|
|
|
|
|
|
if(hasLower()) {
|
|
sym+="_{";
|
|
sym+=lower->toLatex();
|
|
sym+="}";
|
|
}
|
|
|
|
if(hasUpper()) {
|
|
sym+="^{";
|
|
sym+=upper->toLatex();
|
|
sym+="} ";
|
|
}
|
|
|
|
sym += " ";
|
|
|
|
sym+=content->toLatex();
|
|
|
|
|
|
return sym;
|
|
}
|
|
|
|
QString SymbolElement::formulaString()
|
|
{
|
|
QString sym;
|
|
switch ( symbolType ) {
|
|
case 1001:
|
|
sym="int(";
|
|
break;
|
|
case 1002:
|
|
sym="sum(";
|
|
break;
|
|
case 1003:
|
|
sym="prod(";
|
|
break;
|
|
default:
|
|
sym="(";
|
|
}
|
|
sym += content->formulaString();
|
|
if ( hasLower() ) {
|
|
sym += ", " + lower->formulaString();
|
|
}
|
|
if ( hasUpper() ) {
|
|
sym += ", " + upper->formulaString();
|
|
}
|
|
return sym + ")";
|
|
}
|
|
|
|
void SymbolElement::writeMathML( QDomDocument& doc, QDomNode& parent, bool oasisFormat ) const
|
|
{
|
|
QDomElement de = doc.createElement( oasisFormat ? "math:mrow" : "mrow" );
|
|
QDomElement mo = doc.createElement( oasisFormat ? "math:mo" : "mo" );
|
|
|
|
QString value;
|
|
|
|
switch( symbolType )
|
|
{
|
|
case EmptyBracket: break;
|
|
case LeftLineBracket: case RightLineBracket:
|
|
mo.appendChild( doc.createTextNode( "|" ) ); break;
|
|
case Integral:
|
|
mo.appendChild( doc.createEntityReference( "int" ) ); break;
|
|
case Sum:
|
|
mo.appendChild( doc.createEntityReference( "sum" ) ); break;
|
|
case Product:
|
|
mo.appendChild( doc.createEntityReference( "prod" ) ); break;
|
|
default:
|
|
mo.appendChild( doc.createTextNode( QChar( symbolType ) ) );
|
|
}
|
|
|
|
QDomElement between;
|
|
if ( hasUpper() && hasLower() )
|
|
{
|
|
between = doc.createElement( oasisFormat ? "math:msubsup" : "msubsup" );
|
|
between.appendChild( mo );
|
|
lower->writeMathML( doc, between, oasisFormat );
|
|
upper->writeMathML( doc, between, oasisFormat );
|
|
}
|
|
else if ( hasUpper() )
|
|
{
|
|
between = doc.createElement( oasisFormat ? "math:msup" : "msup" );
|
|
between.appendChild( mo );
|
|
upper->writeMathML( doc, between, oasisFormat );
|
|
}
|
|
else if ( hasLower() )
|
|
{
|
|
between = doc.createElement( oasisFormat ? "math:msub" : "msub" );
|
|
between.appendChild( mo );
|
|
lower->writeMathML( doc, between, oasisFormat );
|
|
}
|
|
else
|
|
between = mo;
|
|
|
|
de.appendChild( between );
|
|
content->writeMathML( doc, de, oasisFormat );
|
|
|
|
parent.appendChild( de );
|
|
}
|
|
|
|
KFORMULA_NAMESPACE_END
|