kword

KWCanvas.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999 Reginald Stadlbauer <reggie@kde.org>
00003    Copyright (C) 2002-2006 David Faure <faure@kde.org>
00004    Copyright (C) 2005 Thomas Zander <zander@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 
00023 #include "KWCanvas.h"
00024 #include "KWTableFrameSet.h"
00025 #include "KWPartFrameSet.h"
00026 #include "KWFormulaFrameSet.h"
00027 #include "KWDocument.h"
00028 #include "KWView.h"
00029 #include "KWViewMode.h"
00030 #include "KWFrameDia.h"
00031 #include "KWCommand.h"
00032 #include "KWTableTemplate.h"
00033 #include "KWTextDocument.h"
00034 #include "KWFrameList.h"
00035 #include "KWPageManager.h"
00036 #include "KWPage.h"
00037 #include "KWPictureFrameSet.h"
00038 #include "KWFrameView.h"
00039 #include "KWFrameViewManager.h"
00040 
00041 #include <qbuffer.h>
00042 #include <qtimer.h>
00043 #include <qclipboard.h>
00044 #include <qprogressdialog.h>
00045 #include <qobjectlist.h>
00046 #include <qapplication.h>
00047 #include <qwhatsthis.h>
00048 
00049 #include <KoStore.h>
00050 #include <KoStoreDrag.h>
00051 #include <KoPictureCollection.h>
00052 
00053 #include <ktempfile.h>
00054 #include <klocale.h>
00055 #include <kcursor.h>
00056 #include <kdebug.h>
00057 #include <kmessagebox.h>
00058 #include <kmultipledrag.h>
00059 #include <kurl.h>
00060 #include <kurldrag.h>
00061 #include <kio/netaccess.h>
00062 #include <kmimetype.h>
00063 
00064 #include <assert.h>
00065 
00066 KWCanvas::KWCanvas(const QString& viewMode, QWidget *parent, KWDocument *d, KWGUI *lGui)
00067     : QScrollView( parent, "canvas", /*WNorthWestGravity*/ WStaticContents| WResizeNoErase | WRepaintNoErase ), m_doc( d )
00068 {
00069     m_frameViewManager = new KWFrameViewManager(d);
00070     m_gui = lGui;
00071     m_currentFrameSetEdit = 0L;
00072     m_mouseMeaning = MEANING_NONE;
00073     m_mousePressed = false;
00074     m_imageDrag = false;
00075     m_frameInline = false;
00076     m_overwriteMode = false;
00077 
00078     //used by insert picture dialogbox
00079     m_picture.pictureInline = false;
00080     m_picture.keepRatio = true;
00081 
00082 
00083 
00084     m_frameInlineType = FT_TABLE;
00085     m_viewMode = KWViewMode::create( viewMode, m_doc, this );
00086     m_interactionPolicy = 0;
00087 
00088     // Default table parameters.
00089     m_table.rows = 3;
00090     m_table.cols = 2;
00091     m_table.width = KWTableFrameSet::TblAuto;
00092     m_table.height = KWTableFrameSet::TblAuto;
00093     m_table.floating = true;
00094     m_table.tableTemplateName=QString::null;
00095     m_table.format=31;
00096 
00097     m_footEndNote.noteType = FootNote;
00098     m_footEndNote.numberingType = KWFootNoteVariable::Auto;
00099 
00100 
00101     m_currentTable = 0L;
00102     m_printing = false;
00103     m_deleteMovingRect = false;
00104     m_resizedFrameInitialMinHeight = 0;
00105     m_temporaryStatusBarTextShown = false;
00106 
00107     viewport()->setBackgroundMode( PaletteBase );
00108     viewport()->setAcceptDrops( TRUE );
00109 
00110     setKeyCompression( TRUE );
00111     viewport()->setMouseTracking( TRUE );
00112 
00113     m_scrollTimer = new QTimer( this );
00114     connect( m_scrollTimer, SIGNAL( timeout() ),
00115              this, SLOT( doAutoScroll() ) );
00116 
00117     viewport()->setFocusProxy( this );
00118     viewport()->setFocusPolicy( WheelFocus );
00119     setInputMethodEnabled( true );
00120     setFocus();
00121     viewport()->installEventFilter( this );
00122     installEventFilter( this );
00123     KCursor::setAutoHideCursor( this, true, true );
00124 
00125     connect( this, SIGNAL(contentsMoving( int, int )),
00126              this, SLOT(slotContentsMoving( int, int )) );
00127 
00128     connect( m_doc, SIGNAL( newContentsSize() ),
00129              this, SLOT( slotNewContentsSize() ) );
00130 
00131     connect( m_doc, SIGNAL( mainTextHeightChanged() ),
00132              this, SLOT( slotMainTextHeightChanged() ) );
00133 
00134     connect( m_doc, SIGNAL( sig_terminateEditing( KWFrameSet * ) ),
00135              this, SLOT( terminateEditing( KWFrameSet * ) ) );
00136 
00137     slotNewContentsSize();
00138 
00139     m_mouseMode = MM_EDIT; // avoid UMR in setMouseMode
00140     setMouseMode( MM_EDIT );
00141 
00142     // Create the current frameset-edit last, to have everything ready for it
00143     KWFrameSet * fs = 0L;
00144     QString fsName = m_doc->initialFrameSet();
00145     if ( !fsName.isEmpty() )
00146         fs = m_doc->frameSetByName( fsName );
00147     if ( !fs )
00148         fs = m_doc->frameSet( 0 );
00149     //Q_ASSERT( fs ); // empty page template -> no fs
00150     if ( fs && fs->isVisible( m_viewMode ) ) {
00151         checkCurrentEdit( fs );
00152         KWTextFrameSetEdit* textedit = dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit);
00153         if ( textedit ) {
00154             int paragId = m_doc->initialCursorParag();
00155             int index = m_doc->initialCursorIndex();
00156             if ( paragId != 0 || index != 0 ) {
00157                 KoTextParag* parag = textedit->textDocument()->paragAt( paragId );
00158                 if ( parag )
00159                     textedit->setCursor( parag, index );
00160             }
00161         }
00162     }
00163     m_doc->deleteInitialEditingInfo();
00164 
00165     connect(frameViewManager(), SIGNAL(sigFrameResized(const QValueList<KWFrame*>&)),
00166         m_doc, SLOT(framesChanged(const QValueList<KWFrame*>&)));
00167     connect(frameViewManager(), SIGNAL(sigFrameMoved(const QValueList<KWFrame*>&)),
00168         m_doc, SLOT(framesChanged(const QValueList<KWFrame*>&)));
00169 }
00170 
00171 KWCanvas::~KWCanvas()
00172 {
00173     delete m_interactionPolicy;
00174     delete m_currentFrameSetEdit;
00175     m_currentFrameSetEdit = 0;
00176     delete m_viewMode;
00177     m_viewMode = 0;
00178     disconnect(frameViewManager(), SIGNAL(sigFrameResized(const QValueList<KWFrame*>&)),
00179         m_doc, SLOT(framesChanged(const QValueList<KWFrame*>&)));
00180     disconnect(frameViewManager(), SIGNAL(sigFrameMoved(const QValueList<KWFrame*>&)),
00181         m_doc, SLOT(framesChanged(const QValueList<KWFrame*>&)));
00182     delete m_frameViewManager;
00183     m_frameViewManager = 0;
00184 }
00185 
00186 void KWCanvas::repaintChanged( KWFrameSet * fs, bool resetChanged )
00187 {
00188     assert(fs); // the new code can't support fs being 0L here. Mail me if it happens (DF)
00189     //kdDebug(32002) << "KWCanvas::repaintChanged this=" << this << " fs=" << fs << endl;
00190     QPainter p( viewport() );
00191     p.translate( -contentsX(), -contentsY() );
00192     p.setBrushOrigin( -contentsX(), -contentsY() );
00193     QRect crect( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
00194     drawFrameSet( fs, &p, crect, true, resetChanged, m_viewMode );
00195     // ###### This repaints the whole grid every time. Ouch.
00196     // We should return a QRegion from drawFrameSet.... Tricky.
00197     if ( m_doc->showGrid() )
00198       drawGrid( p, crect );
00199 }
00200 
00201 void KWCanvas::repaintAll( bool erase /* = false */ )
00202 {
00203     //kdDebug(32002) << "KWCanvas::repaintAll erase=" << erase << endl;
00204     viewport()->repaint( erase );
00205 }
00206 
00207 void KWCanvas::viewportResizeEvent( QResizeEvent * )
00208 {
00209     viewport()->update();
00210 }
00211 
00212 void KWCanvas::print( QPainter *painter, KPrinter *printer )
00213 {
00214     // Prevent cursor drawing and editing
00215     if ( m_currentFrameSetEdit )
00216         m_currentFrameSetEdit->focusOutEvent();
00217     m_printing = true;
00218     KWViewMode *viewMode = new KWViewModePrint( m_doc, this );
00219     // Use page list specified in kdeprint dialogbox
00220     QValueList<int> pageList = printer->pageList();
00221     QProgressDialog progress( i18n( "Printing..." ), i18n( "Cancel" ),
00222                               pageList.count() + 1, this );
00223     int j = 0;
00224     progress.setProgress( 0 );
00225     QValueList<int>::Iterator it = pageList.begin();
00226     for ( ; it != pageList.end(); ++it )
00227     {
00228         progress.setProgress( ++j );
00229         qApp->processEvents();
00230 
00231         if ( progress.wasCancelled() )
00232             break;
00233 
00234         if ( it != pageList.begin() )
00235             printer->newPage();
00236 
00237         painter->save();
00238         int pgNum = (*it);
00239         int yOffset = m_doc->zoomItY( m_doc->pageManager()->topOfPage( pgNum ) );
00240         kdDebug(32001) << "printing page " << pgNum << " yOffset=" << yOffset << endl;
00241         QRect pageRect = m_doc->pageManager()->page(pgNum)->zoomedRect(m_doc);
00242         painter->fillRect( pageRect, white );
00243 
00244         painter->translate( 0, -yOffset );
00245         painter->setBrushOrigin( 0, -yOffset );
00246         drawDocument( painter, pageRect, viewMode );
00247         qApp->processEvents();
00248         painter->restore();
00249     }
00250     if ( m_currentFrameSetEdit )
00251         m_currentFrameSetEdit->focusInEvent();
00252     m_printing = false;
00253     delete viewMode;
00254 }
00255 
00256 void KWCanvas::drawContents( QPainter *painter, int cx, int cy, int cw, int ch )
00257 {
00258   if ( isUpdatesEnabled() )
00259   {
00260     // Note: in drawContents, the painter is already translated to the contents coordinates
00261     painter->setBrushOrigin( -contentsX(), -contentsY() );
00262     drawDocument( painter, QRect( cx, cy, cw, ch ), m_viewMode );
00263     if ( m_doc->showGrid() )
00264       drawGrid( *painter, QRect( cx, cy, cw, ch ) );
00265     else if ( m_doc->snapToGrid() && ( m_interactionPolicy && m_interactionPolicy->gotDragEvents()
00266                 || m_mouseMode != MM_EDIT ) )
00267       drawGrid( *painter, QRect(contentsX(), contentsY(), visibleWidth(), visibleHeight()) );
00268   }
00269 }
00270 
00271 void KWCanvas::drawDocument( QPainter *painter, const QRect &crect, KWViewMode* viewMode )
00272 {
00273     //kdDebug(32002) << "KWCanvas::drawDocument crect: " << crect << endl;
00274 
00275     // Draw the outside of the pages (shadow, gray area)
00276     // and the empty area first (in case of transparent frames)
00277     if ( painter->device()->devType() != QInternal::Printer ) // except when printing
00278     {
00279         QRegion emptySpaceRegion( crect );
00280         m_doc->createEmptyRegion( crect, emptySpaceRegion, viewMode );
00281         viewMode->drawPageBorders( painter, crect, emptySpaceRegion );
00282     }
00283 
00284     // Draw all framesets contents
00285     QPtrListIterator<KWFrameSet> fit = m_doc->framesetsIterator();
00286     for ( ; fit.current() ; ++fit )
00287     {
00288         KWFrameSet * frameset = fit.current();
00289         if(! frameset->isVisible()) continue;
00290         drawFrameSet( frameset, painter, crect, false, true, viewMode );
00291     }
00292 
00293     m_doc->maybeDeleteDoubleBufferPixmap();
00294 }
00295 
00296 void KWCanvas::drawFrameSet( KWFrameSet * frameset, QPainter * painter,
00297                              const QRect & crect, bool onlyChanged, bool resetChanged, KWViewMode* viewMode )
00298 {
00299     if ( !frameset->isVisible( viewMode ) )
00300         return;
00301     if ( !onlyChanged && frameset->isFloating() )
00302         return;
00303 
00304     bool focus = hasFocus() || viewport()->hasFocus();
00305     if ( painter->device()->devType() == QInternal::Printer )
00306         focus = false;
00307 
00308     QColorGroup gb = QApplication::palette().active();
00309     if ( focus && m_currentFrameSetEdit && frameset == m_currentFrameSetEdit->frameSet() )
00310         // Currently edited frameset
00311         m_currentFrameSetEdit->drawContents( painter, crect, gb, onlyChanged, resetChanged, viewMode, m_frameViewManager );
00312     else
00313         frameset->drawContents( painter, crect, gb, onlyChanged, resetChanged, 0L, viewMode, m_frameViewManager );
00314 }
00315 
00316 void KWCanvas::keyPressEvent( QKeyEvent *e )
00317 {
00318     if( !m_doc->isReadWrite()) {
00319         switch( e->key() ) {
00320         case Qt::Key_Down:
00321             setContentsPos( contentsX(), contentsY() + 10 );
00322             break;
00323         case Qt::Key_Up:
00324             setContentsPos( contentsX(), contentsY() - 10 );
00325             break;
00326         case Qt::Key_Left:
00327             setContentsPos( contentsX() - 10, contentsY() );
00328             break;
00329         case Qt::Key_Right:
00330             setContentsPos( contentsX() + 10, contentsY() );
00331             break;
00332         case Qt::Key_PageUp:
00333             setContentsPos( contentsX(), contentsY() - visibleHeight() );
00334             break;
00335         case Qt::Key_PageDown:
00336             setContentsPos( contentsX(), contentsY() + visibleHeight() );
00337             break;
00338         case Qt::Key_Home:
00339             setContentsPos( contentsX(), 0 );
00340             break;
00341         case Qt::Key_End:
00342             setContentsPos( contentsX(), contentsHeight() - visibleHeight() );
00343             break;
00344         default:
00345             break;
00346         }
00347     }
00348     // The key events in read-write mode are handled by eventFilter(), otherwise
00349     // we don't get <Tab> key presses.
00350 }
00351 
00352 void KWCanvas::switchViewMode( const QString& newViewMode )
00353 {
00354     delete m_viewMode;
00355     m_viewMode = KWViewMode::create( newViewMode, m_doc, this );
00356 }
00357 
00358 void KWCanvas::mpCreate( const QPoint& normalPoint, bool noGrid )
00359 {
00360     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
00361     if ( m_doc->snapToGrid() && !noGrid )
00362         applyGrid( docPoint );
00363     m_insRect.setCoords( docPoint.x(), docPoint.y(), 0, 0 );
00364     m_deleteMovingRect = false;
00365 }
00366 
00367 void KWCanvas::mpCreatePixmap( const QPoint& normalPoint, bool noGrid  )
00368 {
00369     if ( !m_kopicture.isNull() )
00370     {
00371         // Apply grid for the first corner only
00372         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
00373         if ( m_doc->snapToGrid() && ! noGrid )
00374             applyGrid( docPoint );
00375         int pageNum = m_doc->pageManager()->pageNumber( docPoint );
00376         m_insRect.setRect( docPoint.x(), docPoint.y(), 0, 0 );
00377         m_deleteMovingRect = false;
00378 
00379         if ( !m_pixmapSize.isEmpty() )
00380         {
00381             // This ensures 1-1 at 100% on screen, but allows zooming and printing with correct DPI values
00382             uint width = qRound( (double)m_pixmapSize.width() * m_doc->zoomedResolutionX() / POINT_TO_INCH( KoGlobal::dpiX() ) );
00383             uint height = qRound( (double)m_pixmapSize.height() * m_doc->zoomedResolutionY() / POINT_TO_INCH( KoGlobal::dpiY() ) );
00384             m_insRect.setWidth( m_doc->unzoomItX( width ) );
00385             m_insRect.setHeight( m_doc->unzoomItY( height ) );
00386             // Apply reasonable limits
00387             width = kMin( width, m_doc->paperWidth(pageNum) - normalPoint.x() - 5 );
00388             height = kMin( height, m_doc->paperHeight(pageNum) - normalPoint.y() - 5 );
00389             // And apply aspect-ratio if set
00390             if ( m_keepRatio )
00391             {
00392                 double ratio = ((double) m_pixmapSize.width()) / ((double) m_pixmapSize.height());
00393                 applyAspectRatio( ratio, m_insRect );
00394             }
00395 
00396             QPoint nPoint( normalPoint.x() + m_doc->zoomItX( m_insRect.width() ),
00397                            normalPoint.y() + m_doc->zoomItY( m_insRect.height() ) );
00398             QPoint vPoint = m_viewMode->normalToView( nPoint );
00399             vPoint = contentsToViewport( vPoint );
00400             QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() );
00401             if ( viewportRect.contains( vPoint ) ) // Don't move the mouse out of the viewport
00402                 QCursor::setPos( viewport()->mapToGlobal( vPoint ) );
00403         }
00404         emit docStructChanged(Pictures);
00405         if ( !m_doc->showGrid() && m_doc->snapToGrid() )
00406           repaintContents( FALSE ); //draw the grid over the whole canvas
00407     }
00408 }
00409 
00410 void KWCanvas::contentsMousePressEvent( QMouseEvent *e )
00411 {
00412     QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
00413     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
00414 
00415 
00416     if ( e->button() == LeftButton )
00417     {
00418       m_mousePressed = true;
00419     }
00420 
00421     // Only edit-mode (and only LMB) allowed on read-only documents (to select text)
00422     if ( !m_doc->isReadWrite() && ( m_mouseMode != MM_EDIT || e->button() != LeftButton ) )
00423         return;
00424     if ( m_printing )
00425         return;
00426 
00427     // This code here is common to all mouse buttons, so that RMB and MMB place the cursor (or select the frame) too
00428     switch ( m_mouseMode ) {
00429     case MM_EDIT:
00430     {
00431         if(! viewMode()->hasFrames() ) { // for the text mode we just forward the click to the text
00432             // first, make clicks left of text be on the border;
00433             docPoint = KoPoint(QMAX(0, docPoint.x()), QMAX(0, docPoint.y()));
00434             if ( m_currentFrameSetEdit )
00435                 m_currentFrameSetEdit->mousePressEvent( e, normalPoint, docPoint );
00436             break;
00437         }
00438         // See if we clicked on a frame's border
00439         m_mouseMeaning = m_frameViewManager->mouseMeaning( docPoint, e->state());
00440 
00441         //kdDebug(32001) << "contentsMousePressEvent meaning=" << m_mouseMeaning << endl;
00442         switch ( m_mouseMeaning )  {
00443         case MEANING_MOUSE_INSIDE:
00444         case MEANING_MOUSE_OVER_LINK:
00445         case MEANING_MOUSE_OVER_FOOTNOTE:
00446         case MEANING_MOUSE_INSIDE_TEXT:
00447         case MEANING_ACTIVATE_PART:
00448         {
00449             // LMB/MMB inside a frame always unselects all frames
00450             // RMB inside a frame unselects too, except when
00451             //     right-clicking on a selected frame
00452             KWFrameView *view = m_frameViewManager->view( docPoint, KWFrameViewManager::frameOnTop );
00453             if ( ! ( e->button() == RightButton && view && view->selected() ) )
00454                 selectAllFrames( false );
00455 
00456             KWFrame * frame = view ? view->frame() : 0L;
00457             KWFrameSet * fs = frame ? frame->frameSet() : 0L;
00458             if ( fs && fs->groupmanager() )
00459                 fs = fs->groupmanager();
00460             bool emitChanged = false;
00461             if ( fs )
00462             {
00463                 // Clicked inside a frame - start editing it
00464                 emitChanged = checkCurrentEdit( fs );
00465             }
00466 
00467             if ( m_currentFrameSetEdit )
00468                 m_currentFrameSetEdit->mousePressEvent( e, normalPoint, docPoint );
00469 
00470             if ( emitChanged ) { // emitted after mousePressEvent [for tables]
00471                 emit currentFrameSetEditChanged();
00472                 emit updateRuler();
00473             }
00474 
00475             if ( m_frameInline )
00476             {
00477                 bool inlineCreated = true;
00478                 if(m_frameInlineType == FT_TABLE)
00479                     inlineCreated = insertInlineTable();
00480                 else if(m_frameInlineType == FT_PICTURE)
00481                     inlineCreated = insertInlinePicture();
00482                 if (!inlineCreated)
00483                     KMessageBox::information(0L, i18n("Read-only content cannot be changed. No modifications will be accepted."));
00484             }
00485             break;
00486         }
00487         case MEANING_RESIZE_COLUMN:
00488         case MEANING_RESIZE_ROW:
00489         {
00490             terminateCurrentEdit();
00491 
00492             // We know we're resizing a row or column, but we don't know which one yet...
00493             // We're between two rows (or columns) so frameUnderMouse is a bit unprecise...
00494             // We need it to find out which table we clicked on, though.
00495             KWFrameView *view = m_frameViewManager->view(docPoint, KWFrameViewManager::frameOnTop);
00496             if (view)
00497             {
00498                 KWTableFrameSet::Cell* cell = dynamic_cast<KWTableFrameSet::Cell *>(view->frame()->frameSet());
00499                 if ( cell )
00500                 {
00501                     KWTableFrameSet* table = cell->groupmanager();
00502                     if ( m_mouseMeaning == MEANING_RESIZE_COLUMN )
00503                     {
00504                         m_rowColResized = table->columnEdgeAt( docPoint.x() );
00505                         m_previousTableSize = table->columnSize( m_rowColResized );
00506                     }
00507                     else
00508                     {
00509                         m_rowColResized = table->rowEdgeAt( docPoint.y() );
00510                         m_previousTableSize = table->rowSize( m_rowColResized );
00511                     }
00512                     m_currentTable = table;
00513                     kdDebug(32002) << "resizing row/col edge. m_rowColResized=" << m_rowColResized << endl;
00514                 }
00515             }
00516             break;
00517         }
00518         default:
00519             m_mousePressed = true;
00520             m_deleteMovingRect = false;
00521 
00522             delete m_interactionPolicy;
00523             m_interactionPolicy = InteractionPolicy::createPolicy(this, m_mouseMeaning, docPoint, e->button(), e->state());
00524             if(m_interactionPolicy)
00525                 terminateCurrentEdit();
00526             viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, e->state() ) );
00527         }
00528     }
00529     break;
00530     case MM_CREATE_TEXT: case MM_CREATE_PART: case MM_CREATE_TABLE:
00531     case MM_CREATE_FORMULA:
00532         if ( e->button() == LeftButton )
00533             mpCreate( normalPoint, e->state() & Qt::ShiftButton);
00534         break;
00535     case MM_CREATE_PIX:
00536         if ( e->button() == LeftButton )
00537             mpCreatePixmap( normalPoint, e->state() & Qt::ShiftButton );
00538         break;
00539     default: break;
00540     }
00541     m_scrollTimer->start( 50 );
00542 
00543     if ( e->button() == MidButton ) {
00544         if ( m_doc->isReadWrite() && m_currentFrameSetEdit && m_mouseMode == MM_EDIT )
00545         {
00546             QApplication::clipboard()->setSelectionMode( true );
00547             m_currentFrameSetEdit->paste();
00548             QApplication::clipboard()->setSelectionMode( false );
00549         }
00550     }
00551     else if ( e->button() == RightButton ) {
00552         if(!m_doc->isReadWrite()) // The popups are not available in readonly mode, since the GUI isn't built...
00553             return;
00554         if ( m_deleteMovingRect )
00555             deleteMovingRect();
00556         // rmb menu
00557         switch ( m_mouseMode )
00558         {
00559         case MM_EDIT:
00560             if ( !viewMode()->hasFrames() ) { // text view mode
00561                 KWFrameView *view = m_frameViewManager->view(m_doc->frameSet( 0 )->frame(0));
00562                 view->showPopup(docPoint, m_gui->getView(), QCursor::pos());
00563             }
00564             else
00565                 m_frameViewManager->showPopup(docPoint, m_gui->getView(), e->state(), QCursor::pos());
00566             break;
00567         case MM_CREATE_TEXT:
00568         case MM_CREATE_PART:
00569         case MM_CREATE_TABLE:
00570         case MM_CREATE_FORMULA:
00571         case MM_CREATE_PIX:
00572             setMouseMode( MM_EDIT );
00573         default: break;
00574         }
00575         m_mousePressed = false;
00576     }
00577 }
00578 
00579 // Called by KWTableDia
00580 void KWCanvas::createTable( unsigned int rows, unsigned int cols,
00581                             int wid, int hei,
00582                             bool isFloating,
00583                             KWTableTemplate *tt, int format )
00584 {
00585     // Remember for next time in any case
00586     m_table.rows = rows;
00587     m_table.cols = cols;
00588     m_table.width = wid;
00589     m_table.height = hei;
00590     m_table.floating = isFloating;
00591     m_table.format = format;
00592 
00593     m_table.tableTemplateName = tt ? tt->displayName():QString::null;
00594     m_table.tt = tt;
00595 
00596     if ( isFloating  )
00597     {
00598         m_frameInline=true;
00599         m_frameInlineType=FT_TABLE;
00600         m_gui->getView()->displayFrameInlineInfo();
00601     }
00602     else
00603     {
00604         m_frameInline=false;
00605         setMouseMode( MM_CREATE_TABLE );
00606     }
00607 }
00608 
00609 bool KWCanvas::insertInlinePicture() // also called by DCOP
00610 {
00611     bool inserted = m_gui->getView()->insertInlinePicture();
00612     if ( inserted )
00613         m_frameInline = false;
00614     return inserted;
00615 }
00616 
00617 bool KWCanvas::insertInlineTable()
00618 {
00619     KWTextFrameSetEdit * edit = dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit);
00620     if(edit)
00621     {
00622         if ( edit->textFrameSet()->textObject()->protectContent() )
00623             return false;
00624         m_insRect = KoRect( 0, 0, edit->frameSet()->frame(0)->width(), 10 );
00625 
00626         KWTableFrameSet * table = createTable();
00627         m_doc->addFrameSet( table, false );
00628         edit->insertFloatingFrameSet( table, i18n("Insert Inline Table") );
00629         table->finalize();
00630 
00631         if (m_table.tt) {
00632             KWTableTemplateCommand *ttCmd=new KWTableTemplateCommand( "Apply template to inline table", table, m_table.tt );
00633             m_doc->addCommand(ttCmd);
00634             ttCmd->execute();
00635         }
00636 
00637         m_doc->updateAllFrames();
00638         m_doc->refreshDocStructure(Tables);
00639     }
00640     m_gui->getView()->updateFrameStatusBarItem();
00641     m_frameInline = false;
00642     return true;
00643 }
00644 
00645 void KWCanvas::applyGrid( KoPoint &p )
00646 {
00647   if ( m_viewMode->type() != "ModeNormal" )
00648     return;
00649   // The 1e-10 here is a workaround for some weird division problem.
00650   // 360.00062366 / 2.83465058 gives 127 'exactly' when shown as a double,
00651   // but when casting into an int, we get 126. In fact it's 127 - 5.64e-15 !
00652 
00653   // This is a problem when calling applyGrid twice, we get 1 less than the time before.
00654   p.setX( static_cast<int>( p.x() / m_doc->gridX() + 1e-10 ) * m_doc->gridX() );
00655   p.setY( static_cast<int>( p.y() / m_doc->gridY() + 1e-10 ) * m_doc->gridY() );
00656 
00657   //FIXME It doesn't work in preview mode - apply viewmode
00658 }
00659 
00660 void KWCanvas::drawGrid( QPainter &p, const QRect& rect )
00661 {
00662     // Grid-positioning makes no sense in text view mode
00663     if ( !m_viewMode->hasFrames() )
00664         return;
00665     QPen pen = QPen( Qt::black, 6, Qt::DotLine );
00666     QPen oldPen = p.pen();
00667     p.setPen( pen );
00668 
00669     const double offsetX = m_doc->gridX();
00670     const double offsetY = m_doc->gridY();
00671 
00672     // per page, this is needed to paint correctly on preview mode as well as making sure
00673     // we start the grid from the topleft of each page.
00674     for ( int pgNum = m_doc->startPage() ; pgNum <= m_doc->lastPage() ; ++pgNum) {
00675         const QRect pageRect = m_viewMode->viewPageRect( pgNum );
00676         const QRect crect = pageRect & rect;
00677         if ( crect.isEmpty() )
00678             continue;
00679 
00680         // To convert back to view coordinates later we can calculate the offset for each
00681         // point again, or we can do it one time for the page and re-use the answer.
00682         KoPoint pageTopLeft (0, m_doc->pageManager()->topOfPage(pgNum) + 2); // +2 to get around rounding problems..
00683         QPoint pageTopLeftView = m_viewMode->normalToView( m_doc->zoomPoint(pageTopLeft) );
00684 
00685         // docRect is the part of the document that needs to be painted.. Coordinates in pt
00686         const KoRect docRect = m_doc->unzoomRect( m_viewMode->viewToNormal( crect ) );
00687         // kdDebug() << "drawGrid page " << pgNum << " pageRect=" << pageRect << " crect=" << crect << " docRect=" << docRect << endl;
00688 
00689         // the following is effectively a docRect.y() modulo offsetY
00690         const double firstOffsetY = pageTopLeft.y() - offsetY * static_cast<int>( docRect.y() / offsetY );
00691         const double bottom = docRect.bottom() - pageTopLeft.y();
00692 
00693         for ( double x = 0; x <= docRect.right(); x += offsetX ) {
00694             const int zoomedX = m_doc->zoomItX( x ) + pageTopLeftView.x();
00695             for ( double y = firstOffsetY; y <= bottom; y += offsetY ) {
00696                 const int zoomedY = m_doc->zoomItY( y ) + pageTopLeftView.y();
00697                 p.drawPoint( zoomedX, zoomedY );
00698             }
00699         }
00700     }
00701 
00702     p.setPen( oldPen );
00703 }
00704 
00705 void KWCanvas::applyAspectRatio( double ratio, KoRect& insRect )
00706 {
00707     double width = insRect.width();
00708     double height = insRect.height();
00709     if ( width < height ) // the biggest border is the one in control
00710         width = height * ratio;
00711     else
00712         height = width / ratio;
00713     insRect.setRight( insRect.left() + width );
00714     insRect.setBottom( insRect.top() + height );
00715     //kdDebug() << "KWCanvas::applyAspectRatio: width=" << width << " height=" << height << " insRect=" << DEBUGRECT(insRect) << endl;
00716 }
00717 
00718 void KWCanvas::mmCreate( const QPoint& normalPoint, bool noGrid ) // Mouse move when creating a frame
00719 {
00720     QPainter p;
00721     p.begin( viewport() );
00722     p.translate( -contentsX(), -contentsY() );
00723     p.setRasterOp( NotROP );
00724     p.setPen( black );
00725     p.setBrush( NoBrush );
00726 
00727     if ( m_deleteMovingRect )
00728         drawMovingRect( p );
00729 
00730     int page = m_doc->pageManager()->pageNumber( m_insRect );
00731     if( page == -1) {
00732         return;
00733     }
00734     KoRect oldRect = m_insRect;
00735 
00736     // Resize the rectangle
00737     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
00738     if ( m_doc->snapToGrid() && m_mouseMode != MM_CREATE_PIX && !noGrid )
00739         applyGrid( docPoint );
00740 
00741     m_insRect.setRight( docPoint.x() );
00742     m_insRect.setBottom( docPoint.y() );
00743 
00744     // But not out of the page
00745     KoRect r = m_insRect.normalize();
00746     if ( !m_doc->pageManager()->page(page)->rect().contains(r) )
00747     {
00748         // Even better would be to go to the limit of the page boundary, so that the result,
00749         // when moving the mouse of the page, doesn't depend on how fast we're moving it...
00750         m_insRect = oldRect;
00751         // #### QCursor::setPos( viewport()->mapToGlobal( zoomPoint( m_insRect.bottomRight() ) ) );
00752     }
00753 
00754     // Apply keep-aspect-ratio feature
00755     if ( m_mouseMode == MM_CREATE_PIX && m_keepRatio )
00756     {
00757         double ratio = (double)m_pixmapSize.width() / (double)m_pixmapSize.height();
00758         applyAspectRatio( ratio, m_insRect );
00759     }
00760 
00761     drawMovingRect( p );
00762     p.end();
00763     m_deleteMovingRect = true;
00764 }
00765 
00766 void KWCanvas::drawMovingRect( QPainter & p )
00767 {
00768     p.setPen( black );
00769     p.drawRect( m_viewMode->normalToView( m_doc->zoomRect( m_insRect ) ) );
00770 }
00771 
00772 void KWCanvas::deleteMovingRect()
00773 {
00774     Q_ASSERT( m_deleteMovingRect );
00775     QPainter p;
00776     p.begin( viewport() );
00777     p.translate( -contentsX(), -contentsY() );
00778     p.setRasterOp( NotROP );
00779     p.setPen( black );
00780     p.setBrush( NoBrush );
00781     drawMovingRect( p );
00782     m_deleteMovingRect = false;
00783     p.end();
00784 }
00785 
00786 void KWCanvas::contentsMouseMoveEvent( QMouseEvent *e )
00787 {
00788     if ( m_printing )
00789         return;
00790     QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
00791     if(normalPoint.x() == -1) // e->pos() is an exceptional state...
00792         return;
00793     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
00794 
00795     if ( m_mousePressed ) {
00796         //doAutoScroll();
00797 
00798         switch ( m_mouseMode ) {
00799             case MM_EDIT:
00800             {
00801                 if ( m_currentFrameSetEdit )
00802                     m_currentFrameSetEdit->mouseMoveEvent( e, normalPoint, docPoint );
00803                 if( ! m_doc->isReadWrite() )
00804                     break;
00805                 if ( m_mouseMeaning == MEANING_RESIZE_COLUMN || m_mouseMeaning == MEANING_RESIZE_ROW )
00806                 {
00807                     // TODO undo/redo support (esp. in mouse-release)
00808                     QRect oldRect( m_viewMode->normalToView( m_doc->zoomRect( m_currentTable->boundingRect() ) ) );
00809                     if ( m_mouseMeaning == MEANING_RESIZE_ROW )
00810                         m_currentTable->resizeRow( m_rowColResized, docPoint.y() );
00811                     else
00812                         m_currentTable->resizeColumn( m_rowColResized, docPoint.x() );
00813                     // Repaint only the changed rects (oldRect U newRect)
00814                     QRect newRect( m_viewMode->normalToView( m_doc->zoomRect( m_currentTable->boundingRect() ) ) );
00815                     repaintContents( QRegion(oldRect).unite(newRect).boundingRect(), FALSE );
00816                 }
00817                 else if (m_interactionPolicy) {
00818                     m_interactionPolicy->handleMouseMove(e->state(),
00819                             m_doc->unzoomPoint( normalPoint ));
00820                     m_interactionPolicy->hadDragEvents();
00821                 }
00822             } break;
00823             case MM_CREATE_TEXT: case MM_CREATE_PIX: case MM_CREATE_PART:
00824             case MM_CREATE_TABLE: case MM_CREATE_FORMULA:
00825                 mmCreate( normalPoint, e->state() & ShiftButton );
00826             default:
00827                 break;
00828         }
00829     }
00830     else {
00831         if ( m_mouseMode == MM_EDIT )
00832         {
00833             MouseMeaning meaning = m_frameViewManager->mouseMeaning( docPoint, e->state() );
00834             switch ( meaning ) {
00835              case MEANING_MOUSE_OVER_FOOTNOTE:
00836              {
00837                  KWFrameView *view = m_frameViewManager->view(docPoint, KWFrameViewManager::frameOnTop);
00838                  KWFrame* frame = view ? view->frame() : 0;
00839                  KWFrameSet * fs = frame ? frame->frameSet() : 0;
00840                  if (fs && fs->type() == FT_TEXT)
00841                  {
00842                     KoVariable* var = static_cast<KWTextFrameSet *>(fs)->variableUnderMouse(docPoint);
00843                     if ( var )
00844                     {
00845                         KWFootNoteVariable * footNoteVar = dynamic_cast<KWFootNoteVariable *>( var );
00846                         if ( footNoteVar )
00847                         {
00848                             // show the content of the footnote in the status bar
00849                             gui()->getView()->setTemporaryStatusBarText( footNoteVar->frameSet()->textDocument()->firstParag()->string()->toString() );
00850                             m_temporaryStatusBarTextShown = true;
00851                         }
00852                     }
00853 
00854                  }
00855                  break;
00856              }
00857             case MEANING_MOUSE_OVER_LINK:
00858             {
00859                 KWFrameView *view = m_frameViewManager->view(docPoint, KWFrameViewManager::frameOnTop);
00860                 KWFrame* frame = view ? view->frame() : 0;
00861                 KWFrameSet * fs = frame ? frame->frameSet() : 0L;
00862                 if (fs && fs->type() == FT_TEXT)
00863                 {
00864                     KWTextFrameSet *frameset = static_cast<KWTextFrameSet *>(fs);
00865                     //show the link target in the status bar
00866                     QString link = frameset->linkVariableUnderMouse(docPoint)->url();
00867                     if ( link.startsWith("bkm://") )
00868                         link.replace( 0, 6, i18n("Bookmark target: ") );
00869                     gui()->getView()->setTemporaryStatusBarText( link );
00870                     m_temporaryStatusBarTextShown = true;
00871                 }
00872                 break;
00873             }
00874             default:
00875                 resetStatusBarText();
00876                 break;
00877             }
00878             if(viewMode()->hasFrames())
00879                 viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, e->state() ) );
00880             else
00881                 viewport()->setCursor( Qt::ibeamCursor );
00882         }
00883     }
00884 }
00885 
00886 void KWCanvas::mrEditFrame() {
00887     //kdDebug() << "KWCanvas::mrEditFrame" << endl;
00888     if(m_interactionPolicy) {
00889         m_interactionPolicy->finishInteraction();
00890         KCommand *cmd = m_interactionPolicy->createCommand();
00891         if(cmd)
00892             m_doc->addCommand(cmd);
00893         delete(m_interactionPolicy);
00894         m_interactionPolicy = 0;
00895         if ( !m_doc->showGrid() && m_doc->snapToGrid() )
00896             repaintContents();
00897     }
00898     m_mousePressed = false;
00899 }
00900 
00901 KCommand *KWCanvas::createTextBox( const KoRect & rect )
00902 {
00903     if ( !m_doc->snapToGrid() || ( rect.width() > m_doc->gridX() && rect.height() > m_doc->gridY() ) ) {
00904         KWFrame *frame = new KWFrame(0L, rect.x(), rect.y(), rect.width(), rect.height() );
00905         frame->setNewFrameBehavior(KWFrame::Reconnect);
00906         frame->setZOrder( m_doc->maxZOrder( frame->pageNumber(m_doc) ) + 1 ); // make sure it's on top
00907 
00908         QString name = m_doc->generateFramesetName( i18n( "Text Frameset %1" ) );
00909         KWTextFrameSet *_frameSet = new KWTextFrameSet(m_doc, name );
00910         _frameSet->addFrame( frame );
00911         m_doc->addFrameSet( _frameSet );
00912         KWCreateFrameCommand *cmd=new KWCreateFrameCommand( i18n("Create Text Frame"), frame );
00913         if ( checkCurrentEdit(frame->frameSet(), true) )
00914             emit currentFrameSetEditChanged();
00915         return cmd;
00916     }
00917     return 0L;
00918 }
00919 
00920 void KWCanvas::mrCreateText()
00921 {
00922     m_insRect = m_insRect.normalize();
00923     if ( !m_doc->snapToGrid() || ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) ) {
00924         KWFrame *frame = new KWFrame(0L, m_insRect.x(), m_insRect.y(), m_insRect.width(), m_insRect.height() );
00925         frame->setMinimumFrameHeight( frame->height() ); // so that AutoExtendFrame doesn't resize it down right away
00926         frame->setNewFrameBehavior(KWFrame::Reconnect);
00927         frame->setZOrder( m_doc->maxZOrder( frame->pageNumber(m_doc) ) + 1 ); // make sure it's on top
00928         KWFrameDia frameDia( this, frame, m_doc, FT_TEXT );
00929         frameDia.setCaption(i18n("Connect Frame"));
00930         frameDia.exec();
00931         if ( checkCurrentEdit(frame->frameSet(), true) )
00932             emit currentFrameSetEditChanged();
00933     }
00934     setMouseMode( MM_EDIT );
00935     m_doc->repaintAllViews();
00936     emit docStructChanged(TextFrames);
00937     emit currentFrameSetEditChanged();
00938 }
00939 
00940 void KWCanvas::mrCreatePixmap()
00941 {
00942     // kdDebug() << "KWCanvas::mrCreatePixmap m_insRect=" << DEBUGRECT(m_insRect) << endl;
00943     Q_ASSERT(m_insRect.width() > 0 && m_insRect.height() > 0);
00944     // Make sure the pic is completely in document.
00945     double ratio = m_insRect.width() / m_insRect.height();
00946     KoRect picRect(m_doc->pageManager()->clipToDocument(m_insRect.topLeft()),
00947             m_doc->pageManager()->clipToDocument(m_insRect.bottomRight()) );
00948     picRect = picRect.normalize();
00949 
00950     // Make sure it's completely on page.
00951     KWPage *page = m_doc->pageManager()->page( picRect.bottom() );
00952     KoRect pageRect = page->rect();
00953     picRect = pageRect.intersect(picRect);
00954 
00955     // make sure we keep ratio!
00956     double height = picRect.width() / ratio ;
00957     if(picRect.height() > height)
00958         picRect.setBottom(picRect.top() + height);
00959     else // moving bottom would make it bigger, so alter width
00960         picRect.setRight(picRect.left() + ratio * picRect.height());
00961 
00962     setMouseMode( MM_EDIT );
00963     if ( !m_kopicture.isNull() ) {
00964         KWPictureFrameSet *fs = new KWPictureFrameSet( m_doc, QString::null /*automatic name*/ );
00965         fs->insertPicture( m_kopicture );
00966         fs->setKeepAspectRatio( m_keepRatio );
00967         KWFrame *frame = new KWFrame(fs, picRect.x(), picRect.y(), picRect.width(),
00968                 picRect.height() );
00969         frame->setZOrder( m_doc->maxZOrder( page->pageNumber() ) +1 ); // make sure it's on top
00970         fs->addFrame( frame, false );
00971         m_doc->addFrameSet( fs );
00972         KWCreateFrameCommand *cmd=new KWCreateFrameCommand( i18n("Insert Picture"), frame );
00973         m_doc->addCommand(cmd);
00974         m_doc->frameChanged( frame );
00975         frameViewManager()->view(frame)->setSelected(true);
00976     }
00977     emit docStructChanged(Pictures);
00978 }
00979 
00980 void KWCanvas::mrCreatePart() // mouse release, when creating part
00981 {
00982     m_insRect = m_insRect.normalize();
00983     if ( !m_doc->snapToGrid() || ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) ) {
00984         KWPartFrameSet *fs = m_doc->insertObject( m_insRect, m_partEntry, this );
00985 Q_ASSERT(viewMode()->canvas());
00986         if(fs)
00987             fs->updateChildGeometry(); // set initial coordinates of 'ch' correctly
00988     }
00989     setMouseMode( MM_EDIT );
00990     emit docStructChanged(Embedded);
00991 }
00992 
00993 void KWCanvas::mrCreateFormula()
00994 {
00995     m_insRect = m_insRect.normalize();
00996     if ( !m_doc->snapToGrid() || ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) ) {
00997         KWFormulaFrameSet *frameset = new KWFormulaFrameSet( m_doc, QString::null );
00998         KWFrame *frame = new KWFrame(frameset, m_insRect.x(), m_insRect.y(), m_insRect.width(), m_insRect.height() );
00999         frame->setZOrder( m_doc->maxZOrder( frame->pageNumber(m_doc) ) + 1 ); // make sure it's on top
01000         frameset->addFrame( frame, false );
01001         m_doc->addFrameSet( frameset );
01002         KWCreateFrameCommand *cmd=new KWCreateFrameCommand( i18n("Create Formula Frame"), frame );
01003         m_doc->addCommand(cmd);
01004         m_doc->frameChanged( frame );
01005     }
01006     setMouseMode( MM_EDIT );
01007     emit docStructChanged(FormulaFrames);
01008 }
01009 
01010 void KWCanvas::mrCreateTable()
01011 {
01012     m_insRect = m_insRect.normalize();
01013     if ( !m_doc->snapToGrid() || ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) ) {
01014         if ( m_table.cols * s_minFrameWidth + m_insRect.x() > m_doc->pageManager()->pageLayout(0).ptWidth )
01015         {
01016             KMessageBox::sorry(0, i18n("KWord is unable to insert the table because there "
01017                                        "is not enough space available."));
01018         }
01019         else {
01020             KWTableFrameSet * table = createTable();
01021             KMacroCommand *macroCmd = new KMacroCommand( i18n("Create Table") );
01022 
01023             KWCreateTableCommand *cmd=new KWCreateTableCommand( "Create table", table );
01024             macroCmd->addCommand(cmd);
01025             if (m_table.tt) {
01026                 KWTableTemplateCommand *ttCmd=new KWTableTemplateCommand( "Apply template to table", table, m_table.tt );
01027                 macroCmd->addCommand(ttCmd);
01028             }
01029             m_doc->addCommand(macroCmd);
01030             macroCmd->execute();
01031 
01032             emit docStructChanged(Tables);
01033         }
01034         m_doc->updateAllFrames();
01035         m_doc->layout();
01036         repaintAll();
01037 
01038     }
01039     setMouseMode( MM_EDIT );
01040 }
01041 
01042 KWTableFrameSet * KWCanvas::createTable() // uses m_insRect and m_table to create the table
01043 {
01044     KWTableFrameSet *table = new KWTableFrameSet( m_doc, QString::null /*automatic name*/ );
01045     int pageNum = m_doc->pageManager()->pageNumber(m_insRect.topLeft());
01046 
01047     // Create a set of cells with random-size frames.
01048     for ( unsigned int i = 0; i < m_table.rows; i++ ) {
01049         for ( unsigned int j = 0; j < m_table.cols; j++ ) {
01050             KWTableFrameSet::Cell *cell = new KWTableFrameSet::Cell( table, i, j, QString::null /*automatic name*/ );
01051             KWFrame *frame = new KWFrame(cell, 0, 0, 0, 0, KWFrame::RA_BOUNDINGRECT ); // pos and size will be set in setBoundingRect
01052             frame->setZOrder( m_doc->maxZOrder( pageNum ) + 1 ); // make sure it's on top
01053             cell->addFrame( frame, false );
01054             frame->setFrameBehavior(KWFrame::AutoExtendFrame);
01055             frame->setNewFrameBehavior(KWFrame::NoFollowup);
01056         }
01057     }
01058     KWTableFrameSet::CellSize w;
01059     w=static_cast<KWTableFrameSet::CellSize>( m_table.width );
01060     if(m_frameInline) w=KWTableFrameSet::TblManual;
01061     table->setBoundingRect( m_insRect , w, static_cast<KWTableFrameSet::CellSize>( m_table.height ));
01062     return table;
01063 }
01064 
01065 void KWCanvas::contentsMouseReleaseEvent( QMouseEvent * e )
01066 {
01067     if ( m_printing )
01068         return;
01069     if ( m_scrollTimer->isActive() )
01070         m_scrollTimer->stop();
01071     if ( m_mousePressed ) {
01072         if ( m_deleteMovingRect )
01073             deleteMovingRect();
01074 
01075         QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
01076         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01077 
01078         if(m_insRect.bottom()==0 && m_insRect.right()==0) {
01079             // if the user did not drag, just click; make a 200x150 square for him.
01080             int page = m_doc->pageManager()->pageNumber(docPoint);
01081             if(page == -1)
01082                 return;
01083             KoPageLayout pageLayout = m_doc->pageManager()->pageLayout(page);
01084             m_insRect.setLeft(QMIN(m_insRect.left(), pageLayout.ptWidth - 200));
01085             m_insRect.setTop(QMIN(m_insRect.top(), pageLayout.ptHeight - 150));
01086             m_insRect.setBottom(m_insRect.top()+150);
01087             m_insRect.setRight(m_insRect.left()+200);
01088         }
01089         MouseMode old_mouseMove = m_mouseMode;
01090         switch ( m_mouseMode ) {
01091             case MM_EDIT:
01092                 if ( m_currentFrameSetEdit )
01093                     m_currentFrameSetEdit->mouseReleaseEvent( e, normalPoint, docPoint );
01094                 else {
01095                   if ( m_mouseMeaning == MEANING_RESIZE_COLUMN )
01096                   {
01097                     KWResizeColumnCommand *cmd = new KWResizeColumnCommand( m_currentTable, m_rowColResized, m_previousTableSize, docPoint.x() );
01098                     m_doc->addCommand(cmd);
01099                     cmd->execute();
01100                   }
01101                   else if ( m_mouseMeaning == MEANING_RESIZE_ROW )
01102                   {
01103                     KWResizeRowCommand *cmd = new KWResizeRowCommand( m_currentTable, m_rowColResized, m_previousTableSize, docPoint.y() );
01104                     m_doc->addCommand(cmd);
01105                     cmd->execute();
01106                   }
01107                   else
01108                     mrEditFrame();
01109                   m_mouseMeaning = MEANING_NONE;
01110                 }
01111                 break;
01112             case MM_CREATE_TEXT:
01113                 mrCreateText();
01114                 break;
01115             case MM_CREATE_PIX:
01116                 mrCreatePixmap();
01117                 break;
01118             case MM_CREATE_PART:
01119                 mrCreatePart();
01120                 break;
01121             case MM_CREATE_TABLE:
01122                 mrCreateTable();
01123                 break;
01124             case MM_CREATE_FORMULA:
01125                 mrCreateFormula();
01126                 break;
01127         }
01128 
01129         if ( old_mouseMove != MM_EDIT && !m_doc->showGrid() && m_doc->snapToGrid() )
01130           repaintContents( FALSE ); //draw the grid over the whole canvas
01131         m_mousePressed = false;
01132     }
01133 }
01134 
01135 void KWCanvas::contentsMouseDoubleClickEvent( QMouseEvent * e )
01136 {
01137     if ( m_printing )
01138         return;
01139     QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
01140     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01141     switch ( m_mouseMode ) {
01142         case MM_EDIT:
01143             if ( m_currentFrameSetEdit )
01144             {
01145                 m_mousePressed = true; // needed for the dbl-click + move feature.
01146                 m_scrollTimer->start( 50 );
01147                 m_currentFrameSetEdit->mouseDoubleClickEvent( e, normalPoint, docPoint );
01148             }
01149             else
01150             {
01151                 // Double-click on an embedded object should edit it, not pop up the frame dialog
01152                 // So we have to test for that.
01153                 KWFrameView *view = m_frameViewManager->selectedFrame();
01154                 bool isPartFrameSet = view && dynamic_cast<KWPartFrameSet*>(view->frame()->frameSet());
01155                 if ( !isPartFrameSet )
01156                     editFrameProperties();
01157                 // KWDocumentChild::hitTest and KWView::slotChildActivated take care of embedded objects
01158                 m_mousePressed = false;
01159             }
01160             break;
01161         default:
01162             break;
01163     }
01164 }
01165 
01166 void KWCanvas::setFrameBackgroundColor( const QBrush &_backColor )
01167 {
01168     QValueList<KWFrameView*> selectedFrames = m_frameViewManager->selectedFrames();
01169     if (selectedFrames.isEmpty())
01170         return;
01171     bool colorChanged=false;
01172     QPtrList<FrameIndex> frameindexList;
01173     QPtrList<QBrush> oldColor;
01174 
01175     QValueListIterator<KWFrameView*> framesIterator = selectedFrames.begin();
01176     while(framesIterator != selectedFrames.end()) {
01177         KWFrame *frame = KWFrameSet::settingsFrame( (*framesIterator)->frame() );
01178         FrameIndex *index=new FrameIndex( frame );
01179         frameindexList.append(index);
01180 
01181         QBrush *_color=new QBrush(frame->backgroundColor());
01182         oldColor.append(_color);
01183 
01184         if (frame->frameSet() && frame->frameSet()->type()!=FT_PICTURE && frame->frameSet()->type()!=FT_PART &&  _backColor!=frame->backgroundColor())
01185         {
01186             colorChanged=true;
01187             frame->setBackgroundColor(_backColor);
01188         }
01189         ++framesIterator;
01190     }
01191     if(colorChanged)
01192     {
01193         KWFrameBackGroundColorCommand *cmd=new KWFrameBackGroundColorCommand(i18n("Change Frame Background Color"),frameindexList,oldColor,_backColor);
01194         m_doc->addCommand(cmd);
01195         m_doc->repaintAllViews();
01196     }
01197     else
01198     {
01199         frameindexList.setAutoDelete(true);
01200         oldColor.setAutoDelete(true);
01201     }
01202 }
01203 
01204 void KWCanvas::editFrameProperties( KWFrameSet * frameset )
01205 {
01206     KWFrameDia *frameDia;
01207     KWFrame *frame = frameset->frame(0);
01208     frameDia = new KWFrameDia( this, frame );
01209     frameDia->exec();
01210     delete frameDia;
01211 }
01212 
01213 void KWCanvas::editFrameProperties()
01214 {
01215     QValueList<KWFrameView*> selectedFrames = m_frameViewManager->selectedFrames();
01216     if(selectedFrames.count()==0) return;
01217 
01218     KWFrameDia *frameDia;
01219     if(selectedFrames.count()==1)
01220         frameDia = new KWFrameDia( this, selectedFrames[0]->frame());
01221     else { // multi frame dia.
01222         QPtrList<KWFrame> frames;
01223         QValueListIterator<KWFrameView*> framesIterator = selectedFrames.begin();
01224         for(;framesIterator != selectedFrames.end(); ++framesIterator)
01225             frames.append( (*framesIterator)->frame() );
01226         frameDia = new KWFrameDia( this, frames );
01227     }
01228     frameDia->exec();
01229     delete frameDia;
01230 }
01231 
01232 void KWCanvas::selectAllFrames( bool select ) {
01233     QValueList<KWFrameView*> frameViews = m_frameViewManager->frameViewsIterator();
01234     QValueList<KWFrameView*>::iterator frames = frameViews.begin();
01235     for(; frames != frameViews.end(); ++frames ) {
01236         KWFrameSet *fs = (*frames)->frame()->frameSet();
01237         if ( !fs->isVisible() ) continue;
01238         if ( select && fs->isMainFrameset() )
01239             continue; // "select all frames" shouldn't select the page
01240         (*frames)->setSelected(select);
01241     }
01242 }
01243 
01244 void KWCanvas::tableSelectCell(KWTableFrameSet *table, KWFrameSet *cell)
01245 {
01246     terminateCurrentEdit();
01247     m_frameViewManager->view(cell->frame(0))->setSelected(true);
01248     m_currentTable = table;
01249 }
01250 
01251 void KWCanvas::editFrameSet( KWFrameSet * frameSet, bool onlyText /*=false*/ )
01252 {
01253     selectAllFrames( false );
01254     bool emitChanged = checkCurrentEdit( frameSet, onlyText );
01255 
01256     if ( emitChanged ) // emitted after mousePressEvent [for tables]
01257         emit currentFrameSetEditChanged();
01258     emit updateRuler();
01259 }
01260 
01261 void KWCanvas::editTextFrameSet( KWFrameSet * fs, KoTextParag* parag, int index )
01262 {
01263     selectAllFrames( false );
01264 
01265 #if 0
01266     //active header/footer when it's possible
01267     // DF: what is this code doing here?
01268     if ( fs->isAHeader() && !m_doc->isHeaderVisible() && !(viewMode()->type()=="ModeText"))
01269         m_doc->setHeaderVisible( true );
01270     if ( fs->isAFooter() && !m_doc->isFooterVisible() && !(viewMode()->type()=="ModeText"))
01271         m_doc->setFooterVisible( true );
01272 #endif
01273 
01274     if ( !fs->isVisible( viewMode() ) )
01275         return;
01276     setMouseMode( MM_EDIT );
01277     bool emitChanged = checkCurrentEdit( fs );
01278 
01279     if ( m_currentFrameSetEdit && m_currentFrameSetEdit->frameSet()->type()==FT_TEXT ) {
01280         if ( !parag )
01281         {
01282             KWTextDocument *tmp = static_cast<KWTextFrameSet*>(m_currentFrameSetEdit->frameSet())->kwTextDocument();
01283             parag = tmp->firstParag();
01284         }
01285         // The _new_ cursor position must be visible.
01286         KWTextFrameSetEdit *textedit = currentTextEdit();
01287         if ( textedit ) {
01288             textedit->hideCursor();
01289             textedit->setCursor( parag, index );
01290             textedit->showCursor();
01291             textedit->ensureCursorVisible();
01292         }
01293     }
01294     if ( emitChanged )
01295         emit currentFrameSetEditChanged();
01296     emit updateRuler();
01297 }
01298 
01299 void KWCanvas::ensureCursorVisible()
01300 {
01301     Q_ASSERT( m_currentFrameSetEdit );
01302     KWTextFrameSetEdit *textedit = currentTextEdit();
01303     if ( textedit )
01304         textedit->ensureCursorVisible();
01305 }
01306 
01307 bool KWCanvas::checkCurrentEdit( KWFrameSet * fs , bool onlyText )
01308 {
01309     bool emitChanged = false;
01310     if ( fs && m_currentFrameSetEdit && m_currentFrameSetEdit->frameSet() != fs )
01311     {
01312         KWTextFrameSet * tmp = dynamic_cast<KWTextFrameSet *>(fs );
01313         if ( tmp && tmp->protectContent() && !m_doc->cursorInProtectedArea() )
01314             return false;
01315 
01316         KWTextFrameSetEdit *edit = currentTextEdit();
01317         if(edit && onlyText)
01318         {
01319             // Don't use terminateCurrentEdit here, we want to emit changed only once
01320             //don't remove selection in dnd
01321             m_currentFrameSetEdit->terminate(false);
01322         }
01323         else
01324             m_currentFrameSetEdit->terminate();
01325         delete m_currentFrameSetEdit;
01326         m_currentFrameSetEdit = 0L;
01327         emitChanged = true;
01328 
01329     }
01330 
01331     // Edit the frameset "fs"
01332     if ( fs && !m_currentFrameSetEdit )
01333     {
01334         KWTextFrameSet * tmp = dynamic_cast<KWTextFrameSet *>(fs );
01335         if ( tmp && tmp->protectContent() && !m_doc->cursorInProtectedArea() )
01336             return false;
01337         // test for "text frameset only" if requested
01338         if(fs->type()==FT_TABLE || fs->type()==FT_TEXT || !onlyText)
01339         {
01340             if ( fs->type() == FT_TABLE )
01341                 m_currentTable = static_cast<KWTableFrameSet *>(fs);
01342             else if ( fs->type() == FT_TEXT )
01343                 m_currentTable = static_cast<KWTextFrameSet *>(fs)->groupmanager();
01344             else
01345                 m_currentTable = 0L;
01346             if ( m_currentTable ) {
01347                 m_currentFrameSetEdit = m_currentTable->createFrameSetEdit( this );
01348                 static_cast<KWTableFrameSetEdit *>( m_currentFrameSetEdit )->setCurrentCell( fs );
01349             }
01350             else
01351                 m_currentFrameSetEdit = fs->createFrameSetEdit( this );
01352 
01353             if ( m_currentFrameSetEdit ) {
01354                 KWTextFrameSetEdit *edit = currentTextEdit();
01355                 if ( edit )
01356                     edit->setOverwriteMode( m_overwriteMode );
01357             }
01358         }
01359         emitChanged = true;
01360     }
01361     return emitChanged;
01362 }
01363 
01364 void KWCanvas::terminateCurrentEdit()
01365 {
01366     if(m_currentFrameSetEdit == 0)
01367         return;
01368     m_lastCaretPos = caretPos();
01369     m_currentFrameSetEdit->terminate();
01370     delete m_currentFrameSetEdit;
01371     m_currentFrameSetEdit = 0L;
01372     emit currentFrameSetEditChanged();
01373     repaintAll();
01374 }
01375 
01376 void KWCanvas::terminateEditing( KWFrameSet *fs )
01377 {
01378     if ( m_currentFrameSetEdit && m_currentFrameSetEdit->frameSet() == fs )
01379         terminateCurrentEdit();
01380     // Also deselect the frames from this frameset
01381     QPtrListIterator<KWFrame> frameIt = fs->frameIterator();
01382     for ( ; frameIt.current(); ++frameIt ) {
01383         KWFrameView* view = m_frameViewManager->view(frameIt.current());
01384         Q_ASSERT(view);
01385         if(view) view->setSelected(false);
01386     }
01387 }
01388 
01389 KWTextFrameSetEdit* KWCanvas::currentTextEdit() const
01390 {
01391     if ( m_currentFrameSetEdit )
01392         return dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit->currentTextEdit());
01393     return 0;
01394 }
01395 
01396 void KWCanvas::setMouseMode( MouseMode newMouseMode )
01397 {
01398     if ( m_mouseMode != newMouseMode )
01399     {
01400         selectAllFrames( false );
01401 
01402         if ( newMouseMode != MM_EDIT )
01403             terminateCurrentEdit();
01404 
01405         m_mouseMode = newMouseMode;
01406         if ( !m_doc->showGrid() && m_doc->snapToGrid() )
01407           repaintContents( FALSE ); //draw the grid over the whole canvas
01408     }
01409     else
01410         m_mouseMode = newMouseMode;
01411     emit currentMouseModeChanged(m_mouseMode);
01412 
01413     switch ( m_mouseMode ) {
01414     case MM_EDIT: {
01415         QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01416         QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01417         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01418         viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, 0 ) );
01419         m_frameInline = false;
01420     } break;
01421     case MM_CREATE_TEXT:
01422     case MM_CREATE_PIX:
01423     case MM_CREATE_TABLE:
01424     case MM_CREATE_FORMULA:
01425     case MM_CREATE_PART:
01426         viewport()->setCursor( crossCursor );
01427         break;
01428     }
01429 }
01430 
01431 void KWCanvas::insertPicture( const KoPicture& newPicture, QSize pixmapSize, bool _keepRatio )
01432 {
01433     setMouseMode( MM_CREATE_PIX );
01434     m_kopicture = newPicture;
01435     m_pixmapSize = pixmapSize;
01436     if ( pixmapSize.isEmpty() )
01437         m_pixmapSize = newPicture.getOriginalSize();
01438     m_keepRatio = _keepRatio;
01439 }
01440 
01441 void KWCanvas::insertPictureDirect( const KoPicture& picture, const KoPoint& pos, const QSize& sz )
01442 {
01443     // Prepare things for mrCreatePixmap
01444     m_pixmapSize = sz.isEmpty() ? picture.getOriginalSize() : sz;
01445     m_kopicture = picture;
01446     m_insRect = KoRect( pos.x(), pos.y(), m_doc->unzoomItX( m_pixmapSize.width() ), m_doc->unzoomItY( m_pixmapSize.height() ) );
01447     m_keepRatio = true;
01448     mrCreatePixmap();
01449 }
01450 
01451 void KWCanvas::insertPart( const KoDocumentEntry &entry )
01452 {
01453     m_partEntry = entry;
01454     if ( m_partEntry.isEmpty() )
01455     {
01456         setMouseMode( MM_EDIT );
01457         return;
01458     }
01459     setMouseMode( MM_CREATE_PART );
01460 }
01461 
01462 void KWCanvas::contentsDragEnterEvent( QDragEnterEvent *e )
01463 {
01464     int provides = KWView::checkClipboard( e );
01465     if ( ( provides & KWView::ProvidesImage ) || KURLDrag::canDecode( e ) )
01466     {
01467         m_imageDrag = true;
01468         e->acceptAction();
01469     }
01470     else
01471     {
01472         m_imageDrag = false;
01473         if ( m_currentFrameSetEdit )
01474             m_currentFrameSetEdit->dragEnterEvent( e );
01475     }
01476 }
01477 
01478 void KWCanvas::contentsDragMoveEvent( QDragMoveEvent *e )
01479 {
01480     if ( !m_imageDrag /*&& m_currentFrameSetEdit*/ )
01481     {
01482         QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
01483         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01484         KWFrameView *view = m_frameViewManager->view(docPoint, KWFrameViewManager::frameOnTop);
01485         KWFrame *frame = view ? view->frame() : 0;
01486         KWFrameSet * fs = frame ? frame->frameSet() : 0L;
01487         bool emitChanged = false;
01488         if ( fs )
01489         {
01490             //kdDebug()<<"table :"<<table<<endl;
01491             emitChanged = checkCurrentEdit( fs, true );
01492         }
01493         if ( m_currentFrameSetEdit )
01494         {
01495             m_currentFrameSetEdit->dragMoveEvent( e, normalPoint, docPoint );
01496 
01497             if ( emitChanged ) // emitted after mousePressEvent [for tables]
01498                 emit currentFrameSetEditChanged();
01499         }
01500     }
01501 }
01502 
01503 void KWCanvas::contentsDragLeaveEvent( QDragLeaveEvent *e )
01504 {
01505     if ( !m_imageDrag && m_currentFrameSetEdit )
01506         m_currentFrameSetEdit->dragLeaveEvent( e );
01507 }
01508 
01509 void KWCanvas::contentsDropEvent( QDropEvent *e )
01510 {
01511     QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
01512     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01513 
01514     if ( QImageDrag::canDecode( e ) ) {
01515         pasteImage( e, docPoint );
01516     } else if ( KURLDrag::canDecode( e ) ) {
01517 
01518         // TODO ask (with a popupmenu) between inserting a link and inserting the contents
01519         // TODO fix khtml to export images when dragging an image+link (as it does when using "Copy")
01520 
01521         KURL::List lst;
01522         KURLDrag::decode( e, lst );
01523 
01524         KURL::List::ConstIterator it = lst.begin();
01525         for ( ; it != lst.end(); ++it ) {
01526             const KURL &url( *it );
01527 
01528             QString filename;
01529             if ( !KIO::NetAccess::download( url, filename, this ) )
01530                 continue;
01531 
01532             KMimeType::Ptr res = KMimeType::findByFileContent( filename );
01533 
01534             if ( res && res->isValid() ) {
01535                 QString mimetype = res->name();
01536                 if ( mimetype.contains( "image" ) ) {
01537                     KoPictureKey key;
01538                     key.setKeyFromFile( filename );
01539                     KoPicture newKoPicture;
01540                     newKoPicture.setKey( key );
01541                     newKoPicture.loadFromFile( filename );
01542                     insertPictureDirect( newKoPicture, docPoint );
01543                 }
01544             }
01545             KIO::NetAccess::removeTempFile( filename );
01546         }
01547     }
01548     else
01549     {
01550         if ( m_currentFrameSetEdit )
01551             m_currentFrameSetEdit->dropEvent( e, normalPoint, docPoint, m_gui->getView() );
01552         else
01553             m_gui->getView()->pasteData( e, true );
01554     }
01555     m_mousePressed = false;
01556     m_imageDrag = false;
01557 }
01558 
01559 void KWCanvas::pasteImage( QMimeSource *e, const KoPoint &docPoint )
01560 {
01561     QImage i;
01562     if ( !QImageDrag::decode(e, i) ) {
01563         kdWarning() << "Couldn't decode image" << endl;
01564         return;
01565     }
01566     KTempFile tmpFile( QString::null, ".png");
01567     tmpFile.setAutoDelete( true );
01568     if ( !i.save(tmpFile.name(), "PNG") ) {
01569         kdWarning() << "Couldn't save image to " << tmpFile.name() << endl;
01570         return;
01571     }
01572     m_pixmapSize = i.size();
01573     // Prepare things for mrCreatePixmap
01574     KoPictureKey key;
01575     key.setKeyFromFile( tmpFile.name() );
01576     KoPicture newKoPicture;
01577     newKoPicture.setKey( key );
01578     newKoPicture.loadFromFile( tmpFile.name() );
01579     m_kopicture = newKoPicture;
01580     m_insRect = KoRect( docPoint.x(), docPoint.y(), m_doc->unzoomItX( i.width() ), m_doc->unzoomItY( i.height() ) );
01581     m_keepRatio = true;
01582     mrCreatePixmap();
01583 }
01584 
01585 void KWCanvas::doAutoScroll()
01586 {
01587     if ( !m_mousePressed )
01588     {
01589         m_scrollTimer->stop();
01590         return;
01591     }
01592 
01593     // This code comes from khtml
01594     QPoint pos( mapFromGlobal( QCursor::pos() ) );
01595 
01596     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
01597     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
01598          (pos.x() < 0) || (pos.x() > visibleWidth()) )
01599     {
01600         int xm, ym;
01601         viewportToContents(pos.x(), pos.y(), xm, ym);
01602         if ( m_currentFrameSetEdit )
01603             m_currentFrameSetEdit->focusOutEvent(); // Hide cursor
01604         if ( m_deleteMovingRect )
01605             deleteMovingRect();
01606         ensureVisible( xm, ym, 0, 5 );
01607         if ( m_currentFrameSetEdit )
01608             m_currentFrameSetEdit->focusInEvent(); // Show cursor
01609     }
01610 }
01611 
01612 void KWCanvas::slotContentsMoving( int cx, int cy )
01613 {
01614     //QPoint nPointTop = m_viewMode->viewToNormal( QPoint( cx, cy ) );
01615     QPoint nPointBottom = m_viewMode->viewToNormal( QPoint( cx + visibleWidth(), cy + visibleHeight() ) );
01616     //kdDebug() << "KWCanvas::slotContentsMoving cx=" << cx << " cy=" << cy << endl;
01617     //kdDebug() << " visibleWidth()=" << visibleWidth() << " visibleHeight()=" << visibleHeight() << endl;
01618     // Update our "formatted paragraphs needs" in all the text framesets
01619     QPtrList<KWTextFrameSet> textFrameSets = m_doc->allTextFramesets( false );
01620     QPtrListIterator<KWTextFrameSet> fit( textFrameSets );
01621     for ( ; fit.current() ; ++fit )
01622     {
01623         if(! fit.current()->isVisible()) continue;
01624         fit.current()->updateViewArea( this, m_viewMode, nPointBottom );
01625     }
01626     // cx and cy contain the future values for contentsx and contentsy, so we need to
01627     // pass them to updateRulerOffsets.
01628     updateRulerOffsets( cx, cy );
01629 
01630     // Tell KoView that the view transformations have changed (e.g. the centering of the page, or the scrolling offsets)
01631     // so that it will reposition any active embedded object.
01632     // This needs to be delayed since contents moving is emitted -before- moving,
01633     // and from resizeEvent it's too early too.
01634     QTimer::singleShot( 0, this, SIGNAL( viewTransformationsChanged() ) );
01635 }
01636 
01637 void KWCanvas::slotMainTextHeightChanged()
01638 {
01639     // Check that the viewmode is a KWViewModeText, and that the rulers have been built already
01640     if ( dynamic_cast<KWViewModeText *>(m_viewMode) && m_gui->getHorzRuler() )
01641     {
01642         slotNewContentsSize();
01643         m_viewMode->setPageLayout( m_gui->getHorzRuler(), m_gui->getVertRuler(), KoPageLayout() /*unused*/ );
01644         emit updateRuler();
01645     }
01646 }
01647 
01648 void KWCanvas::slotNewContentsSize()
01649 {
01650     QSize size = m_viewMode->contentsSize();
01651     if ( size != QSize( contentsWidth(), contentsHeight() ) )
01652     {
01653         //kdDebug() << "KWCanvas::slotNewContentsSize " << size.width() << "x" << size.height() << endl;
01654         resizeContents( size.width(), size.height() );
01655     }
01656 }
01657 
01658 void KWCanvas::resizeEvent( QResizeEvent *e )
01659 {
01660     slotContentsMoving( contentsX(), contentsY() );
01661     QScrollView::resizeEvent( e );
01662 }
01663 
01664 void KWCanvas::scrollToOffset( const KoPoint & d )
01665 {
01666     kdDebug() << "KWCanvas::scrollToOffset " << d.x() << "," << d.y() << endl;
01667 #if 0
01668     bool blinking = blinkTimer.isActive();
01669     if ( blinking )
01670         stopBlinkCursor();
01671 #endif
01672     QPoint nPoint = m_doc->zoomPoint( d );
01673     QPoint cPoint = m_viewMode->normalToView( nPoint );
01674     setContentsPos( cPoint.x(), cPoint.y() );
01675 
01676 #if 0
01677     if ( blinking )
01678         startBlinkCursor();
01679 #endif
01680 }
01681 
01682 void KWCanvas::updateRulerOffsets( int cx, int cy )
01683 {
01684     if ( cx == -1 && cy == -1 )
01685     {
01686         cx = contentsX();
01687         cy = contentsY();
01688     }
01689     // The offset is usually just the scrollview offset
01690     // But we also need to offset to the current page, for the graduations
01691     QPoint pc = m_viewMode->pageCorner();
01692     //kdDebug() << "KWCanvas::updateRulerOffsets contentsX=" << cx << ", contentsY=" << cy << endl;
01693     if (m_gui->getHorzRuler())
01694         m_gui->getHorzRuler()->setOffset( cx - pc.x(), 0 );
01695     if (m_gui->getVertRuler())
01696         m_gui->getVertRuler()->setOffset( 0, cy - pc.y() );
01697 
01698 }
01699 
01700 bool KWCanvas::eventFilter( QObject *o, QEvent *e )
01701 {
01702     if ( o == this || o == viewport() ) {
01703 
01704         if(m_currentFrameSetEdit && o == this )
01705         {
01706             // Pass event to auto-hide-cursor code (see kcursor.h for details)
01707             KCursor::autoHideEventFilter( o, e );
01708         }
01709 
01710         switch ( e->type() ) {
01711             case QEvent::FocusIn:
01712                 //  kdDebug() << "KWCanvas::eventFilter QEvent::FocusIn" << endl;
01713                 if ( m_currentFrameSetEdit && !m_printing )
01714                     m_currentFrameSetEdit->focusInEvent();
01715                 break;
01716             case QEvent::FocusOut:
01717                 //  kdDebug() << "KWCanvas::eventFilter QEvent::FocusOut" << endl;
01718                 if ( m_currentFrameSetEdit && !m_printing )
01719                     m_currentFrameSetEdit->focusOutEvent();
01720                 if ( m_scrollTimer->isActive() )
01721                     m_scrollTimer->stop();
01722                 m_mousePressed = false;
01723                 break;
01724             case QEvent::AccelOverride: // was part of KeyPress - changed due to kdelibs BUG!
01725             {
01726                 //  kdDebug() << " KeyPress m_currentFrameSetEdit=" << m_currentFrameSetEdit << " isRW="<<m_doc->isReadWrite() << endl;
01727                 //  kdDebug() << " m_printing=" << m_printing << " mousemode=" << m_mouseMode << " (MM_EDIT=" << MM_EDIT<<")"<<endl;
01728                 QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
01729 #ifndef NDEBUG
01730                 // Debug keys
01731                 if ( ( keyev->state() & ControlButton ) && ( keyev->state() & ShiftButton ) )
01732                 {
01733                     switch ( keyev->key() ) {
01734                         case Qt::Key_P: // 'P' -> paragraph debug
01735                             printRTDebug( 0 );
01736                             keyev->accept();
01737                             break;
01738                         case Qt::Key_V: // 'V' -> verbose parag debug
01739                             printRTDebug( 1 );
01740                             keyev->accept();
01741                             break;
01742                         case Qt::Key_F: // 'F' -> frames debug
01743                             m_doc->printDebug();
01744                             kdDebug(32002) << "Current framesetedit: " << m_currentFrameSetEdit << " " <<
01745                                 ( m_currentFrameSetEdit ? m_currentFrameSetEdit->frameSet()->className() : "" ) << endl;
01746                             keyev->accept();
01747                             break;
01748                         case Qt::Key_S: // 'S' -> styles debug
01749                             m_doc->printStyleDebug();
01750                             keyev->accept();
01751                             break;
01752                         case Qt::Key_M: // 'M' -> mark debug output
01753                             {
01754                                 const QDateTime dtMark ( QDateTime::currentDateTime() );
01755                                 kdDebug(32002) << "Developer mark: " << dtMark.toString("yyyy-MM-dd hh:mm:ss,zzz") << endl;
01756                                 keyev->accept();
01757                                 break;
01758                             }
01759                         default:
01760                             break;
01761                     };
01762                     // For some reason 'T' doesn't work (maybe kxkb)
01763                 }
01764 #endif
01765             }
01766                 break;
01767             case QEvent::KeyPress:
01768             {
01769                 //  kdDebug() << " KeyPress m_currentFrameSetEdit=" << m_currentFrameSetEdit << " isRW="<<m_doc->isReadWrite() << endl;
01770                 //  kdDebug() << " m_printing=" << m_printing << " mousemode=" << m_mouseMode << " (MM_EDIT=" << MM_EDIT<<")"<<endl;
01771                 QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
01772                 // By default PgUp and PgDown move the scrollbars and not the caret anymore - this is done here
01773                 if ( !m_doc->pgUpDownMovesCaret() && ( (keyev->state() & ShiftButton) == 0 )
01774                      && ( keyev->key() == Qt::Key_PageUp || keyev->key() == Key_PageDown ) )
01775                 {
01776                     viewportScroll( keyev->key() == Qt::Key_PageUp );
01777                 }
01778                 // Activate this code (and in focusNextPreviousChild() to allow Shift+Tab
01779                 // out of document window.  Disabled because it conflicts with Shift+Tab inside a table.
01780                 // else if ( keyev->key() == Qt::Key_BackTab )
01781                 //    return FALSE;
01782                 else if ( keyev->key() == KGlobalSettings::contextMenuKey() ) {
01783                     // The popups are not available in readonly mode, since the GUI isn't built...
01784                     if(!m_doc->isReadWrite()) return TRUE;
01785                     if (m_mouseMode != MM_EDIT) return TRUE;
01786                     KoPoint docPoint = m_doc->unzoomPoint( QCursor::pos() );
01787 
01788                     if ( viewMode()->type()=="ModeText") {
01789                         KWFrameView *view = m_frameViewManager->view(m_doc->frameSet( 0 )->frame(0));
01790                         view->showPopup(docPoint, m_gui->getView(), QCursor::pos());
01791                     }
01792                     else {
01793                         m_frameViewManager->showPopup( docPoint, m_gui->getView(), keyev->state(), pos());
01794                     }
01795                     return true;
01796                 }
01797                 else if ( keyev->key() == Qt::Key_Return && keyev->state() == 0
01798                     && (m_mouseMode != MM_EDIT || m_frameInline )) {
01799                     // When inserting an inline or non-line frame,
01800                     // simulate mouse press and release at caret position.
01801                     // In the case of a regular frame, the caret position was saved when
01802                     // they left edit mode.  In the case of an inline frame,
01803                     // get current caret position, since user can type and move caret
01804                     // around before they click or hit Enter.
01805                     if (m_frameInline)
01806                         m_lastCaretPos = caretPos();
01807                     if (m_lastCaretPos.isNull()) return TRUE;
01808                     int page = m_doc->pageManager()->pageNumber(m_lastCaretPos);
01809                     if(page == -1) return TRUE;
01810                     QPoint normalPoint = m_doc->zoomPoint(m_lastCaretPos);
01811                     // Coordinate is at the very top of the caret.  In the case of an
01812                     // inline frame, adjust slightly down and to the right in order
01813                     // to avoid "clicking" the frame border.
01814                     if (m_frameInline)
01815                         normalPoint += QPoint(2,2);
01816                     QPoint vP = m_viewMode->normalToView(normalPoint);
01817                     QPoint gP = mapToGlobal(vP);
01818                     QMouseEvent mevPress(QEvent::MouseButtonPress, vP,
01819                         gP, Qt::LeftButton, 0);
01820                     contentsMousePressEvent(&mevPress);
01821                     QMouseEvent mevRelease(QEvent::MouseButtonRelease, vP,
01822                         gP, Qt::LeftButton, 0);
01823                     contentsMouseReleaseEvent(&mevRelease);
01824                 }
01825                 else if ( keyev->key() == Qt::Key_Escape  ) {
01826                     if ( m_mouseMode != MM_EDIT ) // Abort frame creation
01827                         setMouseMode( MM_EDIT );
01828                     else if(m_interactionPolicy) {
01829                         m_interactionPolicy->cancelInteraction();
01830                         delete(m_interactionPolicy);
01831                         m_interactionPolicy = 0;
01832                         m_mousePressed = false;
01833 
01834                         // reset cursor
01835                         QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01836                         QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01837                         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01838                         viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, keyev->stateAfter() ) );
01839                         if ( !m_doc->showGrid() && m_doc->snapToGrid() )
01840                             repaintContents();
01841                     }
01842                 }
01843                 else if ( keyev->key() == Key_Insert && keyev->state() == 0 ) {
01844                     m_overwriteMode = !m_overwriteMode;
01845                     KWTextFrameSetEdit *edit = currentTextEdit();
01846                     if ( edit ) {
01847                         edit->setOverwriteMode( m_overwriteMode );
01848                         emit overwriteModeChanged( m_overwriteMode );
01849                     }
01850                     kdDebug()<<"Insert is pressed, overwrite mode: "<< m_overwriteMode << endl;
01851                 }
01852                 else // normal key processing
01853                     if ( m_currentFrameSetEdit && m_mouseMode == MM_EDIT && m_doc->isReadWrite() && !m_printing )
01854                 {
01855                     KWTextFrameSetEdit *edit = dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit );
01856                     if ( edit )
01857                     {
01858                         if ( !edit->textFrameSet()->textObject()->protectContent() || (keyev->text().length() == 0))
01859                             m_currentFrameSetEdit->keyPressEvent( keyev );
01860                         else if(keyev->text().length() > 0)
01861                             KMessageBox::information(this, i18n("Read-only content cannot be changed. No modifications will be accepted."));
01862                     }
01863                     else
01864                         m_currentFrameSetEdit->keyPressEvent( keyev );
01865                     return TRUE;
01866                 }
01867 
01868                 // Because of the dependency on the control key, we need to update the mouse cursor here
01869                 if ( keyev->key() == Qt::Key_Control )
01870                 {
01871                     QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01872                     QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01873                     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01874                     viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, keyev->stateAfter() ) );
01875                 }
01876                 else if ( (keyev->key() == Qt::Key_Delete || keyev->key() ==Key_Backspace )
01877                           && m_frameViewManager->selectedFrame() && !m_printing )
01878                     m_gui->getView()->editDeleteFrame();
01879             } break;
01880             case QEvent::KeyRelease:
01881             {
01882                 QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
01883                 if ( keyev->key() == Qt::Key_Control )
01884                 {
01885                     QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01886                     QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01887                     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01888                     viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, keyev->stateAfter() ) );
01889                 }
01890 
01891                 if ( m_currentFrameSetEdit && m_mouseMode == MM_EDIT && m_doc->isReadWrite() && !m_printing )
01892                 {
01893                     m_currentFrameSetEdit->keyReleaseEvent( keyev );
01894                     return TRUE;
01895                 }
01896             }
01897                 break;
01898             case QEvent::IMStart:
01899             {
01900                 QIMEvent * imev = static_cast<QIMEvent *>(e);
01901                 m_currentFrameSetEdit->imStartEvent( imev );
01902             }
01903                 break;
01904             case QEvent::IMCompose:
01905             {
01906                 QIMEvent * imev = static_cast<QIMEvent *>(e);
01907                 m_currentFrameSetEdit->imComposeEvent( imev );
01908             }
01909                 break;
01910             case QEvent::IMEnd:
01911             {
01912                 QIMEvent * imev = static_cast<QIMEvent *>(e);
01913                 m_currentFrameSetEdit->imEndEvent( imev );
01914             }
01915                 break;
01916             default:
01917                 break;
01918         }
01919     }
01920     return QScrollView::eventFilter( o, e );
01921 }
01922 
01923 bool KWCanvas::focusNextPrevChild( bool next)
01924 {
01925     Q_UNUSED(next);
01926     return TRUE; // Don't allow to go out of the canvas widget by pressing "Tab"
01927     // Don't allow to go out of the canvas widget by pressing Tab, but do allow Shift+Tab.
01928     // if (next) return TRUE;
01929     // return QWidget::focusNextPrevChild( next );
01930 }
01931 
01932 void KWCanvas::updateCurrentFormat()
01933 {
01934     KWTextFrameSetEdit * edit = dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit);
01935     if ( edit )
01936         edit->updateUI( true, true );
01937 }
01938 
01939 #ifndef NDEBUG
01940 void KWCanvas::printRTDebug( int info )
01941 {
01942     KWTextFrameSet * textfs = 0L;
01943     if ( m_currentFrameSetEdit ) {
01944         KWTextFrameSetEdit* edit = currentTextEdit();
01945         if ( edit ) {
01946             textfs = dynamic_cast<KWTextFrameSet *>( edit->frameSet() );
01947             Q_ASSERT( textfs );
01948         }
01949     }
01950     if ( !textfs )
01951         textfs = dynamic_cast<KWTextFrameSet *>(m_doc->frameSet( 0 ));
01952     if ( textfs )
01953         textfs->textObject()->printRTDebug( info );
01954 }
01955 #endif
01956 
01957 void KWCanvas::setXimPosition( int x, int y, int w, int h )
01958 {
01959     /* Check for hasFocus() to avoid crashes in QXIMInputContext as in bug #123941.
01960        This is only a workaround, the real problem might be in Qt. See also
01961        http://lists.kde.org/?l=kde-core-devel&m=115770546313922&w=2 .
01962     */
01963     if (hasFocus())
01964       QWidget::setMicroFocusHint( x - contentsX(), y - contentsY(), w, h );
01965 }
01966 
01967 void KWCanvas::inlinePictureStarted()
01968 {
01969     m_frameInline=true;
01970     m_frameInlineType=FT_PICTURE;
01971 }
01972 
01973 int KWCanvas::currentTableRow() const
01974 {
01975     if ( !m_currentFrameSetEdit )
01976         return -1;
01977     KWTextFrameSetEdit *edit = currentTextEdit();
01978     if ( !edit )
01979         return -1;
01980     KWTextFrameSet* textfs = edit->textFrameSet();
01981     if ( textfs && textfs->groupmanager() )
01982         return static_cast<KWTableFrameSet::Cell *>(textfs)->firstRow();
01983     return -1;
01984 }
01985 
01986 int KWCanvas::currentTableCol() const
01987 {
01988     if ( !m_currentFrameSetEdit )
01989         return -1;
01990     KWTextFrameSetEdit *edit = currentTextEdit();
01991     if ( !edit )
01992         return -1;
01993     KWTextFrameSet* textfs = edit->textFrameSet();
01994     if ( textfs && textfs->groupmanager() )
01995         return static_cast<KWTableFrameSet::Cell *>(textfs)->firstColumn();
01996     return -1;
01997 }
01998 
01999 void KWCanvas::viewportScroll( bool up )
02000 {
02001     if ( up )
02002         setContentsPos( contentsX(), contentsY() - visibleHeight() );
02003     else
02004         setContentsPos( contentsX(), contentsY() + visibleHeight() );
02005 }
02006 
02007 void KWCanvas::resetStatusBarText()
02008 {
02009     if ( m_temporaryStatusBarTextShown )
02010     {
02011         gui()->getView()->updateFrameStatusBarItem();
02012         m_temporaryStatusBarTextShown = false;
02013     }
02014 }
02015 
02016 
02017 /* Returns the caret position in document coordinates.
02018    The current frame must be editable, i.e., a caret is possible. */
02019 KoPoint KWCanvas::caretPos()
02020 {
02021     if (!m_currentFrameSetEdit) return KoPoint();
02022     KWTextFrameSetEdit* textEdit = currentTextEdit();
02023     if (!textEdit) return KoPoint();
02024     KoTextCursor* cursor = textEdit->cursor();
02025     if (!cursor) return KoPoint();
02026     KWTextFrameSet* textFrameset =
02027         dynamic_cast<KWTextFrameSet *>(m_currentFrameSetEdit->frameSet());
02028     if (!textFrameset) return KoPoint();
02029     KWFrame* currentFrame = m_currentFrameSetEdit->currentFrame();
02030     if (!currentFrame) return KoPoint();
02031 
02032     QPoint viewP = textFrameset->cursorPos(cursor, this, currentFrame);
02033     viewP.rx() += contentsX();
02034     viewP.ry() += contentsY();
02035     QPoint normalP = m_viewMode->viewToNormal(viewP);
02036     KoPoint docP = m_doc->unzoomPoint(normalP);
02037     return docP;
02038 }
02039 
02040 
02041 // ************** InteractionPolicy ***********************
02042 InteractionPolicy::InteractionPolicy(KWCanvas *parent, bool doInit, bool includeInlineFrames) {
02043     m_gotDragEvents = false;
02044     m_parent = parent;
02045     if(doInit) {
02046         QValueList<KWFrameView*> selectedFrames = m_parent->frameViewManager()->selectedFrames();
02047         QValueListIterator<KWFrameView*> framesIterator = selectedFrames.begin();
02048         for(;framesIterator != selectedFrames.end(); ++framesIterator) {
02049             KWFrame *frame = (*framesIterator)->frame();
02050             KWFrameSet *fs = frame->frameSet();
02051             if(! fs) continue;
02052             if(!fs->isVisible()) continue;
02053             if(fs->isMainFrameset() ) continue;
02054             if(fs->isFloating() && !includeInlineFrames) continue;
02055             if(fs->isProtectSize() ) continue;
02056             if(fs->type() == FT_TABLE ) continue;
02057             if(fs->type() == FT_TEXT && fs->frameSetInfo() != KWFrameSet::FI_BODY ) continue;
02058             m_frames.append( frame );
02059             m_indexFrame.append( FrameIndex( frame ) );
02060         }
02061     }
02062 }
02063 
02064 InteractionPolicy* InteractionPolicy::createPolicy(KWCanvas *parent, MouseMeaning meaning, KoPoint &point, Qt::ButtonState buttonState, Qt::ButtonState keyState) {
02065     if(buttonState & Qt::LeftButton || buttonState & Qt::RightButton) {
02066         // little inner class to make sure we don't duplicate code
02067         class Selector {
02068           public:
02069             Selector(KWCanvas *canvas, KoPoint &point, Qt::ButtonState buttonState, Qt::ButtonState keyState) :
02070                 m_canvas(canvas), m_point(point), m_state(keyState) {
02071                 m_leftClick = buttonState & Qt::LeftButton;
02072                 KWFrameView *view = canvas->frameViewManager()->view(point,
02073                         KWFrameViewManager::frameOnTop);
02074                 m_doSomething = (view && !view->selected());
02075             }
02076 
02077             void doSelect() {
02078                 if(! m_doSomething) return;
02079                 m_canvas->frameViewManager()->selectFrames(m_point, m_state, m_leftClick);
02080             }
02081           private:
02082             KWCanvas *m_canvas;
02083             KoPoint m_point;
02084             Qt::ButtonState m_state;
02085             bool m_leftClick, m_doSomething;
02086         };
02087 
02088         Selector selector(parent, point, buttonState, keyState);
02089         switch(meaning) {
02090             case MEANING_MOUSE_MOVE:
02091                 selector.doSelect();
02092                 return new FrameMovePolicy(parent, point);
02093             case MEANING_TOPLEFT:
02094             case MEANING_TOP:
02095             case MEANING_TOPRIGHT:
02096             case MEANING_RIGHT:
02097             case MEANING_BOTTOMRIGHT:
02098             case MEANING_BOTTOM:
02099             case MEANING_BOTTOMLEFT:
02100             case MEANING_LEFT:
02101                 selector.doSelect();
02102                 return new FrameResizePolicy(parent, meaning, point);
02103             default:
02104                 FrameSelectPolicy *fsp = new FrameSelectPolicy(parent, meaning, point, buttonState, keyState);
02105                 if(fsp->isValid())
02106                     return fsp;
02107                 delete fsp;
02108         }
02109     }
02110     return 0; // no interaction policy found
02111 }
02112 
02113 void InteractionPolicy::cancelInteraction() {
02114     KCommand *cmd = createCommand();
02115     if(cmd) {
02116         cmd->unexecute();
02117         delete cmd;
02118     }
02119 }
02120 
02121 
02122 // ************** FrameResizePolicy ***********************
02123 FrameResizePolicy::FrameResizePolicy(KWCanvas *parent, MouseMeaning meaning, KoPoint &point) :
02124     InteractionPolicy (parent, true, true), m_boundingRect() {
02125 
02126     if( meaning == MEANING_TOPLEFT) {
02127         m_top = true; m_bottom = false; m_left = true; m_right = false;
02128     }
02129     else if( meaning == MEANING_TOP) {
02130         m_top = true; m_bottom = false; m_left = false; m_right = false;
02131     }
02132     else if( meaning == MEANING_TOPRIGHT) {
02133         m_top = true; m_bottom = false; m_left = false; m_right = true;
02134     }
02135     else if( meaning == MEANING_RIGHT) {
02136         m_top = false; m_bottom = false; m_left = false; m_right = true;
02137     }
02138     else if( meaning == MEANING_BOTTOMRIGHT) {
02139         m_top = false; m_bottom = true; m_left = false; m_right = true;
02140     }
02141     else if( meaning == MEANING_BOTTOM) {
02142         m_top = false; m_bottom = true; m_left = false; m_right = false;
02143     }
02144     else if( meaning == MEANING_BOTTOMLEFT) {
02145         m_top = false; m_bottom = true; m_left = true; m_right = false;
02146     }
02147     else if( meaning == MEANING_LEFT) {
02148         m_top = false; m_bottom = false; m_left = true; m_right = false;
02149     }
02150 
02151     QValueListConstIterator<KWFrame*> framesIterator = m_frames.begin();
02152     for(;framesIterator != m_frames.end(); ++framesIterator) {
02153         KWFrame *frame = *framesIterator;
02154         FrameResizeStruct frs(*frame, frame->minimumFrameHeight(), *frame);
02155         m_frameResize.append(frs);
02156         m_boundingRect |= frame->outerKoRect();
02157     }
02158     m_hotSpot = point - m_boundingRect.topLeft();
02159 }
02160 
02161 void FrameResizePolicy::handleMouseMove(Qt::ButtonState keyState, const KoPoint &point) {
02162     //kdDebug() << "handleMouseMove " << (m_top?"top ":"") << (m_bottom?"bottom ":"") << (m_left?"left ":"") << (m_right?"right":"") << endl;
02163     //kdDebug() << " + point: " << point
02164     //          << "  boundingrect: " << m_boundingRect << endl;
02165 
02166     bool keepAspect = keyState & Qt::AltButton;
02167     for(unsigned int i=0; !keepAspect && i < m_frames.count(); i++) {
02168         KWPictureFrameSet *picFs = dynamic_cast<KWPictureFrameSet*>(m_frames[i]->frameSet());
02169         if(picFs)
02170             keepAspect = picFs->keepAspectRatio();
02171     }
02172 
02173     bool noGrid = keyState & Qt::ShiftButton;
02174     bool scaleFromCenter = keyState & Qt::ControlButton;
02175 
02176     KoPoint p( point.x() - (m_hotSpot.x() + m_boundingRect.x()),
02177             point.y() - (m_hotSpot.y() + m_boundingRect.y()) );
02178 
02179     if ( m_parent->kWordDocument()->snapToGrid() && !noGrid )
02180         m_parent->applyGrid( p );
02181 
02182     KoRect sizeRect = m_boundingRect;
02183     if(m_top)
02184         sizeRect.setY(sizeRect.y() + p.y());
02185     if(m_bottom)
02186         sizeRect.setBottom(sizeRect.bottom() + p.y());
02187     if(m_left)
02188         sizeRect.setX(sizeRect.left() + p.x());
02189     if(m_right)
02190         sizeRect.setRight(sizeRect.right() + p.x());
02191     if(keepAspect) {
02192         double ratio = m_boundingRect.width() / m_boundingRect.height();
02193         double width = sizeRect.width();
02194         double height = sizeRect.height();
02195         int toLargestEdge = (m_bottom?1:0) + (m_top?1:0) + // should be false when only one
02196             (m_left?1:0) + (m_right?1:0);                  // of the direction bools is set
02197         bool horizontal = m_left || m_right;
02198 
02199         if(toLargestEdge != 1) { // one of the corners.
02200             if (width < height) // the biggest border is the one in control
02201                 width = height * ratio;
02202             else
02203                 height = width / ratio;
02204         } else {
02205             if (horizontal)
02206                 height = width / ratio;
02207             else
02208                 width = height * ratio;
02209         }
02210         if(m_bottom)
02211             sizeRect.setBottom(sizeRect.top() + height);
02212         else
02213             sizeRect.setTop(sizeRect.bottom() - height);
02214 
02215         if(m_left)
02216             sizeRect.setLeft(sizeRect.right() - width);
02217         else
02218             sizeRect.setRight(sizeRect.left() + width);
02219     }
02220     if(scaleFromCenter) {
02221         KoPoint origCenter(m_boundingRect.x() + m_boundingRect.width() / 2,
02222                 m_boundingRect.y() + m_boundingRect.height() / 2);
02223         KoPoint newCenter(sizeRect.x() + sizeRect.width() / 2,
02224                 sizeRect.y() + sizeRect.height() / 2);
02225         sizeRect.moveTopLeft(sizeRect.topLeft() + (origCenter - newCenter));
02226     }
02227     if(m_parent) {
02228         KWPageManager *pageManager = m_parent->kWordDocument()->pageManager();
02229         sizeRect.moveTopLeft(pageManager->clipToDocument(sizeRect.topLeft()));
02230         sizeRect.moveBottomRight(pageManager->clipToDocument(sizeRect.bottomRight()));
02231         sizeRect.setX( QMAX(0, sizeRect.x()) ); // otherwise it would get wider than the page
02232     }
02233 
02234     // each frame in m_frames should be reshaped from the original size stored in the
02235     // m_frameResize data to a size that equals the reshaping of m_boundingrect to sizeRect
02236     class Converter {
02237       public:
02238         Converter(KoRect &from, KoRect &to, KWViewMode *viewMode) {
02239             m_from = from.topLeft();
02240             m_to = to.topLeft();
02241             m_viewMode = viewMode;
02242             m_diffX = to.width() / from.width();
02243             m_diffY = to.height() / from.height();
02244             //kdDebug() << "Converter " << from << ", " << to << " x: " << m_diffX << ", y: " << m_diffY << endl;
02245         }
02246         void update(KWFrame *frame, KoRect &orig) {
02247             QRect oldRect( m_viewMode->normalToView( frame->outerRect(m_viewMode) ) );
02248             if(! frame->frameSet()->isFloating())
02249                 frame->moveTopLeft( convert( orig.topLeft() ) );
02250             KoPoint bottomRight( convert( orig.bottomRight() ) );
02251             frame->setBottom( bottomRight.y() );
02252             frame->setRight( bottomRight.x() );
02253 
02254             QRect newRect( frame->outerRect(m_viewMode) );
02255             QRect frameRect( m_viewMode->normalToView( newRect ) );
02256             // Repaint only the changed rects (oldRect U newRect)
02257             m_repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect();
02258         }
02259 
02260         QRegion repaintRegion() {
02261             return m_repaintRegion;
02262         }
02263 
02264       private:
02265         KoPoint convert(KoPoint point) {
02266             double offsetX = point.x() - m_from.x();
02267             double offsetY = point.y() - m_from.y();
02268             KoPoint answer(m_to.x() + offsetX * m_diffX, m_to.y() + offsetY * m_diffY);
02269             return answer;
02270         }
02271       private: // vars
02272         KoPoint m_from, m_to;
02273         KWViewMode *m_viewMode;
02274         QRegion m_repaintRegion;
02275         double m_diffX, m_diffY;
02276     };
02277 
02278     Converter converter(m_boundingRect, sizeRect, m_parent->viewMode());
02279     for(unsigned int i=0; i < m_frames.count(); i++)
02280         converter.update(m_frames[i], m_frameResize[i].oldRect);
02281 
02282     if ( !m_parent->kWordDocument()->showGrid() && m_parent->kWordDocument()->snapToGrid() )
02283       m_parent->repaintContents( false ); //draw the grid over the whole canvas
02284     else
02285       m_parent->repaintContents( converter.repaintRegion().boundingRect(), false );
02286     m_parent->gui()->getView()->updateFrameStatusBarItem();
02287 }
02288 
02289 KCommand *FrameResizePolicy::createCommand() {
02290     for(unsigned int i=0; i < m_frames.count(); i++) {
02291         KWFrame *frame = m_frames[i];
02292         FrameResizeStruct frs = m_frameResize[i];
02293         frs.newRect = frame->rect();
02294         frs.newMinHeight = frame->height();
02295         m_frameResize[i] = frs;
02296     }
02297     return new KWFrameResizeCommand(i18n("Resize Frame"), m_indexFrame, m_frameResize);
02298 }
02299 
02300 void FrameResizePolicy::finishInteraction() {
02301     KWFrameViewManager *frameViewManager = m_parent->frameViewManager();
02302     for(unsigned int i=0; i < m_frames.count(); i++) {
02303         KWFrame *frame = m_frames[i];
02304         frame->setMinimumFrameHeight(frame->height());
02305         frameViewManager->slotFrameResized(frame);
02306     }
02307 }
02308 
02309 
02310 // *************** FrameMovePolicy ************************
02311 FrameMovePolicy::FrameMovePolicy(KWCanvas *parent, KoPoint &point) :
02312     InteractionPolicy (parent), m_boundingRect() {
02313 
02314     QValueListConstIterator<KWFrame*> framesIterator = m_frames.begin();
02315     for(;framesIterator != m_frames.end(); ++framesIterator) {
02316         KWFrame *frame = *framesIterator;
02317         m_boundingRect |= frame->outerKoRect();
02318         FrameMoveStruct fms(frame->topLeft(), KoPoint(0,0));
02319         m_frameMove.append(fms);
02320     }
02321 
02322     m_hotSpot = point - m_boundingRect.topLeft();
02323     m_startPoint = m_boundingRect.topLeft();
02324 }
02325 
02326 void FrameMovePolicy::handleMouseMove(Qt::ButtonState keyState, const KoPoint &point) {
02327     bool noGrid = keyState & Qt::ShiftButton;
02328     bool linearMove = (keyState & Qt::AltButton) || (keyState & Qt::ControlButton);
02329 
02330     KWPageManager *pageManager = m_parent->kWordDocument()->pageManager();
02331 
02332     KoRect oldBoundingRect = m_boundingRect;
02333     //kdDebug() << "KWCanvas::mmEditFrameMove point: " << point
02334     //          << "  boundingrect: " << m_boundingRect << endl;
02335 
02336     KoPoint p( point.x() - m_hotSpot.x(), point.y() - m_hotSpot.y() );
02337     if(linearMove) {
02338         if(QABS(p.x() - m_startPoint.x()) < QABS(p.y() - m_startPoint.y()))
02339             p.setX(m_startPoint.x());
02340         else
02341             p.setY(m_startPoint.y());
02342     }
02343     if ( m_parent->kWordDocument()->snapToGrid() && !noGrid )
02344         m_parent->applyGrid( p );
02345 
02346     p = pageManager->clipToDocument(p);
02347     m_boundingRect.moveTopLeft( p );
02348     m_boundingRect.moveBottomRight( pageManager->clipToDocument(m_boundingRect.bottomRight()) );
02349 
02350     // Another annoying case is if the top and bottom points are not in the same page....
02351     int topPage = pageManager->pageNumber( m_boundingRect.topLeft() );
02352     int bottomPage = pageManager->pageNumber( m_boundingRect.bottomRight() );
02353     //kdDebug() << "KWCanvas::mmEditFrameMove topPage=" << topPage << " bottomPage=" << bottomPage << endl;
02354     if ( topPage != bottomPage ) {
02355         // Choose the closest page...
02356         Q_ASSERT( bottomPage == -1 || topPage + 1 == bottomPage ); // Not too sure what to do otherwise
02357         double topPart = m_boundingRect.bottom() - pageManager->bottomOfPage(topPage);
02358         if ( topPart < m_boundingRect.height() / 2 ) // Most of the rect is in the top page
02359             p.setY( pageManager->bottomOfPage(topPage) - m_boundingRect.height() - 1 );
02360         else // Most of the rect is in the bottom page
02361             p.setY( pageManager->topOfPage(bottomPage) );
02362         m_boundingRect.moveTopLeft( p );
02363         m_boundingRect.moveBottomRight( pageManager->clipToDocument(m_boundingRect.bottomRight()) );
02364     }
02365 
02366     if( m_boundingRect.topLeft() == oldBoundingRect.topLeft() )
02367         return; // nothing happened (probably due to the grid)
02368 
02369     /*kdDebug() << "boundingRect moved by " << m_boundingRect.left() - oldBoundingRect.left() << ","
02370       << m_boundingRect.top() - oldBoundingRect.top() << endl;
02371       kdDebug() << " boundingX+hotspotX=" << m_boundingRect.left() + m_hotSpot.x() << endl;
02372       kdDebug() << " point.x()=" << point.x() << endl; */
02373 
02374     QPtrList<KWTableFrameSet> tablesMoved;
02375     tablesMoved.setAutoDelete( FALSE );
02376     QRegion repaintRegion;
02377     KoPoint _move=m_boundingRect.topLeft() - oldBoundingRect.topLeft();
02378 
02379     QValueListIterator<KWFrame*> framesIterator = m_frames.begin();
02380     for(; framesIterator != m_frames.end(); ++framesIterator) {
02381         KWFrame *frame = *framesIterator;
02382         KWFrameSet *fs = frame->frameSet();
02383 
02384         if ( fs->type() == FT_TABLE ) {
02385             if ( tablesMoved.findRef( static_cast<KWTableFrameSet *> (fs) ) == -1 )
02386                 tablesMoved.append( static_cast<KWTableFrameSet *> (fs));
02387         }
02388         else {
02389             QRect oldRect( m_parent->viewMode()->normalToView( frame->outerRect(m_parent->viewMode()) ) );
02390             // Move the frame
02391             frame->moveTopLeft( frame->topLeft() + _move );
02392             // Calculate new rectangle for this frame
02393             QRect newRect( frame->outerRect(m_parent->viewMode()) );
02394 
02395             QRect frameRect( m_parent->viewMode()->normalToView( newRect ) );
02396             // Repaint only the changed rects (oldRect U newRect)
02397             repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect();
02398         }
02399     }
02400 
02401     if ( !tablesMoved.isEmpty() ) {
02402         //kdDebug() << "KWCanvas::mmEditFrameMove TABLESMOVED" << endl;
02403         for ( unsigned int i = 0; i < tablesMoved.count(); i++ ) {
02404             KWTableFrameSet *table = tablesMoved.at( i );
02405             for ( KWTableFrameSet::TableIter k(table) ; k ; ++k ) {
02406                 KWFrame * frame = k->frame( 0 );
02407                 QRect oldRect( m_parent->viewMode()->normalToView( frame->outerRect(m_parent->viewMode()) ) );
02408                 frame->moveTopLeft( frame->topLeft() + _move );
02409                 // Calculate new rectangle for this frame
02410                 QRect newRect( frame->outerRect(m_parent->viewMode()) );
02411                 QRect frameRect( m_parent->viewMode()->normalToView( newRect ) );
02412                 // Repaing only the changed rects (oldRect U newRect)
02413                 repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect();
02414             }
02415         }
02416     }
02417 
02418     if ( !m_parent->kWordDocument()->showGrid() && m_parent->kWordDocument()->snapToGrid() )
02419       m_parent->repaintContents( false ); //draw the grid over the whole canvas
02420     else
02421       m_parent->repaintContents( repaintRegion.boundingRect(), false );
02422     m_parent->gui()->getView()->updateFrameStatusBarItem();
02423 }
02424 
02425 KCommand *FrameMovePolicy::createCommand() {
02426     for(unsigned int i=0; i < m_frames.count(); i++) {
02427         KWFrame *frame = m_frames[i];
02428         FrameMoveStruct fms = m_frameMove[i];
02429         fms.newPos = frame->topLeft();
02430         m_frameMove[i] = fms;
02431     }
02432     return new KWFrameMoveCommand( i18n("Move Frame"), m_indexFrame, m_frameMove );
02433 }
02434 
02435 void FrameMovePolicy::finishInteraction() {
02436     KWFrameViewManager *frameViewManager = m_parent->frameViewManager();
02437     for(unsigned int i=0; i < m_frames.count(); i++) {
02438         KWFrame *frame = m_frames[i];
02439         frameViewManager->slotFrameMoved(frame, m_frameMove[i].oldPos.y());
02440     }
02441 }
02442 
02443 
02444 // ************** FrameSelectPolicy ***********************
02445 FrameSelectPolicy::FrameSelectPolicy(KWCanvas *parent, MouseMeaning meaning, KoPoint &point, Qt::ButtonState buttonState, Qt::ButtonState keyState)
02446     : InteractionPolicy(parent, false) {
02447 
02448     bool leftButton = buttonState & Qt::LeftButton;
02449     // this is a special case; if a frame that is curently being edited is 'selected' on the border
02450     // we redirect that click to the text part of the frame.
02451     // this means we give the user a lot more space to click on the left side of the frame to
02452     // select the first characters.
02453     KWFrameSetEdit *fse = parent->currentFrameSetEdit();
02454     if(leftButton && fse) {
02455         KWFrameView *view = m_parent->frameViewManager()->view(point,
02456                 KWFrameViewManager::unselected, true);
02457         if(view && view->frame()->frameSet() == fse->frameSet()) {
02458             // make sure 'point' is inside the frame
02459             point.setX(QMAX(point.x(), view->frame()->left()));
02460             point.setY(QMAX(point.y(), view->frame()->top()));
02461             point.setX(QMIN(point.x(), view->frame()->right()));
02462             point.setY(QMIN(point.y(), view->frame()->bottom()));
02463 
02464             // convert point to the view coordinate system.
02465             QPoint normalPoint = parent->kWordDocument()->zoomPoint(point);
02466             QPoint mousePos = parent->viewMode()->normalToView(normalPoint);
02467             QMouseEvent *me = new QMouseEvent(QEvent::MouseButtonPress, mousePos,
02468                     buttonState, keyState);
02469             fse->mousePressEvent(me, normalPoint, point );
02470             delete me;
02471 
02472             m_validSelection = false;
02473             return;
02474         }
02475     }
02476 
02477     m_validSelection = meaning != MEANING_NONE;
02478     m_parent->frameViewManager()->selectFrames(point, keyState, leftButton );
02479 }
02480 
02481 void FrameSelectPolicy::handleMouseMove(Qt::ButtonState keyState, const KoPoint &point) {
02482     Q_UNUSED(keyState);
02483     Q_UNUSED(point);
02484 }
02485 
02486 KCommand *FrameSelectPolicy::createCommand() {
02487     return 0;
02488 }
02489 
02490 void FrameSelectPolicy::finishInteraction() {
02491 }
02492 
02493 #include "KWCanvas.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys