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 );
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->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         m_frameViewManager->view(frameIt.current())->setSelected(false);
01384 }
01385 
01386 KWTextFrameSetEdit* KWCanvas::currentTextEdit() const
01387 {
01388     if ( m_currentFrameSetEdit )
01389         return dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit->currentTextEdit());
01390     return 0;
01391 }
01392 
01393 void KWCanvas::setMouseMode( MouseMode newMouseMode )
01394 {
01395     if ( m_mouseMode != newMouseMode )
01396     {
01397         selectAllFrames( false );
01398 
01399         if ( newMouseMode != MM_EDIT )
01400             terminateCurrentEdit();
01401 
01402         m_mouseMode = newMouseMode;
01403         if ( !m_doc->showGrid() && m_doc->snapToGrid() )
01404           repaintContents( FALSE ); //draw the grid over the whole canvas
01405     }
01406     else
01407         m_mouseMode = newMouseMode;
01408     emit currentMouseModeChanged(m_mouseMode);
01409 
01410     switch ( m_mouseMode ) {
01411     case MM_EDIT: {
01412         QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01413         QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01414         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01415         viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, 0 ) );
01416         m_frameInline = false;
01417     } break;
01418     case MM_CREATE_TEXT:
01419     case MM_CREATE_PIX:
01420     case MM_CREATE_TABLE:
01421     case MM_CREATE_FORMULA:
01422     case MM_CREATE_PART:
01423         viewport()->setCursor( crossCursor );
01424         break;
01425     }
01426 }
01427 
01428 void KWCanvas::insertPicture( const KoPicture& newPicture, QSize pixmapSize, bool _keepRatio )
01429 {
01430     setMouseMode( MM_CREATE_PIX );
01431     m_kopicture = newPicture;
01432     m_pixmapSize = pixmapSize;
01433     if ( pixmapSize.isEmpty() )
01434         m_pixmapSize = newPicture.getOriginalSize();
01435     m_keepRatio = _keepRatio;
01436 }
01437 
01438 void KWCanvas::insertPictureDirect( const KoPicture& picture, const KoPoint& pos, const QSize& sz )
01439 {
01440     // Prepare things for mrCreatePixmap
01441     m_pixmapSize = sz.isEmpty() ? picture.getOriginalSize() : sz;
01442     m_kopicture = picture;
01443     m_insRect = KoRect( pos.x(), pos.y(), m_doc->unzoomItX( m_pixmapSize.width() ), m_doc->unzoomItY( m_pixmapSize.height() ) );
01444     m_keepRatio = true;
01445     mrCreatePixmap();
01446 }
01447 
01448 void KWCanvas::insertPart( const KoDocumentEntry &entry )
01449 {
01450     m_partEntry = entry;
01451     if ( m_partEntry.isEmpty() )
01452     {
01453         setMouseMode( MM_EDIT );
01454         return;
01455     }
01456     setMouseMode( MM_CREATE_PART );
01457 }
01458 
01459 void KWCanvas::contentsDragEnterEvent( QDragEnterEvent *e )
01460 {
01461     int provides = KWView::checkClipboard( e );
01462     if ( ( provides & KWView::ProvidesImage ) || KURLDrag::canDecode( e ) )
01463     {
01464         m_imageDrag = true;
01465         e->acceptAction();
01466     }
01467     else
01468     {
01469         m_imageDrag = false;
01470         if ( m_currentFrameSetEdit )
01471             m_currentFrameSetEdit->dragEnterEvent( e );
01472     }
01473 }
01474 
01475 void KWCanvas::contentsDragMoveEvent( QDragMoveEvent *e )
01476 {
01477     if ( !m_imageDrag /*&& m_currentFrameSetEdit*/ )
01478     {
01479         QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
01480         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01481         KWFrameView *view = m_frameViewManager->view(docPoint, KWFrameViewManager::frameOnTop);
01482         KWFrame *frame = view ? view->frame() : 0;
01483         KWFrameSet * fs = frame ? frame->frameSet() : 0L;
01484         bool emitChanged = false;
01485         if ( fs )
01486         {
01487             //kdDebug()<<"table :"<<table<<endl;
01488             emitChanged = checkCurrentEdit( fs, true );
01489         }
01490         if ( m_currentFrameSetEdit )
01491         {
01492             m_currentFrameSetEdit->dragMoveEvent( e, normalPoint, docPoint );
01493 
01494             if ( emitChanged ) // emitted after mousePressEvent [for tables]
01495                 emit currentFrameSetEditChanged();
01496         }
01497     }
01498 }
01499 
01500 void KWCanvas::contentsDragLeaveEvent( QDragLeaveEvent *e )
01501 {
01502     if ( !m_imageDrag && m_currentFrameSetEdit )
01503         m_currentFrameSetEdit->dragLeaveEvent( e );
01504 }
01505 
01506 void KWCanvas::contentsDropEvent( QDropEvent *e )
01507 {
01508     QPoint normalPoint = m_viewMode->viewToNormal( e->pos() );
01509     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01510 
01511     if ( QImageDrag::canDecode( e ) ) {
01512         pasteImage( e, docPoint );
01513     } else if ( KURLDrag::canDecode( e ) ) {
01514 
01515         // TODO ask (with a popupmenu) between inserting a link and inserting the contents
01516 
01517         KURL::List lst;
01518         KURLDrag::decode( e, lst );
01519 
01520         KURL::List::ConstIterator it = lst.begin();
01521         for ( ; it != lst.end(); ++it ) {
01522             const KURL &url( *it );
01523 
01524             QString filename;
01525             if ( !KIO::NetAccess::download( url, filename, this ) )
01526                 continue;
01527 
01528             KMimeType::Ptr res = KMimeType::findByFileContent( filename );
01529 
01530             if ( res && res->isValid() ) {
01531                 QString mimetype = res->name();
01532                 if ( mimetype.contains( "image" ) ) {
01533                     KoPictureKey key;
01534                     key.setKeyFromFile( filename );
01535                     KoPicture newKoPicture;
01536                     newKoPicture.setKey( key );
01537                     newKoPicture.loadFromFile( filename );
01538                     insertPictureDirect( newKoPicture, docPoint );
01539                 }
01540             }
01541             KIO::NetAccess::removeTempFile( filename );
01542         }
01543     }
01544     else
01545     {
01546         if ( m_currentFrameSetEdit )
01547             m_currentFrameSetEdit->dropEvent( e, normalPoint, docPoint, m_gui->getView() );
01548         else
01549             m_gui->getView()->pasteData( e, true );
01550     }
01551     m_mousePressed = false;
01552     m_imageDrag = false;
01553 }
01554 
01555 void KWCanvas::pasteImage( QMimeSource *e, const KoPoint &docPoint )
01556 {
01557     QImage i;
01558     QImageDrag::decode(e, i);
01559     KTempFile tmpFile( QString::null, ".png");
01560     tmpFile.setAutoDelete( true );
01561     i.save(tmpFile.name(), "PNG");
01562     m_pixmapSize = i.size();
01563     // Prepare things for mrCreatePixmap
01564     KoPictureKey key;
01565     key.setKeyFromFile( tmpFile.name() );
01566     KoPicture newKoPicture;
01567     newKoPicture.setKey( key );
01568     newKoPicture.loadFromFile( tmpFile.name() );
01569     m_kopicture = newKoPicture;
01570     m_insRect = KoRect( docPoint.x(), docPoint.y(), m_doc->unzoomItX( i.width() ), m_doc->unzoomItY( i.height() ) );
01571     m_keepRatio = true;
01572     mrCreatePixmap();
01573 }
01574 
01575 void KWCanvas::doAutoScroll()
01576 {
01577     if ( !m_mousePressed )
01578     {
01579         m_scrollTimer->stop();
01580         return;
01581     }
01582 
01583     // This code comes from khtml
01584     QPoint pos( mapFromGlobal( QCursor::pos() ) );
01585 
01586     pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y());
01587     if ( (pos.y() < 0) || (pos.y() > visibleHeight()) ||
01588          (pos.x() < 0) || (pos.x() > visibleWidth()) )
01589     {
01590         int xm, ym;
01591         viewportToContents(pos.x(), pos.y(), xm, ym);
01592         if ( m_currentFrameSetEdit )
01593             m_currentFrameSetEdit->focusOutEvent(); // Hide cursor
01594         if ( m_deleteMovingRect )
01595             deleteMovingRect();
01596         ensureVisible( xm, ym, 0, 5 );
01597         if ( m_currentFrameSetEdit )
01598             m_currentFrameSetEdit->focusInEvent(); // Show cursor
01599     }
01600 }
01601 
01602 void KWCanvas::slotContentsMoving( int cx, int cy )
01603 {
01604     //QPoint nPointTop = m_viewMode->viewToNormal( QPoint( cx, cy ) );
01605     QPoint nPointBottom = m_viewMode->viewToNormal( QPoint( cx + visibleWidth(), cy + visibleHeight() ) );
01606     //kdDebug() << "KWCanvas::slotContentsMoving cx=" << cx << " cy=" << cy << endl;
01607     //kdDebug() << " visibleWidth()=" << visibleWidth() << " visibleHeight()=" << visibleHeight() << endl;
01608     // Update our "formatted paragraphs needs" in all the text framesets
01609     QPtrList<KWTextFrameSet> textFrameSets = m_doc->allTextFramesets( false );
01610     QPtrListIterator<KWTextFrameSet> fit( textFrameSets );
01611     for ( ; fit.current() ; ++fit )
01612     {
01613         if(! fit.current()->isVisible()) continue;
01614         fit.current()->updateViewArea( this, m_viewMode, nPointBottom );
01615     }
01616     // cx and cy contain the future values for contentsx and contentsy, so we need to
01617     // pass them to updateRulerOffsets.
01618     updateRulerOffsets( cx, cy );
01619 
01620     // Tell KoView that the view transformations have changed (e.g. the centering of the page, or the scrolling offsets)
01621     // so that it will reposition any active embedded object.
01622     // This needs to be delayed since contents moving is emitted -before- moving,
01623     // and from resizeEvent it's too early too.
01624     QTimer::singleShot( 0, this, SIGNAL( viewTransformationsChanged() ) );
01625 }
01626 
01627 void KWCanvas::slotMainTextHeightChanged()
01628 {
01629     // Check that the viewmode is a KWViewModeText, and that the rulers have been built already
01630     if ( dynamic_cast<KWViewModeText *>(m_viewMode) && m_gui->getHorzRuler() )
01631     {
01632         slotNewContentsSize();
01633         m_viewMode->setPageLayout( m_gui->getHorzRuler(), m_gui->getVertRuler(), KoPageLayout() /*unused*/ );
01634         emit updateRuler();
01635     }
01636 }
01637 
01638 void KWCanvas::slotNewContentsSize()
01639 {
01640     QSize size = m_viewMode->contentsSize();
01641     if ( size != QSize( contentsWidth(), contentsHeight() ) )
01642     {
01643         //kdDebug() << "KWCanvas::slotNewContentsSize " << size.width() << "x" << size.height() << endl;
01644         resizeContents( size.width(), size.height() );
01645     }
01646 }
01647 
01648 void KWCanvas::resizeEvent( QResizeEvent *e )
01649 {
01650     slotContentsMoving( contentsX(), contentsY() );
01651     QScrollView::resizeEvent( e );
01652 }
01653 
01654 void KWCanvas::scrollToOffset( const KoPoint & d )
01655 {
01656     kdDebug() << "KWCanvas::scrollToOffset " << d.x() << "," << d.y() << endl;
01657 #if 0
01658     bool blinking = blinkTimer.isActive();
01659     if ( blinking )
01660         stopBlinkCursor();
01661 #endif
01662     QPoint nPoint = m_doc->zoomPoint( d );
01663     QPoint cPoint = m_viewMode->normalToView( nPoint );
01664     setContentsPos( cPoint.x(), cPoint.y() );
01665 
01666 #if 0
01667     if ( blinking )
01668         startBlinkCursor();
01669 #endif
01670 }
01671 
01672 void KWCanvas::updateRulerOffsets( int cx, int cy )
01673 {
01674     if ( cx == -1 && cy == -1 )
01675     {
01676         cx = contentsX();
01677         cy = contentsY();
01678     }
01679     // The offset is usually just the scrollview offset
01680     // But we also need to offset to the current page, for the graduations
01681     QPoint pc = m_viewMode->pageCorner();
01682     //kdDebug() << "KWCanvas::updateRulerOffsets contentsX=" << cx << ", contentsY=" << cy << endl;
01683     m_gui->getHorzRuler()->setOffset( cx - pc.x(), 0 );
01684     m_gui->getVertRuler()->setOffset( 0, cy - pc.y() );
01685 
01686 }
01687 
01688 bool KWCanvas::eventFilter( QObject *o, QEvent *e )
01689 {
01690     if ( o == this || o == viewport() ) {
01691 
01692         if(m_currentFrameSetEdit && o == this )
01693         {
01694             // Pass event to auto-hide-cursor code (see kcursor.h for details)
01695             KCursor::autoHideEventFilter( o, e );
01696         }
01697 
01698         switch ( e->type() ) {
01699             case QEvent::FocusIn:
01700                 //  kdDebug() << "KWCanvas::eventFilter QEvent::FocusIn" << endl;
01701                 if ( m_currentFrameSetEdit && !m_printing )
01702                     m_currentFrameSetEdit->focusInEvent();
01703                 break;
01704             case QEvent::FocusOut:
01705                 //  kdDebug() << "KWCanvas::eventFilter QEvent::FocusOut" << endl;
01706                 if ( m_currentFrameSetEdit && !m_printing )
01707                     m_currentFrameSetEdit->focusOutEvent();
01708                 if ( m_scrollTimer->isActive() )
01709                     m_scrollTimer->stop();
01710                 m_mousePressed = false;
01711                 break;
01712             case QEvent::AccelOverride: // was part of KeyPress - changed due to kdelibs BUG!
01713             {
01714                 //  kdDebug() << " KeyPress m_currentFrameSetEdit=" << m_currentFrameSetEdit << " isRW="<<m_doc->isReadWrite() << endl;
01715                 //  kdDebug() << " m_printing=" << m_printing << " mousemode=" << m_mouseMode << " (MM_EDIT=" << MM_EDIT<<")"<<endl;
01716                 QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
01717 #ifndef NDEBUG
01718                 // Debug keys
01719                 if ( ( keyev->state() & ControlButton ) && ( keyev->state() & ShiftButton ) )
01720                 {
01721                     switch ( keyev->key() ) {
01722                         case Qt::Key_P: // 'P' -> paragraph debug
01723                             printRTDebug( 0 );
01724                             keyev->accept();
01725                             break;
01726                         case Qt::Key_V: // 'V' -> verbose parag debug
01727                             printRTDebug( 1 );
01728                             keyev->accept();
01729                             break;
01730                         case Qt::Key_F: // 'F' -> frames debug
01731                             m_doc->printDebug();
01732                             kdDebug(32002) << "Current framesetedit: " << m_currentFrameSetEdit << " " <<
01733                                 ( m_currentFrameSetEdit ? m_currentFrameSetEdit->frameSet()->className() : "" ) << endl;
01734                             keyev->accept();
01735                             break;
01736                         case Qt::Key_S: // 'S' -> styles debug
01737                             m_doc->printStyleDebug();
01738                             keyev->accept();
01739                             break;
01740                         case Qt::Key_M: // 'M' -> mark debug output
01741                             {
01742                                 const QDateTime dtMark ( QDateTime::currentDateTime() );
01743                                 kdDebug(32002) << "Developer mark: " << dtMark.toString("yyyy-MM-dd hh:mm:ss,zzz") << endl;
01744                                 keyev->accept();
01745                                 break;
01746                             }
01747                         default:
01748                             break;
01749                     };
01750                     // For some reason 'T' doesn't work (maybe kxkb)
01751                 }
01752 #endif
01753             }
01754                 break;
01755             case QEvent::KeyPress:
01756             {
01757                 //  kdDebug() << " KeyPress m_currentFrameSetEdit=" << m_currentFrameSetEdit << " isRW="<<m_doc->isReadWrite() << endl;
01758                 //  kdDebug() << " m_printing=" << m_printing << " mousemode=" << m_mouseMode << " (MM_EDIT=" << MM_EDIT<<")"<<endl;
01759                 QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
01760                 // By default PgUp and PgDown move the scrollbars and not the caret anymore - this is done here
01761                 if ( !m_doc->pgUpDownMovesCaret() && ( (keyev->state() & ShiftButton) == 0 )
01762                      && ( keyev->key() == Qt::Key_PageUp || keyev->key() == Key_PageDown ) )
01763                 {
01764                     viewportScroll( keyev->key() == Qt::Key_PageUp );
01765                 }
01766                 // Activate this code (and in focusNextPreviousChild() to allow Shift+Tab
01767                 // out of document window.  Disabled because it conflicts with Shift+Tab inside a table.
01768                 // else if ( keyev->key() == Qt::Key_BackTab )
01769                 //    return FALSE;
01770                 else if ( keyev->key() == KGlobalSettings::contextMenuKey() ) {
01771                     // The popups are not available in readonly mode, since the GUI isn't built...
01772                     if(!m_doc->isReadWrite()) return TRUE;
01773                     if (m_mouseMode != MM_EDIT) return TRUE;
01774                     KoPoint docPoint = m_doc->unzoomPoint( QCursor::pos() );
01775 
01776                     if ( viewMode()->type()=="ModeText") {
01777                         KWFrameView *view = m_frameViewManager->view(m_doc->frameSet( 0 )->frame(0));
01778                         view->showPopup(docPoint, m_gui->getView(), QCursor::pos());
01779                     }
01780                     else {
01781                         m_frameViewManager->showPopup( docPoint, m_gui->getView(), keyev->state(), pos());
01782                     }
01783                     return true;
01784                 }
01785                 else if ( keyev->key() == Qt::Key_Return && keyev->state() == 0
01786                     && (m_mouseMode != MM_EDIT || m_frameInline )) {
01787                     // When inserting an inline or non-line frame,
01788                     // simulate mouse press and release at caret position.
01789                     // In the case of a regular frame, the caret position was saved when
01790                     // they left edit mode.  In the case of an inline frame,
01791                     // get current caret position, since user can type and move caret
01792                     // around before they click or hit Enter.
01793                     if (m_frameInline)
01794                         m_lastCaretPos = caretPos();
01795                     if (m_lastCaretPos.isNull()) return TRUE;
01796                     int page = m_doc->pageManager()->pageNumber(m_lastCaretPos);
01797                     if(page == -1) return TRUE;
01798                     QPoint normalPoint = m_doc->zoomPoint(m_lastCaretPos);
01799                     // Coordinate is at the very top of the caret.  In the case of an
01800                     // inline frame, adjust slightly down and to the right in order
01801                     // to avoid "clicking" the frame border.
01802                     if (m_frameInline)
01803                         normalPoint += QPoint(2,2);
01804                     QPoint vP = m_viewMode->normalToView(normalPoint);
01805                     QPoint gP = mapToGlobal(vP);
01806                     QMouseEvent mevPress(QEvent::MouseButtonPress, vP,
01807                         gP, Qt::LeftButton, 0);
01808                     contentsMousePressEvent(&mevPress);
01809                     QMouseEvent mevRelease(QEvent::MouseButtonRelease, vP,
01810                         gP, Qt::LeftButton, 0);
01811                     contentsMouseReleaseEvent(&mevRelease);
01812                 }
01813                 else if ( keyev->key() == Qt::Key_Escape  ) {
01814                     if ( m_mouseMode != MM_EDIT ) // Abort frame creation
01815                         setMouseMode( MM_EDIT );
01816                     else if(m_interactionPolicy) {
01817                         m_interactionPolicy->cancelInteraction();
01818                         delete(m_interactionPolicy);
01819                         m_interactionPolicy = 0;
01820                         m_mousePressed = false;
01821 
01822                         // reset cursor
01823                         QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01824                         QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01825                         KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01826                         viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, keyev->stateAfter() ) );
01827                         if ( !m_doc->showGrid() && m_doc->snapToGrid() )
01828                             repaintContents();
01829                     }
01830                 }
01831                 else if ( keyev->key() == Key_Insert && keyev->state() == 0 ) {
01832                     m_overwriteMode = !m_overwriteMode;
01833                     KWTextFrameSetEdit *edit = currentTextEdit();
01834                     if ( edit ) {
01835                         edit->setOverwriteMode( m_overwriteMode );
01836                         emit overwriteModeChanged( m_overwriteMode );
01837                     }
01838                     kdDebug()<<"Insert is pressed, overwrite mode: "<< m_overwriteMode << endl;
01839                 }
01840                 else // normal key processing
01841                     if ( m_currentFrameSetEdit && m_mouseMode == MM_EDIT && m_doc->isReadWrite() && !m_printing )
01842                 {
01843                     KWTextFrameSetEdit *edit = dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit );
01844                     if ( edit )
01845                     {
01846                         if ( !edit->textFrameSet()->textObject()->protectContent() || (keyev->text().length() == 0))
01847                             m_currentFrameSetEdit->keyPressEvent( keyev );
01848                         else if(keyev->text().length() > 0)
01849                             KMessageBox::information(this, i18n("Read-only content cannot be changed. No modifications will be accepted."));
01850                     }
01851                     else
01852                         m_currentFrameSetEdit->keyPressEvent( keyev );
01853                     return TRUE;
01854                 }
01855 
01856                 // Because of the dependency on the control key, we need to update the mouse cursor here
01857                 if ( keyev->key() == Qt::Key_Control )
01858                 {
01859                     QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01860                     QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01861                     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01862                     viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, keyev->stateAfter() ) );
01863                 }
01864                 else if ( (keyev->key() == Qt::Key_Delete || keyev->key() ==Key_Backspace )
01865                           && m_frameViewManager->selectedFrame() && !m_printing )
01866                     m_gui->getView()->editDeleteFrame();
01867             } break;
01868             case QEvent::KeyRelease:
01869             {
01870                 QKeyEvent * keyev = static_cast<QKeyEvent *>(e);
01871                 if ( keyev->key() == Qt::Key_Control )
01872                 {
01873                     QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() );
01874                     QPoint normalPoint = m_viewMode->viewToNormal( mousep );
01875                     KoPoint docPoint = m_doc->unzoomPoint( normalPoint );
01876                     viewport()->setCursor( m_frameViewManager->mouseCursor( docPoint, keyev->stateAfter() ) );
01877                 }
01878 
01879                 if ( m_currentFrameSetEdit && m_mouseMode == MM_EDIT && m_doc->isReadWrite() && !m_printing )
01880                 {
01881                     m_currentFrameSetEdit->keyReleaseEvent( keyev );
01882                     return TRUE;
01883                 }
01884             }
01885                 break;
01886             case QEvent::IMStart:
01887             {
01888                 QIMEvent * imev = static_cast<QIMEvent *>(e);
01889                 m_currentFrameSetEdit->imStartEvent( imev );
01890             }
01891                 break;
01892             case QEvent::IMCompose:
01893             {
01894                 QIMEvent * imev = static_cast<QIMEvent *>(e);
01895                 m_currentFrameSetEdit->imComposeEvent( imev );
01896             }
01897                 break;
01898             case QEvent::IMEnd:
01899             {
01900                 QIMEvent * imev = static_cast<QIMEvent *>(e);
01901                 m_currentFrameSetEdit->imEndEvent( imev );
01902             }
01903                 break;
01904             default:
01905                 break;
01906         }
01907     }
01908     return QScrollView::eventFilter( o, e );
01909 }
01910 
01911 bool KWCanvas::focusNextPrevChild( bool next)
01912 {
01913     Q_UNUSED(next);
01914     return TRUE; // Don't allow to go out of the canvas widget by pressing "Tab"
01915     // Don't allow to go out of the canvas widget by pressing Tab, but do allow Shift+Tab.
01916     // if (next) return TRUE;
01917     // return QWidget::focusNextPrevChild( next );
01918 }
01919 
01920 void KWCanvas::updateCurrentFormat()
01921 {
01922     KWTextFrameSetEdit * edit = dynamic_cast<KWTextFrameSetEdit *>(m_currentFrameSetEdit);
01923     if ( edit )
01924         edit->updateUI( true, true );
01925 }
01926 
01927 #ifndef NDEBUG
01928 void KWCanvas::printRTDebug( int info )
01929 {
01930     KWTextFrameSet * textfs = 0L;
01931     if ( m_currentFrameSetEdit ) {
01932         KWTextFrameSetEdit* edit = currentTextEdit();
01933         if ( edit ) {
01934             textfs = dynamic_cast<KWTextFrameSet *>( edit->frameSet() );
01935             Q_ASSERT( textfs );
01936         }
01937     }
01938     if ( !textfs )
01939         textfs = dynamic_cast<KWTextFrameSet *>(m_doc->frameSet( 0 ));
01940     if ( textfs )
01941         textfs->textObject()->printRTDebug( info );
01942 }
01943 #endif
01944 
01945 void KWCanvas::setXimPosition( int x, int y, int w, int h )
01946 {
01947     QWidget::setMicroFocusHint( x - contentsX(), y - contentsY(), w, h );
01948 }
01949 
01950 void KWCanvas::inlinePictureStarted()
01951 {
01952     m_frameInline=true;
01953     m_frameInlineType=FT_PICTURE;
01954 }
01955 
01956 int KWCanvas::currentTableRow() const
01957 {
01958     if ( !m_currentFrameSetEdit )
01959         return -1;
01960     KWTextFrameSetEdit *edit = currentTextEdit();
01961     if ( !edit )
01962         return -1;
01963     KWTextFrameSet* textfs = edit->textFrameSet();
01964     if ( textfs && textfs->groupmanager() )
01965         return static_cast<KWTableFrameSet::Cell *>(textfs)->firstRow();
01966     return -1;
01967 }
01968 
01969 int KWCanvas::currentTableCol() const
01970 {
01971     if ( !m_currentFrameSetEdit )
01972         return -1;
01973     KWTextFrameSetEdit *edit = currentTextEdit();
01974     if ( !edit )
01975         return -1;
01976     KWTextFrameSet* textfs = edit->textFrameSet();
01977     if ( textfs && textfs->groupmanager() )
01978         return static_cast<KWTableFrameSet::Cell *>(textfs)->firstColumn();
01979     return -1;
01980 }
01981 
01982 void KWCanvas::viewportScroll( bool up )
01983 {
01984     if ( up )
01985         setContentsPos( contentsX(), contentsY() - visibleHeight() );
01986     else
01987         setContentsPos( contentsX(), contentsY() + visibleHeight() );
01988 }
01989 
01990 void KWCanvas::resetStatusBarText()
01991 {
01992     if ( m_temporaryStatusBarTextShown )
01993     {
01994         gui()->getView()->updateFrameStatusBarItem();
01995         m_temporaryStatusBarTextShown = false;
01996     }
01997 }
01998 
01999 
02000 /* Returns the caret position in document coordinates.
02001    The current frame must be editable, i.e., a caret is possible. */
02002 KoPoint KWCanvas::caretPos()
02003 {
02004     if (!m_currentFrameSetEdit) return KoPoint();
02005     KWTextFrameSetEdit* textEdit = currentTextEdit();
02006     if (!textEdit) return KoPoint();
02007     KoTextCursor* cursor = textEdit->cursor();
02008     if (!cursor) return KoPoint();
02009     KWTextFrameSet* textFrameset =
02010         dynamic_cast<KWTextFrameSet *>(m_currentFrameSetEdit->frameSet());
02011     if (!textFrameset) return KoPoint();
02012     KWFrame* currentFrame = m_currentFrameSetEdit->currentFrame();
02013     if (!currentFrame) return KoPoint();
02014 
02015     QPoint viewP = textFrameset->cursorPos(cursor, this, currentFrame);
02016     viewP.rx() += contentsX();
02017     viewP.ry() += contentsY();
02018     QPoint normalP = m_viewMode->viewToNormal(viewP);
02019     KoPoint docP = m_doc->unzoomPoint(normalP);
02020     return docP;
02021 }
02022 
02023 
02024 // ************** InteractionPolicy ***********************
02025 InteractionPolicy::InteractionPolicy(KWCanvas *parent, bool doInit, bool includeInlineFrames) {
02026     m_gotDragEvents = false;
02027     m_parent = parent;
02028     if(doInit) {
02029         QValueList<KWFrameView*> selectedFrames = m_parent->frameViewManager()->selectedFrames();
02030         QValueListIterator<KWFrameView*> framesIterator = selectedFrames.begin();
02031         for(;framesIterator != selectedFrames.end(); ++framesIterator) {
02032             KWFrame *frame = (*framesIterator)->frame();
02033             KWFrameSet *fs = frame->frameSet();
02034             if(! fs) continue;
02035             if(!fs->isVisible()) continue;
02036             if(fs->isMainFrameset() ) continue;
02037             if(fs->isFloating() && !includeInlineFrames) continue;
02038             if(fs->isProtectSize() ) continue;
02039             if(fs->type() == FT_TABLE ) continue;
02040             if(fs->type() == FT_TEXT && fs->frameSetInfo() != KWFrameSet::FI_BODY ) continue;
02041             m_frames.append( frame );
02042             m_indexFrame.append( FrameIndex( frame ) );
02043         }
02044     }
02045 }
02046 
02047 InteractionPolicy* InteractionPolicy::createPolicy(KWCanvas *parent, MouseMeaning meaning, KoPoint &point, Qt::ButtonState buttonState, Qt::ButtonState keyState) {
02048     if(buttonState & Qt::LeftButton || buttonState & Qt::RightButton) {
02049         // little inner class to make sure we don't duplicate code
02050         class Selector {
02051           public:
02052             Selector(KWCanvas *canvas, KoPoint &point, Qt::ButtonState buttonState, Qt::ButtonState keyState) :
02053                 m_canvas(canvas), m_point(point), m_state(keyState) {
02054                 m_leftClick = buttonState & Qt::LeftButton;
02055                 KWFrameView *view = canvas->frameViewManager()->view(point,
02056                         KWFrameViewManager::frameOnTop);
02057                 m_doSomething = (view && !view->selected());
02058             }
02059 
02060             void doSelect() {
02061                 if(! m_doSomething) return;
02062                 m_canvas->frameViewManager()->selectFrames(m_point, m_state, m_leftClick);
02063             }
02064           private:
02065             KWCanvas *m_canvas;
02066             KoPoint m_point;
02067             Qt::ButtonState m_state;
02068             bool m_leftClick, m_doSomething;
02069         };
02070 
02071         Selector selector(parent, point, buttonState, keyState);
02072         switch(meaning) {
02073             case MEANING_MOUSE_MOVE:
02074                 selector.doSelect();
02075                 return new FrameMovePolicy(parent, point);
02076             case MEANING_TOPLEFT:
02077             case MEANING_TOP:
02078             case MEANING_TOPRIGHT:
02079             case MEANING_RIGHT:
02080             case MEANING_BOTTOMRIGHT:
02081             case MEANING_BOTTOM:
02082             case MEANING_BOTTOMLEFT:
02083             case MEANING_LEFT:
02084                 selector.doSelect();
02085                 return new FrameResizePolicy(parent, meaning, point);
02086             default:
02087                 FrameSelectPolicy *fsp = new FrameSelectPolicy(parent, meaning, point, buttonState, keyState);
02088                 if(fsp->isValid())
02089                     return fsp;
02090                 delete fsp;
02091         }
02092     }
02093     return 0; // no interaction policy found
02094 }
02095 
02096 void InteractionPolicy::cancelInteraction() {
02097     KCommand *cmd = createCommand();
02098     if(cmd) {
02099         cmd->unexecute();
02100         delete cmd;
02101     }
02102 }
02103 
02104 
02105 // ************** FrameResizePolicy ***********************
02106 FrameResizePolicy::FrameResizePolicy(KWCanvas *parent, MouseMeaning meaning, KoPoint &point) :
02107     InteractionPolicy (parent, true, true), m_boundingRect() {
02108 
02109     if( meaning == MEANING_TOPLEFT) {
02110         m_top = true; m_bottom = false; m_left = true; m_right = false;
02111     }
02112     else if( meaning == MEANING_TOP) {
02113         m_top = true; m_bottom = false; m_left = false; m_right = false;
02114     }
02115     else if( meaning == MEANING_TOPRIGHT) {
02116         m_top = true; m_bottom = false; m_left = false; m_right = true;
02117     }
02118     else if( meaning == MEANING_RIGHT) {
02119         m_top = false; m_bottom = false; m_left = false; m_right = true;
02120     }
02121     else if( meaning == MEANING_BOTTOMRIGHT) {
02122         m_top = false; m_bottom = true; m_left = false; m_right = true;
02123     }
02124     else if( meaning == MEANING_BOTTOM) {
02125         m_top = false; m_bottom = true; m_left = false; m_right = false;
02126     }
02127     else if( meaning == MEANING_BOTTOMLEFT) {
02128         m_top = false; m_bottom = true; m_left = true; m_right = false;
02129     }
02130     else if( meaning == MEANING_LEFT) {
02131         m_top = false; m_bottom = false; m_left = true; m_right = false;
02132     }
02133 
02134     QValueListConstIterator<KWFrame*> framesIterator = m_frames.begin();
02135     for(;framesIterator != m_frames.end(); ++framesIterator) {
02136         KWFrame *frame = *framesIterator;
02137         FrameResizeStruct frs(*frame, frame->minimumFrameHeight(), *frame);
02138         m_frameResize.append(frs);
02139         m_boundingRect |= frame->outerKoRect();
02140     }
02141     m_hotSpot = point - m_boundingRect.topLeft();
02142 }
02143 
02144 void FrameResizePolicy::handleMouseMove(Qt::ButtonState keyState, const KoPoint &point) {
02145     //kdDebug() << "handleMouseMove " << (m_top?"top ":"") << (m_bottom?"bottom ":"") << (m_left?"left ":"") << (m_right?"right":"") << endl;
02146     //kdDebug() << " + point: " << point
02147     //          << "  boundingrect: " << m_boundingRect << endl;
02148 
02149     bool keepAspect = keyState & Qt::AltButton;
02150     for(unsigned int i=0; !keepAspect && i < m_frames.count(); i++) {
02151         KWPictureFrameSet *picFs = dynamic_cast<KWPictureFrameSet*>(m_frames[i]->frameSet());
02152         if(picFs)
02153             keepAspect = picFs->keepAspectRatio();
02154     }
02155 
02156     bool noGrid = keyState & Qt::ShiftButton;
02157     bool scaleFromCenter = keyState & Qt::ControlButton;
02158 
02159     KoPoint p( point.x() - (m_hotSpot.x() + m_boundingRect.x()),
02160             point.y() - (m_hotSpot.y() + m_boundingRect.y()) );
02161 
02162     if ( m_parent->kWordDocument()->snapToGrid() && !noGrid )
02163         m_parent->applyGrid( p );
02164 
02165     KoRect sizeRect = m_boundingRect;
02166     if(m_top)
02167         sizeRect.setY(sizeRect.y() + p.y());
02168     if(m_bottom)
02169         sizeRect.setBottom(sizeRect.bottom() + p.y());
02170     if(m_left)
02171         sizeRect.setX(sizeRect.left() + p.x());
02172     if(m_right)
02173         sizeRect.setRight(sizeRect.right() + p.x());
02174     if(keepAspect) {
02175         double ratio = m_boundingRect.width() / m_boundingRect.height();
02176         double width = sizeRect.width();
02177         double height = sizeRect.height();
02178         int toLargestEdge = (m_bottom?1:0) + (m_top?1:0) + // should be false when only one
02179             (m_left?1:0) + (m_right?1:0);                  // of the direction bools is set
02180         bool horizontal = m_left || m_right;
02181 
02182         if(toLargestEdge != 1) { // one of the corners.
02183             if (width < height) // the biggest border is the one in control
02184                 width = height * ratio;
02185             else
02186                 height = width / ratio;
02187         } else {
02188             if (horizontal)
02189                 height = width / ratio;
02190             else
02191                 width = height * ratio;
02192         }
02193         if(m_bottom)
02194             sizeRect.setBottom(sizeRect.top() + height);
02195         else
02196             sizeRect.setTop(sizeRect.bottom() - height);
02197 
02198         if(m_left)
02199             sizeRect.setLeft(sizeRect.right() - width);
02200         else
02201             sizeRect.setRight(sizeRect.left() + width);
02202     }
02203     if(scaleFromCenter) {
02204         KoPoint origCenter(m_boundingRect.x() + m_boundingRect.width() / 2,
02205                 m_boundingRect.y() + m_boundingRect.height() / 2);
02206         KoPoint newCenter(sizeRect.x() + sizeRect.width() / 2,
02207                 sizeRect.y() + sizeRect.height() / 2);
02208         sizeRect.moveTopLeft(sizeRect.topLeft() + (origCenter - newCenter));
02209     }
02210     if(m_parent) {
02211         KWPageManager *pageManager = m_parent->kWordDocument()->pageManager();
02212         sizeRect.moveTopLeft(pageManager->clipToDocument(sizeRect.topLeft()));
02213         sizeRect.moveBottomRight(pageManager->clipToDocument(sizeRect.bottomRight()));
02214         sizeRect.setX( QMAX(0, sizeRect.x()) ); // otherwise it would get wider than the page
02215     }
02216 
02217     // each frame in m_frames should be reshaped from the original size stored in the
02218     // m_frameResize data to a size that equals the reshaping of m_boundingrect to sizeRect
02219     class Converter {
02220       public:
02221         Converter(KoRect &from, KoRect &to, KWViewMode *viewMode) {
02222             m_from = from.topLeft();
02223             m_to = to.topLeft();
02224             m_viewMode = viewMode;
02225             m_diffX = to.width() / from.width();
02226             m_diffY = to.height() / from.height();
02227             //kdDebug() << "Converter " << from << ", " << to << " x: " << m_diffX << ", y: " << m_diffY << endl;
02228         }
02229         void update(KWFrame *frame, KoRect &orig) {
02230             QRect oldRect( m_viewMode->normalToView( frame->outerRect(m_viewMode) ) );
02231             if(! frame->frameSet()->isFloating())
02232                 frame->moveTopLeft( convert( orig.topLeft() ) );
02233             KoPoint bottomRight( convert( orig.bottomRight() ) );
02234             frame->setBottom( bottomRight.y() );
02235             frame->setRight( bottomRight.x() );
02236 
02237             QRect newRect( frame->outerRect(m_viewMode) );
02238             QRect frameRect( m_viewMode->normalToView( newRect ) );
02239             // Repaint only the changed rects (oldRect U newRect)
02240             m_repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect();
02241         }
02242 
02243         QRegion repaintRegion() {
02244             return m_repaintRegion;
02245         }
02246 
02247       private:
02248         KoPoint convert(KoPoint point) {
02249             double offsetX = point.x() - m_from.x();
02250             double offsetY = point.y() - m_from.y();
02251             KoPoint answer(m_to.x() + offsetX * m_diffX, m_to.y() + offsetY * m_diffY);
02252             return answer;
02253         }
02254       private: // vars
02255         KoPoint m_from, m_to;
02256         KWViewMode *m_viewMode;
02257         QRegion m_repaintRegion;
02258         double m_diffX, m_diffY;
02259     };
02260 
02261     Converter converter(m_boundingRect, sizeRect, m_parent->viewMode());
02262     for(unsigned int i=0; i < m_frames.count(); i++)
02263         converter.update(m_frames[i], m_frameResize[i].oldRect);
02264 
02265     if ( !m_parent->kWordDocument()->showGrid() && m_parent->kWordDocument()->snapToGrid() )
02266       m_parent->repaintContents( false ); //draw the grid over the whole canvas
02267     else
02268       m_parent->repaintContents( converter.repaintRegion().boundingRect(), false );
02269     m_parent->gui()->getView()->updateFrameStatusBarItem();
02270 }
02271 
02272 KCommand *FrameResizePolicy::createCommand() {
02273     for(unsigned int i=0; i < m_frames.count(); i++) {
02274         KWFrame *frame = m_frames[i];
02275         FrameResizeStruct frs = m_frameResize[i];
02276         frs.newRect = frame->rect();
02277         frs.newMinHeight = frame->height();
02278         m_frameResize[i] = frs;
02279     }
02280     return new KWFrameResizeCommand(i18n("Resize Frame"), m_indexFrame, m_frameResize);
02281 }
02282 
02283 void FrameResizePolicy::finishInteraction() {
02284     KWFrameViewManager *frameViewManager = m_parent->frameViewManager();
02285     for(unsigned int i=0; i < m_frames.count(); i++) {
02286         KWFrame *frame = m_frames[i];
02287         frame->setMinimumFrameHeight(frame->height());
02288         frameViewManager->slotFrameResized(frame);
02289     }
02290 }
02291 
02292 
02293 // *************** FrameMovePolicy ************************
02294 FrameMovePolicy::FrameMovePolicy(KWCanvas *parent, KoPoint &point) :
02295     InteractionPolicy (parent), m_boundingRect() {
02296 
02297     QValueListConstIterator<KWFrame*> framesIterator = m_frames.begin();
02298     for(;framesIterator != m_frames.end(); ++framesIterator) {
02299         KWFrame *frame = *framesIterator;
02300         m_boundingRect |= frame->outerKoRect();
02301         FrameMoveStruct fms(frame->topLeft(), KoPoint(0,0));
02302         m_frameMove.append(fms);
02303     }
02304 
02305     m_hotSpot = point - m_boundingRect.topLeft();
02306     m_startPoint = m_boundingRect.topLeft();
02307 }
02308 
02309 void FrameMovePolicy::handleMouseMove(Qt::ButtonState keyState, const KoPoint &point) {
02310     bool noGrid = keyState & Qt::ShiftButton;
02311     bool linearMove = (keyState & Qt::AltButton) || (keyState & Qt::ControlButton);
02312 
02313     KWPageManager *pageManager = m_parent->kWordDocument()->pageManager();
02314 
02315     KoRect oldBoundingRect = m_boundingRect;
02316     //kdDebug() << "KWCanvas::mmEditFrameMove point: " << point
02317     //          << "  boundingrect: " << m_boundingRect << endl;
02318 
02319     KoPoint p( point.x() - m_hotSpot.x(), point.y() - m_hotSpot.y() );
02320     if(linearMove) {
02321         if(QABS(p.x() - m_startPoint.x()) < QABS(p.y() - m_startPoint.y()))
02322             p.setX(m_startPoint.x());
02323         else
02324             p.setY(m_startPoint.y());
02325     }
02326     if ( m_parent->kWordDocument()->snapToGrid() && !noGrid )
02327         m_parent->applyGrid( p );
02328 
02329     p = pageManager->clipToDocument(p);
02330     m_boundingRect.moveTopLeft( p );
02331     m_boundingRect.moveBottomRight( pageManager->clipToDocument(m_boundingRect.bottomRight()) );
02332 
02333     // Another annoying case is if the top and bottom points are not in the same page....
02334     int topPage = pageManager->pageNumber( m_boundingRect.topLeft() );
02335     int bottomPage = pageManager->pageNumber( m_boundingRect.bottomRight() );
02336     //kdDebug() << "KWCanvas::mmEditFrameMove topPage=" << topPage << " bottomPage=" << bottomPage << endl;
02337     if ( topPage != bottomPage ) {
02338         // Choose the closest page...
02339         Q_ASSERT( bottomPage == -1 || topPage + 1 == bottomPage ); // Not too sure what to do otherwise
02340         double topPart = m_boundingRect.bottom() - pageManager->bottomOfPage(topPage);
02341         if ( topPart < m_boundingRect.height() / 2 ) // Most of the rect is in the top page
02342             p.setY( pageManager->bottomOfPage(topPage) - m_boundingRect.height() - 1 );
02343         else // Most of the rect is in the bottom page
02344             p.setY( pageManager->topOfPage(bottomPage) );
02345         m_boundingRect.moveTopLeft( p );
02346         m_boundingRect.moveBottomRight( pageManager->clipToDocument(m_boundingRect.bottomRight()) );
02347     }
02348 
02349     if( m_boundingRect.topLeft() == oldBoundingRect.topLeft() )
02350         return; // nothing happened (probably due to the grid)
02351 
02352     /*kdDebug() << "boundingRect moved by " << m_boundingRect.left() - oldBoundingRect.left() << ","
02353       << m_boundingRect.top() - oldBoundingRect.top() << endl;
02354       kdDebug() << " boundingX+hotspotX=" << m_boundingRect.left() + m_hotSpot.x() << endl;
02355       kdDebug() << " point.x()=" << point.x() << endl; */
02356 
02357     QPtrList<KWTableFrameSet> tablesMoved;
02358     tablesMoved.setAutoDelete( FALSE );
02359     QRegion repaintRegion;
02360     KoPoint _move=m_boundingRect.topLeft() - oldBoundingRect.topLeft();
02361 
02362     QValueListIterator<KWFrame*> framesIterator = m_frames.begin();
02363     for(; framesIterator != m_frames.end(); ++framesIterator) {
02364         KWFrame *frame = *framesIterator;
02365         KWFrameSet *fs = frame->frameSet();
02366 
02367         if ( fs->type() == FT_TABLE ) {
02368             if ( tablesMoved.findRef( static_cast<KWTableFrameSet *> (fs) ) == -1 )
02369                 tablesMoved.append( static_cast<KWTableFrameSet *> (fs));
02370         }
02371         else {
02372             QRect oldRect( m_parent->viewMode()->normalToView( frame->outerRect(m_parent->viewMode()) ) );
02373             // Move the frame
02374             frame->moveTopLeft( frame->topLeft() + _move );
02375             // Calculate new rectangle for this frame
02376             QRect newRect( frame->outerRect(m_parent->viewMode()) );
02377 
02378             QRect frameRect( m_parent->viewMode()->normalToView( newRect ) );
02379             // Repaint only the changed rects (oldRect U newRect)
02380             repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect();
02381         }
02382     }
02383 
02384     if ( !tablesMoved.isEmpty() ) {
02385         //kdDebug() << "KWCanvas::mmEditFrameMove TABLESMOVED" << endl;
02386         for ( unsigned int i = 0; i < tablesMoved.count(); i++ ) {
02387             KWTableFrameSet *table = tablesMoved.at( i );
02388             for ( KWTableFrameSet::TableIter k(table) ; k ; ++k ) {
02389                 KWFrame * frame = k->frame( 0 );
02390                 QRect oldRect( m_parent->viewMode()->normalToView( frame->outerRect(m_parent->viewMode()) ) );
02391                 frame->moveTopLeft( frame->topLeft() + _move );
02392                 // Calculate new rectangle for this frame
02393                 QRect newRect( frame->outerRect(m_parent->viewMode()) );
02394                 QRect frameRect( m_parent->viewMode()->normalToView( newRect ) );
02395                 // Repaing only the changed rects (oldRect U newRect)
02396                 repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect();
02397             }
02398         }
02399     }
02400 
02401     if ( !m_parent->kWordDocument()->showGrid() && m_parent->kWordDocument()->snapToGrid() )
02402       m_parent->repaintContents( false ); //draw the grid over the whole canvas
02403     else
02404       m_parent->repaintContents( repaintRegion.boundingRect(), false );
02405     m_parent->gui()->getView()->updateFrameStatusBarItem();
02406 }
02407 
02408 KCommand *FrameMovePolicy::createCommand() {
02409     for(unsigned int i=0; i < m_frames.count(); i++) {
02410         KWFrame *frame = m_frames[i];
02411         FrameMoveStruct fms = m_frameMove[i];
02412         fms.newPos = frame->topLeft();
02413         m_frameMove[i] = fms;
02414     }
02415     return new KWFrameMoveCommand( i18n("Move Frame"), m_indexFrame, m_frameMove );
02416 }
02417 
02418 void FrameMovePolicy::finishInteraction() {
02419     KWFrameViewManager *frameViewManager = m_parent->frameViewManager();
02420     for(unsigned int i=0; i < m_frames.count(); i++) {
02421         KWFrame *frame = m_frames[i];
02422         frameViewManager->slotFrameMoved(frame, m_frameMove[i].oldPos.y());
02423     }
02424 }
02425 
02426 
02427 // ************** FrameSelectPolicy ***********************
02428 FrameSelectPolicy::FrameSelectPolicy(KWCanvas *parent, MouseMeaning meaning, KoPoint &point, Qt::ButtonState buttonState, Qt::ButtonState keyState)
02429     : InteractionPolicy(parent, false) {
02430 
02431     bool leftButton = buttonState & Qt::LeftButton;
02432     // this is a special case; if a frame that is curently being edited is 'selected' on the border
02433     // we redirect that click to the text part of the frame.
02434     // this means we give the user a lot more space to click on the left side of the frame to
02435     // select the first characters.
02436     KWFrameSetEdit *fse = parent->currentFrameSetEdit();
02437     if(leftButton && fse) {
02438         KWFrameView *view = m_parent->frameViewManager()->view(point,
02439                 KWFrameViewManager::unselected, true);
02440         if(view && view->frame()->frameSet() == fse->frameSet()) {
02441             // make sure 'point' is inside the frame
02442             point.setX(QMAX(point.x(), view->frame()->left()));
02443             point.setY(QMAX(point.y(), view->frame()->top()));
02444             point.setX(QMIN(point.x(), view->frame()->right()));
02445             point.setY(QMIN(point.y(), view->frame()->bottom()));
02446 
02447             // convert point to the view coordinate system.
02448             QPoint normalPoint = parent->kWordDocument()->zoomPoint(point);
02449             QPoint mousePos = parent->viewMode()->normalToView(normalPoint);
02450             QMouseEvent *me = new QMouseEvent(QEvent::MouseButtonPress, mousePos,
02451                     buttonState, keyState);
02452             fse->mousePressEvent(me, normalPoint, point );
02453             delete me;
02454 
02455             m_validSelection = false;
02456             return;
02457         }
02458     }
02459 
02460     m_validSelection = meaning != MEANING_NONE;
02461     m_parent->frameViewManager()->selectFrames(point, keyState, leftButton );
02462 }
02463 
02464 void FrameSelectPolicy::handleMouseMove(Qt::ButtonState keyState, const KoPoint &point) {
02465     Q_UNUSED(keyState);
02466     Q_UNUSED(point);
02467 }
02468 
02469 KCommand *FrameSelectPolicy::createCommand() {
02470     return 0;
02471 }
02472 
02473 void FrameSelectPolicy::finishInteraction() {
02474 }
02475 
02476 #include "KWCanvas.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys