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"