summaryrefslogtreecommitdiffstats
path: root/kword/KWFormulaFrameSet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kword/KWFormulaFrameSet.cpp')
-rw-r--r--kword/KWFormulaFrameSet.cpp540
1 files changed, 540 insertions, 0 deletions
diff --git a/kword/KWFormulaFrameSet.cpp b/kword/KWFormulaFrameSet.cpp
new file mode 100644
index 00000000..7f167a23
--- /dev/null
+++ b/kword/KWFormulaFrameSet.cpp
@@ -0,0 +1,540 @@
+/* This file is part of the KDE project
+ Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include <qfile.h>
+
+#include "KWFormulaFrameSet.h"
+
+#include "KWDocument.h"
+#include "KWView.h"
+#include "KWViewMode.h"
+#include "KWCanvas.h"
+#include "KWFrame.h"
+#include "defs.h"
+
+#include <kformulacontainer.h>
+#include <kformuladocument.h>
+#include <kformulaview.h>
+#include <KoOasisContext.h>
+#include <KoXmlNS.h>
+#include <KoXmlWriter.h>
+
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kdebug.h>
+#include <ktempfile.h>
+#include <dcopobject.h>
+#include "KWordFormulaFrameSetIface.h"
+#include "KWordFormulaFrameSetEditIface.h"
+
+#include <assert.h>
+
+// #ifdef __GNUC__
+// #undef k_funcinfo
+// #define k_funcinfo "[\033[36m" << __PRETTY_FUNCTION__ << "\033[m] "
+// #endif
+
+/******************************************************************/
+/* Class: KWFormulaFrameSet */
+/******************************************************************/
+KWFormulaFrameSet::KWFormulaFrameSet( KWDocument *doc, const QString & name )
+ : KWFrameSet( doc ), m_changed( false ), m_edit( 0 )
+{
+ if ( name.isEmpty() )
+ m_name = doc->generateFramesetName( i18n( "Formula %1" ) );
+ else
+ m_name = name;
+
+ init();
+}
+
+KWFormulaFrameSet::KWFormulaFrameSet( KWDocument* doc, const QDomElement& frameTag,
+ const QDomElement& mathTag, KoOasisContext& context )
+ : KWFrameSet( doc ), m_changed( false ), m_edit( 0 )
+{
+ m_name = frameTag.attributeNS( KoXmlNS::draw, "name", QString::null );
+ if ( doc->frameSetByName( m_name ) ) // already exists!
+ m_name = doc->generateFramesetName( m_name + " %1" );
+
+ init();
+
+ context.styleStack().save();
+ context.fillStyleStack( frameTag, KoXmlNS::draw, "style-name", "graphic" ); // get the style for the graphics element
+ /*KWFrame* frame =*/ loadOasisFrame( frameTag, context );
+ context.styleStack().restore();
+
+ formula->loadMathML( mathTag );
+}
+
+void KWFormulaFrameSet::init()
+{
+ // The newly created formula is not yet part of the formula
+ // document. It will be added when a frame is created.
+ formula = m_doc->formulaDocument()->createFormula( -1, false );
+
+ // With the new drawing scheme (drawFrame being called with translated painter)
+ // there is no need to move the KFormulaContainer anymore, it remains at (0,0).
+ formula->moveTo( 0, 0 );
+
+ connect( formula, SIGNAL( formulaChanged( double, double ) ),
+ this, SLOT( slotFormulaChanged( double, double ) ) );
+ connect( formula, SIGNAL( errorMsg( const QString& ) ),
+ this, SLOT( slotErrorMessage( const QString& ) ) );
+
+ /*
+ if ( isFloating() ) {
+ // we need to look for the anchor every time, don't cache this value.
+ // undo/redo creates/deletes anchors
+ KWAnchor * anchor = findAnchor( 0 );
+ if ( anchor ) {
+ KoTextFormat * format = anchor->format();
+ formula->setFontSize( format->pointSize() );
+ }
+ }
+ */
+ QRect rect = formula->boundingRect();
+ slotFormulaChanged(rect.width(), rect.height());
+}
+
+KWordFrameSetIface* KWFormulaFrameSet::dcopObject()
+{
+ if ( !m_dcop )
+ m_dcop = new KWordFormulaFrameSetIface( this );
+
+ return m_dcop;
+}
+
+KWFormulaFrameSet::~KWFormulaFrameSet()
+{
+ kdDebug() << k_funcinfo << endl;
+ delete formula;
+}
+
+void KWFormulaFrameSet::addFrame( KWFrame *frame, bool recalc )
+{
+ kdDebug() << k_funcinfo << endl;
+ if ( formula ) {
+ frame->setWidth( formula->width() );
+ frame->setHeight( formula->height() );
+ }
+ KWFrameSet::addFrame( frame, recalc );
+ if ( formula ) {
+ formula->registerFormula();
+ }
+}
+
+void KWFormulaFrameSet::deleteFrame( unsigned int num, bool remove, bool recalc )
+{
+ kdDebug() << k_funcinfo << endl;
+ assert( num == 0 );
+ KWFrameSet::deleteFrame( num, remove, recalc );
+ formula->unregisterFormula();
+}
+
+
+KWFrameSetEdit* KWFormulaFrameSet::createFrameSetEdit(KWCanvas* canvas)
+{
+ return new KWFormulaFrameSetEdit(this, canvas);
+}
+
+void KWFormulaFrameSet::drawFrameContents( KWFrame* /*frame*/,
+ QPainter* painter, const QRect& crect,
+ const QColorGroup& cg, bool onlyChanged,
+ bool resetChanged,
+ KWFrameSetEdit* /*edit*/, KWViewMode * )
+{
+ if ( m_changed || !onlyChanged )
+ {
+ if ( resetChanged )
+ m_changed = false;
+
+ bool printing = painter->device()->devType() == QInternal::Printer;
+ bool clipping = true;
+ QPainter *p;
+ QPixmap* pix = 0L;
+ if ( printing ) {
+ p = painter;
+ clipping = painter->hasClipping();
+
+ // That's unfortunate for formulas wider than the page.
+ // However it helps a lot with ordinary formulas.
+ painter->setClipping( false );
+ }
+ else {
+ pix = doubleBufferPixmap( crect.size() );
+ p = new QPainter( pix );
+ p->translate( -crect.x(), -crect.y() );
+ }
+
+ if ( m_edit ) {
+ //KWFormulaFrameSetEdit * formulaEdit = static_cast<KWFormulaFrameSetEdit *>(edit);
+ if ( m_edit->getFormulaView() ) {
+ m_edit->getFormulaView()->draw( *p, crect, cg );
+ }
+ else {
+ formula->draw( *p, crect, cg );
+ }
+ }
+ else {
+ formula->draw( *p, crect, cg );
+ }
+
+ if ( !printing ) {
+ p->end();
+ delete p;
+ painter->drawPixmap( crect.topLeft(), *pix );
+ }
+ else {
+ painter->setClipping( clipping );
+ }
+ }
+}
+
+
+void KWFormulaFrameSet::slotFormulaChanged( double width, double height )
+{
+ if ( m_frames.isEmpty() )
+ return;
+
+ double oldWidth = m_frames.first()->width();
+ double oldHeight = m_frames.first()->height();
+
+ m_frames.first()->setWidth( width );
+ m_frames.first()->setHeight( height );
+
+ updateFrames();
+ kWordDocument()->layout();
+ if ( ( oldWidth != width ) || ( oldHeight != height ) ) {
+ kWordDocument()->repaintAllViews( false );
+ kWordDocument()->updateRulerFrameStartEnd();
+ }
+
+ m_changed = true;
+
+ if ( !m_edit ) {
+ // A change without a FrameSetEdit! This must be the result of
+ // an undo. We need to evaluate.
+ formula->startEvaluation();
+ }
+}
+
+void KWFormulaFrameSet::slotErrorMessage( const QString& msg )
+{
+ KMessageBox::error( /*m_widget*/ 0, msg );
+}
+
+MouseMeaning KWFormulaFrameSet::getMouseMeaningInsideFrame( const KoPoint& )
+{
+ return MEANING_MOUSE_INSIDE_TEXT;
+}
+
+QDomElement KWFormulaFrameSet::save(QDomElement& parentElem, bool saveFrames)
+{
+ if ( m_frames.isEmpty() ) // Deleted frameset -> don't save
+ return QDomElement();
+ QDomElement framesetElem = parentElem.ownerDocument().createElement("FRAMESET");
+ parentElem.appendChild(framesetElem);
+
+ KWFrameSet::saveCommon(framesetElem, saveFrames);
+
+ QDomElement formulaElem = parentElem.ownerDocument().createElement("FORMULA");
+ framesetElem.appendChild(formulaElem);
+ formula->save(formulaElem);
+ return framesetElem;
+}
+
+void KWFormulaFrameSet::saveOasis(KoXmlWriter& writer, KoSavingContext& context, bool) const
+{
+ KWFrame *frame = m_frames.getFirst();
+ frame->startOasisFrame( writer, context.mainStyles(), name() );
+
+ KTempFile contentTmpFile;
+ contentTmpFile.setAutoDelete( true );
+ QFile* tmpFile = contentTmpFile.file();
+
+ QTextStream stream(tmpFile);
+ stream.setEncoding( QTextStream::UnicodeUTF8 );
+ formula->saveMathML( stream, true );
+ tmpFile->close();
+
+ writer.startElement( "draw:object" );
+ writer.startElement( "math:math" );
+ writer.addCompleteElement( tmpFile );
+ writer.endElement(); // math:math
+ writer.endElement(); // draw:object
+ writer.endElement(); // draw:frame
+}
+
+void KWFormulaFrameSet::load(QDomElement& attributes, bool loadFrames)
+{
+ KWFrameSet::load(attributes, loadFrames);
+ QDomElement formulaElem = attributes.namedItem("FORMULA").toElement();
+ paste( formulaElem );
+}
+
+void KWFormulaFrameSet::paste( QDomNode& formulaElem )
+{
+ if (!formulaElem.isNull()) {
+ if (formula == 0) {
+ formula = m_doc->formulaDocument()->createFormula( -1, false );
+ connect(formula, SIGNAL(formulaChanged(double, double)),
+ this, SLOT(slotFormulaChanged(double, double)));
+ connect( formula, SIGNAL( errorMsg( const QString& ) ),
+ this, SLOT( slotErrorMessage( const QString& ) ) );
+ }
+ m_doc->formulaDocument()->setCreationStrategy( "Oasis" );
+ if ( !formula->loadMathML( formulaElem.firstChild().toElement() ) ) {
+ kdError(32001) << "Error loading formula" << endl;
+ }
+ }
+ else {
+ kdError(32001) << "Missing math tag in FRAMESET" << endl;
+ }
+}
+
+void KWFormulaFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position )
+{
+ kdDebug() << k_funcinfo << endl;
+ KWFrameSet::moveFloatingFrame( frameNum, position );
+ if ( !m_frames.isEmpty() ) {
+ formula->setDocumentPosition( position.x(), position.y()+formula->baseline() );
+ }
+}
+
+int KWFormulaFrameSet::floatingFrameBaseline( int /*frameNum*/ )
+{
+ if ( !m_frames.isEmpty() )
+ {
+ return m_doc->ptToLayoutUnitPixY( formula->baseline() );
+ }
+ return -1;
+}
+
+void KWFormulaFrameSet::setAnchorFormat( KoTextFormat* format, int /*frameNum*/ )
+{
+ if ( !m_frames.isEmpty() ) {
+ formula->setFontSizeDirect( format->pointSize() );
+ }
+}
+
+
+QPixmap* KWFormulaFrameSet::m_bufPixmap = 0;
+
+// stolen from KWDocument
+// However, I don't see if a formula frame can be an underlying
+// frame. That is why I use my own buffer.
+QPixmap* KWFormulaFrameSet::doubleBufferPixmap( const QSize& s )
+{
+ if ( !m_bufPixmap ) {
+ int w = QABS( s.width() );
+ int h = QABS( s.height() );
+ m_bufPixmap = new QPixmap( w, h );
+ } else {
+ if ( m_bufPixmap->width() < s.width() ||
+ m_bufPixmap->height() < s.height() ) {
+ m_bufPixmap->resize( QMAX( s.width(), m_bufPixmap->width() ),
+ QMAX( s.height(), m_bufPixmap->height() ) );
+ }
+ }
+
+ return m_bufPixmap;
+}
+
+
+KWFormulaFrameSetEdit::KWFormulaFrameSetEdit(KWFormulaFrameSet* fs, KWCanvas* canvas)
+ : KWFrameSetEdit(fs, canvas)
+{
+ formulaView = new KFormula::View( fs->getFormula() );
+
+ connect( formulaView, SIGNAL( cursorChanged( bool, bool ) ),
+ this, SLOT( cursorChanged( bool, bool ) ) );
+ connect( fs->getFormula(), SIGNAL( leaveFormula( Container*, FormulaCursor*, int ) ),
+ this, SLOT( slotLeaveFormula( Container*, FormulaCursor*, int ) ) );
+
+ fs->m_edit = this;
+
+ m_canvas->gui()->getView()->showFormulaToolbar(true);
+ focusInEvent();
+ dcop=0;
+}
+
+DCOPObject* KWFormulaFrameSetEdit::dcopObject()
+{
+ if ( !dcop )
+ dcop = new KWordFormulaFrameSetEditIface( this );
+ return dcop;
+}
+
+KWFormulaFrameSetEdit::~KWFormulaFrameSetEdit()
+{
+ formulaFrameSet()->m_edit = 0;
+ focusOutEvent();
+ // this causes a core dump on quit
+ m_canvas->gui()->getView()->showFormulaToolbar(false);
+ delete formulaView;
+ formulaView = 0;
+ formulaFrameSet()->getFormula()->startEvaluation();
+ formulaFrameSet()->setChanged();
+ m_canvas->repaintChanged( formulaFrameSet(), true );
+ delete dcop;
+}
+
+const KFormula::View* KWFormulaFrameSetEdit::getFormulaView() const { return formulaView; }
+KFormula::View* KWFormulaFrameSetEdit::getFormulaView() { return formulaView; }
+
+void KWFormulaFrameSetEdit::keyPressEvent( QKeyEvent* event )
+{
+ //kdDebug(32001) << "KWFormulaFrameSetEdit::keyPressEvent" << endl;
+ formulaView->keyPressEvent( event );
+}
+
+void KWFormulaFrameSetEdit::mousePressEvent( QMouseEvent* event,
+ const QPoint&,
+ const KoPoint& pos )
+{
+ // [Note that this method is called upon RMB and MMB as well, now]
+ KoPoint tl = m_currentFrame->topLeft();
+ formulaView->mousePressEvent( event, pos-tl );
+}
+
+void KWFormulaFrameSetEdit::mouseMoveEvent( QMouseEvent* event,
+ const QPoint&,
+ const KoPoint& pos )
+{
+ KoPoint tl = m_currentFrame->topLeft();
+ formulaView->mouseMoveEvent( event, pos-tl );
+}
+
+void KWFormulaFrameSetEdit::mouseReleaseEvent( QMouseEvent* event,
+ const QPoint&,
+ const KoPoint& pos )
+{
+ KoPoint tl = m_currentFrame->topLeft();
+ formulaView->mouseReleaseEvent( event, pos-tl );
+}
+
+void KWFormulaFrameSetEdit::focusInEvent()
+{
+ //kdDebug(32001) << "KWFormulaFrameSetEdit::focusInEvent" << endl;
+ if ( formulaView != 0 ) {
+ formulaView->focusInEvent(0);
+ }
+}
+
+void KWFormulaFrameSetEdit::focusOutEvent()
+{
+ //kdDebug(32001) << "KWFormulaFrameSetEdit::focusOutEvent" <<
+ //endl;
+ if ( formulaView != 0 ) {
+ formulaView->focusOutEvent(0);
+ }
+}
+
+void KWFormulaFrameSetEdit::copy()
+{
+ formulaView->getDocument()->copy();
+}
+
+void KWFormulaFrameSetEdit::cut()
+{
+ formulaView->getDocument()->cut();
+}
+
+void KWFormulaFrameSetEdit::paste()
+{
+ formulaView->getDocument()->paste();
+}
+
+void KWFormulaFrameSetEdit::pasteData( QMimeSource* /*data*/, int /*provides*/, bool )
+{
+ paste(); // TODO use data, for DnD
+}
+
+void KWFormulaFrameSetEdit::selectAll()
+{
+ formulaView->slotSelectAll();
+}
+
+void KWFormulaFrameSetEdit::moveHome()
+{
+ formulaView->moveHome( KFormula::WordMovement );
+}
+void KWFormulaFrameSetEdit::moveEnd()
+{
+ formulaView->moveEnd( KFormula::WordMovement );
+}
+
+void KWFormulaFrameSetEdit::removeFormula()
+{
+ if ( formulaFrameSet()->isFloating() ) {
+ KWCanvas* canvas = m_canvas;
+
+ // This call will destroy us! We cannot use 'this' afterwards!
+ exitRight();
+
+ QKeyEvent keyEvent( QEvent::KeyPress, Key_Backspace, 0, 0 );
+ canvas->currentFrameSetEdit()->keyPressEvent( &keyEvent );
+ }
+}
+
+void KWFormulaFrameSetEdit::cursorChanged( bool visible, bool /*selecting*/ )
+{
+ if ( visible ) {
+ if ( m_currentFrame )
+ {
+ // Add the cursor position to the (zoomed) frame position
+ QPoint nPoint = frameSet()->kWordDocument()->zoomPoint( m_currentFrame->topLeft() );
+ nPoint += formulaView->getCursorPoint();
+ // Apply viewmode conversion
+ QPoint p = m_canvas->viewMode()->normalToView( nPoint );
+ m_canvas->ensureVisible( p.x(), p.y() );
+ }
+ }
+ formulaFrameSet()->setChanged();
+ m_canvas->repaintChanged( formulaFrameSet(), true );
+}
+
+void KWFormulaFrameSetEdit::slotLeaveFormula( KFormula::Container*,
+ KFormula::FormulaCursor* cursor,
+ int cmd )
+{
+ kdDebug() << k_funcinfo << endl;
+
+ if ( cursor == formulaView->getCursor() ) {
+ switch ( cmd ) {
+ case KFormula::Container::EXIT_LEFT:
+ exitLeft();
+ break;
+ case KFormula::Container::EXIT_RIGHT:
+ exitRight();
+ break;
+ case KFormula::Container::EXIT_ABOVE:
+ exitLeft();
+ break;
+ case KFormula::Container::EXIT_BELOW:
+ exitRight();
+ break;
+ case KFormula::Container::REMOVE_FORMULA:
+ removeFormula();
+ break;
+ }
+ }
+}
+
+#include "KWFormulaFrameSet.moc"