summaryrefslogtreecommitdiffstats
path: root/lib/kformula/kformulacontainer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kformula/kformulacontainer.cpp')
-rw-r--r--lib/kformula/kformulacontainer.cpp643
1 files changed, 643 insertions, 0 deletions
diff --git a/lib/kformula/kformulacontainer.cpp b/lib/kformula/kformulacontainer.cpp
new file mode 100644
index 00000000..a6123154
--- /dev/null
+++ b/lib/kformula/kformulacontainer.cpp
@@ -0,0 +1,643 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001 Andrea Rizzi <rizzi@kde.org>
+ Ulrich Kuettler <ulrich.kuettler@mailbox.tu-dresden.de>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <tqapplication.h>
+#include <tqdom.h>
+#include <tqevent.h>
+#include <tqfile.h>
+#include <tqpainter.h>
+#include <tqpixmap.h>
+#include <tqstring.h>
+#include <tqtextstream.h>
+
+#include <kdebug.h>
+#include <tdelocale.h>
+#include <kprinter.h>
+
+#include "KoGlobal.h"
+#include "bracketelement.h"
+#include "contextstyle.h"
+#include "formulacursor.h"
+#include "formulaelement.h"
+#include "fractionelement.h"
+#include "indexelement.h"
+#include "kformulacommand.h"
+#include "kformulacompatibility.h"
+#include "kformulacontainer.h"
+#include "kformuladocument.h"
+#include "kformulamathmlread.h"
+#include "kformulamimesource.h"
+#include "matrixelement.h"
+#include "rootelement.h"
+#include "sequenceelement.h"
+#include "symbolelement.h"
+#include "symboltable.h"
+#include "spaceelement.h"
+#include "textelement.h"
+
+#include <assert.h>
+
+KFORMULA_NAMESPACE_BEGIN
+using namespace std;
+
+
+struct Container::Container_Impl {
+
+ Container_Impl( Document* doc )
+ : dirty( true ), cursorMoved( false ), document( doc )
+ {
+ }
+
+ ~Container_Impl()
+ {
+ delete internCursor;
+ delete rootElement;
+ document = 0;
+ }
+
+ /**
+ * If true we need to recalc the formula.
+ */
+ bool dirty;
+
+ /**
+ * Tells whether a request caused the cursor to move.
+ */
+ bool cursorMoved;
+
+ /**
+ * The element tree's root.
+ */
+ FormulaElement* rootElement;
+
+ /**
+ * The active cursor is the one that triggered the last command.
+ */
+ FormulaCursor* activeCursor;
+
+ /**
+ * The cursor that is used if there is no view.
+ */
+ FormulaCursor* internCursor;
+
+ /**
+ * The document we belong to.
+ */
+ Document* document;
+};
+
+
+FormulaElement* Container::rootElement() const { return impl->rootElement; }
+Document* Container::document() const { return impl->document; }
+
+Container::Container( Document* doc, int pos, bool registerMe )
+{
+ impl = new Container_Impl( doc );
+ impl->rootElement = 0;
+ if ( registerMe ) {
+ registerFormula( pos );
+ }
+}
+
+Container::~Container()
+{
+ unregisterFormula();
+ delete impl;
+ impl = 0;
+}
+
+
+void Container::initialize()
+{
+ assert( impl->rootElement == 0 );
+ impl->rootElement = createMainSequence();
+ impl->activeCursor = impl->internCursor = createCursor();
+ recalc();
+}
+
+
+FormulaElement* Container::createMainSequence()
+{
+ return new FormulaElement( this );
+}
+
+
+FormulaCursor* Container::createCursor()
+{
+ return new FormulaCursor(rootElement());
+}
+
+
+KoCommandHistory* Container::getHistory() const
+{
+ return document()->getHistory();
+}
+
+
+/**
+ * Gets called just before the child is removed from
+ * the element tree.
+ */
+void Container::elementRemoval(BasicElement* child)
+{
+ emit elementWillVanish(child);
+}
+
+/**
+ * Gets called whenever something changes and we need to
+ * recalc.
+ */
+void Container::changed()
+{
+ impl->dirty = true;
+}
+
+void Container::cursorHasMoved( FormulaCursor* )
+{
+ impl->cursorMoved = true;
+}
+
+void Container::moveOutLeft( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_LEFT );
+}
+
+void Container::moveOutRight( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_RIGHT );
+}
+
+void Container::moveOutAbove( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_ABOVE );
+}
+
+void Container::moveOutBelow( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, EXIT_BELOW );
+}
+
+void Container::tell( const TQString& msg )
+{
+ emit statusMsg( msg );
+}
+
+void Container::removeFormula( FormulaCursor* cursor )
+{
+ emit leaveFormula( this, cursor, REMOVE_FORMULA );
+}
+
+
+void Container::registerFormula( int pos )
+{
+ document()->registerFormula( this, pos );
+}
+
+void Container::unregisterFormula()
+{
+ document()->unregisterFormula( this );
+}
+
+
+void Container::baseSizeChanged( int size, bool owned )
+{
+ if ( owned ) {
+ emit baseSizeChanged( size );
+ }
+ else {
+ const ContextStyle& context = document()->getContextStyle();
+ emit baseSizeChanged( context.baseSize() );
+ }
+}
+
+FormulaCursor* Container::activeCursor()
+{
+ return impl->activeCursor;
+}
+
+const FormulaCursor* Container::activeCursor() const
+{
+ return impl->activeCursor;
+}
+
+
+/**
+ * Tells the formula that a view got the focus and might want to
+ * edit the formula.
+ */
+void Container::setActiveCursor(FormulaCursor* cursor)
+{
+ document()->activate(this);
+ if (cursor != 0) {
+ impl->activeCursor = cursor;
+ }
+ else {
+ *(impl->internCursor) = *(impl->activeCursor);
+ impl->activeCursor = impl->internCursor;
+ }
+}
+
+
+bool Container::hasValidCursor() const
+{
+ return (impl->activeCursor != 0) && !impl->activeCursor->isReadOnly();
+}
+
+void Container::testDirty()
+{
+ if (impl->dirty) {
+ recalc();
+ }
+}
+
+void Container::recalc()
+{
+ impl->dirty = false;
+ ContextStyle& context = impl->document->getContextStyle();
+ rootElement()->calcSizes( context );
+
+ emit formulaChanged( context.layoutUnitToPixelX( rootElement()->getWidth() ),
+ context.layoutUnitToPixelY( rootElement()->getHeight() ) );
+ emit formulaChanged( context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) ),
+ context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) ) );
+ emit cursorMoved( activeCursor() );
+}
+
+bool Container::isEmpty()
+{
+ return rootElement()->countChildren() == 0;
+}
+
+
+const SymbolTable& Container::getSymbolTable() const
+{
+ return document()->getSymbolTable();
+}
+
+
+void Container::draw( TQPainter& painter, const TQRect& r, const TQColorGroup& cg, bool edit )
+{
+ painter.fillRect( r, cg.base() );
+ draw( painter, r, edit );
+}
+
+
+void Container::draw( TQPainter& painter, const TQRect& r, bool edit )
+{
+ //ContextStyle& context = document()->getContextStyle( painter.device()->devType() == TQInternal::Printer );
+ ContextStyle& context = document()->getContextStyle( edit );
+ rootElement()->draw( painter, context.pixelToLayoutUnit( r ), context );
+}
+
+
+void Container::checkCursor()
+{
+ if ( impl->cursorMoved ) {
+ impl->cursorMoved = false;
+ emit cursorMoved( activeCursor() );
+ }
+}
+
+void Container::input( TQKeyEvent* event )
+{
+ //if ( !hasValidCursor() )
+ if ( impl->activeCursor == 0 ) {
+ return;
+ }
+ execute( activeCursor()->getElement()->input( this, event ) );
+ checkCursor();
+}
+
+
+void Container::performRequest( Request* request )
+{
+ if ( !hasValidCursor() )
+ return;
+ execute( activeCursor()->getElement()->buildCommand( this, request ) );
+ checkCursor();
+}
+
+
+void Container::paste()
+{
+ if (!hasValidCursor())
+ return;
+ TQClipboard* clipboard = TQApplication::clipboard();
+ const TQMimeSource* source = clipboard->data();
+ if (source->provides( MimeSource::selectionMimeType() )) {
+ TQByteArray data = source->encodedData( MimeSource::selectionMimeType() );
+ TQDomDocument formula;
+ formula.setContent(data);
+ paste( formula, i18n("Paste") );
+ }
+}
+
+void Container::paste( const TQDomDocument& document, TQString desc )
+{
+ FormulaCursor* cursor = activeCursor();
+ TQPtrList<BasicElement> list;
+ list.setAutoDelete( true );
+ if ( cursor->buildElementsFromMathMLDom( document.documentElement(), list ) ) {
+ uint count = list.count();
+ // You must not execute an add command that adds nothing.
+ if (count > 0) {
+ KFCReplace* command = new KFCReplace( desc, this );
+ for (uint i = 0; i < count; i++) {
+ command->addElement(list.take(0));
+ }
+ execute(command);
+ }
+ }
+}
+
+void Container::copy()
+{
+ // read-only cursors are fine for copying.
+ FormulaCursor* cursor = activeCursor();
+ if (cursor != 0) {
+ TQDomDocument formula = document()->createMathMLDomDocument();
+ cursor->copy( formula );
+ TQClipboard* clipboard = TQApplication::clipboard();
+ clipboard->setData(new MimeSource(document(), formula));
+ }
+}
+
+void Container::cut()
+{
+ if (!hasValidCursor())
+ return;
+ FormulaCursor* cursor = activeCursor();
+ if (cursor->isSelection()) {
+ copy();
+ DirectedRemove r( req_remove, beforeCursor );
+ performRequest( &r );
+ }
+}
+
+
+void Container::emitErrorMsg( const TQString& msg )
+{
+ emit errorMsg( msg );
+}
+
+void Container::execute(KCommand* command)
+{
+ if ( command != 0 ) {
+ getHistory()->addCommand(command);
+ }
+}
+
+
+TQRect Container::boundingRect() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ return TQRect( context.layoutUnitToPixelX( rootElement()->getX() ),
+ context.layoutUnitToPixelY( rootElement()->getY() ),
+ context.layoutUnitToPixelX( rootElement()->getWidth() ),
+ context.layoutUnitToPixelY( rootElement()->getHeight() ) );
+}
+
+TQRect Container::coveredRect()
+{
+ if ( impl->activeCursor != 0 ) {
+ const ContextStyle& context = document()->getContextStyle();
+ const LuPixelRect& cursorRect = impl->activeCursor->getCursorSize();
+ return TQRect( context.layoutUnitToPixelX( rootElement()->getX() ),
+ context.layoutUnitToPixelY( rootElement()->getY() ),
+ context.layoutUnitToPixelX( rootElement()->getWidth() ),
+ context.layoutUnitToPixelY( rootElement()->getHeight() ) ) |
+ TQRect( context.layoutUnitToPixelX( cursorRect.x() ),
+ context.layoutUnitToPixelY( cursorRect.y() ),
+ context.layoutUnitToPixelX( cursorRect.width() ),
+ context.layoutUnitToPixelY( cursorRect.height() ) );
+ }
+ return boundingRect();
+}
+
+double Container::width() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ return context.layoutUnitPtToPt( context.pixelXToPt( rootElement()->getWidth() ) );
+}
+
+double Container::height() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getHeight() ) );
+}
+
+double Container::baseline() const
+{
+ const ContextStyle& context = document()->getContextStyle();
+ //return context.layoutUnitToPixelY( rootElement()->getBaseline() );
+ return context.layoutUnitPtToPt( context.pixelYToPt( rootElement()->getBaseline() ) );
+}
+
+void Container::moveTo( int x, int y )
+{
+ const ContextStyle& context = document()->getContextStyle();
+ rootElement()->setX( context.pixelToLayoutUnitX( x ) );
+ rootElement()->setY( context.pixelToLayoutUnitY( y ) );
+}
+
+int Container::fontSize() const
+{
+ if ( rootElement()->hasOwnBaseSize() ) {
+ return rootElement()->getBaseSize();
+ }
+ else {
+ const ContextStyle& context = document()->getContextStyle();
+ return tqRound( context.baseSize() );
+ }
+}
+
+void Container::setFontSize( int pointSize, bool /*forPrint*/ )
+{
+ if ( rootElement()->getBaseSize() != pointSize ) {
+ execute( new KFCChangeBaseSize( i18n( "Base Size Change" ), this, rootElement(), pointSize ) );
+ }
+}
+
+void Container::setFontSizeDirect( int pointSize )
+{
+ rootElement()->setBaseSize( pointSize );
+ recalc();
+}
+
+void Container::updateMatrixActions()
+{
+ BasicElement *currentElement = activeCursor()->getElement();
+ if ( ( currentElement = currentElement->getParent() ) != 0 )
+ document()->wrapper()->enableMatrixActions( dynamic_cast<MatrixElement*>(currentElement) );
+ else
+ document()->wrapper()->enableMatrixActions( false );
+}
+
+void Container::save( TQDomElement &root )
+{
+ TQDomDocument ownerDoc = root.ownerDocument();
+ root.appendChild(rootElement()->getElementDom(ownerDoc));
+}
+
+
+/**
+ * Loads a formula from the document.
+ */
+bool Container::load( const TQDomElement &fe )
+{
+ if (!fe.isNull()) {
+ FormulaElement* root = createMainSequence();
+ if (root->buildFromDom(fe)) {
+ delete impl->rootElement;
+ impl->rootElement = root;
+ emit formulaLoaded(rootElement());
+
+ recalc();
+ return true;
+ }
+ else {
+ delete root;
+ kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
+ }
+ }
+ else {
+ kdWarning( DEBUGID ) << "Empty element." << endl;
+ }
+ return false;
+}
+
+
+void Container::saveMathML( TQTextStream& stream, bool oasisFormat )
+{
+ TQDomDocument doc;
+ if ( !oasisFormat ) {
+ doc = document()->createMathMLDomDocument();
+ }
+ rootElement()->writeMathML( doc, doc, oasisFormat );
+ stream << doc;
+}
+
+bool Container::loadMathML( const TQDomDocument &doc, bool oasisFormat )
+{
+ return loadMathML( doc.documentElement(), oasisFormat );
+}
+
+/*
+bool Container::loadMathML( const TQDomElement &element, bool oasisFormat )
+{
+ const ContextStyle& context = document()->getContextStyle();
+ MathML2KFormula filter( element, context, oasisFormat );
+ filter.startConversion();
+ if (filter.m_error) {
+ return false;
+ }
+
+ if ( load( filter.getKFormulaDom().documentElement() ) ) {
+ getHistory()->clear();
+ return true;
+ }
+ return false;
+}
+*/
+
+bool Container::loadMathML( const TQDomElement &fe, bool /*oasisFormat*/ )
+{
+ kdDebug( DEBUGID ) << "loadMathML" << endl;
+ if (!fe.isNull()) {
+ FormulaElement* root = createMainSequence();
+ if ( root->buildFromMathMLDom( fe ) != - 1) {
+ delete impl->rootElement;
+ impl->rootElement = root;
+ emit formulaLoaded(rootElement());
+
+ recalc();
+ return true;
+ }
+ else {
+ delete root;
+ kdWarning( DEBUGID ) << "Error constructing element tree." << endl;
+ }
+ }
+ else {
+ kdWarning( DEBUGID ) << "Empty element." << endl;
+ }
+ return false;
+}
+
+
+void Container::print(KPrinter& printer)
+{
+ //printer.setFullPage(true);
+ TQPainter painter;
+ if (painter.begin(&printer)) {
+ rootElement()->draw( painter, LuPixelRect( rootElement()->getX(),
+ rootElement()->getY(),
+ rootElement()->getWidth(),
+ rootElement()->getHeight() ),
+ document()->getContextStyle( false ) );
+ }
+}
+
+TQImage Container::drawImage( int width, int height )
+{
+ ContextStyle& context = document()->getContextStyle( false );
+ TQRect rect(impl->rootElement->getX(), impl->rootElement->getY(),
+ impl->rootElement->getWidth(), impl->rootElement->getHeight());
+
+ int realWidth = context.layoutUnitToPixelX( impl->rootElement->getWidth() );
+ int realHeight = context.layoutUnitToPixelY( impl->rootElement->getHeight() );
+
+ double f = TQMAX( static_cast<double>( width )/static_cast<double>( realWidth ),
+ static_cast<double>( height )/static_cast<double>( realHeight ) );
+
+ int oldZoom = context.zoom();
+ context.setZoomAndResolution( tqRound( oldZoom*f ), KoGlobal::dpiX(), KoGlobal::dpiY() );
+
+ kdDebug( DEBUGID ) << "Container::drawImage "
+ << "(" << width << " " << height << ")"
+ << "(" << context.layoutUnitToPixelX( impl->rootElement->getWidth() )
+ << " " << context.layoutUnitToPixelY( impl->rootElement->getHeight() ) << ")"
+ << endl;
+
+ TQPixmap pm( context.layoutUnitToPixelX( impl->rootElement->getWidth() ),
+ context.layoutUnitToPixelY( impl->rootElement->getHeight() ) );
+ pm.fill();
+ TQPainter paint(&pm);
+ impl->rootElement->draw(paint, rect, context);
+ paint.end();
+ context.setZoomAndResolution( oldZoom, KoGlobal::dpiX(), KoGlobal::dpiY() );
+ //return pm.convertToImage().smoothScale( width, height );
+ return pm.convertToImage();
+}
+
+TQString Container::texString()
+{
+ return rootElement()->toLatex();
+}
+
+TQString Container::formulaString()
+{
+ return rootElement()->formulaString();
+}
+
+KFORMULA_NAMESPACE_END
+
+using namespace KFormula;
+#include "kformulacontainer.moc"