kword

KWFormulaFrameSet.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 Ulrich Kuettler <ulrich.kuettler@gmx.de>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    General Public License for more details.
00013 
00014    You should have received a copy of the GNU General Public License
00015    along with this program; see the file COPYING.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include <qfile.h>
00021 
00022 #include "KWFormulaFrameSet.h"
00023 
00024 #include "KWDocument.h"
00025 #include "KWView.h"
00026 #include "KWViewMode.h"
00027 #include "KWCanvas.h"
00028 #include "KWFrame.h"
00029 #include "defs.h"
00030 
00031 #include <kformulacontainer.h>
00032 #include <kformuladocument.h>
00033 #include <kformulaview.h>
00034 #include <KoOasisContext.h>
00035 #include <KoXmlNS.h>
00036 #include <KoXmlWriter.h>
00037 
00038 #include <klocale.h>
00039 #include <kmessagebox.h>
00040 #include <kdebug.h>
00041 #include <ktempfile.h>
00042 #include <dcopobject.h>
00043 #include "KWordFormulaFrameSetIface.h"
00044 #include "KWordFormulaFrameSetEditIface.h"
00045 
00046 #include <assert.h>
00047 
00048 // #ifdef __GNUC__
00049 // #undef k_funcinfo
00050 // #define k_funcinfo "[\033[36m" << __PRETTY_FUNCTION__ << "\033[m] "
00051 // #endif
00052 
00053 /******************************************************************/
00054 /* Class: KWFormulaFrameSet                                       */
00055 /******************************************************************/
00056 KWFormulaFrameSet::KWFormulaFrameSet( KWDocument *doc, const QString & name )
00057     : KWFrameSet( doc ), m_changed( false ), m_edit( 0 )
00058 {
00059     if ( name.isEmpty() )
00060         m_name = doc->generateFramesetName( i18n( "Formula %1" ) );
00061     else
00062         m_name = name;
00063 
00064     init();
00065 }
00066 
00067 KWFormulaFrameSet::KWFormulaFrameSet( KWDocument* doc, const QDomElement& frameTag,
00068                                       const QDomElement& mathTag, KoOasisContext& context )
00069     : KWFrameSet( doc ), m_changed( false ), m_edit( 0 )
00070 {
00071     m_name = frameTag.attributeNS( KoXmlNS::draw, "name", QString::null );
00072     if ( doc->frameSetByName( m_name ) ) // already exists!
00073         m_name = doc->generateFramesetName( m_name + " %1" );
00074 
00075     init();
00076 
00077     context.styleStack().save();
00078     context.fillStyleStack( frameTag, KoXmlNS::draw, "style-name", "graphic" ); // get the style for the graphics element
00079     /*KWFrame* frame =*/ loadOasisFrame( frameTag, context );
00080     context.styleStack().restore();
00081 
00082     formula->loadMathML( mathTag );
00083 }
00084 
00085 void KWFormulaFrameSet::init()
00086 {
00087     // The newly created formula is not yet part of the formula
00088     // document. It will be added when a frame is created.
00089     formula = m_doc->formulaDocument()->createFormula( -1, false );
00090 
00091     // With the new drawing scheme (drawFrame being called with translated painter)
00092     // there is no need to move the KFormulaContainer anymore, it remains at (0,0).
00093     formula->moveTo( 0, 0 );
00094 
00095     connect( formula, SIGNAL( formulaChanged( double, double ) ),
00096              this, SLOT( slotFormulaChanged( double, double ) ) );
00097     connect( formula, SIGNAL( errorMsg( const QString& ) ),
00098              this, SLOT( slotErrorMessage( const QString& ) ) );
00099 
00100     /*
00101     if ( isFloating() ) {
00102         // we need to look for the anchor every time, don't cache this value.
00103         // undo/redo creates/deletes anchors
00104         KWAnchor * anchor = findAnchor( 0 );
00105         if ( anchor ) {
00106             KoTextFormat * format = anchor->format();
00107             formula->setFontSize( format->pointSize() );
00108         }
00109     }
00110     */
00111     QRect rect = formula->boundingRect();
00112     slotFormulaChanged(rect.width(), rect.height());
00113 }
00114 
00115 KWordFrameSetIface* KWFormulaFrameSet::dcopObject()
00116 {
00117     if ( !m_dcop )
00118         m_dcop = new KWordFormulaFrameSetIface( this );
00119 
00120     return m_dcop;
00121 }
00122 
00123 KWFormulaFrameSet::~KWFormulaFrameSet()
00124 {
00125     kdDebug() << k_funcinfo << endl;
00126     delete formula;
00127 }
00128 
00129 void KWFormulaFrameSet::addFrame( KWFrame *frame, bool recalc )
00130 {
00131     kdDebug() << k_funcinfo << endl;
00132     if ( formula ) {
00133         frame->setWidth( formula->width() );
00134         frame->setHeight( formula->height() );
00135     }
00136     KWFrameSet::addFrame( frame, recalc );
00137     if ( formula ) {
00138         formula->registerFormula();
00139     }
00140 }
00141 
00142 void KWFormulaFrameSet::deleteFrame( unsigned int num, bool remove, bool recalc )
00143 {
00144     kdDebug() << k_funcinfo << endl;
00145     assert( num == 0 );
00146     KWFrameSet::deleteFrame( num, remove, recalc );
00147     formula->unregisterFormula();
00148 }
00149 
00150 
00151 KWFrameSetEdit* KWFormulaFrameSet::createFrameSetEdit(KWCanvas* canvas)
00152 {
00153     return new KWFormulaFrameSetEdit(this, canvas);
00154 }
00155 
00156 void KWFormulaFrameSet::drawFrameContents( KWFrame* /*frame*/,
00157                                            QPainter* painter, const QRect& crect,
00158                                            const QColorGroup& cg, bool onlyChanged,
00159                                            bool resetChanged,
00160                                            KWFrameSetEdit* /*edit*/, KWViewMode * )
00161 {
00162     if ( m_changed || !onlyChanged )
00163     {
00164         if ( resetChanged )
00165             m_changed = false;
00166 
00167         bool printing = painter->device()->devType() == QInternal::Printer;
00168         bool clipping = true;
00169         QPainter *p;
00170         QPixmap* pix = 0L;
00171         if ( printing ) {
00172             p = painter;
00173             clipping = painter->hasClipping();
00174 
00175             // That's unfortunate for formulas wider than the page.
00176             // However it helps a lot with ordinary formulas.
00177             painter->setClipping( false );
00178         }
00179         else {
00180             pix = doubleBufferPixmap( crect.size() );
00181             p = new QPainter( pix );
00182             p->translate( -crect.x(), -crect.y() );
00183         }
00184 
00185         if ( m_edit ) {
00186             //KWFormulaFrameSetEdit * formulaEdit = static_cast<KWFormulaFrameSetEdit *>(edit);
00187             if ( m_edit->getFormulaView() ) {
00188                 m_edit->getFormulaView()->draw( *p, crect, cg );
00189             }
00190             else {
00191                 formula->draw( *p, crect, cg );
00192             }
00193         }
00194         else {
00195             formula->draw( *p, crect, cg );
00196         }
00197 
00198         if ( !printing ) {
00199             p->end();
00200             delete p;
00201             painter->drawPixmap( crect.topLeft(), *pix );
00202         }
00203         else {
00204             painter->setClipping( clipping );
00205         }
00206     }
00207 }
00208 
00209 
00210 void KWFormulaFrameSet::slotFormulaChanged( double width, double height )
00211 {
00212     if ( m_frames.isEmpty() )
00213         return;
00214 
00215     double oldWidth = m_frames.first()->width();
00216     double oldHeight = m_frames.first()->height();
00217 
00218     m_frames.first()->setWidth( width );
00219     m_frames.first()->setHeight( height );
00220 
00221     updateFrames();
00222     kWordDocument()->layout();
00223     if ( ( oldWidth != width ) || ( oldHeight != height ) ) {
00224         kWordDocument()->repaintAllViews( false );
00225         kWordDocument()->updateRulerFrameStartEnd();
00226     }
00227 
00228     m_changed = true;
00229 
00230     if ( !m_edit ) {
00231         // A change without a FrameSetEdit! This must be the result of
00232         // an undo. We need to evaluate.
00233         formula->startEvaluation();
00234     }
00235 }
00236 
00237 void KWFormulaFrameSet::slotErrorMessage( const QString& msg )
00238 {
00239     KMessageBox::error( /*m_widget*/ 0, msg );
00240 }
00241 
00242 MouseMeaning KWFormulaFrameSet::getMouseMeaningInsideFrame( const KoPoint& )
00243 {
00244     return MEANING_MOUSE_INSIDE_TEXT;
00245 }
00246 
00247 QDomElement KWFormulaFrameSet::save(QDomElement& parentElem, bool saveFrames)
00248 {
00249     if ( m_frames.isEmpty() ) // Deleted frameset -> don't save
00250         return QDomElement();
00251     QDomElement framesetElem = parentElem.ownerDocument().createElement("FRAMESET");
00252     parentElem.appendChild(framesetElem);
00253 
00254     KWFrameSet::saveCommon(framesetElem, saveFrames);
00255 
00256     QDomElement formulaElem = parentElem.ownerDocument().createElement("FORMULA");
00257     framesetElem.appendChild(formulaElem);
00258     formula->save(formulaElem);
00259     return framesetElem;
00260 }
00261 
00262 void KWFormulaFrameSet::saveOasis(KoXmlWriter& writer, KoSavingContext& context, bool) const
00263 {
00264     KWFrame *frame = m_frames.getFirst();
00265     frame->startOasisFrame( writer, context.mainStyles(), name() );
00266 
00267     KTempFile contentTmpFile;
00268     contentTmpFile.setAutoDelete( true );
00269     QFile* tmpFile = contentTmpFile.file();
00270 
00271     QTextStream stream(tmpFile);
00272     stream.setEncoding( QTextStream::UnicodeUTF8 );
00273     formula->saveMathML( stream, true );
00274     tmpFile->close();
00275 
00276     writer.startElement( "draw:object" );
00277     writer.startElement( "math:math" );
00278     writer.addCompleteElement( tmpFile );
00279     writer.endElement(); // math:math
00280     writer.endElement(); // draw:object
00281     writer.endElement(); // draw:frame
00282 }
00283 
00284 void KWFormulaFrameSet::load(QDomElement& attributes, bool loadFrames)
00285 {
00286     KWFrameSet::load(attributes, loadFrames);
00287     QDomElement formulaElem = attributes.namedItem("FORMULA").toElement();
00288     paste( formulaElem );
00289 }
00290 
00291 void KWFormulaFrameSet::paste( QDomNode& formulaElem )
00292 {
00293     if (!formulaElem.isNull()) {
00294         if (formula == 0) {
00295             formula = m_doc->formulaDocument()->createFormula( -1, false );
00296             connect(formula, SIGNAL(formulaChanged(double, double)),
00297                     this, SLOT(slotFormulaChanged(double, double)));
00298             connect( formula, SIGNAL( errorMsg( const QString& ) ),
00299                      this, SLOT( slotErrorMessage( const QString& ) ) );
00300         }
00301         if ( !formula->load( formulaElem.firstChild().toElement() ) ) {
00302             kdError(32001) << "Error loading formula" << endl;
00303         }
00304     }
00305     else {
00306         kdError(32001) << "Missing FORMULA tag in FRAMESET" << endl;
00307     }
00308 }
00309 
00310 void KWFormulaFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position )
00311 {
00312     kdDebug() << k_funcinfo << endl;
00313     KWFrameSet::moveFloatingFrame( frameNum, position );
00314     if ( !m_frames.isEmpty() ) {
00315         formula->setDocumentPosition( position.x(), position.y()+formula->baseline() );
00316     }
00317 }
00318 
00319 int KWFormulaFrameSet::floatingFrameBaseline( int /*frameNum*/ )
00320 {
00321     if ( !m_frames.isEmpty() )
00322     {
00323         return m_doc->ptToLayoutUnitPixY( formula->baseline() );
00324     }
00325     return -1;
00326 }
00327 
00328 void KWFormulaFrameSet::setAnchorFormat( KoTextFormat* format, int /*frameNum*/ )
00329 {
00330     if ( !m_frames.isEmpty() ) {
00331         formula->setFontSizeDirect( format->pointSize() );
00332     }
00333 }
00334 
00335 
00336 QPixmap* KWFormulaFrameSet::m_bufPixmap = 0;
00337 
00338 // stolen from KWDocument
00339 // However, I don't see if a formula frame can be an underlying
00340 // frame. That is why I use my own buffer.
00341 QPixmap* KWFormulaFrameSet::doubleBufferPixmap( const QSize& s )
00342 {
00343     if ( !m_bufPixmap ) {
00344         int w = QABS( s.width() );
00345         int h = QABS( s.height() );
00346         m_bufPixmap = new QPixmap( w, h );
00347     } else {
00348         if ( m_bufPixmap->width() < s.width() ||
00349                 m_bufPixmap->height() < s.height() ) {
00350             m_bufPixmap->resize( QMAX( s.width(), m_bufPixmap->width() ),
00351                                  QMAX( s.height(), m_bufPixmap->height() ) );
00352         }
00353     }
00354 
00355     return m_bufPixmap;
00356 }
00357 
00358 
00359 KWFormulaFrameSetEdit::KWFormulaFrameSetEdit(KWFormulaFrameSet* fs, KWCanvas* canvas)
00360         : KWFrameSetEdit(fs, canvas)
00361 {
00362     formulaView = new KFormula::View( fs->getFormula() );
00363 
00364     connect( formulaView, SIGNAL( cursorChanged( bool, bool ) ),
00365              this, SLOT( cursorChanged( bool, bool ) ) );
00366     connect( fs->getFormula(), SIGNAL( leaveFormula( Container*, FormulaCursor*, int ) ),
00367              this, SLOT( slotLeaveFormula( Container*, FormulaCursor*, int ) ) );
00368 
00369     fs->m_edit = this;
00370 
00371     m_canvas->gui()->getView()->showFormulaToolbar(true);
00372     focusInEvent();
00373     dcop=0;
00374 }
00375 
00376 DCOPObject* KWFormulaFrameSetEdit::dcopObject()
00377 {
00378     if ( !dcop )
00379         dcop = new KWordFormulaFrameSetEditIface( this );
00380     return dcop;
00381 }
00382 
00383 KWFormulaFrameSetEdit::~KWFormulaFrameSetEdit()
00384 {
00385     formulaFrameSet()->m_edit = 0;
00386     focusOutEvent();
00387     // this causes a core dump on quit
00388     m_canvas->gui()->getView()->showFormulaToolbar(false);
00389     delete formulaView;
00390     formulaView = 0;
00391     formulaFrameSet()->getFormula()->startEvaluation();
00392     formulaFrameSet()->setChanged();
00393     m_canvas->repaintChanged( formulaFrameSet(), true );
00394     delete dcop;
00395 }
00396 
00397 const KFormula::View* KWFormulaFrameSetEdit::getFormulaView() const { return formulaView; }
00398 KFormula::View* KWFormulaFrameSetEdit::getFormulaView() { return formulaView; }
00399 
00400 void KWFormulaFrameSetEdit::keyPressEvent( QKeyEvent* event )
00401 {
00402     //kdDebug(32001) << "KWFormulaFrameSetEdit::keyPressEvent" << endl;
00403     formulaView->keyPressEvent( event );
00404 }
00405 
00406 void KWFormulaFrameSetEdit::mousePressEvent( QMouseEvent* event,
00407                                              const QPoint&,
00408                                              const KoPoint& pos )
00409 {
00410     // [Note that this method is called upon RMB and MMB as well, now]
00411     KoPoint tl = m_currentFrame->topLeft();
00412     formulaView->mousePressEvent( event, pos-tl );
00413 }
00414 
00415 void KWFormulaFrameSetEdit::mouseMoveEvent( QMouseEvent* event,
00416                                             const QPoint&,
00417                                             const KoPoint& pos )
00418 {
00419     KoPoint tl = m_currentFrame->topLeft();
00420     formulaView->mouseMoveEvent( event, pos-tl );
00421 }
00422 
00423 void KWFormulaFrameSetEdit::mouseReleaseEvent( QMouseEvent* event,
00424                                                const QPoint&,
00425                                                const KoPoint& pos )
00426 {
00427     KoPoint tl = m_currentFrame->topLeft();
00428     formulaView->mouseReleaseEvent( event, pos-tl );
00429 }
00430 
00431 void KWFormulaFrameSetEdit::focusInEvent()
00432 {
00433     //kdDebug(32001) << "KWFormulaFrameSetEdit::focusInEvent" << endl;
00434     if ( formulaView != 0 ) {
00435         formulaView->focusInEvent(0);
00436     }
00437 }
00438 
00439 void KWFormulaFrameSetEdit::focusOutEvent()
00440 {
00441     //kdDebug(32001) << "KWFormulaFrameSetEdit::focusOutEvent" <<
00442     //endl;
00443     if ( formulaView != 0 ) {
00444         formulaView->focusOutEvent(0);
00445     }
00446 }
00447 
00448 void KWFormulaFrameSetEdit::copy()
00449 {
00450     formulaView->getDocument()->copy();
00451 }
00452 
00453 void KWFormulaFrameSetEdit::cut()
00454 {
00455     formulaView->getDocument()->cut();
00456 }
00457 
00458 void KWFormulaFrameSetEdit::paste()
00459 {
00460     formulaView->getDocument()->paste();
00461 }
00462 
00463 void KWFormulaFrameSetEdit::pasteData( QMimeSource* /*data*/, int /*provides*/, bool )
00464 {
00465     paste(); // TODO use data, for DnD
00466 }
00467 
00468 void KWFormulaFrameSetEdit::selectAll()
00469 {
00470     formulaView->slotSelectAll();
00471 }
00472 
00473 void KWFormulaFrameSetEdit::moveHome()
00474 {
00475     formulaView->moveHome( KFormula::WordMovement );
00476 }
00477 void KWFormulaFrameSetEdit::moveEnd()
00478 {
00479     formulaView->moveEnd( KFormula::WordMovement );
00480 }
00481 
00482 void KWFormulaFrameSetEdit::removeFormula()
00483 {
00484     if ( formulaFrameSet()->isFloating() ) {
00485         KWCanvas* canvas = m_canvas;
00486 
00487         // This call will destroy us! We cannot use 'this' afterwards!
00488         exitRight();
00489 
00490         QKeyEvent keyEvent( QEvent::KeyPress, Key_Backspace, 0, 0 );
00491         canvas->currentFrameSetEdit()->keyPressEvent( &keyEvent );
00492     }
00493 }
00494 
00495 void KWFormulaFrameSetEdit::cursorChanged( bool visible, bool /*selecting*/ )
00496 {
00497     if ( visible ) {
00498         if ( m_currentFrame )
00499         {
00500             // Add the cursor position to the (zoomed) frame position
00501             QPoint nPoint = frameSet()->kWordDocument()->zoomPoint( m_currentFrame->topLeft() );
00502             nPoint += formulaView->getCursorPoint();
00503             // Apply viewmode conversion
00504             QPoint p = m_canvas->viewMode()->normalToView( nPoint );
00505             m_canvas->ensureVisible( p.x(), p.y() );
00506         }
00507     }
00508     formulaFrameSet()->setChanged();
00509     m_canvas->repaintChanged( formulaFrameSet(), true );
00510 }
00511 
00512 void KWFormulaFrameSetEdit::slotLeaveFormula( KFormula::Container*,
00513                                               KFormula::FormulaCursor* cursor,
00514                                               int cmd )
00515 {
00516     kdDebug() << k_funcinfo << endl;
00517 
00518     if ( cursor == formulaView->getCursor() ) {
00519         switch ( cmd ) {
00520         case KFormula::Container::EXIT_LEFT:
00521             exitLeft();
00522             break;
00523         case KFormula::Container::EXIT_RIGHT:
00524             exitRight();
00525             break;
00526         case KFormula::Container::EXIT_ABOVE:
00527             exitLeft();
00528             break;
00529         case KFormula::Container::EXIT_BELOW:
00530             exitRight();
00531             break;
00532         case KFormula::Container::REMOVE_FORMULA:
00533             removeFormula();
00534             break;
00535         }
00536     }
00537 }
00538 
00539 #include "KWFormulaFrameSet.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys