00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <qapplication.h>
00022 #include <qdom.h>
00023 #include <qevent.h>
00024 #include <qfile.h>
00025 #include <qpainter.h>
00026 #include <qpixmap.h>
00027 #include <qstring.h>
00028 #include <qtextstream.h>
00029
00030 #include <kdebug.h>
00031 #include <klocale.h>
00032 #include <kprinter.h>
00033
00034 #include "KoGlobal.h"
00035 #include "bracketelement.h"
00036 #include "contextstyle.h"
00037 #include "formulacursor.h"
00038 #include "formulaelement.h"
00039 #include "fractionelement.h"
00040 #include "indexelement.h"
00041 #include "kformulacommand.h"
00042 #include "kformulacompatibility.h"
00043 #include "kformulacontainer.h"
00044 #include "kformuladocument.h"
00045 #include "kformulamathmlread.h"
00046 #include "kformulamimesource.h"
00047 #include "matrixelement.h"
00048 #include "rootelement.h"
00049 #include "sequenceelement.h"
00050 #include "symbolelement.h"
00051 #include "symboltable.h"
00052 #include "spaceelement.h"
00053 #include "textelement.h"
00054
00055 #include <assert.h>
00056
00057 KFORMULA_NAMESPACE_BEGIN
00058 using namespace std;
00059
00060
00061 struct Container::Container_Impl {
00062
00063 Container_Impl( Document* doc )
00064 : dirty( true ), cursorMoved( false ), document( doc )
00065 {
00066 }
00067
00068 ~Container_Impl()
00069 {
00070 delete internCursor;
00071 delete rootElement;
00072 document = 0;
00073 }
00074
00078 bool dirty;
00079
00083 bool cursorMoved;
00084
00088 FormulaElement* rootElement;
00089
00093 FormulaCursor* activeCursor;
00094
00098 FormulaCursor* internCursor;
00099
00103 Document* document;
00104 };
00105
00106
00107 FormulaElement* Container::rootElement() const { return impl->rootElement; }
00108 Document* Container::document() const { return impl->document; }
00109
00110 Container::Container( Document* doc, int pos, bool registerMe )
00111 {
00112 impl = new Container_Impl( doc );
00113 impl->rootElement = 0;
00114 if ( registerMe ) {
00115 registerFormula( pos );
00116 }
00117 }
00118
00119 Container::~Container()
00120 {
00121 unregisterFormula();
00122 delete impl;
00123 impl = 0;
00124 }
00125
00126
00127 void Container::initialize()
00128 {
00129 assert( impl->rootElement == 0 );
00130 impl->rootElement = createMainSequence();
00131 impl->activeCursor = impl->internCursor = createCursor();
00132 recalc();
00133 }
00134
00135
00136 FormulaElement* Container::createMainSequence()
00137 {
00138 return new FormulaElement( this );
00139 }
00140
00141
00142 FormulaCursor* Container::createCursor()
00143 {
00144 return new FormulaCursor(rootElement());
00145 }
00146
00147
00148 KoCommandHistory* Container::getHistory() const
00149 {
00150 return document()->getHistory();
00151 }
00152
00153
00158 void Container::elementRemoval(BasicElement* child)
00159 {
00160 emit elementWillVanish(child);
00161 }
00162
00167 void Container::changed()
00168 {
00169 impl->dirty = true;
00170 }
00171
00172 void Container::cursorHasMoved( FormulaCursor* )
00173 {
00174 impl->cursorMoved = true;
00175 }
00176
00177 void Container::moveOutLeft( FormulaCursor* cursor )
00178 {
00179 emit leaveFormula( this, cursor, EXIT_LEFT );
00180 }
00181
00182 void Container::moveOutRight( FormulaCursor* cursor )
00183 {
00184 emit leaveFormula( this, cursor, EXIT_RIGHT );
00185 }
00186
00187 void Container::moveOutAbove( FormulaCursor* cursor )
00188 {
00189 emit leaveFormula( this, cursor, EXIT_ABOVE );
00190 }
00191
00192 void Container::moveOutBelow( FormulaCursor* cursor )
00193 {
00194 emit leaveFormula( this, cursor, EXIT_BELOW );
00195 }
00196
00197 void Container::tell( const QString& msg )
00198 {
00199 emit statusMsg( msg );
00200 }
00201
00202 void Container::removeFormula( FormulaCursor* cursor )
00203 {
00204 emit leaveFormula( this, cursor, REMOVE_FORMULA );
00205 }
00206
00207
00208 void Container::registerFormula( int pos )
00209 {
00210 document()->registerFormula( this, pos );
00211 }
00212
00213 void Container::unregisterFormula()
00214 {
00215 document()->unregisterFormula( this );
00216 }
00217
00218
00219 void Container::baseSizeChanged( int size, bool owned )
00220 {
00221 if ( owned ) {
00222 emit baseSizeChanged( size );
00223 }
00224 else {
00225 const ContextStyle& context = document()->getContextStyle();
00226 emit baseSizeChanged( context.baseSize() );
00227 }
00228 }
00229
00230 FormulaCursor* Container::activeCursor()
00231 {
00232 return impl->activeCursor;
00233 }
00234
00235 const FormulaCursor* Container::activeCursor() const
00236 {
00237 return impl->activeCursor;
00238 }
00239
00240
00245 void Container::setActiveCursor(FormulaCursor* cursor)
00246 {
00247 document()->activate(this);
00248 if (cursor != 0) {
00249 impl->activeCursor = cursor;
00250 }
00251 else {
00252 *(impl->internCursor) = *(impl->activeCursor);
00253 impl->activeCursor = impl->internCursor;
00254 }
00255 }
00256
00257
00258 bool Container::hasValidCursor() const
00259 {
00260 return (impl->activeCursor != 0) && !impl->activeCursor->isReadOnly();
00261 }
00262
00263 void Container::testDirty()
00264 {
00265 if (impl->dirty) {
00266 recalc();
00267 }
00268 }
00269
00270 void Container::recalc()
00271 {
00272 impl->dirty = false;
00273 ContextStyle& context = impl->document->getContextStyle();
00274 rootElement()->calcSizes( context );
00275
00276 emit formulaChanged( context.layoutUnitToPixelX( rootElement()->getWidth() ),
00277 context.layoutUnitToPixelY( rootElement()->getHeight() ) );
00278 emit formulaChanged( context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) ),
00279 context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) ) );
00280 emit cursorMoved( activeCursor() );
00281 }
00282
00283 bool Container::isEmpty()
00284 {
00285 return rootElement()->countChildren() == 0;
00286 }
00287
00288
00289 const SymbolTable& Container::getSymbolTable() const
00290 {
00291 return document()->getSymbolTable();
00292 }
00293
00294
00295 void Container::draw( QPainter& painter, const QRect& r, const QColorGroup& cg, bool edit )
00296 {
00297 painter.fillRect( r, cg.base() );
00298 draw( painter, r, edit );
00299 }
00300
00301
00302 void Container::draw( QPainter& painter, const QRect& r, bool edit )
00303 {
00304
00305 ContextStyle& context = document()->getContextStyle( edit );
00306 rootElement()->draw( painter, context.pixelToLayoutUnit( r ), context );
00307 }
00308
00309
00310 void Container::checkCursor()
00311 {
00312 if ( impl->cursorMoved ) {
00313 impl->cursorMoved = false;
00314 emit cursorMoved( activeCursor() );
00315 }
00316 }
00317
00318 void Container::input( QKeyEvent* event )
00319 {
00320
00321 if ( impl->activeCursor == 0 ) {
00322 return;
00323 }
00324 execute( activeCursor()->getElement()->input( this, event ) );
00325 checkCursor();
00326 }
00327
00328
00329 void Container::performRequest( Request* request )
00330 {
00331 if ( !hasValidCursor() )
00332 return;
00333 execute( activeCursor()->getElement()->buildCommand( this, request ) );
00334 checkCursor();
00335 }
00336
00337
00338 void Container::paste()
00339 {
00340 if (!hasValidCursor())
00341 return;
00342 QClipboard* clipboard = QApplication::clipboard();
00343 const QMimeSource* source = clipboard->data();
00344 if (source->provides( MimeSource::selectionMimeType() )) {
00345 QByteArray data = source->encodedData( MimeSource::selectionMimeType() );
00346 QDomDocument formula;
00347 formula.setContent(data);
00348 paste( formula, i18n("Paste") );
00349 }
00350 }
00351
00352 void Container::paste( const QDomDocument& document, QString desc )
00353 {
00354 FormulaCursor* cursor = activeCursor();
00355 QPtrList<BasicElement> list;
00356 list.setAutoDelete( true );
00357 if ( cursor->buildElementsFromMathMLDom( document.documentElement(), list ) ) {
00358 uint count = list.count();
00359
00360 if (count > 0) {
00361 KFCReplace* command = new KFCReplace( desc, this );
00362 for (uint i = 0; i < count; i++) {
00363 command->addElement(list.take(0));
00364 }
00365 execute(command);
00366 }
00367 }
00368 }
00369
00370 void Container::copy()
00371 {
00372
00373 FormulaCursor* cursor = activeCursor();
00374 if (cursor != 0) {
00375 QDomDocument formula = document()->createMathMLDomDocument();
00376 cursor->copy( formula );
00377 QClipboard* clipboard = QApplication::clipboard();
00378 clipboard->setData(new MimeSource(document(), formula));
00379 }
00380 }
00381
00382 void Container::cut()
00383 {
00384 if (!hasValidCursor())
00385 return;
00386 FormulaCursor* cursor = activeCursor();
00387 if (cursor->isSelection()) {
00388 copy();
00389 DirectedRemove r( req_remove, beforeCursor );
00390 performRequest( &r );
00391 }
00392 }
00393
00394
00395 void Container::emitErrorMsg( const QString& msg )
00396 {
00397 emit errorMsg( msg );
00398 }
00399
00400 void Container::execute(KCommand* command)
00401 {
00402 if ( command != 0 ) {
00403 getHistory()->addCommand(command);
00404 }
00405 }
00406
00407
00408 QRect Container::boundingRect() const
00409 {
00410 const ContextStyle& context = document()->getContextStyle();
00411 return QRect( context.layoutUnitToPixelX( rootElement()->getX() ),
00412 context.layoutUnitToPixelY( rootElement()->getY() ),
00413 context.layoutUnitToPixelX( rootElement()->getWidth() ),
00414 context.layoutUnitToPixelY( rootElement()->getHeight() ) );
00415 }
00416
00417 QRect Container::coveredRect()
00418 {
00419 if ( impl->activeCursor != 0 ) {
00420 const ContextStyle& context = document()->getContextStyle();
00421 const LuPixelRect& cursorRect = impl->activeCursor->getCursorSize();
00422 return QRect( context.layoutUnitToPixelX( rootElement()->getX() ),
00423 context.layoutUnitToPixelY( rootElement()->getY() ),
00424 context.layoutUnitToPixelX( rootElement()->getWidth() ),
00425 context.layoutUnitToPixelY( rootElement()->getHeight() ) ) |
00426 QRect( context.layoutUnitToPixelX( cursorRect.x() ),
00427 context.layoutUnitToPixelY( cursorRect.y() ),
00428 context.layoutUnitToPixelX( cursorRect.width() ),
00429 context.layoutUnitToPixelY( cursorRect.height() ) );
00430 }
00431 return boundingRect();
00432 }
00433
00434 double Container::width() const
00435 {
00436 const ContextStyle& context = document()->getContextStyle();
00437 return context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) );
00438 }
00439
00440 double Container::height() const
00441 {
00442 const ContextStyle& context = document()->getContextStyle();
00443 return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) );
00444 }
00445
00446 double Container::baseline() const
00447 {
00448 const ContextStyle& context = document()->getContextStyle();
00449
00450 return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getBaseline() ) );
00451 }
00452
00453 void Container::moveTo( int x, int y )
00454 {
00455 const ContextStyle& context = document()->getContextStyle();
00456 rootElement()->setX( context.pixelToLayoutUnitX( x ) );
00457 rootElement()->setY( context.pixelToLayoutUnitY( y ) );
00458 }
00459
00460 int Container::fontSize() const
00461 {
00462 if ( rootElement()->hasOwnBaseSize() ) {
00463 return rootElement()->getBaseSize();
00464 }
00465 else {
00466 const ContextStyle& context = document()->getContextStyle();
00467 return qRound( context.baseSize() );
00468 }
00469 }
00470
00471 void Container::setFontSize( int pointSize, bool )
00472 {
00473 if ( rootElement()->getBaseSize() != pointSize ) {
00474 execute( new KFCChangeBaseSize( i18n( "Base Size Change" ), this, rootElement(), pointSize ) );
00475 }
00476 }
00477
00478 void Container::setFontSizeDirect( int pointSize )
00479 {
00480 rootElement()->setBaseSize( pointSize );
00481 recalc();
00482 }
00483
00484 void Container::updateMatrixActions()
00485 {
00486 BasicElement *currentElement = activeCursor()->getElement();
00487 if ( ( currentElement = currentElement->getParent() ) != 0 )
00488 document()->wrapper()->enableMatrixActions( dynamic_cast<MatrixElement*>(currentElement) );
00489 else
00490 document()->wrapper()->enableMatrixActions( false );
00491 }
00492
00493 void Container::save( QDomElement &root )
00494 {
00495 QDomDocument ownerDoc = root.ownerDocument();
00496 root.appendChild(rootElement()->getElementDom(ownerDoc));
00497 }
00498
00499
00503 bool Container::load( const QDomElement &fe )
00504 {
00505 if (!fe.isNull()) {
00506 FormulaElement* root = createMainSequence();
00507 if (root->buildFromDom(fe)) {
00508 delete impl->rootElement;
00509 impl->rootElement = root;
00510 emit formulaLoaded(rootElement());
00511
00512 recalc();
00513 return true;
00514 }
00515 else {
00516 delete root;
00517 kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
00518 }
00519 }
00520 else {
00521 kdWarning( DEBUGID ) << "Empty element." << endl;
00522 }
00523 return false;
00524 }
00525
00526
00527 void Container::saveMathML( QTextStream& stream, bool oasisFormat )
00528 {
00529 QDomDocument doc;
00530 if ( !oasisFormat ) {
00531 doc = document()->createMathMLDomDocument();
00532 }
00533 rootElement()->writeMathML( doc, doc, oasisFormat );
00534 stream << doc;
00535 }
00536
00537 bool Container::loadMathML( const QDomDocument &doc, bool oasisFormat )
00538 {
00539 return loadMathML( doc.documentElement(), oasisFormat );
00540 }
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560 bool Container::loadMathML( const QDomElement &fe, bool )
00561 {
00562 kdDebug( DEBUGID ) << "loadMathML" << endl;
00563 if (!fe.isNull()) {
00564 FormulaElement* root = createMainSequence();
00565 if ( root->buildFromMathMLDom( fe ) != - 1) {
00566 delete impl->rootElement;
00567 impl->rootElement = root;
00568 emit formulaLoaded(rootElement());
00569
00570 recalc();
00571 return true;
00572 }
00573 else {
00574 delete root;
00575 kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
00576 }
00577 }
00578 else {
00579 kdWarning( DEBUGID ) << "Empty element." << endl;
00580 }
00581 return false;
00582 }
00583
00584
00585 void Container::print(KPrinter& printer)
00586 {
00587
00588 QPainter painter;
00589 if (painter.begin(&printer)) {
00590 rootElement()->draw( painter, LuPixelRect( rootElement()->getX(),
00591 rootElement()->getY(),
00592 rootElement()->getWidth(),
00593 rootElement()->getHeight() ),
00594 document()->getContextStyle( false ) );
00595 }
00596 }
00597
00598 QImage Container::drawImage( int width, int height )
00599 {
00600 ContextStyle& context = document()->getContextStyle( false );
00601 QRect rect(impl->rootElement->getX(), impl->rootElement->getY(),
00602 impl->rootElement->getWidth(), impl->rootElement->getHeight());
00603
00604 int realWidth = context.layoutUnitToPixelX( impl->rootElement->getWidth() );
00605 int realHeight = context.layoutUnitToPixelY( impl->rootElement->getHeight() );
00606
00607 double f = QMAX( static_cast<double>( width )/static_cast<double>( realWidth ),
00608 static_cast<double>( height )/static_cast<double>( realHeight ) );
00609
00610 int oldZoom = context.zoom();
00611 context.setZoomAndResolution( qRound( oldZoom*f ), KoGlobal::dpiX(), KoGlobal::dpiY() );
00612
00613 kdDebug( DEBUGID ) << "Container::drawImage "
00614 << "(" << width << " " << height << ")"
00615 << "(" << context.layoutUnitToPixelX( impl->rootElement->getWidth() )
00616 << " " << context.layoutUnitToPixelY( impl->rootElement->getHeight() ) << ")"
00617 << endl;
00618
00619 QPixmap pm( context.layoutUnitToPixelX( impl->rootElement->getWidth() ),
00620 context.layoutUnitToPixelY( impl->rootElement->getHeight() ) );
00621 pm.fill();
00622 QPainter paint(&pm);
00623 impl->rootElement->draw(paint, rect, context);
00624 paint.end();
00625 context.setZoomAndResolution( oldZoom, KoGlobal::dpiX(), KoGlobal::dpiY() );
00626
00627 return pm.convertToImage();
00628 }
00629
00630 QString Container::texString()
00631 {
00632 return rootElement()->toLatex();
00633 }
00634
00635 QString Container::formulaString()
00636 {
00637 return rootElement()->formulaString();
00638 }
00639
00640 KFORMULA_NAMESPACE_END
00641
00642 using namespace KFormula;
00643 #include "kformulacontainer.moc"