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         m_doc->formulaDocument()->setCreationStrategy( "Ordinary" );
00302         if ( !formula->load( formulaElem.firstChild().toElement() ) ) {
00303             kdError(32001) << "Error loading formula" << endl;
00304         }
00305     }
00306     else {
00307         kdError(32001) << "Missing FORMULA tag in FRAMESET" << endl;
00308     }
00309 }
00310 
00311 void KWFormulaFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position )
00312 {
00313     kdDebug() << k_funcinfo << endl;
00314     KWFrameSet::moveFloatingFrame( frameNum, position );
00315     if ( !m_frames.isEmpty() ) {
00316         formula->setDocumentPosition( position.x(), position.y()+formula->baseline() );
00317     }
00318 }
00319 
00320 int KWFormulaFrameSet::floatingFrameBaseline( int /*frameNum*/ )
00321 {
00322     if ( !m_frames.isEmpty() )
00323     {
00324         return m_doc->ptToLayoutUnitPixY( formula->baseline() );
00325     }
00326     return -1;
00327 }
00328 
00329 void KWFormulaFrameSet::setAnchorFormat( KoTextFormat* format, int /*frameNum*/ )
00330 {
00331     if ( !m_frames.isEmpty() ) {
00332         formula->setFontSizeDirect( format->pointSize() );
00333     }
00334 }
00335 
00336 
00337 QPixmap* KWFormulaFrameSet::m_bufPixmap = 0;
00338 
00339 // stolen from KWDocument
00340 // However, I don't see if a formula frame can be an underlying
00341 // frame. That is why I use my own buffer.
00342 QPixmap* KWFormulaFrameSet::doubleBufferPixmap( const QSize& s )
00343 {
00344     if ( !m_bufPixmap ) {
00345         int w = QABS( s.width() );
00346         int h = QABS( s.height() );
00347         m_bufPixmap = new QPixmap( w, h );
00348     } else {
00349         if ( m_bufPixmap->width() < s.width() ||
00350                 m_bufPixmap->height() < s.height() ) {
00351             m_bufPixmap->resize( QMAX( s.width(), m_bufPixmap->width() ),
00352                                  QMAX( s.height(), m_bufPixmap->height() ) );
00353         }
00354     }
00355 
00356     return m_bufPixmap;
00357 }
00358 
00359 
00360 KWFormulaFrameSetEdit::KWFormulaFrameSetEdit(KWFormulaFrameSet* fs, KWCanvas* canvas)
00361         : KWFrameSetEdit(fs, canvas)
00362 {
00363     formulaView = new KFormula::View( fs->getFormula() );
00364 
00365     connect( formulaView, SIGNAL( cursorChanged( bool, bool ) ),
00366              this, SLOT( cursorChanged( bool, bool ) ) );
00367     connect( fs->getFormula(), SIGNAL( leaveFormula( Container*, FormulaCursor*, int ) ),
00368              this, SLOT( slotLeaveFormula( Container*, FormulaCursor*, int ) ) );
00369 
00370     fs->m_edit = this;
00371 
00372     m_canvas->gui()->getView()->showFormulaToolbar(true);
00373     focusInEvent();
00374     dcop=0;
00375 }
00376 
00377 DCOPObject* KWFormulaFrameSetEdit::dcopObject()
00378 {
00379     if ( !dcop )
00380         dcop = new KWordFormulaFrameSetEditIface( this );
00381     return dcop;
00382 }
00383 
00384 KWFormulaFrameSetEdit::~KWFormulaFrameSetEdit()
00385 {
00386     formulaFrameSet()->m_edit = 0;
00387     focusOutEvent();
00388     // this causes a core dump on quit
00389     m_canvas->gui()->getView()->showFormulaToolbar(false);
00390     delete formulaView;
00391     formulaView = 0;
00392     formulaFrameSet()->getFormula()->startEvaluation();
00393     formulaFrameSet()->setChanged();
00394     m_canvas->repaintChanged( formulaFrameSet(), true );
00395     delete dcop;
00396 }
00397 
00398 const KFormula::View* KWFormulaFrameSetEdit::getFormulaView() const { return formulaView; }
00399 KFormula::View* KWFormulaFrameSetEdit::getFormulaView() { return formulaView; }
00400 
00401 void KWFormulaFrameSetEdit::keyPressEvent( QKeyEvent* event )
00402 {
00403     //kdDebug(32001) << "KWFormulaFrameSetEdit::keyPressEvent" << endl;
00404     formulaView->keyPressEvent( event );
00405 }
00406 
00407 void KWFormulaFrameSetEdit::mousePressEvent( QMouseEvent* event,
00408                                              const QPoint&,
00409                                              const KoPoint& pos )
00410 {
00411     // [Note that this method is called upon RMB and MMB as well, now]
00412     KoPoint tl = m_currentFrame->topLeft();
00413     formulaView->mousePressEvent( event, pos-tl );
00414 }
00415 
00416 void KWFormulaFrameSetEdit::mouseMoveEvent( QMouseEvent* event,
00417                                             const QPoint&,
00418                                             const KoPoint& pos )
00419 {
00420     KoPoint tl = m_currentFrame->topLeft();
00421     formulaView->mouseMoveEvent( event, pos-tl );
00422 }
00423 
00424 void KWFormulaFrameSetEdit::mouseReleaseEvent( QMouseEvent* event,
00425                                                const QPoint&,
00426                                                const KoPoint& pos )
00427 {
00428     KoPoint tl = m_currentFrame->topLeft();
00429     formulaView->mouseReleaseEvent( event, pos-tl );
00430 }
00431 
00432 void KWFormulaFrameSetEdit::focusInEvent()
00433 {
00434     //kdDebug(32001) << "KWFormulaFrameSetEdit::focusInEvent" << endl;
00435     if ( formulaView != 0 ) {
00436         formulaView->focusInEvent(0);
00437     }
00438 }
00439 
00440 void KWFormulaFrameSetEdit::focusOutEvent()
00441 {
00442     //kdDebug(32001) << "KWFormulaFrameSetEdit::focusOutEvent" <<
00443     //endl;
00444     if ( formulaView != 0 ) {
00445         formulaView->focusOutEvent(0);
00446     }
00447 }
00448 
00449 void KWFormulaFrameSetEdit::copy()
00450 {
00451     formulaView->getDocument()->copy();
00452 }
00453 
00454 void KWFormulaFrameSetEdit::cut()
00455 {
00456     formulaView->getDocument()->cut();
00457 }
00458 
00459 void KWFormulaFrameSetEdit::paste()
00460 {
00461     formulaView->getDocument()->paste();
00462 }
00463 
00464 void KWFormulaFrameSetEdit::pasteData( QMimeSource* /*data*/, int /*provides*/, bool )
00465 {
00466     paste(); // TODO use data, for DnD
00467 }
00468 
00469 void KWFormulaFrameSetEdit::selectAll()
00470 {
00471     formulaView->slotSelectAll();
00472 }
00473 
00474 void KWFormulaFrameSetEdit::moveHome()
00475 {
00476     formulaView->moveHome( KFormula::WordMovement );
00477 }
00478 void KWFormulaFrameSetEdit::moveEnd()
00479 {
00480     formulaView->moveEnd( KFormula::WordMovement );
00481 }
00482 
00483 void KWFormulaFrameSetEdit::removeFormula()
00484 {
00485     if ( formulaFrameSet()->isFloating() ) {
00486         KWCanvas* canvas = m_canvas;
00487 
00488         // This call will destroy us! We cannot use 'this' afterwards!
00489         exitRight();
00490 
00491         QKeyEvent keyEvent( QEvent::KeyPress, Key_Backspace, 0, 0 );
00492         canvas->currentFrameSetEdit()->keyPressEvent( &keyEvent );
00493     }
00494 }
00495 
00496 void KWFormulaFrameSetEdit::cursorChanged( bool visible, bool /*selecting*/ )
00497 {
00498     if ( visible ) {
00499         if ( m_currentFrame )
00500         {
00501             // Add the cursor position to the (zoomed) frame position
00502             QPoint nPoint = frameSet()->kWordDocument()->zoomPoint( m_currentFrame->topLeft() );
00503             nPoint += formulaView->getCursorPoint();
00504             // Apply viewmode conversion
00505             QPoint p = m_canvas->viewMode()->normalToView( nPoint );
00506             m_canvas->ensureVisible( p.x(), p.y() );
00507         }
00508     }
00509     formulaFrameSet()->setChanged();
00510     m_canvas->repaintChanged( formulaFrameSet(), true );
00511 }
00512 
00513 void KWFormulaFrameSetEdit::slotLeaveFormula( KFormula::Container*,
00514                                               KFormula::FormulaCursor* cursor,
00515                                               int cmd )
00516 {
00517     kdDebug() << k_funcinfo << endl;
00518 
00519     if ( cursor == formulaView->getCursor() ) {
00520         switch ( cmd ) {
00521         case KFormula::Container::EXIT_LEFT:
00522             exitLeft();
00523             break;
00524         case KFormula::Container::EXIT_RIGHT:
00525             exitRight();
00526             break;
00527         case KFormula::Container::EXIT_ABOVE:
00528             exitLeft();
00529             break;
00530         case KFormula::Container::EXIT_BELOW:
00531             exitRight();
00532             break;
00533         case KFormula::Container::REMOVE_FORMULA:
00534             removeFormula();
00535             break;
00536         }
00537     }
00538 }
00539 
00540 #include "KWFormulaFrameSet.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys