diff options
Diffstat (limited to 'lib/kformula/kformulacontainer.cpp')
-rw-r--r-- | lib/kformula/kformulacontainer.cpp | 643 |
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" |