00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "MultiscriptElement.h"
00022 #include "AttributeManager.h"
00023 #include <KoXmlWriter.h>
00024 #include <KoXmlReader.h>
00025 #include <QPainter>
00026 #include "FormulaCursor.h"
00027 #include "kdebug.h"
00028
00029 MultiscriptElement::MultiscriptElement( BasicElement* parent ) : FixedElement( parent )
00030 {
00031 m_baseElement = new RowElement( this );
00032 }
00033
00034 MultiscriptElement::~MultiscriptElement()
00035 {
00036 delete m_baseElement;
00037
00038 while (!m_preScripts.isEmpty())
00039 delete m_preScripts.takeFirst();
00040 while (!m_postScripts.isEmpty())
00041 delete m_postScripts.takeFirst();
00042 }
00043
00044 void MultiscriptElement::paint( QPainter& painter, AttributeManager* am )
00045 {
00046 Q_UNUSED(painter)
00047 Q_UNUSED(am)
00048
00049 }
00050
00051 void MultiscriptElement::ensureEvenNumberElements() {
00052 if(m_postScripts.size() % 2 == 1) {
00053
00054 m_postScripts.append(NULL);
00055 }
00056 if(m_preScripts.size() % 2 == 1) {
00057
00058 m_preScripts.append(NULL);
00059 }
00060 }
00061
00062 void MultiscriptElement::layout( const AttributeManager* am )
00063 {
00064
00065 double subscriptshift = am->doubleOf( "subscriptshift", this );
00066 double superscriptshift = am->doubleOf( "superscriptshift", this );
00067
00068
00069 double halfthinspace = am->layoutSpacing( this )/2.0;
00070
00071
00072 ensureEvenNumberElements();
00073
00074
00075
00076
00077 double maxSuperScriptDepth = 0.0;
00078 double maxSuperScriptBaseLine = 0.0;
00079 double maxSubScriptDepth = 0.0;
00080 double maxSubScriptBaseLine = 0.0;
00081 bool isSuperscript = true;
00082 foreach( BasicElement *script, m_postScripts ) {
00083 isSuperscript = !isSuperscript;
00084 if(!script)
00085 continue;
00086 if(isSuperscript) {
00087 maxSuperScriptDepth = qMax( script->height() - script->baseLine(), maxSuperScriptDepth );
00088 maxSuperScriptBaseLine = qMax( script->baseLine(), maxSuperScriptBaseLine );
00089 } else {
00090
00091 maxSubScriptDepth = qMax( script->height() - script->baseLine(), maxSubScriptDepth );
00092 maxSubScriptBaseLine = qMax( script->baseLine(), maxSubScriptBaseLine );
00093 }
00094 }
00095 foreach( BasicElement *script, m_preScripts ) {
00096 isSuperscript = !isSuperscript;
00097 if(!script)
00098 continue;
00099 if(isSuperscript) {
00100 maxSuperScriptDepth = qMax( script->height() - script->baseLine(), maxSuperScriptDepth );
00101 maxSuperScriptBaseLine = qMax( script->baseLine(), maxSuperScriptBaseLine );
00102 } else {
00103
00104 maxSubScriptDepth = qMax( script->height() - script->baseLine(), maxSubScriptDepth );
00105 maxSubScriptBaseLine = qMax( script->baseLine(), maxSubScriptBaseLine );
00106 }
00107 }
00108
00109
00110 double yOffsetBase = 0;
00111 if(maxSuperScriptDepth + maxSuperScriptBaseLine > 0) {
00112 yOffsetBase = maxSuperScriptDepth + maxSuperScriptBaseLine - m_baseElement->height()/2.0 + halfthinspace;
00113 yOffsetBase = qMax( yOffsetBase, superscriptshift );
00114 }
00115
00116 double yOffsetSub = yOffsetBase + maxSubScriptBaseLine +
00117 qMax( m_baseElement->height()/2 + halfthinspace,
00118 m_baseElement->height() - maxSubScriptBaseLine
00119 + subscriptshift );
00120
00121 double xOffset = 0.0;
00122 double lastSuperScriptWidth= 0.0;
00123
00124
00125 for( int i = m_preScripts.size()-1; i >= 0; i--) {
00126
00127
00128 if( i%2 == 0) {
00129
00130 if(!m_preScripts[i]) {
00131 xOffset += lastSuperScriptWidth;
00132 } else {
00133
00134 double offset = qMax(0.0, (lastSuperScriptWidth - m_preScripts[i]->width())/2.0);
00135 m_preScripts[i]->setOrigin( QPointF(
00136 offset + xOffset,
00137 yOffsetSub - m_preScripts[i]->baseLine() ) );
00138 xOffset += qMax(lastSuperScriptWidth, m_preScripts[i]->width());
00139 }
00140 if(i!=0)
00141 xOffset += halfthinspace;
00142 } else {
00143
00144
00145
00146
00147 if( !m_preScripts[i] )
00148 lastSuperScriptWidth = 0.0;
00149 else {
00150 lastSuperScriptWidth = m_preScripts[i]->width();
00151 double offset = 0.0;
00152 if(m_preScripts[i-1])
00153 offset = qMax(0.0, (m_preScripts[i-1]->width() - lastSuperScriptWidth)/2.0);
00154 m_preScripts[i]->setOrigin( QPointF(
00155 offset + xOffset,
00156 maxSuperScriptBaseLine - m_preScripts[i]->baseLine()));
00157 }
00158 }
00159 }
00160
00161
00162 m_baseElement->setOrigin( QPointF( xOffset, yOffsetBase ) );
00163 xOffset += m_baseElement->width();
00164 double lastSubScriptWidth = 0.0;
00165
00166
00167 for( int i = 0; i < m_postScripts.size(); i++) {
00168
00169
00170 if( i%2 == 0) {
00171
00172
00173
00174
00175
00176 if(!m_postScripts[i]) {
00177 lastSubScriptWidth = 0.0;
00178 } else {
00179 lastSubScriptWidth = m_postScripts[i]->width();
00180
00181 double offset = 0.0;
00182 if(m_postScripts.size() > i+1 && m_postScripts[i+1] != NULL)
00183 offset = qMax(0.0, (m_postScripts[i+1]->width() - lastSubScriptWidth)/2.0);
00184 m_postScripts[i]->setOrigin( QPointF(
00185 offset + xOffset,
00186 yOffsetSub - m_postScripts[i]->baseLine() ) );
00187 }
00188 } else {
00189
00190 if( !m_postScripts[i] )
00191 xOffset += lastSubScriptWidth;
00192 else {
00193 double offset = qMax(0.0, (lastSubScriptWidth - m_postScripts[i]->width())/2.0);
00194 m_postScripts[i]->setOrigin( QPointF(
00195 offset + xOffset,
00196 maxSuperScriptBaseLine - m_postScripts[i]->baseLine()));
00197 xOffset += qMax(lastSubScriptWidth, m_postScripts[i]->width());
00198 }
00199 if(i != m_postScripts.size()-1)
00200 xOffset += halfthinspace;
00201 }
00202 }
00203
00204
00205
00206 setWidth( xOffset );
00207 setHeight( yOffsetSub + maxSubScriptDepth );
00208 setBaseLine( yOffsetBase + m_baseElement->baseLine() );
00209 }
00210
00211 bool MultiscriptElement::acceptCursor( const FormulaCursor& cursor )
00212 {
00213 Q_UNUSED( cursor )
00214 return false;
00215 }
00216
00217 const QList<BasicElement*> MultiscriptElement::childElements() const
00218 {
00219 QList<BasicElement*> list;
00220 for (int i=m_preScripts.count()-2;i>=0; i-=2 ) {
00221 if(m_preScripts[i]) list << m_preScripts[i];
00222 if(m_preScripts[i+1]) list << m_preScripts[i+1];
00223 }
00224 list << m_baseElement;
00225 foreach( BasicElement* tmp, m_postScripts ) {
00226 if(tmp)
00227 list << tmp;
00228 }
00229
00230
00231 return list;
00232 }
00233
00234 QString MultiscriptElement::attributesDefaultValue( const QString& attribute ) const
00235 {
00236 Q_UNUSED( attribute )
00237 return QString();
00238 }
00239
00240 ElementType MultiscriptElement::elementType() const
00241 {
00242 return MultiScript;
00243 }
00244
00245 bool MultiscriptElement::readMathMLContent( const KoXmlElement& parent )
00246 {
00247 QString name = parent.tagName().toLower();
00248 BasicElement* tmpElement = 0;
00249 KoXmlElement tmp;
00250 bool prescript = false;
00251 bool baseElement = true;
00252 forEachElement( tmp, parent ) {
00253 if(tmp.tagName() == "none") {
00254
00255
00256
00257 if(prescript)
00258 m_preScripts.append(NULL);
00259 else
00260 m_postScripts.append(NULL);
00261 continue;
00262 } else if(tmp.tagName() == "mprescripts") {
00263 prescript = true;
00264
00265
00266 continue;
00267 }
00268
00269 tmpElement = ElementFactory::createElement( tmp.tagName(), this );
00270 if( !tmpElement->readMathML( tmp ) )
00271 return false;
00272 if( baseElement ) {
00273 delete m_baseElement;
00274 m_baseElement = tmpElement;
00275 baseElement = true;
00276 }
00277 else if( prescript)
00278 m_preScripts.append( tmpElement );
00279 else
00280 m_postScripts.append( tmpElement );
00281 }
00282 ensureEvenNumberElements();
00283 Q_ASSERT(m_baseElement);
00284 return true;
00285 }
00286
00287 void MultiscriptElement::writeMathMLContent( KoXmlWriter* writer ) const
00288 {
00289 m_baseElement->writeMathML( writer );
00290
00291 foreach( BasicElement* tmp, m_postScripts ) {
00292 if(tmp)
00293 tmp->writeMathML( writer );
00294 else {
00295
00296 writer->startElement("none");
00297 writer->endElement();
00298 }
00299 }
00300 if( m_preScripts.isEmpty() ) return;
00301 writer->startElement("mprescripts");
00302 writer->endElement();
00303 foreach( BasicElement* tmp, m_preScripts ) {
00304 if(tmp)
00305 tmp->writeMathML( writer );
00306 else {
00307
00308 writer->startElement("none");
00309 writer->endElement();
00310 }
00311 }
00312 }
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324 bool MultiscriptElement::moveCursor ( FormulaCursor& newcursor, FormulaCursor& oldcursor )
00325 {
00326
00327
00328
00329
00330
00331
00332 int childposition=newcursor.position()/2;
00333
00334 int prescriptCount=0;
00335 foreach (BasicElement* tmp, m_preScripts) {
00336 if (tmp) {
00337 prescriptCount++;
00338 }
00339 }
00340 if (childposition==prescriptCount) {
00341
00342 if (newcursor.direction()==MoveUp || newcursor.direction()==MoveDown) {
00343 return false;
00344 }
00345 if (m_postScripts.isEmpty() && m_preScripts.isEmpty()) {
00346
00347 return moveSingleSituation(newcursor,oldcursor,
00348 childElements().indexOf(m_baseElement));
00349 }
00350 if (newcursor.direction()==MoveLeft) {
00351 if (!m_preScripts.isEmpty()) {
00352
00353 int i;
00354 for (i=0; i<m_preScripts.count(); i++) {
00355 if (m_preScripts[i]) {
00356 break;
00357 }
00358 }
00359 if ((i<m_preScripts.count()) && m_preScripts[i]) {
00360 return moveHorSituation(newcursor,oldcursor,
00361 childElements().indexOf(m_preScripts[i]),
00362 childElements().indexOf(m_baseElement));
00363 }
00364 }
00365 return moveSingleSituation(newcursor,oldcursor,0);
00366 } else if (newcursor.direction()==MoveRight) {
00367 if (!m_postScripts.isEmpty()) {
00368
00369 int i;
00370 for (i=0; i<m_postScripts.count(); i++) {
00371 if (m_postScripts[i]) {
00372 break;
00373 }
00374 }
00375 if (m_postScripts[i]) {
00376 return moveHorSituation(newcursor,oldcursor,
00377 childElements().indexOf(m_baseElement),
00378 childElements().indexOf(m_postScripts[i]));
00379 }
00380 }
00381 return moveSingleSituation(newcursor,oldcursor,
00382 childElements().indexOf(m_baseElement));
00383 }
00384 } else {
00385 int groupposition;
00386 bool prescript=true;
00387 if (childposition<prescriptCount) {
00388
00389 groupposition=m_preScripts.indexOf(childElements()[childposition]);
00390 } else {
00391 groupposition=m_postScripts.indexOf(childElements()[childposition]);
00392 prescript=false;
00393 }
00394 int pair=groupposition/2;
00395 if (newcursor.direction()==MoveUp || newcursor.direction()==MoveDown) {
00396
00397 if (prescript) {
00398 if (m_preScripts[pair*2] && m_preScripts[pair*2+1]) {
00399 return moveVertSituation(newcursor,oldcursor,
00400 childElements().indexOf(m_preScripts[pair*2+1]),
00401 childElements().indexOf(m_preScripts[pair*2]));
00402 } else {
00403 return false;
00404 }
00405 } else {
00406 if (m_postScripts[pair*2] && m_postScripts[pair*2+1]) {
00407 return moveVertSituation(newcursor,oldcursor,
00408 childElements().indexOf(m_postScripts[pair*2+1]),
00409 childElements().indexOf(m_postScripts[pair*2]));
00410 } else {
00411 return false;
00412 }
00413 }
00414 } else if (newcursor.direction()==MoveLeft) {
00415 if (prescript) {
00416
00417 int i=groupposition+2;
00418 if (!((i<m_preScripts.count()) && m_preScripts[i])) {
00419 for (i=groupposition+1; i<m_preScripts.count(); i++) {
00420 if (m_preScripts[i]) {
00421 break;
00422 }
00423 }
00424 }
00425 if ((i<m_preScripts.count()) && m_preScripts[i]) {
00426 return moveHorSituation(newcursor,oldcursor,
00427 childElements().indexOf(m_preScripts[i]),
00428 childElements().indexOf(m_preScripts[groupposition]));
00429 } else {
00430 return moveSingleSituation(newcursor,oldcursor,
00431 childElements().indexOf(m_preScripts[groupposition]));
00432 }
00433 } else {
00434
00435 int i=groupposition-1;
00436 if (!(i>=0) && m_postScripts[i]) {
00437 for (i=groupposition-2; i>=0; i--) {
00438 if (m_postScripts[i]) {
00439 break;
00440 }
00441 }
00442 }
00443 if ((i>=0) && m_postScripts[i]) {
00444 return moveHorSituation(newcursor,oldcursor,
00445 childElements().indexOf(m_postScripts[i]),
00446 childElements().indexOf(m_postScripts[groupposition]));
00447 } else {
00448 return moveHorSituation(newcursor,oldcursor,
00449 childElements().indexOf(m_baseElement),
00450 childElements().indexOf(elementNext(newcursor.position())));
00451 }
00452 }
00453 } else if (newcursor.direction()==MoveRight) {
00454 if (prescript) {
00455
00456 int i=groupposition-2;
00457 if (!((i>=0) && m_preScripts[i])) {
00458 for (i=groupposition-1; i>=0; i--) {
00459 if (m_preScripts[i]) {
00460 break;
00461 }
00462 }
00463 }
00464 if ((i>=0) && m_preScripts[i]) {
00465
00466 return moveHorSituation(newcursor,oldcursor,
00467 childElements().indexOf(m_preScripts[groupposition]),
00468 childElements().indexOf(m_preScripts[i]));
00469 } else {
00470 return moveHorSituation(newcursor,oldcursor,
00471 childElements().indexOf(elementNext(newcursor.position())),
00472 childElements().indexOf(m_baseElement));
00473 }
00474 } else {
00475
00476 int i=groupposition+2;
00477 if (!((i<m_postScripts.count()) && m_postScripts[i])) {
00478 for (i=groupposition+1; i<m_postScripts.count(); i++) {
00479 if (m_postScripts[i]) {
00480 break;
00481 }
00482 }
00483 }
00484 if ((i<m_postScripts.count()) && m_postScripts[i]) {
00485 return moveHorSituation(newcursor,oldcursor,
00486 childElements().indexOf(m_postScripts[groupposition]),
00487 childElements().indexOf(m_postScripts[i]));
00488 } else {
00489 return moveSingleSituation(newcursor,oldcursor,
00490 childElements().indexOf(m_preScripts[groupposition]));
00491 }
00492 }
00493 }
00494 }
00495 return false;
00496 }
00497
00498 bool MultiscriptElement::setCursorTo ( FormulaCursor& cursor, QPointF point )
00499 {
00500 if (cursor.isSelecting()) {
00501 return false;
00502 }
00503 foreach (BasicElement* tmp, childElements()) {
00504 if (tmp->boundingRect().contains(point)) {
00505 return tmp->setCursorTo(cursor,point-tmp->origin());
00506 }
00507 }
00508 return m_baseElement->setCursorTo(cursor,point-m_baseElement->origin());
00509 }