kformula/flake

FractionElement.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
00003                       Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
00004                  2006 Martin Pfeiffer <hubipete@gmx.net>
00005                  2009 Jeremias Epperlein <jeeree@web.de>
00006  
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020    Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "FractionElement.h"
00024 #include "FormulaCursor.h"
00025 #include "AttributeManager.h"
00026 #include <KoXmlWriter.h>
00027 #include <KoXmlReader.h>
00028 #include <QPainter>
00029 #include <kdebug.h>
00030 
00031 FractionElement::FractionElement( BasicElement* parent ) : FixedElement( parent )
00032 {
00033     m_numerator = new RowElement( this );
00034     m_denominator = new RowElement( this );
00035     m_lineThickness = 1.0;
00036 }
00037 
00038 FractionElement::~FractionElement()
00039 {
00040     delete m_numerator;
00041     delete m_denominator;
00042 }
00043 
00044 void FractionElement::paint( QPainter& painter, AttributeManager* am )
00045 {
00046     Q_UNUSED( am )
00047     // return if there is nothing to paint
00048     if( m_lineThickness == 0.0 )
00049         return;
00050 
00051     // paint the fraction line with the specified line width
00052     QPen pen;
00053     pen.setWidthF( m_lineThickness );
00054     painter.setPen( pen );
00055     painter.drawLine( m_fractionLine );
00056 }
00057 
00058 void FractionElement::layout( const AttributeManager* am )
00059 {
00060     // get values of all attributes
00061     QString value = am->findValue( "linethickness", this );
00062     Length length;
00063     if(value == "thick")
00064         length.value = 2;
00065     else if(value == "medium")
00066         length.value = 1;
00067     else if(value == "thin")
00068         length.value = 0.5;
00069     else
00070         length = am->parseUnit( value, this );
00071 
00072     if(length.unit == Length::None)
00073         m_lineThickness = am->lineThickness(this) * length.value;
00074     else 
00075         m_lineThickness = am->lengthToPixels(length, this, "linethickness");
00076 
00077     // decide which layout is wanted
00078     if( am->boolOf( "bevelled", this ) )
00079     {
00080         layoutBevelledFraction( am );
00081         return;
00082     }
00083 
00084     double distY = am->layoutSpacing( this );
00085     Align numalign = am->alignOf( "numalign", this ); 
00086     Align denomalign = am->alignOf( "denomalign", this );
00087 
00088     // align the numerator and the denominator
00089     QPointF numeratorOrigin;
00090     QPointF denominatorOrigin( 0.0, m_numerator->height() + m_lineThickness + 2*distY );
00091     setWidth( qMax( m_numerator->width(), m_denominator->width() ) + m_lineThickness*2 );
00092     
00093     if( numalign == Right )
00094         numeratorOrigin.setX( width() - m_numerator->width() - m_lineThickness );
00095     else if( numalign == Center )
00096     numeratorOrigin.setX( ( width() - m_numerator->width() ) / 2 );
00097 
00098     if( denomalign == Right )
00099         denominatorOrigin.setX( width() - m_denominator->width() - m_lineThickness );
00100     else if( numalign == Center )
00101     denominatorOrigin.setX( ( width() - m_denominator->width() ) / 2 );
00102 
00103     m_numerator->setOrigin( numeratorOrigin );
00104     m_denominator->setOrigin( denominatorOrigin );
00105 
00106     // construct the fraction's line    
00107     double fractionLineY =  m_numerator->height() + m_lineThickness/2 + distY;
00108     m_fractionLine = QLineF( QPointF( m_lineThickness, fractionLineY ),
00109                              QPointF( width()-m_lineThickness, fractionLineY ) );
00110 
00111     setHeight( m_numerator->height() + m_denominator->height() +
00112                m_lineThickness + 2*distY );
00113     setBaseLine( denominatorOrigin.y() ); 
00114 }
00115 
00116 void FractionElement::layoutBevelledFraction( const AttributeManager* am )
00117 {
00118     // the shown line should have a width that has 1/3 of the height
00119     // the line is heigher as the content by 2*thinmathspace = 2*borderY
00120 
00121     double borderY = am->layoutSpacing( this );
00122     setHeight( m_numerator->height() + m_denominator->height() + 2*borderY );
00123     setWidth( m_numerator->width() + m_denominator->width() + height()/3 );
00124     setBaseLine( height()/2 );
00125 
00126     m_numerator->setOrigin( QPointF( 0.0, borderY ) );
00127     m_denominator->setOrigin( QPointF( width()-m_denominator->width(),
00128                                        borderY+m_numerator->height() ) );
00129     m_fractionLine = QLineF( QPointF( m_numerator->width(), height() ),
00130                              QPointF( width()-m_denominator->width(), 0.0 ) );
00131 }
00132 
00133 const QList<BasicElement*> FractionElement::childElements() const
00134 {
00135     QList<BasicElement*> list;
00136     list << m_numerator<<m_denominator;
00137     return list;
00138 }
00139 
00140 int FractionElement::endPosition() const {
00141     return 3;
00142 }
00143 
00144 // QLineF FractionElement::cursorLine(int position) const {
00145 //     QPointF top=absoluteBoundingRect().topLeft();
00146 //     QPointF bottom;
00147 //     switch (position) {
00148 //  case 0:
00149 //      top+=m_numerator->origin();
00150 //      break;
00151 //  case 1:
00152 //      top+=m_numerator->origin()+QPointF(m_numerator->width(),0.0);
00153 //      break;
00154 //  case 2:
00155 //      top+=m_denominator->origin();
00156 //      break;
00157 //  case 3:
00158 //      top+=m_denominator->origin()+QPointF(m_denominator->width(),0.0);
00159 //      break;
00160 //     }
00161 //     if (position<=1) {
00162 //  bottom=top+QPointF(0.0,m_numerator->height());
00163 //     }
00164 //     else {
00165 //  bottom=top+QPointF(0.0,m_denominator->height());
00166 //     }
00167 //     return QLineF(top, bottom);
00168 // }
00169 
00170 
00171 QList< BasicElement* > FractionElement::elementsBetween ( int pos1, int pos2 ) const
00172 {
00173     QList<BasicElement*> tmp;
00174     if (pos1==0 && pos2 >0) { 
00175         tmp.append(m_numerator);
00176     }
00177     if (pos1<3 && pos2==3) {
00178         tmp.append(m_denominator);
00179     }
00180     return tmp;
00181 }
00182 
00183 
00184 int FractionElement::positionOfChild(BasicElement* child) const {
00185     if (m_numerator==child){
00186     return 0;
00187     }
00188     else if (m_denominator==child) {
00189     return 2;
00190     }
00191     return -1;
00192 }
00193 
00194 bool FractionElement::moveCursor(FormulaCursor& newcursor, FormulaCursor& oldcursor)  {
00195     if (newcursor.isSelecting()) {
00196         return false;
00197     } else {
00198         //TODO: How can I get the attribute of the Attributemanager here?
00199         // The movement should be different in the bevelled case
00200         //if (bevelled) {
00201         // return moveHorSituation(newcursor,oldcursor,0,1 )
00202         return moveVertSituation(newcursor,oldcursor,0,1);
00203     }
00204 }
00205 
00206 bool FractionElement::setCursorTo( FormulaCursor& cursor, QPointF point )
00207 {
00208     //check if the point is above the fraction line, the origin is in the top left corner
00209     bool inNumerator=point.y() < (m_numerator->boundingRect().bottom() +  m_denominator->boundingRect().top())/2 ;
00210     if (cursor.isSelecting()) {
00211         return false;
00212     } else {
00213         if (point.x() > width()) {
00214             cursor.moveTo(this,inNumerator? 1 : 3);
00215             return true;
00216         }
00217         if (point.x() < 0) {
00218             cursor.moveTo(this,inNumerator? 0 : 2);
00219             return true;
00220         }
00221         if ( inNumerator ) {
00222             point-=m_numerator->origin();
00223             //TODO: maybe place it directly in the fraction if this fails
00224             return m_numerator->setCursorTo(cursor,point);
00225         } else {
00226             point-=m_denominator->origin();
00227             return m_denominator->setCursorTo(cursor,point);
00228         }
00229     }
00230 }
00231 
00232 bool FractionElement::replaceChild ( BasicElement* oldelement, BasicElement* newelement )
00233 {
00234     //TODO: investigate, if we really need this
00235     if (newelement->elementType()==Row) {
00236         RowElement* newrow=static_cast<RowElement*>(newelement);
00237         if( oldelement == m_numerator ) {
00238             m_numerator = newrow;
00239             return true;
00240         } else if( oldelement == m_denominator ) {
00241             m_denominator = newrow;
00242             return true;
00243         }
00244     }
00245     return false;
00246 }
00247    
00248 QString FractionElement::attributesDefaultValue( const QString& attribute ) const
00249 {
00250     if( attribute == "linethickness" )
00251         return "1";
00252     else if( attribute == "numalign" || attribute == "denomalign" )
00253         return "center";
00254     else if( attribute == "bevelled" )
00255         return "false";
00256     else
00257         return QString();
00258 }
00259 
00260 bool FractionElement::readMathMLContent( const KoXmlElement& parent )
00261 {
00262     KoXmlElement tmp;
00263     int counter=0;
00264     forEachElement( tmp, parent ) {
00265         if (counter==0) {
00266             loadElement(tmp,&m_numerator);
00267         } else if (counter==1) {
00268             loadElement(tmp,&m_denominator);
00269         } else {
00270             kDebug(39001) << "Too many arguments to mfrac";
00271         }
00272         counter++;
00273     }
00274     if (counter<2) {
00275         kDebug(39001) << "Not enough arguments to mfrac";
00276     }
00277     return true;
00278 }
00279 
00280 void FractionElement::writeMathMLContent( KoXmlWriter* writer ) const
00281 {
00282     m_numerator->writeMathML( writer );
00283     m_denominator->writeMathML( writer );
00284 }
00285 
00286 ElementType FractionElement::elementType() const
00287 {
00288     return Fraction;
00289 }