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