diff options
Diffstat (limited to 'lib/kformula/kformulacontainer.cc')
-rw-r--r-- | lib/kformula/kformulacontainer.cc | 643 |
1 files changed, 643 insertions, 0 deletions
diff --git a/lib/kformula/kformulacontainer.cc b/lib/kformula/kformulacontainer.cc new file mode 100644 index 00000000..84471e1b --- /dev/null +++ b/lib/kformula/kformulacontainer.cc @@ -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 <qapplication.h> +#include <qdom.h> +#include <qevent.h> +#include <qfile.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qstring.h> +#include <qtextstream.h> + +#include <kdebug.h> +#include <klocale.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 QString& 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( QPainter& painter, const QRect& r, const QColorGroup& cg, bool edit ) +{ + painter.fillRect( r, cg.base() ); + draw( painter, r, edit ); +} + + +void Container::draw( QPainter& painter, const QRect& r, bool edit ) +{ + //ContextStyle& context = document()->getContextStyle( painter.device()->devType() == QInternal::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( QKeyEvent* 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; + QClipboard* clipboard = QApplication::clipboard(); + const QMimeSource* source = clipboard->data(); + if (source->provides( MimeSource::selectionMimeType() )) { + QByteArray data = source->encodedData( MimeSource::selectionMimeType() ); + QDomDocument formula; + formula.setContent(data); + paste( formula, i18n("Paste") ); + } +} + +void Container::paste( const QDomDocument& document, QString desc ) +{ + FormulaCursor* cursor = activeCursor(); + QPtrList<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) { + QDomDocument formula = document()->createMathMLDomDocument(); + cursor->copy( formula ); + QClipboard* clipboard = QApplication::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 QString& msg ) +{ + emit errorMsg( msg ); +} + +void Container::execute(KCommand* command) +{ + if ( command != 0 ) { + getHistory()->addCommand(command); + } +} + + +QRect Container::boundingRect() const +{ + const ContextStyle& context = document()->getContextStyle(); + return QRect( context.layoutUnitToPixelX( rootElement()->getX() ), + context.layoutUnitToPixelY( rootElement()->getY() ), + context.layoutUnitToPixelX( rootElement()->getWidth() ), + context.layoutUnitToPixelY( rootElement()->getHeight() ) ); +} + +QRect Container::coveredRect() +{ + if ( impl->activeCursor != 0 ) { + const ContextStyle& context = document()->getContextStyle(); + const LuPixelRect& cursorRect = impl->activeCursor->getCursorSize(); + return QRect( context.layoutUnitToPixelX( rootElement()->getX() ), + context.layoutUnitToPixelY( rootElement()->getY() ), + context.layoutUnitToPixelX( rootElement()->getWidth() ), + context.layoutUnitToPixelY( rootElement()->getHeight() ) ) | + QRect( 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 qRound( 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( QDomElement &root ) +{ + QDomDocument ownerDoc = root.ownerDocument(); + root.appendChild(rootElement()->getElementDom(ownerDoc)); +} + + +/** + * Loads a formula from the document. + */ +bool Container::load( const QDomElement &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( QTextStream& stream, bool oasisFormat ) +{ + QDomDocument doc; + if ( !oasisFormat ) { + doc = document()->createMathMLDomDocument(); + } + rootElement()->writeMathML( doc, doc, oasisFormat ); + stream << doc; +} + +bool Container::loadMathML( const QDomDocument &doc, bool oasisFormat ) +{ + return loadMathML( doc.documentElement(), oasisFormat ); +} + +/* +bool Container::loadMathML( const QDomElement &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 QDomElement &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); + QPainter painter; + if (painter.begin(&printer)) { + rootElement()->draw( painter, LuPixelRect( rootElement()->getX(), + rootElement()->getY(), + rootElement()->getWidth(), + rootElement()->getHeight() ), + document()->getContextStyle( false ) ); + } +} + +QImage Container::drawImage( int width, int height ) +{ + ContextStyle& context = document()->getContextStyle( false ); + QRect 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 = QMAX( static_cast<double>( width )/static_cast<double>( realWidth ), + static_cast<double>( height )/static_cast<double>( realHeight ) ); + + int oldZoom = context.zoom(); + context.setZoomAndResolution( qRound( oldZoom*f ), KoGlobal::dpiX(), KoGlobal::dpiY() ); + + kdDebug( DEBUGID ) << "Container::drawImage " + << "(" << width << " " << height << ")" + << "(" << context.layoutUnitToPixelX( impl->rootElement->getWidth() ) + << " " << context.layoutUnitToPixelY( impl->rootElement->getHeight() ) << ")" + << endl; + + QPixmap pm( context.layoutUnitToPixelX( impl->rootElement->getWidth() ), + context.layoutUnitToPixelY( impl->rootElement->getHeight() ) ); + pm.fill(); + QPainter 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(); +} + +QString Container::texString() +{ + return rootElement()->toLatex(); +} + +QString Container::formulaString() +{ + return rootElement()->formulaString(); +} + +KFORMULA_NAMESPACE_END + +using namespace KFormula; +#include "kformulacontainer.moc" |