1 /* This file is part of the KDE project
2    Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
3                       Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
4                  2006 Martin Pfeiffer <hubipete@gmx.net>
5    Copyright (C) 2007 Alfredo Beaumont Sainz <alfredo.beaumont@gmail.com>
6                  2009 Jeremias Epperlein <jeeree@web.de>
7    Copyright (C) 2010 Inge Wallin <inge@lysator.liu.se>
8 
9    This library is free software; you can redistribute it and/or
10    modify it under the terms of the GNU Library General Public
11    License as published by the Free Software Foundation; either
12    version 2 of the License, or (at your option) any later version.
13 
14    This library is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17    Library General Public License for more details.
18 
19    You should have received a copy of the GNU Library General Public License
20    along with this library; see the file COPYING.LIB.  If not, write to
21    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22    Boston, MA 02110-1301, USA.
23 */
24 
25 #include "RootElement.h"
26 
27 #include "AttributeManager.h"
28 #include "FormulaCursor.h"
29 #include "RowElement.h"
30 #include "FormulaDebug.h"
31 
32 #include <KoXmlReader.h>
33 
34 #include <QPainter>
35 #include <QPen>
36 
RootElement(BasicElement * parent)37 RootElement::RootElement( BasicElement* parent ) : FixedElement( parent )
38 {
39     m_radicand = new RowElement( this );
40     m_exponent = new RowElement( this );
41 }
42 
~RootElement()43 RootElement::~RootElement()
44 {
45     delete m_radicand;
46     delete m_exponent;
47 }
48 
paint(QPainter & painter,AttributeManager * am)49 void RootElement::paint( QPainter& painter, AttributeManager* am )
50 {
51     Q_UNUSED( am )
52     QPen pen;
53     pen.setWidth( m_lineThickness );
54     painter.setPen( pen );
55     painter.drawPath( m_rootSymbol );
56 }
57 
layout(const AttributeManager * am)58 void RootElement::layout( const AttributeManager* am )
59 {
60     // Calculate values to layout the root symbol
61     qreal thinSpace = am->layoutSpacing( this );
62     qreal symbolHeight  = m_radicand->baseLine();
63     if( m_radicand->height() > symbolHeight*1.3 ) symbolHeight = m_radicand->height();
64     symbolHeight += thinSpace;
65     qreal tickWidth = symbolHeight / 3.0;  // The width of the root symbol's tick part
66 
67     m_lineThickness = am->lineThickness(this);
68 
69     // The root symbol an xOffset and yOffset due to the exponent.
70     qreal xOffset = m_exponent->width() - tickWidth/2;
71     xOffset = xOffset < 0 ? 0 : xOffset; // no negative offset for the root symbol
72     qreal yOffset =  m_exponent->height() - 2.0*symbolHeight/5.0;
73     yOffset = yOffset < 0 ? 0 : yOffset;
74 
75     // Set the roots dimensions
76     setBaseLine( yOffset + thinSpace + m_radicand->baseLine() );
77     setHeight( yOffset + thinSpace + m_radicand->height() );
78     setWidth( xOffset + tickWidth + m_radicand->width() + thinSpace );
79 
80     // Place the children in the correct place
81     m_radicand->setOrigin( QPointF( xOffset+tickWidth+thinSpace, yOffset+thinSpace ) );
82     m_exponent->setOrigin( QPointF( 0.0, 0.0 ) );
83 
84     // Draw the actual root symbol to a path as buffer
85     m_rootSymbol = QPainterPath();
86     m_rootSymbol.moveTo( xOffset+m_lineThickness, yOffset +  2.0 * symbolHeight / 3.0 );
87     m_rootSymbol.lineTo( m_rootSymbol.currentPosition().x()+tickWidth*0.5, yOffset + symbolHeight - m_lineThickness/2 );
88     m_rootSymbol.lineTo( m_rootSymbol.currentPosition().x()+tickWidth*0.5, yOffset + m_lineThickness/2 );
89     m_rootSymbol.lineTo( width()-m_lineThickness/2, yOffset + m_lineThickness/2);
90 }
91 
childElements() const92 const QList<BasicElement*> RootElement::childElements() const
93 {
94     QList<BasicElement*> tmp;
95     tmp << m_exponent << m_radicand;
96     return tmp;
97 }
98 
99 
100 // QList< BasicElement* > RootElement::elementsBetween(int pos1, int pos2) const
101 // {
102 //     QList<BasicElement*> tmp;
103 //     if (pos1==0 && pos2 >0) {
104 //         tmp.append(m_exponent);
105 //     }
106 //     if (pos1<3 && pos2==3) {
107 //         tmp.append(m_radicand);
108 //     }
109 //     return tmp;
110 // }
111 
112 // int RootElement::positionOfChild(BasicElement* child) const
113 // {
114 //     if (child==m_exponent) {
115 //         return 0;
116 //     } else if (child==m_radicand) {
117 //         return 2;
118 //     }
119 //     return -1;
120 // }
121 
setCursorTo(FormulaCursor & cursor,QPointF point)122 bool RootElement::setCursorTo(FormulaCursor& cursor, QPointF point)
123 {
124     if (cursor.isSelecting()) {
125         return false;
126     }
127     if (m_exponent->boundingRect().contains(point)) {
128         return m_exponent->setCursorTo(cursor, point-m_exponent->origin());
129     } else {
130         return m_radicand->setCursorTo(cursor, point-m_radicand->origin());
131     }
132 }
133 
moveCursor(FormulaCursor & newcursor,FormulaCursor & oldcursor)134 bool RootElement::moveCursor(FormulaCursor& newcursor, FormulaCursor& oldcursor)
135 {
136     if (newcursor.isSelecting()) {
137         return false;
138     } else {
139         return moveHorSituation(newcursor,oldcursor,0,1);
140     }
141 }
142 
143 
endPosition() const144 int RootElement::endPosition() const
145 {
146     return 3;
147 }
148 
149 
replaceChild(BasicElement * oldelement,BasicElement * newelement)150 bool RootElement::replaceChild ( BasicElement* oldelement, BasicElement* newelement )
151 {
152     if (newelement->elementType()==Row) {
153         RowElement* newrow = static_cast<RowElement*>(newelement);
154         if (oldelement == m_exponent) {
155             m_exponent = newrow;
156             return true;
157         } else if (oldelement == m_radicand) {
158             m_radicand = newrow;
159             return true;
160         }
161     }
162     return false;
163 }
164 
elementType() const165 ElementType RootElement::elementType() const
166 {
167     return Root;
168 }
169 
readMathMLContent(const KoXmlElement & element)170 bool RootElement::readMathMLContent( const KoXmlElement& element )
171 {
172     KoXmlElement tmp;
173     int counter = 0;
174     forEachElement(tmp, element) {
175         if (counter==0) {
176             loadElement(tmp, &m_radicand);
177         } else if (counter==1) {
178             loadElement(tmp, &m_exponent);
179         } else {
180             debugFormula << "Too many arguments to mroot";
181         }
182         counter++;
183     }
184     if (counter < 2) {
185         debugFormula << "Not enough arguments to mroot";
186     }
187 
188     return true;
189 }
190 
writeMathMLContent(KoXmlWriter * writer,const QString & ns) const191 void RootElement::writeMathMLContent( KoXmlWriter* writer, const QString& ns ) const
192 {
193     Q_ASSERT( m_radicand );
194     Q_ASSERT( m_exponent );
195     m_radicand->writeMathML( writer, ns );
196     m_exponent->writeMathML( writer, ns );
197 }
198 
199