summaryrefslogtreecommitdiffstats
path: root/lib/kformula/textelement.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kformula/textelement.cpp')
-rw-r--r--lib/kformula/textelement.cpp567
1 files changed, 567 insertions, 0 deletions
diff --git a/lib/kformula/textelement.cpp b/lib/kformula/textelement.cpp
new file mode 100644
index 00000000..7f146b49
--- /dev/null
+++ b/lib/kformula/textelement.cpp
@@ -0,0 +1,567 @@
+/* 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 <tqfontmetrics.h>
+#include <tqpainter.h>
+
+#include <kdebug.h>
+
+#include "basicelement.h"
+#include "contextstyle.h"
+#include "elementtype.h"
+#include "elementvisitor.h"
+#include "fontstyle.h"
+#include "formulaelement.h"
+#include "kformulacommand.h"
+#include "sequenceelement.h"
+#include "symboltable.h"
+#include "textelement.h"
+
+
+KFORMULA_NAMESPACE_BEGIN
+
+TextElement::TextElement(TQChar ch, bool beSymbol, BasicElement* parent)
+ : BasicElement(parent), character(ch), symbol(beSymbol)
+{
+ charStyle( anyChar );
+ charFamily( anyFamily );
+}
+
+
+TextElement::TextElement( const TextElement& other )
+ : BasicElement( other ),
+ character( other.character ),
+ symbol( other.symbol ),
+ m_format( other.m_format )
+{
+}
+
+
+bool TextElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+TokenType TextElement::getTokenType() const
+{
+ if ( isSymbol() ) {
+ return getSymbolTable().charClass( character );
+ }
+
+ switch ( character.unicode() ) {
+ case '+':
+ case '-':
+ case '*':
+ //case '/': because it counts as text -- no extra spaces
+ return BINOP;
+ case '=':
+ case '<':
+ case '>':
+ return RELATION;
+ case ',':
+ case ';':
+ case ':':
+ return PUNCTUATION;
+ case '\\':
+ return SEPARATOR;
+ case '\0':
+ return ELEMENT;
+ default:
+ if ( character.isNumber() ) {
+ return NUMBER;
+ }
+ else {
+ return ORDINARY;
+ }
+ }
+}
+
+
+bool TextElement::isInvisible() const
+{
+ if (getElementType() != 0) {
+ return getElementType()->isInvisible(*this);
+ }
+ return false;
+}
+
+
+/**
+ * Calculates our width and height and
+ * our children's parentPosition.
+ */
+void TextElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style )
+{
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+
+ setCharStyle( style.charStyle() );
+ setCharFamily( style.charFamily() );
+
+ TQFont font = getFont( context, style );
+ double fontsize = context.layoutUnitPtToPt( mySize );
+ double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
+ double size = fontsize * scriptsize;
+ font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
+
+ TQFontMetrics fm( font );
+ if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
+ setWidth( 0 );
+ setHeight( 0 );
+ setBaseline( getHeight() );
+ }
+ else {
+ TQChar ch = getRealCharacter(context);
+ if ( ch == TQChar::null ) {
+ setWidth( tqRound( context.getEmptyRectWidth( factor ) * 2./3. ) );
+ setHeight( tqRound( context.getEmptyRectHeight( factor ) * 2./3. ) );
+ setBaseline( getHeight() );
+ }
+ else {
+ TQRect bound = fm.boundingRect( ch );
+ setWidth( context.ptToLayoutUnitPt( fm.width( ch ) ) );
+ setHeight( context.ptToLayoutUnitPt( bound.height() ) );
+ setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
+
+ // There are some glyphs in TeX that have
+ // baseline==0. (\int, \sum, \prod)
+ if ( getBaseline() == 0 ) {
+ //setBaseline( getHeight()/2 + context.axisHeight( tstyle ) );
+ setBaseline( -1 );
+ }
+ }
+ }
+}
+
+/**
+ * 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 TextElement::draw( TQPainter& painter, const LuPixelRect& /*r*/,
+ const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style,
+ const LuPixelPoint& parentOrigin )
+{
+ if ( character == applyFunctionChar || character == invisibleTimes || character == invisibleComma ) {
+ return;
+ }
+
+ LuPixelPoint myPos( parentOrigin.x()+getX(), parentOrigin.y()+getY() );
+ //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ // return;
+
+ // Let container set the color, instead of elementType
+ //setUpPainter( context, painter );
+ painter.setPen( style.color() );
+
+ setCharStyle( style.charStyle() );
+ setCharFamily( style.charFamily() );
+
+ double factor = style.sizeFactor();
+ luPt mySize = context.getAdjustedSize( tstyle, factor );
+ TQFont font = getFont( context, style );
+ double fontsize = context.layoutUnitPtToPt( mySize );
+ double scriptsize = pow( style.scriptSizeMultiplier(), style.scriptLevel() );
+ double size = fontsize * scriptsize;
+ font.setPointSizeFloat( size < style.scriptMinSize() ? style.scriptMinSize() : size );
+ painter.setFont( font );
+
+ //kdDebug( DEBUGID ) << "TextElement::draw font=" << font.rawName() << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw size=" << mySize << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw size=" << context.layoutUnitToFontSize( mySize, false ) << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw height: " << getHeight() << endl;
+ //kdDebug( DEBUGID ) << "TextElement::draw width: " << getWidth() << endl;
+ //kdDebug( DEBUGID ) << endl;
+
+ // Each starting element draws the whole token
+ /*
+ ElementType* token = getElementType();
+ if ( ( token != 0 ) && !symbol ) {
+ TQString text = token->text( static_cast<SequenceElement*>( getParent() ) );
+// kdDebug() << "draw text: " << text[0].unicode()
+// << " " << painter.font().family().latin1()
+// << endl;
+ painter.fillRect( context.layoutUnitToPixelX( parentOrigin.x() ),
+ context.layoutUnitToPixelY( parentOrigin.y() ),
+ context.layoutUnitToPixelX( getParent()->getWidth() ),
+ context.layoutUnitToPixelY( getParent()->getHeight() ),
+ style.background() );
+ painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getBaseline() ),
+ text );
+ }
+ else {
+ */
+ TQChar ch = getRealCharacter(context);
+ if ( ch != TQChar::null ) {
+ luPixel bl = getBaseline();
+ if ( bl == -1 ) {
+ // That's quite hacky and actually not the way it's
+ // meant to be. You shouldn't calculate a lot in
+ // draw. But I don't see how else to deal with
+ // baseline==0 glyphs without yet another flag.
+ bl = -( getHeight()/2 + context.axisHeight( tstyle, factor ) );
+ }
+ painter.drawText( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+bl ),
+ TQString(ch) );
+ }
+ else {
+ painter.setPen( TQPen( context.getErrorColor(),
+ context.layoutUnitToPixelX( context.getLineWidth( factor ) ) ) );
+ painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y() ),
+ context.layoutUnitToPixelX( getWidth() ),
+ context.layoutUnitToPixelY( getHeight() ) );
+ }
+// }
+
+ // Debug
+ //painter.setBrush(TQt::NoBrush);
+// if ( isSymbol() ) {
+// painter.setPen( TQt::red );
+// painter.drawRect( context.layoutUnitToPixelX( myPos.x() ),
+// context.layoutUnitToPixelX( myPos.y() ),
+// context.layoutUnitToPixelX( getWidth() ),
+// context.layoutUnitToPixelX( getHeight() ) );
+// painter.setPen(TQt::green);
+// painter.drawLine(myPos.x(), myPos.y()+axis( context, tstyle ),
+// myPos.x()+getWidth(), myPos.y()+axis( context, tstyle ));
+// }
+}
+
+
+void TextElement::dispatchFontCommand( FontCommand* cmd )
+{
+ cmd->addTextElement( this );
+}
+
+void TextElement::setCharStyle( CharStyle cs )
+{
+ charStyle( cs );
+ formula()->changed();
+}
+
+void TextElement::setCharFamily( CharFamily cf )
+{
+ charFamily( cf );
+ formula()->changed();
+}
+
+TQChar TextElement::getRealCharacter(const ContextStyle& context)
+{
+ return character;
+/*
+ if ( !isSymbol() ) {
+ const FontStyle& fontStyle = context.fontStyle();
+ const AlphaTable* alphaTable = fontStyle.alphaTable();
+ if ( alphaTable != 0 ) {
+ AlphaTableEntry ate = alphaTable->entry( character,
+ charFamily(),
+ charStyle() );
+ if ( ate.valid() ) {
+ return ate.pos;
+ }
+ }
+ return character;
+ }
+ else {
+ return getSymbolTable().character(character, charStyle());
+ }
+*/
+}
+
+
+TQFont TextElement::getFont(const ContextStyle& context, const StyleAttributes& style)
+{
+ const FontStyle& fontStyle = context.fontStyle();
+ TQFont font;
+ if ( style.customFont() ) {
+ font = style.font();
+ }
+ else if (getElementType() != 0) {
+ font = getElementType()->getFont(context);
+ }
+ else {
+ font = context.getDefaultFont();
+ }
+ switch ( charStyle() ) {
+ case anyChar:
+ font.setItalic( false );
+ font.setBold( false );
+ break;
+ case normalChar:
+ font.setItalic( false );
+ font.setBold( false );
+ break;
+ case boldChar:
+ font.setItalic( false );
+ font.setBold( true );
+ break;
+ case italicChar:
+ font.setItalic( true );
+ font.setBold( false );
+ break;
+ case boldItalicChar:
+ font.setItalic( true );
+ font.setBold( true );
+ break;
+ }
+ return fontStyle.symbolTable()->font( character, font );
+}
+
+
+void TextElement::setUpPainter(const ContextStyle& context, TQPainter& painter)
+{
+ if (getElementType() != 0) {
+ getElementType()->setUpPainter(context, painter);
+ }
+ else {
+ painter.setPen(TQt::red);
+ }
+}
+
+const SymbolTable& TextElement::getSymbolTable() const
+{
+ return formula()->getSymbolTable();
+}
+
+
+void TextElement::writeMathML( TQDomDocument& doc, TQDomNode& parent, bool ) const
+{
+ parent.appendChild( doc.createTextNode( getCharacter() ) );
+}
+
+/**
+ * Appends our attributes to the dom element.
+ */
+void TextElement::writeDom(TQDomElement element)
+{
+ BasicElement::writeDom(element);
+ element.setAttribute("CHAR", TQString(character));
+ //TQString s;
+ //element.setAttribute("CHAR", s.sprintf( "#x%05X", character ) );
+ if (symbol) element.setAttribute("SYMBOL", "3");
+
+ switch ( charStyle() ) {
+ case anyChar: break;
+ case normalChar: element.setAttribute("STYLE", "normal"); break;
+ case boldChar: element.setAttribute("STYLE", "bold"); break;
+ case italicChar: element.setAttribute("STYLE", "italic"); break;
+ case boldItalicChar: element.setAttribute("STYLE", "bolditalic"); break;
+ }
+
+ switch ( charFamily() ) {
+ case normalFamily: element.setAttribute("FAMILY", "normal"); break;
+ case scriptFamily: element.setAttribute("FAMILY", "script"); break;
+ case frakturFamily: element.setAttribute("FAMILY", "fraktur"); break;
+ case doubleStruckFamily: element.setAttribute("FAMILY", "doublestruck"); break;
+ case anyFamily: break;
+ }
+}
+
+/**
+ * Reads our attributes from the element.
+ * Returns false if it failed.
+ */
+bool TextElement::readAttributesFromDom(TQDomElement element)
+{
+ if (!BasicElement::readAttributesFromDom(element)) {
+ return false;
+ }
+ TQString charStr = element.attribute("CHAR");
+ if(!charStr.isNull()) {
+ character = charStr.at(0);
+ }
+ TQString symbolStr = element.attribute("SYMBOL");
+ if(!symbolStr.isNull()) {
+ int symbolInt = symbolStr.toInt();
+ if ( symbolInt == 1 ) {
+ character = getSymbolTable().unicodeFromSymbolFont(character);
+ }
+ if ( symbolInt == 2 ) {
+ switch ( character.unicode() ) {
+ case 0x03D5: character = 0x03C6; break;
+ case 0x03C6: character = 0x03D5; break;
+ case 0x03Ba: character = 0x03BA; break;
+ case 0x00B4: character = 0x2032; break;
+ case 0x2215: character = 0x2244; break;
+ case 0x00B7: character = 0x2022; break;
+ case 0x1D574: character = 0x2111; break;
+ case 0x1D579: character = 0x211C; break;
+ case 0x2219: character = 0x22C5; break;
+ case 0x2662: character = 0x26C4; break;
+ case 0x220B: character = 0x220D; break;
+ case 0x224C: character = 0x2245; break;
+ case 0x03DB: character = 0x03C2; break;
+ }
+ }
+ symbol = symbolInt != 0;
+ }
+
+ TQString styleStr = element.attribute("STYLE");
+ if ( styleStr == "normal" ) {
+ charStyle( normalChar );
+ }
+ else if ( styleStr == "bold" ) {
+ charStyle( boldChar );
+ }
+ else if ( styleStr == "italic" ) {
+ charStyle( italicChar );
+ }
+ else if ( styleStr == "bolditalic" ) {
+ charStyle( boldItalicChar );
+ }
+ else {
+ charStyle( anyChar );
+ }
+
+ TQString familyStr = element.attribute( "FAMILY" );
+ if ( familyStr == "normal" ) {
+ charFamily( normalFamily );
+ }
+ else if ( familyStr == "script" ) {
+ charFamily( scriptFamily );
+ }
+ else if ( familyStr == "fraktur" ) {
+ charFamily( frakturFamily );
+ }
+ else if ( familyStr == "doublestruck" ) {
+ charFamily( doubleStruckFamily );
+ }
+ else {
+ charFamily( anyFamily );
+ }
+
+// kdDebug() << "charStyle=" << charStyle()
+// << " charFamily=" << charFamily()
+// << " format=" << int( format() ) << endl;
+
+ 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 TextElement::readContentFromDom(TQDomNode& node)
+{
+ return BasicElement::readContentFromDom(node);
+}
+
+TQString TextElement::toLatex()
+{
+ if ( isSymbol() ) {
+ TQString texName = getSymbolTable().name( character );
+ if ( !texName.isNull() )
+ return " \\" + texName + " ";
+ return " ? ";
+ }
+ else {
+ return TQString(character);
+ }
+}
+
+TQString TextElement::formulaString()
+{
+ if ( isSymbol() ) {
+ TQString texName = getSymbolTable().name( character );
+ if ( !texName.isNull() )
+ return " " + texName + " ";
+ return " ? ";
+ }
+ else {
+ return character;
+ }
+}
+
+
+EmptyElement::EmptyElement( BasicElement* parent )
+ : BasicElement( parent )
+{
+}
+
+EmptyElement::EmptyElement( const EmptyElement& other )
+ : BasicElement( other )
+{
+}
+
+
+bool EmptyElement::accept( ElementVisitor* visitor )
+{
+ return visitor->visit( this );
+}
+
+
+void EmptyElement::calcSizes( const ContextStyle& context,
+ ContextStyle::TextStyle tstyle,
+ ContextStyle::IndexStyle /*istyle*/,
+ StyleAttributes& style )
+{
+ luPt mySize = context.getAdjustedSize( tstyle, style.sizeFactor() );
+ //kdDebug( DEBUGID ) << "TextElement::calcSizes size=" << mySize << endl;
+
+ TQFont font = context.getDefaultFont();
+ font.setPointSizeFloat( context.layoutUnitPtToPt( mySize ) );
+
+ TQFontMetrics fm( font );
+ TQChar ch = 'A';
+ TQRect bound = fm.boundingRect( ch );
+ setWidth( 0 );
+ setHeight( context.ptToLayoutUnitPt( bound.height() ) );
+ setBaseline( context.ptToLayoutUnitPt( -bound.top() ) );
+}
+
+void EmptyElement::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() );
+ /*
+ if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
+ return;
+ */
+
+ if ( context.edit() ) {
+ painter.setPen( context.getHelpColor() );
+ painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y() ),
+ context.layoutUnitToPixelX( myPos.x() ),
+ context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
+ }
+}
+
+TQString EmptyElement::toLatex()
+{
+ return "{}";
+}
+
+KFORMULA_NAMESPACE_END