lib

spaceelement.cc

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    Copyright (C) 2006 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include <qfontmetrics.h>
00023 #include <qpainter.h>
00024 
00025 #include <kdebug.h>
00026 #include <kprinter.h>
00027 
00028 #include "contextstyle.h"
00029 #include "elementvisitor.h"
00030 #include "spaceelement.h"
00031 
00032 
00033 KFORMULA_NAMESPACE_BEGIN
00034 
00035 
00036 SpaceElement::SpaceElement( SpaceWidth space, bool tab, BasicElement* parent )
00037     : BasicElement( parent ), 
00038       m_tab( tab ),
00039       m_widthType( NoSize ),
00040       m_heightType( NoSize ),
00041       m_depthType( NoSize ),
00042       m_lineBreak( NoBreakType )
00043 {
00044     // Backwards compatibility with KFO format
00045     switch ( space ) {
00046     case NEGTHIN:
00047         m_widthType = NegativeThinMathSpace;
00048         break;
00049     case THIN:
00050         m_widthType = ThinMathSpace;
00051         break;
00052     case MEDIUM:
00053         m_widthType = MediumMathSpace;
00054         break;
00055     case THICK:
00056         m_widthType = ThickMathSpace;
00057         break;
00058     case QUAD:
00059         m_widthType = VeryVeryThickMathSpace;
00060         break;
00061     }
00062 }
00063 
00064 
00065 SpaceElement::SpaceElement( const SpaceElement& other )
00066     : BasicElement( other ),
00067       m_widthType( other.m_widthType ),
00068       m_width( other.m_width ),
00069       m_heightType( other.m_heightType ),
00070       m_height( other.m_height ),
00071       m_depthType( other.m_depthType ),
00072       m_depth( other.m_depth ),
00073       m_lineBreak( other.m_lineBreak )
00074 {
00075 }
00076 
00077 
00078 bool SpaceElement::accept( ElementVisitor* visitor )
00079 {
00080     return visitor->visit( this );
00081 }
00082 
00083 
00084 void SpaceElement::calcSizes( const ContextStyle& context,
00085                               ContextStyle::TextStyle tstyle,
00086                               ContextStyle::IndexStyle /*istyle*/,
00087                               StyleAttributes& style )
00088 {
00089     double factor = style.sizeFactor();
00090     luPt mySize = context.getAdjustedSize( tstyle, factor );
00091     QFont font = context.getDefaultFont();
00092     font.setPointSize( mySize );
00093 
00094     QFontMetrics fm( font );
00095     QChar w = 'M';
00096     LuPixelRect hbound = fm.boundingRect( w );
00097     QChar h = 'x';
00098     LuPixelRect vbound = fm.boundingRect( h );
00099 
00100     double width = style.getSpace( m_widthType, m_width );
00101     if ( m_widthType == AbsoluteSize ) {
00102         width = m_width / context.layoutUnitPtToPt( context.getBaseSize() );
00103     }
00104     else if ( m_widthType == PixelSize ) {
00105         width = context.pixelYToPt( m_width ) / context.layoutUnitPtToPt( context.getBaseSize() );
00106     }
00107     double height = style.getSpace( m_heightType, m_height );
00108     if ( m_heightType == AbsoluteSize ) {
00109         height = m_height / context.layoutUnitPtToPt( context.getBaseSize() );
00110     }
00111     else if ( m_heightType == PixelSize ) {
00112         height = context.pixelYToPt( m_height ) / context.layoutUnitPtToPt( context.getBaseSize() );
00113     }
00114     double depth = style.getSpace( m_depthType, m_depth );
00115     if ( m_depthType == AbsoluteSize ) {
00116         depth = m_depth / context.layoutUnitPtToPt( context.getBaseSize() );
00117     }
00118     else if ( m_depthType == PixelSize ) {
00119         depth = context.pixelYToPt( m_depth ) / context.layoutUnitPtToPt( context.getBaseSize() );
00120     }
00121 
00122     setWidth( hbound.width() * width );
00123     setHeight( vbound.height() * height + vbound.height() * depth );
00124     setBaseline( vbound.height() * height );
00125 
00126     if ( m_tab ) {
00127         getParent()->registerTab( this );
00128     }
00129 }
00130 
00131 void SpaceElement::draw( QPainter& painter, const LuPixelRect& /*r*/,
00132                          const ContextStyle& context,
00133                          ContextStyle::TextStyle /*tstyle*/,
00134                          ContextStyle::IndexStyle /*istyle*/,
00135                          StyleAttributes& /*style*/,
00136                          const LuPixelPoint& parentOrigin )
00137 {
00138     LuPixelPoint myPos(parentOrigin.x()+getX(), parentOrigin.y()+getY());
00139     // there is such a thing as negative space!
00140     //if ( !LuPixelRect( myPos.x(), myPos.y(), getWidth(), getHeight() ).intersects( r ) )
00141     //    return;
00142 
00143     if ( context.edit() ) {
00144         painter.setPen( context.getEmptyColor() );
00145         painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
00146                           context.layoutUnitToPixelY( myPos.y()+getHeight() ),
00147                           context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
00148                           context.layoutUnitToPixelY( myPos.y()+getHeight() ) );
00149         painter.drawLine( context.layoutUnitToPixelX( myPos.x() ),
00150                           context.layoutUnitToPixelY( myPos.y()+getHeight() ),
00151                           context.layoutUnitToPixelX( myPos.x() ),
00152                           context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
00153         painter.drawLine( context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
00154                           context.layoutUnitToPixelY( myPos.y()+getHeight() ),
00155                           context.layoutUnitToPixelX( myPos.x()+getWidth()-1 ),
00156                           context.layoutUnitToPixelY( myPos.y()+getHeight()-getHeight()/5 ) );
00157     }
00158 }
00159 
00160 
00161 void SpaceElement::writeDom(QDomElement element)
00162 {
00163     BasicElement::writeDom(element);
00164     switch ( m_widthType ) {
00165     case NegativeVeryVeryThinMathSpace:
00166     case NegativeVeryThinMathSpace:
00167     case NegativeThinMathSpace:
00168     case NegativeMediumMathSpace:
00169     case NegativeThickMathSpace:
00170     case NegativeVeryThickMathSpace:
00171     case NegativeVeryVeryThickMathSpace:
00172         element.setAttribute( "WIDTH", "negthin" );
00173         break;
00174     case VeryVeryThinMathSpace:
00175     case VeryThinMathSpace:
00176     case ThinMathSpace:
00177         element.setAttribute( "WIDTH", "thin" );
00178         break;
00179     case MediumMathSpace:
00180         element.setAttribute( "WIDTH", "medium" );
00181         break;
00182     case ThickMathSpace:
00183         element.setAttribute( "WIDTH", "thick" );
00184         break;
00185     case VeryThickMathSpace:
00186     case VeryVeryThickMathSpace:
00187         element.setAttribute( "WIDTH", "quad" );
00188         break;
00189     case AbsoluteSize:
00190     case RelativeSize:
00191     case PixelSize:
00192         if ( m_width < 0 ) {
00193             element.setAttribute( "WIDTH", "negthin" );
00194         }
00195         else {
00196             element.setAttribute( "WIDTH", "thin" );
00197         }
00198     default:
00199         break;
00200     }
00201     if ( m_tab ) {
00202         element.setAttribute( "TAB", "true" );
00203     }
00204 }
00205 
00206 bool SpaceElement::readAttributesFromDom( QDomElement element )
00207 {
00208     if ( !BasicElement::readAttributesFromDom( element ) ) {
00209         return false;
00210     }
00211     QString widthStr = element.attribute( "WIDTH" );
00212     if( !widthStr.isNull() ) {
00213         if ( widthStr.lower() == "quad" ) {
00214             m_widthType = VeryVeryThickMathSpace;
00215         }
00216         else if ( widthStr.lower() == "thick" ) {
00217             m_widthType = ThickMathSpace;
00218         }
00219         else if ( widthStr.lower() == "medium" ) {
00220             m_widthType = MediumMathSpace;
00221         }
00222         else if ( widthStr.lower() == "negthin" ) {
00223             m_widthType = NegativeThinMathSpace;
00224         }
00225         else {
00226             m_widthType = ThinMathSpace;
00227         }
00228     }
00229     else {
00230         return false;
00231     }
00232     QString tabStr = element.attribute( "TAB" );
00233     m_tab = !tabStr.isNull();
00234     return true;
00235 }
00236 
00237 bool SpaceElement::readContentFromDom(QDomNode& node)
00238 {
00239     return BasicElement::readContentFromDom( node );
00240 }
00241 
00242 bool SpaceElement::readAttributesFromMathMLDom(const QDomElement& element)
00243 {
00244     if ( ! BasicElement::readAttributesFromMathMLDom( element ) ) {
00245         return false;
00246     }
00247 
00248     QString widthStr = element.attribute( "width" ).stripWhiteSpace().lower();
00249     if ( ! widthStr.isNull() ) {
00250         m_width = getSize( widthStr, &m_widthType );
00251         if ( m_widthType == NoSize ) {
00252             m_widthType = getSpace( widthStr );
00253         }
00254     }
00255     QString heightStr = element.attribute( "height" ).stripWhiteSpace().lower();
00256     if ( ! heightStr.isNull() ) {
00257         m_height = getSize( heightStr, &m_heightType );
00258     }
00259     QString depthStr = element.attribute( "depth" ).stripWhiteSpace().lower();
00260     if ( ! depthStr.isNull() ) {
00261         m_depth = getSize( depthStr, &m_depthType );
00262     }
00263     QString linebreakStr = element.attribute( "linebreak" ).stripWhiteSpace().lower();
00264     if ( ! linebreakStr.isNull() ) {
00265         if ( linebreakStr == "auto" ) {
00266             m_lineBreak = AutoBreak;
00267         }
00268         else if ( linebreakStr == "newline" ) {
00269             m_lineBreak = NewLineBreak;
00270         }
00271         else if ( linebreakStr == "indentingnewline" ) {
00272             m_lineBreak = IndentingNewLineBreak;
00273         }
00274         else if ( linebreakStr == "nobreak" ) {
00275             m_lineBreak = NoBreak;
00276         }
00277         else if ( linebreakStr == "goodbreak" ) {
00278             m_lineBreak = GoodBreak;
00279         }
00280         else if ( linebreakStr == "badbreak" ) {
00281             m_lineBreak = BadBreak;
00282         }
00283     }
00284     return true;
00285 }
00286 
00287 void SpaceElement::writeMathMLAttributes( QDomElement& element ) const
00288 {
00289     switch ( m_widthType ) {
00290     case AbsoluteSize:
00291         element.setAttribute( "width", QString( "%1pt" ).arg( m_width ) );
00292         break;
00293     case RelativeSize:
00294         element.setAttribute( "width", QString( "%1%" ).arg( m_width * 100.0 ) );
00295         break;
00296     case PixelSize:
00297         element.setAttribute( "width", QString( "%1px" ).arg( m_width ) );
00298         break;
00299     case NegativeVeryVeryThinMathSpace:
00300         element.setAttribute( "width", "negativeveryverythinmathspace" );
00301         break;
00302     case NegativeVeryThinMathSpace:
00303         element.setAttribute( "width", "negativeverythinmathspace" );
00304         break;
00305     case NegativeThinMathSpace:
00306         element.setAttribute( "width", "negativethinmathspace" );
00307         break;
00308     case NegativeMediumMathSpace:
00309         element.setAttribute( "width", "negativemediummathspace" );
00310         break;
00311     case NegativeThickMathSpace:
00312         element.setAttribute( "width", "negativethickmathspace" );
00313         break;
00314     case NegativeVeryThickMathSpace:
00315         element.setAttribute( "width", "negativeverythickmathspace" );
00316         break;
00317     case NegativeVeryVeryThickMathSpace:
00318         element.setAttribute( "width", "negativeveryverythickmathspace" );
00319         break;
00320     case VeryVeryThinMathSpace:
00321         element.setAttribute( "width", "veryverythinmathspace" );
00322         break;
00323     case VeryThinMathSpace:
00324         element.setAttribute( "width", "verythinmathspace" );
00325         break;
00326     case ThinMathSpace:
00327         element.setAttribute( "width", "thinmathspace" );
00328         break;
00329     case MediumMathSpace:
00330         element.setAttribute( "width", "mediummathspace" );
00331         break;
00332     case ThickMathSpace:
00333         element.setAttribute( "width", "thickmathspace" );
00334         break;
00335     case VeryThickMathSpace:
00336         element.setAttribute( "width", "verythickmathspace" );
00337         break;
00338     case VeryVeryThickMathSpace:
00339         element.setAttribute( "width", "veryverythickmathspace" );
00340         break;
00341     default:
00342         break;
00343     }
00344     switch ( m_heightType ) {
00345     case AbsoluteSize:
00346         element.setAttribute( "height", QString( "%1pt" ).arg( m_height ) );
00347         break;
00348     case RelativeSize:
00349         element.setAttribute( "height", QString( "%1%" ).arg( m_height * 100.0 ) );
00350         break;
00351     case PixelSize:
00352         element.setAttribute( "height", QString( "%1px" ).arg( m_height ) );
00353         break;
00354     default:
00355         break;
00356     }
00357     switch ( m_depthType ) {
00358     case AbsoluteSize:
00359         element.setAttribute( "depth", QString( "%1pt" ).arg( m_depth ) );
00360         break;
00361     case RelativeSize:
00362         element.setAttribute( "depth", QString( "%1%" ).arg( m_depth * 100.0 ) );
00363         break;
00364     case PixelSize:
00365         element.setAttribute( "depth", QString( "%1px" ).arg( m_depth ) );
00366         break;
00367     default:
00368         break;
00369     }
00370     switch ( m_lineBreak ) {
00371     case AutoBreak:
00372         element.setAttribute( "linebreak", "auto" );
00373         break;
00374     case NewLineBreak:
00375         element.setAttribute( "linebreak", "newline" );
00376         break;
00377     case IndentingNewLineBreak:
00378         element.setAttribute( "linebreak", "indentingnewline" );
00379         break;
00380     case NoBreak:
00381         element.setAttribute( "linebreak", "nobreak" );
00382         break;
00383     case GoodBreak:
00384         element.setAttribute( "linebreak", "goodbreak" );
00385         break;
00386     case BadBreak:
00387         element.setAttribute( "linebreak", "badbreak" );
00388         break;
00389     default:
00390         break;
00391     }
00392 }
00393 
00394 QString SpaceElement::toLatex()
00395 {
00396     switch ( m_widthType ) {
00397     case NegativeVeryVeryThinMathSpace:
00398     case NegativeVeryThinMathSpace:
00399     case NegativeThinMathSpace:
00400     case NegativeMediumMathSpace:
00401     case NegativeThickMathSpace:
00402     case NegativeVeryThickMathSpace:
00403     case NegativeVeryVeryThickMathSpace:
00404         return "\\!";
00405     case VeryVeryThinMathSpace:
00406     case VeryThinMathSpace:
00407     case ThinMathSpace:
00408         return "\\,";
00409     case MediumMathSpace:
00410         return "\\>";
00411     case ThickMathSpace:
00412         return "\\;";
00413     case VeryThickMathSpace:
00414     case VeryVeryThickMathSpace:
00415         return "\\quad ";
00416     case AbsoluteSize:
00417     case RelativeSize:
00418     case PixelSize:
00419         if ( m_width < 0 ) {
00420             return "\\!";
00421         }
00422         else {
00423             return "\\,";
00424         }
00425     default:
00426         break;
00427     }
00428     return "";
00429 }
00430 
00431 KFORMULA_NAMESPACE_END
KDE Home | KDE Accessibility Home | Description of Access Keys