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