diff --git a/kword/kwcanvas.cc b/kword/kwcanvas.cc index 31a7b581f2..db49167122 100644 --- a/kword/kwcanvas.cc +++ b/kword/kwcanvas.cc @@ -1,2513 +1,2514 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Reginald Stadlbauer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "kwcanvas.h" #include "kwtableframeset.h" #include "kwpartframeset.h" #include "kwdoc.h" #include "kwview.h" #include "kwviewmode.h" #include "kwdrag.h" #include "framedia.h" #include "kwcommand.h" #include "kwtabletemplate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kwtextdocument.h" #include KWCanvas::KWCanvas(KWViewMode* viewMode, QWidget *parent, KWDocument *d, KWGUI *lGui) : QScrollView( parent, "canvas", /*WNorthWestGravity*/ WStaticContents| WResizeNoErase | WRepaintNoErase ), m_doc( d ) { m_gui = lGui; m_currentFrameSetEdit = 0L; m_mouseMeaning = MEANING_NONE; m_mousePressed = false; m_imageDrag = false; m_frameInline = false; //used by insert picture dialogbox m_picture.pictureInline = false; m_picture.keepRatio = true; m_frameInlineType=FT_TABLE; m_viewMode = viewMode; cmdMoveFrame=0L; // Default table parameters. m_table.rows = 3; m_table.cols = 2; m_table.width = KWTableFrameSet::TblAuto; m_table.height = KWTableFrameSet::TblAuto; m_table.floating = true; m_table.tableTemplateName=QString::null; m_table.format=31; m_tableSplit.nbRows=1; m_tableSplit.nbCols=1; m_footEndNote.noteType = FootNote; m_footEndNote.numberingType = KWFootNoteVariable::Auto; curTable = 0L; m_printing = false; m_deleteMovingRect = false; viewport()->setBackgroundMode( PaletteBase ); viewport()->setAcceptDrops( TRUE ); setKeyCompression( TRUE ); viewport()->setMouseTracking( TRUE ); m_scrollTimer = new QTimer( this ); connect( m_scrollTimer, SIGNAL( timeout() ), this, SLOT( doAutoScroll() ) ); viewport()->setFocusProxy( this ); viewport()->setFocusPolicy( WheelFocus ); setFocus(); viewport()->installEventFilter( this ); installEventFilter( this ); KCursor::setAutoHideCursor( this, true, true ); connect( this, SIGNAL(contentsMoving( int, int )), this, SLOT(slotContentsMoving( int, int )) ); connect( m_doc, SIGNAL( newContentsSize() ), this, SLOT( slotNewContentsSize() ) ); connect( m_doc, SIGNAL( mainTextHeightChanged() ), this, SLOT( slotMainTextHeightChanged() ) ); connect( m_doc, SIGNAL( sig_terminateEditing( KWFrameSet * ) ), this, SLOT( terminateEditing( KWFrameSet * ) ) ); slotNewContentsSize(); m_mouseMode = MM_EDIT; // avoid UMR in setMouseMode setMouseMode( MM_EDIT ); // Create the current frameset-edit last, to have everything ready for it KWFrameSet * fs = 0L; QString fsName = m_doc->initialFrameSet(); if ( !fsName.isEmpty() ) fs = m_doc->frameSetByName( fsName ); if ( !fs ) fs = m_doc->frameSet( 0 ); Q_ASSERT( fs ); if ( fs && fs->isVisible( m_viewMode ) ) { m_currentFrameSetEdit = fs->createFrameSetEdit( this ); KWTextFrameSetEdit* textedit = dynamic_cast(m_currentFrameSetEdit); if ( textedit ) { int paragId = m_doc->initialCursorParag(); int index = m_doc->initialCursorIndex(); if ( paragId != 0 || index != 0 ) { KoTextParag* parag = textedit->textDocument()->paragAt( paragId ); if ( parag ) textedit->setCursor( parag, index ); } } } m_doc->deleteInitialEditingInfo(); m_doc->initBookmarkList(); } KWCanvas::~KWCanvas() { // Let the frames destroy their resize handles themselves (atm they are our children at the Qt level!) // We can't call selectAllFrames since the doc my already be deleted (no frameset anymore etc.) // The real fix would be to create an object for 'selected frame' and store it in the view/canvas. // (and remove bool KWFrame::selected - so that a frame can be selected in a view and not in another) QObjectList *l = queryList( "KWResizeHandle" ); QObjectListIt it( *l ); for ( ; it.current() ; ++it ) { QWidget * w = static_cast(it.current()); w->reparent(0L, QPoint(0,0)); // Yes, this is really an awful hack w->hide(); } delete l; delete cmdMoveFrame; delete m_currentFrameSetEdit; m_currentFrameSetEdit = 0L; } void KWCanvas::repaintChanged( KWFrameSet * fs, bool resetChanged ) { assert(fs); // the new code can't support fs being 0L here. Mail me if it happens (DF) //kdDebug(32002) << "KWCanvas::repaintChanged this=" << this << " fs=" << fs << endl; QPainter p( viewport() ); p.translate( -contentsX(), -contentsY() ); p.setBrushOrigin( -contentsX(), -contentsY() ); QRect crect( contentsX(), contentsY(), visibleWidth(), visibleHeight() ); drawFrameSet( fs, &p, crect, true, resetChanged, m_viewMode ); } void KWCanvas::repaintAll( bool erase /* = false */ ) { //kdDebug() << "KWCanvas::repaintAll erase=" << erase << endl; viewport()->repaint( erase ); } void KWCanvas::print( QPainter *painter, KPrinter *printer ) { // Prevent cursor drawing and editing if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->focusOutEvent(); m_printing = true; KWViewMode *viewMode = new KWViewModePrint( m_doc ); //use page specify in kdeprint dialogbox QValueList pageList=printer->pageList(); int from = printer->fromPage(); int to = printer->toPage(); kdDebug(32001) << "KWCanvas::print from=" << from << " to=" << to << endl; /* if ( !from && !to ) // 0, 0 means everything { from = printer->minPage(); to = printer->maxPage(); } for ( int i = from; i <= to; i++ ) pageList.append( i ); */ QProgressDialog progress( i18n( "Printing..." ), i18n( "Cancel" ), pageList.count() + 1, this ); int j = 0; progress.setProgress( 0 ); QValueList::Iterator it = pageList.begin(); for ( ; it != pageList.end(); ++it ) { progress.setProgress( ++j ); kapp->processEvents(); if ( progress.wasCancelled() ) break; if ( it != pageList.begin() ) printer->newPage(); painter->save(); int pgNum = (*it) - 1; int yOffset = m_doc->pageTop( pgNum ); kdDebug(32001) << "printing page " << pgNum << " yOffset=" << yOffset << endl; QRect pageRect( 0, yOffset, m_doc->paperWidth(), m_doc->paperHeight() ); painter->fillRect( pageRect, white ); painter->translate( 0, -yOffset ); painter->setBrushOrigin( 0, -yOffset ); drawDocument( painter, pageRect, viewMode ); kapp->processEvents(); painter->restore(); } if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->focusInEvent(); m_printing = false; delete viewMode; } void KWCanvas::drawContents( QPainter *painter, int cx, int cy, int cw, int ch ) { if ( isUpdatesEnabled() ) { // Note: in drawContents, the painter is already translated to the contents coordinates painter->setBrushOrigin( -contentsX(), -contentsY() ); drawDocument( painter, QRect( cx, cy, cw, ch ), m_viewMode ); } } void KWCanvas::drawDocument( QPainter *painter, const QRect &crect, KWViewMode* viewMode ) { //kdDebug(32002) << "KWCanvas::drawDocument crect: " << DEBUGRECT( crect ) << endl; // Draw the outside of the pages (shadow, gray area) // and the empty area first (in case of transparent frames) if ( painter->device()->devType() != QInternal::Printer ) // except when printing { QRegion emptySpaceRegion( crect ); m_doc->createEmptyRegion( crect, emptySpaceRegion, viewMode ); viewMode->drawPageBorders( painter, crect, emptySpaceRegion ); } // Draw all framesets contents QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWFrameSet * frameset = fit.current(); if(! frameset->isVisible()) continue; drawFrameSet( frameset, painter, crect, false, true, viewMode ); } m_doc->maybeDeleteDoubleBufferPixmap(); } void KWCanvas::drawFrameSet( KWFrameSet * frameset, QPainter * painter, const QRect & crect, bool onlyChanged, bool resetChanged, KWViewMode* viewMode ) { if ( !frameset->isVisible( viewMode ) ) return; if ( !onlyChanged && frameset->isFloating() ) return; bool focus = hasFocus() || viewport()->hasFocus(); if ( painter->device()->devType() == QInternal::Printer ) focus = false; QColorGroup gb = QApplication::palette().active(); if ( focus && m_currentFrameSetEdit && frameset == m_currentFrameSetEdit->frameSet() ) // Currently edited frameset m_currentFrameSetEdit->drawContents( painter, crect, gb, onlyChanged, resetChanged, viewMode ); else frameset->drawContents( painter, crect, gb, onlyChanged, resetChanged, 0L, viewMode ); } void KWCanvas::keyPressEvent( QKeyEvent *e ) { if( !m_doc->isReadWrite()) { switch( e->key() ) { case Key_Down: setContentsPos( contentsX(), contentsY() + 10 ); break; case Key_Up: setContentsPos( contentsX(), contentsY() - 10 ); break; case Key_Left: setContentsPos( contentsX() - 10, contentsY() ); break; case Key_Right: setContentsPos( contentsX() + 10, contentsY() ); break; case Key_PageUp: setContentsPos( contentsX(), contentsY() - visibleHeight() ); break; case Key_PageDown: setContentsPos( contentsX(), contentsY() + visibleHeight() ); break; case Key_Home: setContentsPos( contentsX(), 0 ); break; case Key_End: setContentsPos( contentsX(), contentsHeight() - visibleHeight() ); break; default: break; } } // The key events in read-write mode are handled by eventFilter(), otherwise // we don't get key presses. } void KWCanvas::switchViewMode( KWViewMode * newViewMode ) { m_viewMode = newViewMode; } void KWCanvas::mpEditFrame( QMouseEvent *e, const QPoint &nPoint, MouseMeaning meaning ) // mouse press in edit-frame mode // This can be called by KWResizeHandle::mousePressEvent { KoPoint docPoint( m_doc->unzoomPoint( nPoint ) ); m_mouseMeaning = meaning; m_mousePressed = true; m_frameMoved = false; m_frameResized = false; m_ctrlClickOnSelectedFrame = false; if ( e ) { KWFrame * frame = m_doc->frameUnderMouse( nPoint ); KWFrameSet *fs = frame ? frame->frameSet() : 0; KWTableFrameSet *table= fs ? fs->getGroupManager() : 0; if ( fs && ( e->state() & ShiftButton ) && table ) { // is table and we hold shift KoPoint docPoint( m_doc->unzoomPoint( nPoint ) ); table->selectUntil( docPoint.x(), docPoint.y() ); } else if ( ( e->state() & ShiftButton ) && (m_doc->positionToSelectRowcolTable( nPoint, &table) != KWDocument::TABLE_POSITION_NONE) ) // we are in position to select full row/cells of a table + hold shift { KoPoint docPoint( m_doc->unzoomPoint( nPoint ) ); table->selectUntil( table->boundingRect().right(), docPoint.y() ); } else if ( frame && !frame->isSelected() ) // clicked on a frame that wasn't selected { if ( ! ( e->state() & ShiftButton || e->state() & ControlButton ) ) selectAllFrames( FALSE ); // if we don't hold shift or control, destroy old frame selection KWFrame *f = m_doc->frameUnderMouse(nPoint, 0L, true); if (f == frame) { if (e->state() & ShiftButton) selectAllFrames( FALSE ); // shift deselects everything. selectFrame( frame, TRUE ); // select the frame. } else m_ctrlClickOnSelectedFrame = true; } else if(frame) // clicked on a frame that was already selected { if ( e->state() & ControlButton ) m_ctrlClickOnSelectedFrame = true; else { if ( e->state() & ShiftButton ) selectFrame( frame, FALSE ); else { // Resizing? if ( m_mouseMeaning >= MEANING_TOPLEFT /*hack*/ ) { // We can only resize one frame at a time selectAllFrames( FALSE ); selectFrame( frame, TRUE ); } } } } curTable = table; emit frameSelectedChanged(); } // At least one frame selected ? if( m_doc->getFirstSelectedFrame() ) { KWFrame * frame = m_doc->getFirstSelectedFrame(); // If header/footer, resize the first frame if ( frame->frameSet()->isHeaderOrFooter() ) frame = frame->frameSet()->frame( 0 ); m_resizedFrameInitialSize = frame->normalize(); } QPtrList selectedFrames = m_doc->getSelectedFrames(); QPtrList frameindexList; QPtrList frameindexMove; KWFrame *frame=0L; // When moving many frames, we look at the bounding rect. // It's the one that will be checked against the limits, etc. m_boundingRect = KoRect(); for(frame=selectedFrames.first(); frame != 0; frame=selectedFrames.next() ) { KWFrameSet * fs = frame->frameSet(); if ( !(m_doc->processingType() == KWDocument::WP && m_doc->frameSetNum( fs ) == 0 )&& !fs->isAHeader() && !fs->isAFooter() ) { // If one cell belongs to a table, we are in fact moving the whole table KWTableFrameSet *table = fs->getGroupManager(); // We'll have to do better in the long run if ( table ) { KWTableFrameSet::Cell *theCell=static_cast(fs); for(unsigned int col=0; col < table->getCols(); col++) { KWTableFrameSet::Cell *c = table->getCell(theCell->m_row, col); m_boundingRect |= *c->frame(0); } } else { m_boundingRect |= frame->outerKoRect(); } FrameIndex *index=new FrameIndex( frame ); FrameResizeStruct *move=new FrameResizeStruct; move->sizeOfBegin=frame->normalize(); move->sizeOfEnd=KoRect(); frameindexList.append(index); frameindexMove.append(move); } } m_hotSpot = docPoint - m_boundingRect.topLeft(); if(frameindexMove.count()!=0) { delete cmdMoveFrame; cmdMoveFrame = new KWFrameMoveCommand( i18n("Move Frame"), frameindexList, frameindexMove ); } viewport()->setCursor( m_doc->getMouseCursor( nPoint, e ? e->state() : 0 ) ); m_deleteMovingRect = false; } void KWCanvas::mpCreate( const QPoint& normalPoint ) { KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); applyGrid( docPoint ); m_insRect.setCoords( docPoint.x(), docPoint.y(), 0, 0 ); m_deleteMovingRect = false; } void KWCanvas::mpCreatePixmap( const QPoint& normalPoint ) { if ( !m_kopicture.isNull() ) { // Apply grid for the first corner only KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); applyGrid( docPoint ); m_insRect.setRect( docPoint.x(), docPoint.y(), 0, 0 ); m_deleteMovingRect = false; if ( !m_pixmapSize.isEmpty() ) { // This ensures 1-1 at 100% on screen, but allows zooming and printing with correct DPI values uint width = qRound( (double)m_pixmapSize.width() * m_doc->zoomedResolutionX() / POINT_TO_INCH( QPaintDevice::x11AppDpiX() ) ); uint height = qRound( (double)m_pixmapSize.height() * m_doc->zoomedResolutionY() / POINT_TO_INCH( QPaintDevice::x11AppDpiY() ) ); m_insRect.setWidth( m_doc->unzoomItX( width ) ); m_insRect.setHeight( m_doc->unzoomItY( height ) ); // Apply reasonable limits width = kMin( width, m_doc->paperWidth() - normalPoint.x() - 5 ); height = kMin( height, m_doc->paperHeight()- normalPoint.y() - 5 ); // And apply aspect-ratio if set if ( m_keepRatio ) { double ratio = ((double) m_pixmapSize.width()) / ((double) m_pixmapSize.height()); applyAspectRatio( ratio, m_insRect ); } QPoint nPoint( normalPoint.x() + m_doc->zoomItX( width ), normalPoint.y() + m_doc->zoomItY( height ) ); QPoint vPoint = m_viewMode->normalToView( nPoint ); vPoint = contentsToViewport( vPoint ); QRect viewportRect( contentsX(), contentsY(), visibleWidth(), visibleHeight() ); if ( viewportRect.contains( vPoint ) ) // Don't move the mouse out of the viewport QCursor::setPos( viewport()->mapToGlobal( vPoint ) ); } emit docStructChanged(Pictures); } } void KWCanvas::contentsMousePressEvent( QMouseEvent *e ) { QPoint normalPoint = m_viewMode->viewToNormal( e->pos() ); KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); if ( e->button() == LeftButton ) m_mousePressed = true; // Only edit-mode (and only LMB) allowed on read-only documents (to select text) if ( !m_doc->isReadWrite() && ( m_mouseMode != MM_EDIT || e->button() != LeftButton ) ) return; if ( m_printing ) return; // This code here is common to all mouse buttons, so that RMB and MMB place the cursor (or select the frame) too switch ( m_mouseMode ) { case MM_EDIT: { // See if we clicked on a frame's border KWFrame* frame; m_mouseMeaning = m_doc->getMouseMeaning( normalPoint, e->state(), &frame ); //kdDebug() << "contentsMousePressEvent meaning=" << m_mouseMeaning << endl; Q_ASSERT( m_mouseMeaning < MEANING_TOPLEFT ); // during resizing, the resizehandles are supposed to get the events if ( m_mouseMeaning == MEANING_MOUSE_MOVE ) { if ( m_currentFrameSetEdit ) terminateCurrentEdit(); mpEditFrame( e, normalPoint, m_mouseMeaning ); } else if ( m_mouseMeaning == MEANING_MOUSE_INSIDE || m_mouseMeaning == MEANING_MOUSE_INSIDE_TEXT || m_mouseMeaning == MEANING_ACTIVATE_PART ) { if ( selectAllFrames( false ) ) emit frameSelectedChanged(); KWFrameSet * fs = frame ? frame->frameSet() : 0L; bool emitChanged = false; if ( fs ) { // Clicked inside a frame - start editing it KWTableFrameSet *table = fs->getGroupManager(); emitChanged = checkCurrentEdit( table ? table : fs ); } if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->mousePressEvent( e, normalPoint, docPoint ); if ( emitChanged ) // emitted after mousePressEvent [for tables] emit currentFrameSetEditChanged(); emit updateRuler(); if ( m_frameInline ) { bool inlineCreated = true; if(m_frameInlineType==FT_TABLE) inlineCreated = insertInlineTable(); else if(m_frameInlineType==FT_PICTURE) inlineCreated = m_gui->getView()->insertInlinePicture(); if (inlineCreated) m_frameInline=false; else KMessageBox::information(0L, i18n("Read-only content cannot be changed. No modifications will be accepted")); } } KWTableFrameSet *table = 0L; KWDocument::TableToSelectPosition ePositionTable = m_doc->positionToSelectRowcolTable( normalPoint, &table); // are we in the situation to select row/cols of a table? if (ePositionTable != KWDocument::TABLE_POSITION_NONE) { // YES => select row/col if (ePositionTable == KWDocument::TABLE_POSITION_RIGHT) { // in position to select a ROW // here the cursor is on the left of the table. the y is OK, but the x is not, // hence finding a proper x with the table object KWTableFrameSet::Cell *cell = table->getCellByPos( table->leftWithoutBorder(), m_doc->unzoomItY(normalPoint.y()) ); if (cell) { table->selectRow( cell->getRow() ); curTable = table; emit frameSelectedChanged(); } } else { // in position to select a COLUMN // here the cursor is on top of the table. the x is ok, but the y is not. KWTableFrameSet::Cell *cell = table->getCellByPos( m_doc->unzoomItX(normalPoint.x()), table->topWithoutBorder() ); if (cell) { table->selectCol( cell->getColumn() ); curTable = table; emit frameSelectedChanged(); } } } m_scrollTimer->start( 50 ); } break; case MM_CREATE_TEXT: case MM_CREATE_PART: case MM_CREATE_TABLE: case MM_CREATE_FORMULA: if ( e->button() == LeftButton ) mpCreate( normalPoint ); break; case MM_CREATE_PIX: if ( e->button() == LeftButton ) mpCreatePixmap( normalPoint ); break; default: break; } if ( e->button() == MidButton ) { if ( m_doc->isReadWrite() && m_currentFrameSetEdit && m_mouseMode == MM_EDIT ) { QApplication::clipboard()->setSelectionMode( true ); m_currentFrameSetEdit->paste(); QApplication::clipboard()->setSelectionMode( false ); } } else if ( e->button() == RightButton ) { if(!m_doc->isReadWrite()) // The popups are not available in readonly mode, since the GUI isn't built... return; if ( m_deleteMovingRect ) deleteMovingRect(); // rmb menu switch ( m_mouseMode ) { case MM_EDIT: { if ( viewMode()->type()=="ModeText") m_gui->getView()->openPopupMenuInsideFrame( m_doc->frameSet( 0 )->frame(0), QCursor::pos() ); else { // See if we clicked on a frame's border bool border = false; KWFrame * frame = m_doc->frameUnderMouse( normalPoint, &border ); if ( ( frame && border ) || e->state() & ControlButton ) { m_gui->getView()->openPopupMenuEditFrame( QCursor::pos() ); } else { if ( frame ) m_gui->getView()->openPopupMenuInsideFrame( frame, QCursor::pos() ); else m_gui->getView()->openPopupMenuChangeAction( QCursor::pos() ); } } } break; case MM_CREATE_TEXT: case MM_CREATE_PART: case MM_CREATE_TABLE: case MM_CREATE_FORMULA: case MM_CREATE_PIX: setMouseMode( MM_EDIT ); default: break; } m_mousePressed = false; } } // Called by KWTableDia void KWCanvas::createTable( unsigned int rows, unsigned int cols, int wid, int hei, bool isFloating, KWTableTemplate *tt, int format ) { // Remember for next time in any case m_table.rows = rows; m_table.cols = cols; m_table.width = wid; m_table.height = hei; m_table.floating = isFloating; m_table.format = format; m_table.tableTemplateName = tt ? tt->translatedName():QString::null; m_table.tt = tt; if ( isFloating ) { m_frameInline=true; m_frameInlineType=FT_TABLE; m_gui->getView()->displayFrameInlineInfo(); } else { m_frameInline=false; setMouseMode( MM_CREATE_TABLE ); } } bool KWCanvas::insertInlineTable() { KWTextFrameSetEdit * edit = dynamic_cast(m_currentFrameSetEdit); if(edit) { if ( edit->textFrameSet()->textObject()->protectContent() ) return false; m_insRect = KoRect( 0, 0, edit->frameSet()->frame(0)->width(), 10 ); KWTableFrameSet * table = createTable(); m_doc->addFrameSet( table, false ); edit->insertFloatingFrameSet( table, i18n("Insert Inline Table") ); table->finalize(); if (m_table.tt) { KWTableTemplateCommand *ttCmd=new KWTableTemplateCommand( "Apply template to inline table", table, m_table.tt ); m_doc->addCommand(ttCmd); ttCmd->execute(); } m_doc->updateAllFrames(); m_doc->refreshDocStructure(Tables); } else { m_frameInline=false; } m_gui->getView()->updateFrameStatusBarItem(); return true; } void KWCanvas::mmEditFrameResize( bool top, bool bottom, bool left, bool right, bool noGrid ) { // This one is called by KWResizeHandle KWFrame *frame = m_doc->getFirstSelectedFrame(); if (!frame) { // can't happen, but never say never kdWarning(32001) << "KWCanvas::mmEditFrameResize: no frame selected!" << endl; return; } //kdDebug() << "KWCanvas::mmEditFrameResize top,bottom,left,right: " // << top << "," << bottom << "," << left << "," << right << endl; // Get the mouse position from QCursor. Trying to get it from KWResizeHandle's // mouseMoveEvent leads to the frame 'jumping' because the events are received async. QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() ); mousep = m_viewMode->viewToNormal( mousep ); KoPoint docPoint = m_doc->unzoomPoint( mousep ); // Apply the grid, unless Shift is pressed if ( !noGrid ) applyGrid( docPoint ); double x = docPoint.x(); double y = docPoint.y(); int page = static_cast( y / m_doc->ptPaperHeight() ); int oldPage = static_cast( frame->top() / m_doc->ptPaperHeight() ); Q_ASSERT( oldPage == frame->pageNum() ); // Calculate new frame coordinates, using minimum sizes, and keeping it in the bounds of the page double newLeft = frame->left(); double newTop = frame->top(); double newRight = frame->right(); double newBottom = frame->bottom(); KWFrameSet* frameSet = frame->frameSet(); if ( page == oldPage ) { //kdDebug() << "KWCanvas::mmEditFrameResize old rect " << DEBUGRECT( *frame ) << endl; int minHeight = minFrameHeight + static_cast(frame->bTop() + frame->bBottom()); int minWidth = minFrameWidth + static_cast(frame->bLeft() + frame->bRight()); if ( top && newTop != y ) { if (newBottom - y < /*minFrameHeight*/minHeight+5) y = newBottom - /*minFrameHeight*/minHeight - 5; y = QMAX( y, m_doc->ptPageTop( oldPage ) ); newTop = y; } else if ( bottom && newBottom != y ) { if (y - newTop < minHeight/*minFrameHeight*/+5) y = newTop + /*minFrameHeight*/minHeight + 5; y = QMIN( y, m_doc->ptPageTop( oldPage + 1 ) ); newBottom = y; } if ( left && newLeft != x ) { if (newRight - x < minWidth/*minFrameWidth*/) x = newRight - minWidth/*minFrameWidth*/ - 5; x = QMAX( x, 0 ); newLeft = x; } else if ( right && newRight != x ) { if (x - newLeft < /*minFrameWidth*/minWidth) x = newLeft + /*minFrameWidth*/minWidth + 5; // why +5 ? x = QMIN( x, m_doc->ptPaperWidth() ); newRight = x; } // Keep Aspect Ratio feature if ( frameSet->type() == FT_PICTURE && static_cast( frameSet )->keepAspectRatio() ) { double resizedFrameRatio = m_resizedFrameInitialSize.width() / m_resizedFrameInitialSize.height(); double width = newRight - newLeft; double height = newBottom - newTop; if ( ( top || bottom ) && ( left || right ) ) // resizing by a corner if ( width < height ) width = height * resizedFrameRatio; else height = width / resizedFrameRatio; else // resizing by a border if ( top || bottom ) width = height * resizedFrameRatio; else height = width / resizedFrameRatio; //kdDebug() << "KWCanvas::mmEditFrameResize after aspect ratio: width=" << width << " height=" << height << endl; if ( left ) newLeft = frame->right() - width; else newRight = frame->left() + width; if ( top ) newTop = frame->bottom() - height; else newBottom = frame->top() + height; //kdDebug() << "KWCanvas::mmEditFrameResize after: newRight=" << newRight << " newBottom=" << newBottom << endl; } } // Check if frame was really resized because otherwise no repaint is needed if( newLeft != frame->left() || newRight != frame->right() || newTop != frame->top() || newBottom != frame->bottom() ) { // Keep copy of old rectangle, for repaint() QRect oldRect = m_viewMode->normalToView( frame->outerRect() ); frameSet->resizeFrameSetCoords( frame, newLeft, newTop, newRight, newBottom, false /*not final*/ ); /*frame->setLeft(newLeft); frame->setTop(newTop); frame->setRight(newRight); frame->setBottom(newBottom);*/ //kdDebug() << "KWCanvas::mmEditFrameResize newTop=" << newTop << " newBottom=" << newBottom << " height=" << frame->height() << endl; // If header/footer, resize the first frame if ( frameSet->isHeaderOrFooter() ) { KWFrame * origFrame = frameSet->frame( 0 ); origFrame->setLeft(newLeft); origFrame->setTop(newTop); origFrame->setRight(newRight); origFrame->setBottom(newBottom); } //kdDebug() << "KWCanvas::mmEditFrameResize new rect " << DEBUGRECT( *frame ) << endl; #if 0 int drawX, drawWidth, drawY, drawHeight; drawX=frame->left(); drawWidth=frame->width(); drawY=frame->top(); drawHeight=frame->height(); if (frameSet->getGroupManager()) { // is table if (!(top || bottom)) { /// full height. drawY=frameSet->getGroupManager()->getBoundingRect().y(); drawHeight=frameSet->getGroupManager()->getBoundingRect().height(); } else if (!(left || right)) { // full width. drawX=frameSet->getGroupManager()->getBoundingRect().x(); drawWidth=frameSet->getGroupManager()->getBoundingRect().width(); } } //p.drawRect( drawX, drawY, drawWidth, drawHeight ); //p.end(); #endif // Move resize handles to new position frame->updateResizeHandles(); // Calculate new rectangle for this frame QRect newRect( m_viewMode->normalToView( frame->outerRect() ) ); // Repaint only the changed rects (oldRect U newRect) repaintContents( QRegion(oldRect).unite(newRect).boundingRect(), FALSE ); m_frameResized = true; m_gui->getView()->updateFrameStatusBarItem(); } } void KWCanvas::applyGrid( KoPoint &p ) { // The 1e-10 here is a workaround for some weird division problem. // 360.00062366 / 2.83465058 gives 127 'exactly' when shown as a double, // but when casting into an int, we get 126. In fact it's 127 - 5.64e-15 ! // This is a problem when calling applyGrid twice, we get 1 less than the time before. p.setX( static_cast( p.x() / m_doc->gridX() + 1e-10 ) * m_doc->gridX() ); p.setY( static_cast( p.y() / m_doc->gridY() + 1e-10 ) * m_doc->gridY() ); } void KWCanvas::applyAspectRatio( double ratio, KoRect& insRect ) { double width = insRect.width(); double height = insRect.height(); if ( width < height ) // the biggest border is the one in control width = height * ratio; else height = width / ratio; insRect.setRight( insRect.left() + width ); insRect.setBottom( insRect.top() + height ); //kdDebug() << "KWCanvas::applyAspectRatio: width=" << width << " height=" << height << " insRect=" << DEBUGRECT(insRect) << endl; } void KWCanvas::mmEditFrameMove( const QPoint &normalPoint, bool shiftPressed ) { KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); // Move the bounding rect containing all the selected frames KoRect oldBoundingRect = m_boundingRect; //int page = m_doc->getPageOfRect( m_boundingRect ); //kdDebug() << "KWCanvas::mmEditFrameMove docPoint.x=" << docPoint.x() // << " boundingrect=" << DEBUGRECT(m_boundingRect) << endl; // (x and y separately for a better behaviour at limit of page) KoPoint p( m_boundingRect.topLeft() ); //kdDebug() << "KWCanvas::mmEditFrameMove hotspot.x=" << m_hotSpot.x() << endl; p.setX( docPoint.x() - m_hotSpot.x() ); //kdDebug() << "mmEditFrameMove: x (pixel)=" << DEBUGDOUBLE( normalPoint.x() ) // << " docPoint.x()=" << DEBUGDOUBLE( docPoint.x() ) // << " m_hotSpot.x()=" << DEBUGDOUBLE( m_hotSpot.x() ) << endl; // << " p.x=" << DEBUGDOUBLE( p.x() ) << endl; if ( !shiftPressed ) // Shift disables the grid applyGrid( p ); //kdDebug() << "KWCanvas::mmEditFrameMove p.x is now " << DEBUGDOUBLE( p.x() ) // << " (" << DEBUGDOUBLE( KWUnit::toMM( p.x() ) ) << " mm)" << endl; m_boundingRect.moveTopLeft( p ); //kdDebug() << "KWCanvas::mmEditFrameMove boundingrect now " << DEBUGRECT(m_boundingRect) << endl; // But not out of the margins if ( m_boundingRect.left() < 1 ) // 1 pt margin to avoid drawing problems { p.setX( 1 ); m_boundingRect.moveTopLeft( p ); } else if ( m_boundingRect.right() > m_doc->ptPaperWidth() - 1 ) { p.setX( m_doc->ptPaperWidth() - m_boundingRect.width() - 2 ); m_boundingRect.moveTopLeft( p ); } // Now try Y p = m_boundingRect.topLeft(); p.setY( docPoint.y()- m_hotSpot.y() ); if ( !shiftPressed ) // Shift disables the grid applyGrid( p ); //kdDebug() << " (grid again) p.x is now " << DEBUGDOUBLE( p.x() ) // << " (" << DEBUGDOUBLE( KWUnit::toMM( p.x() ) ) << " mm)" << endl; m_boundingRect.moveTopLeft( p ); // -- Don't limit to the current page. Let the user move a frame between pages -- // But we still want to limit to 0 - lastPage if ( m_boundingRect.top() < 1 ) // 1 pt margin to avoid drawing problems { p.setY( 1 ); m_boundingRect.moveTopLeft( p ); } else if ( m_boundingRect.bottom() > m_doc->numPages() * m_doc->ptPaperHeight() - 1 ) { //kdDebug() << "KWCanvas::mmEditFrameMove limiting to last page" << endl; p.setY( m_doc->numPages() * m_doc->ptPaperHeight() - m_boundingRect.height() - 2 ); m_boundingRect.moveTopLeft( p ); } // Another annoying case is if the top and bottom points are not in the same page.... int topPage = static_cast( m_boundingRect.top() / m_doc->ptPaperHeight() ); int bottomPage = static_cast( m_boundingRect.bottom() / m_doc->ptPaperHeight() ); //kdDebug() << "KWCanvas::mmEditFrameMove topPage=" << topPage << " bottomPage=" << bottomPage << endl; if ( topPage != bottomPage ) { // Choose the closest page... Q_ASSERT( topPage + 1 == bottomPage ); // Not too sure what to do otherwise double topPart = (bottomPage * m_doc->ptPaperHeight()) - m_boundingRect.top(); if ( topPart > m_boundingRect.height() / 2 ) // Most of the rect is in the top page p.setY( bottomPage * m_doc->ptPaperHeight() - m_boundingRect.height() - 1 ); else { // Most of the rect is in the bottom page p.setY( bottomPage * m_doc->ptPaperHeight() + 5 /* grmbl, resize handles.... */ ); topPage = bottomPage; } //kdDebug() << "KWCanvas::mmEditFrameMove y set to " << p.y() << endl; m_boundingRect.moveTopLeft( p ); } if( m_boundingRect.topLeft() == oldBoundingRect.topLeft() ) return; // nothing happened (probably due to the grid) /*kdDebug() << "boundingRect moved by " << m_boundingRect.left() - oldBoundingRect.left() << "," << m_boundingRect.top() - oldBoundingRect.top() << endl; kdDebug() << " boundingX+hotspotX=" << m_boundingRect.left() + m_hotSpot.x() << endl; kdDebug() << " docPoint.x()=" << docPoint.x() << endl;*/ QPtrList tablesMoved; tablesMoved.setAutoDelete( FALSE ); bool bFirst = true; QRegion repaintRegion; KoPoint _move=m_boundingRect.topLeft() - oldBoundingRect.topLeft(); QPtrListIterator framesetIt( m_doc->framesetsIterator() ); for ( ; framesetIt.current(); ++framesetIt, bFirst=false ) { KWFrameSet *frameset = framesetIt.current(); if(! frameset->isVisible()) continue; // Can't move main frameset of a WP document if ( m_doc->processingType() == KWDocument::WP && bFirst || frameset->type() == FT_TEXT && frameset->frameSetInfo() != KWFrameSet::FI_BODY ) continue; // Can't move frame of floating frameset if ( frameset->isFloating() ) continue; if ( frameset->isProtectSize() ) continue; m_frameMoved = true; QPtrListIterator frameIt( frameset->frameIterator() ); for ( ; frameIt.current(); ++frameIt ) { KWFrame *frame = frameIt.current(); if ( frame->isSelected() ) { if ( frameset->type() == FT_TABLE ) { if ( tablesMoved.findRef( static_cast (frameset) ) == -1 ) tablesMoved.append( static_cast (frameset)); } else { QRect oldRect( m_viewMode->normalToView( frame->outerRect() ) ); // Move the frame frame->moveTopLeft( frame->topLeft() + _move ); // Calculate new rectangle for this frame QRect newRect( frame->outerRect() ); QRect frameRect( m_viewMode->normalToView( newRect ) ); // Repaint only the changed rects (oldRect U newRect) repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect(); // Move resize handles to new position frame->updateResizeHandles(); } } } } if ( !tablesMoved.isEmpty() ) { //kdDebug() << "KWCanvas::mmEditFrameMove TABLESMOVED" << endl; for ( unsigned int i = 0; i < tablesMoved.count(); i++ ) { KWTableFrameSet *table = tablesMoved.at( i ); for ( unsigned k = 0; k < table->getNumCells(); k++ ) { KWFrame * frame = table->getCell( k )->frame( 0 ); QRect oldRect( m_viewMode->normalToView( frame->outerRect() ) ); frame->moveTopLeft( frame->topLeft() + _move ); // Calculate new rectangle for this frame QRect newRect( frame->outerRect() ); QRect frameRect( m_viewMode->normalToView( newRect ) ); // Repaing only the changed rects (oldRect U newRect) repaintRegion += QRegion(oldRect).unite(frameRect).boundingRect(); // Move resize handles to new position frame->updateResizeHandles(); } } } // Frames have moved -> update the "frames on top" lists //m_doc->updateAllFrames(); // Not yet in fact. If we relayout the text everytime it's too slow. // But we can fix the clipping easily m_doc->updateFramesOnTopOrBelow( topPage ); repaintContents( repaintRegion.boundingRect(), FALSE ); m_gui->getView()->updateFrameStatusBarItem(); } void KWCanvas::mmCreate( const QPoint& normalPoint, bool shiftPressed ) // Mouse move when creating a frame { QPainter p; p.begin( viewport() ); p.translate( -contentsX(), -contentsY() ); p.setRasterOp( NotROP ); p.setPen( black ); p.setBrush( NoBrush ); if ( m_deleteMovingRect ) drawMovingRect( p ); int page = m_doc->getPageOfRect( m_insRect ); KoRect oldRect = m_insRect; // Resize the rectangle KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); if ( m_mouseMode != MM_CREATE_PIX && !shiftPressed ) applyGrid( docPoint ); m_insRect.setRight( docPoint.x() ); m_insRect.setBottom( docPoint.y() ); // But not out of the page KoRect r = m_insRect.normalize(); if ( m_doc->isOutOfPage( r, page ) ) { m_insRect = oldRect; // #### QCursor::setPos( viewport()->mapToGlobal( zoomPoint( m_insRect.bottomRight() ) ) ); } // Apply keep-aspect-ratio feature if ( m_mouseMode == MM_CREATE_PIX && m_keepRatio ) { double ratio = (double)m_pixmapSize.width() / (double)m_pixmapSize.height(); applyAspectRatio( ratio, m_insRect ); } drawMovingRect( p ); p.end(); m_deleteMovingRect = true; } void KWCanvas::drawMovingRect( QPainter & p ) { p.setPen( black ); p.drawRect( m_viewMode->normalToView( m_doc->zoomRect( m_insRect ) ) ); } void KWCanvas::deleteMovingRect() { Q_ASSERT( m_deleteMovingRect ); QPainter p; p.begin( viewport() ); p.translate( -contentsX(), -contentsY() ); p.setRasterOp( NotROP ); p.setPen( black ); p.setBrush( NoBrush ); drawMovingRect( p ); m_deleteMovingRect = false; p.end(); } void KWCanvas::contentsMouseMoveEvent( QMouseEvent *e ) { if ( m_printing ) return; QPoint normalPoint = m_viewMode->viewToNormal( e->pos() ); KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); if ( m_mousePressed ) { //doAutoScroll(); switch ( m_mouseMode ) { case MM_EDIT: { if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->mouseMoveEvent( e, normalPoint, docPoint ); else if ( m_doc->isReadWrite() ) { if ( m_mouseMeaning == MEANING_MOUSE_MOVE ) mmEditFrameMove( normalPoint, e->state() & ShiftButton ); // mousemove during resizing is handled by the resizehandles directly // (since they are widgets. The canvas doesn't get the event). } } break; case MM_CREATE_TEXT: case MM_CREATE_PIX: case MM_CREATE_PART: case MM_CREATE_TABLE: case MM_CREATE_FORMULA: mmCreate( normalPoint, e->state() & ShiftButton ); default: break; } } else { if ( m_mouseMode == MM_EDIT ) viewport()->setCursor( m_doc->getMouseCursor( normalPoint, e->state() & ControlButton ) ); } } void KWCanvas::mrEditFrame( QMouseEvent *e, const QPoint &nPoint ) // Can be called from KWCanvas and from KWResizeHandle's mouseReleaseEvents { //kdDebug() << "KWCanvas::mrEditFrame" << endl; KWFrame *firstFrame = m_doc->getFirstSelectedFrame(); //kdDebug() << "KWCanvas::mrEditFrame m_frameMoved=" << m_frameMoved << " m_frameResized=" << m_frameResized << endl; if ( firstFrame && ( m_frameMoved || m_frameResized ) ) { KWTableFrameSet *table = firstFrame->frameSet()->getGroupManager(); if (table) { table->recalcCols(); table->recalcRows(); if(m_frameResized) table->refreshSelectedCell(); //repaintTableHeaders( table ); } // Create command if ( m_frameResized ) { KWFrame *frame = m_doc->getFirstSelectedFrame(); KWFrameSet *fs = frame->frameSet(); // If header/footer, resize the first frame if ( fs->isHeaderOrFooter() ) frame = fs->frame( 0 ); Q_ASSERT( frame ); if ( frame ) { FrameIndex index( frame ); FrameResizeStruct tmpResize; tmpResize.sizeOfBegin = m_resizedFrameInitialSize; tmpResize.sizeOfEnd = frame->normalize(); KWFrameResizeCommand *cmd = new KWFrameResizeCommand( i18n("Resize Frame"), index, tmpResize ); m_doc->addCommand(cmd); m_doc->frameChanged( frame, m_gui->getView() ); // repaint etc. if(fs->isAHeader() || fs->isAFooter()) { m_doc->recalcFrames(); frame->updateResizeHandles(); } // Especially useful for EPS images: set final size fs->resizeFrame( frame, frame->width(), frame->height(), true ); if ( frame && fs->type() == FT_PART ) static_cast( fs )->updateChildGeometry( viewMode() ); } delete cmdMoveFrame; // Unused after all cmdMoveFrame = 0L; } else { Q_ASSERT( cmdMoveFrame ); // has been created by mpEditFrame if( cmdMoveFrame ) { // Store final positions QPtrList selectedFrames = m_doc->getSelectedFrames(); int i = 0; for(KWFrame * frame=selectedFrames.first(); frame; frame=selectedFrames.next() ) { KWFrameSet * fs = frame->frameSet(); if ( !(m_doc->processingType() == KWDocument::WP && m_doc->frameSetNum( fs ) == 0 )&& !fs->isAHeader() && !fs->isAFooter() ) { cmdMoveFrame->listFrameMoved().at(i)->sizeOfEnd = frame->normalize(); i++; } if ( frame && fs->type() == FT_PART ) static_cast( fs )->updateChildGeometry( viewMode() ); } m_doc->addCommand(cmdMoveFrame); m_doc->framesChanged( selectedFrames, m_gui->getView() ); // repaint etc. cmdMoveFrame = 0L; } } m_doc->repaintAllViews(); } else { // No frame was moved or resized. if ( e->state() & ControlButton ) { //KWFrame * frame = m_doc->frameUnderMouse( nPoint ); if ( m_ctrlClickOnSelectedFrame /* && frame->isSelected() */ ) // kervel: why the && ? { KWFrame *f = m_doc->frameUnderMouse( nPoint,0L,true ); if (e->state() & ShiftButton) selectAllFrames( false ); if (f) selectFrame(f,true); emit frameSelectedChanged(); } } } m_mousePressed = false; m_ctrlClickOnSelectedFrame = false; } KCommand *KWCanvas::createTextBox( const KoRect & rect ) { if ( rect.width() > m_doc->gridX() && rect.height() > m_doc->gridY() ) { KWFrame *frame = new KWFrame(0L, rect.x(), rect.y(), rect.width(), rect.height() ); frame->setNewFrameBehavior(KWFrame::Reconnect); frame->setZOrder( m_doc->maxZOrder( frame->pageNum(m_doc) ) + 1 ); // make sure it's on top QString name = m_doc->generateFramesetName( i18n( "Text Frameset %1" ) ); KWTextFrameSet *_frameSet = new KWTextFrameSet(m_doc, name ); _frameSet->addFrame( frame ); m_doc->addFrameSet( _frameSet ); KWCreateFrameCommand *cmd=new KWCreateFrameCommand( i18n("Create Text Frame"), frame ); checkCurrentEdit(frame->frameSet(), true); return cmd; } return 0L; } void KWCanvas::mrCreateText() { m_insRect = m_insRect.normalize(); if ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) { KWFrame *frame = new KWFrame(0L, m_insRect.x(), m_insRect.y(), m_insRect.width(), m_insRect.height() ); frame->setNewFrameBehavior(KWFrame::Reconnect); frame->setZOrder( m_doc->maxZOrder( frame->pageNum(m_doc) ) + 1 ); // make sure it's on top KWFrameDia frameDia( this, frame, m_doc, FT_TEXT ); frameDia.setCaption(i18n("Connect Frame")); frameDia.exec(); checkCurrentEdit(frame->frameSet(), true); } setMouseMode( MM_EDIT ); m_doc->repaintAllViews(); emit docStructChanged(TextFrames); emit currentFrameSetEditChanged(); } void KWCanvas::mrCreatePixmap() { kdDebug() << "KWCanvas::mrCreatePixmap m_insRect=" << DEBUGRECT(m_insRect) << endl; // Make sure it's completely on page. KoRect picRect( kMin(m_insRect.left(), m_insRect.right()), kMin( m_insRect.top(), m_insRect.bottom()), kAbs( m_insRect.width()), kAbs(m_insRect.height())); if(picRect.right() > m_doc->ptPaperWidth()) { double width = picRect.width(); m_insRect.setLeft(m_doc->ptPaperWidth() - width); m_insRect.setRight(m_doc->ptPaperWidth()); } int page = static_cast(picRect.top() / m_doc->ptPaperHeight()) + 1; if(picRect.bottom() > m_doc->ptPaperHeight() * page) { double height = picRect.height(); picRect.setTop(m_doc->ptPaperHeight() * page - height); picRect.setBottom(m_doc->ptPaperHeight() * page); } if ( picRect.width() > 0 /*m_doc->gridX()*/ &&picRect.height() > 0 /*m_doc->gridY()*/ && !m_kopicture.isNull() ) { KWFrameSet * fs = 0L; KWPictureFrameSet *frameset = new KWPictureFrameSet( m_doc, QString::null /*automatic name*/ ); frameset->insertPicture( m_kopicture ); frameset->setKeepAspectRatio( m_keepRatio ); fs = frameset; picRect = picRect.normalize(); KWFrame *frame = new KWFrame(fs, picRect.x(), picRect.y(), picRect.width(), picRect.height() ); frame->setZOrder( m_doc->maxZOrder( frame->pageNum(m_doc) ) + 1 ); // make sure it's on top fs->addFrame( frame, false ); m_doc->addFrameSet( fs ); KWCreateFrameCommand *cmd=new KWCreateFrameCommand( i18n("Create a Picture Frame"), frame ); m_doc->addCommand(cmd); m_doc->frameChanged( frame ); } setMouseMode( MM_EDIT ); emit docStructChanged(Pictures); } void KWCanvas::mrCreatePart() // mouse release, when creating part { m_insRect = m_insRect.normalize(); if ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) { m_doc->insertObject( m_insRect, m_partEntry ); } setMouseMode( MM_EDIT ); emit docStructChanged(Embedded); } void KWCanvas::mrCreateFormula() { m_insRect = m_insRect.normalize(); if ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) { KWFormulaFrameSet *frameset = new KWFormulaFrameSet( m_doc, QString::null ); KWFrame *frame = new KWFrame(frameset, m_insRect.x(), m_insRect.y(), m_insRect.width(), m_insRect.height() ); frame->setZOrder( m_doc->maxZOrder( frame->pageNum(m_doc) ) + 1 ); // make sure it's on top frameset->addFrame( frame, false ); m_doc->addFrameSet( frameset ); KWCreateFrameCommand *cmd=new KWCreateFrameCommand( i18n("Create a Formula Frame"), frame ); m_doc->addCommand(cmd); m_doc->frameChanged( frame ); } setMouseMode( MM_EDIT ); emit docStructChanged(FormulaFrames); } void KWCanvas::mrCreateTable() { m_insRect = m_insRect.normalize(); if ( m_insRect.width() > m_doc->gridX() && m_insRect.height() > m_doc->gridY() ) { if ( m_table.cols * minFrameWidth + m_insRect.x() > m_doc->ptPaperWidth() ) { KMessageBox::sorry(0, i18n("KWord is unable to insert the table because there " "is not enough space available.")); } else { KWTableFrameSet * table = createTable(); KMacroCommand *macroCmd = new KMacroCommand( i18n("Create Table") ); KWCreateTableCommand *cmd=new KWCreateTableCommand( "Create table", table ); macroCmd->addCommand(cmd); if (m_table.tt) { KWTableTemplateCommand *ttCmd=new KWTableTemplateCommand( "Apply template to table", table, m_table.tt ); macroCmd->addCommand(ttCmd); } m_doc->addCommand(macroCmd); macroCmd->execute(); emit docStructChanged(Tables); } m_doc->updateAllFrames(); m_doc->layout(); repaintAll(); } setMouseMode( MM_EDIT ); } KWTableFrameSet * KWCanvas::createTable() // uses m_insRect and m_table to create the table { KWTableFrameSet *table = new KWTableFrameSet( m_doc, QString::null /*automatic name*/ ); int pageNum = static_cast(m_insRect.y() / m_doc->ptPaperHeight()); // Create a set of cells with random-size frames. for ( unsigned int i = 0; i < m_table.rows; i++ ) { for ( unsigned int j = 0; j < m_table.cols; j++ ) { KWTableFrameSet::Cell *cell = new KWTableFrameSet::Cell( table, i, j, QString::null /*automatic name*/ ); KWFrame *frame = new KWFrame(cell, 0, 0, 0, 0, KWFrame::RA_BOUNDINGRECT ); // pos and size will be set in setBoundingRect frame->setZOrder( m_doc->maxZOrder( pageNum ) + 1 ); // make sure it's on top cell->addFrame( frame, false ); frame->setFrameBehavior(KWFrame::AutoExtendFrame); frame->setNewFrameBehavior(KWFrame::NoFollowup); } } KWTableFrameSet::CellSize w; w=static_cast( m_table.width ); if(m_frameInline) w=KWTableFrameSet::TblManual; table->setBoundingRect( m_insRect , w, static_cast( m_table.height )); return table; } void KWCanvas::contentsMouseReleaseEvent( QMouseEvent * e ) { if ( m_printing ) return; if ( m_scrollTimer->isActive() ) m_scrollTimer->stop(); if ( m_mousePressed ) { if ( m_deleteMovingRect ) deleteMovingRect(); QPoint normalPoint = m_viewMode->viewToNormal( e->pos() ); KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); if(m_insRect.bottom()==0 && m_insRect.right()==0) { // if the user did not drag, just click; make a 200x150 square for him. m_insRect.setLeft(QMIN(m_insRect.left(), m_doc->ptPaperWidth() - 200)); m_insRect.setTop(QMIN(m_insRect.top(), m_doc->ptPaperHeight() - 150)); m_insRect.setBottom(m_insRect.top()+150); m_insRect.setRight(m_insRect.left()+200); } switch ( m_mouseMode ) { case MM_EDIT: if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->mouseReleaseEvent( e, normalPoint, docPoint ); else { mrEditFrame( e, normalPoint ); m_mouseMeaning = MEANING_NONE; } break; case MM_CREATE_TEXT: mrCreateText(); break; case MM_CREATE_PIX: mrCreatePixmap(); break; case MM_CREATE_PART: mrCreatePart(); break; case MM_CREATE_TABLE: mrCreateTable(); break; case MM_CREATE_FORMULA: mrCreateFormula(); break; } m_mousePressed = false; } } void KWCanvas::contentsMouseDoubleClickEvent( QMouseEvent * e ) { if ( m_printing ) return; QPoint normalPoint = m_viewMode->viewToNormal( e->pos() ); KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); m_mousePressed = true; // needed for the dbl-click + move feature. switch ( m_mouseMode ) { case MM_EDIT: if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->mouseDoubleClickEvent( e, normalPoint, docPoint ); /* disable it otherwise we can edit embedded object else { editFrameProperties(); m_mousePressed = false; } break; */ default: break; } } KCommand *KWCanvas::setLeftFrameBorder( KoBorder newBorder, bool on ) { QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() == 0) return 0L; QPtrList tmpBorderList; QPtrList frameindexList; bool leftFrameBorderChanged=false; if (!on) newBorder.setPenWidth(0); QMap tables; KWFrame *frame=0L; for(frame=selectedFrames.first(); frame != 0; frame=selectedFrames.next() ) { // do all selected frames frame=KWFrameSet::settingsFrame(frame); FrameIndex *index=new FrameIndex( frame ); FrameBorderTypeStruct *tmp=new FrameBorderTypeStruct; tmp->m_OldBorder=frame->leftBorder(); tmp->m_EFrameType= FBLeft; tmpBorderList.append(tmp); frameindexList.append(index); if (newBorder!=frame->leftBorder()) // only commit when it has actually changed { leftFrameBorderChanged=true; KWTableFrameSet::Cell *cell = dynamic_cast(frame->frameSet()); if(cell!=0L) // is a table cell tables[cell->getGroupManager()]=frame; else frame->setLeftBorder(newBorder); } frame->updateResizeHandles(); frame->frameBordersChanged(); } QMap::Iterator it; for ( it = tables.begin(); it != tables.end(); ++it ) it.key()->setLeftBorder(newBorder); if(leftFrameBorderChanged) { KWFrameBorderCommand *cmd=new KWFrameBorderCommand(i18n("Change Left Border Frame"),frameindexList,tmpBorderList,newBorder); m_doc->repaintAllViews(); return cmd; } else { tmpBorderList.setAutoDelete(true); frameindexList.setAutoDelete(true); } return 0L; } KCommand *KWCanvas::setRightFrameBorder( KoBorder newBorder, bool on ) { QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() == 0) return 0L; QPtrList tmpBorderList; QPtrList frameindexList; bool rightFrameBorderChanged=false; KWFrame *frame=0L; if (!on) newBorder.setPenWidth(0); QMap tables; for(frame=selectedFrames.first(); frame != 0; frame=selectedFrames.next() ) { // do all selected frames frame=KWFrameSet::settingsFrame(frame); FrameIndex *index=new FrameIndex( frame ); FrameBorderTypeStruct *tmp=new FrameBorderTypeStruct; tmp->m_OldBorder=frame->rightBorder(); tmp->m_EFrameType= FBRight; tmpBorderList.append(tmp); frameindexList.append(index); if (newBorder!=frame->rightBorder()) { rightFrameBorderChanged=true; KWTableFrameSet::Cell *cell = dynamic_cast(frame->frameSet()); if(cell!=0L) // is a table cell tables[cell->getGroupManager()]=frame; else frame->setRightBorder(newBorder); } frame->updateResizeHandles(); frame->frameBordersChanged(); } QMap::Iterator it; for ( it = tables.begin(); it != tables.end(); ++it ) it.key()->setRightBorder(newBorder); if( rightFrameBorderChanged) { KWFrameBorderCommand *cmd=new KWFrameBorderCommand(i18n("Change Right Border Frame"),frameindexList,tmpBorderList,newBorder); m_doc->repaintAllViews(); return cmd; } else { tmpBorderList.setAutoDelete(true); frameindexList.setAutoDelete(true); } return 0L; } KCommand *KWCanvas::setTopFrameBorder( KoBorder newBorder, bool on ) { QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() == 0) return 0L; QPtrList tmpBorderList; QPtrList frameindexList; bool topFrameBorderChanged=false; KWFrame *frame=0L; if (!on) newBorder.setPenWidth(0); QMap tables; for(frame=selectedFrames.first(); frame != 0; frame=selectedFrames.next() ) { // do all selected frames frame=KWFrameSet::settingsFrame(frame); FrameIndex *index=new FrameIndex( frame ); FrameBorderTypeStruct *tmp=new FrameBorderTypeStruct; tmp->m_OldBorder=frame->topBorder(); tmp->m_EFrameType= FBTop; tmpBorderList.append(tmp); frameindexList.append(index); if (newBorder!=frame->topBorder()) { topFrameBorderChanged=true; KWTableFrameSet::Cell *cell = dynamic_cast(frame->frameSet()); if(cell!=0L) // is a table cell tables[cell->getGroupManager()]=frame; else frame->setTopBorder(newBorder); } frame->updateResizeHandles(); frame->frameBordersChanged(); } QMap::Iterator it; for ( it = tables.begin(); it != tables.end(); ++it ) it.key()->setTopBorder(newBorder); if(topFrameBorderChanged) { KWFrameBorderCommand *cmd=new KWFrameBorderCommand(i18n("Change Top Border Frame"),frameindexList,tmpBorderList,newBorder); m_doc->repaintAllViews(); return cmd; } else { tmpBorderList.setAutoDelete(true); frameindexList.setAutoDelete(true); } return 0L; } KCommand *KWCanvas::setBottomFrameBorder( KoBorder newBorder, bool on ) { QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() == 0) return 0L; bool bottomFrameBorderChanged=false; QPtrList tmpBorderList; QPtrList frameindexList; KWFrame *frame=0L; if (!on) newBorder.setPenWidth(0); QMap tables; for(frame=selectedFrames.first(); frame != 0; frame=selectedFrames.next() ) { // do all selected frames frame=KWFrameSet::settingsFrame(frame); FrameIndex *index=new FrameIndex( frame ); FrameBorderTypeStruct *tmp=new FrameBorderTypeStruct; tmp->m_OldBorder=frame->bottomBorder(); tmp->m_EFrameType= FBBottom; tmpBorderList.append(tmp); frameindexList.append(index); if (newBorder!=frame->bottomBorder()) { bottomFrameBorderChanged=true; KWTableFrameSet::Cell *cell = dynamic_cast(frame->frameSet()); if(cell!=0L) // is a table cell tables[cell->getGroupManager()]=frame; else frame->setBottomBorder(newBorder); } frame->updateResizeHandles(); frame->frameBordersChanged(); } QMap::Iterator it; for ( it = tables.begin(); it != tables.end(); ++it ) it.key()->setBottomBorder(newBorder); if(bottomFrameBorderChanged) { KWFrameBorderCommand *cmd=new KWFrameBorderCommand(i18n("Change Bottom Border Frame"),frameindexList,tmpBorderList,newBorder); m_doc->repaintAllViews(); return cmd; } else { tmpBorderList.setAutoDelete(true); frameindexList.setAutoDelete(true); tmpBorderList.clear(); frameindexList.clear(); } return 0L; } void KWCanvas::setFrameBackgroundColor( const QBrush &_backColor ) { QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() == 0) return; bool colorChanged=false; KWFrame *frame=0L; QPtrList frameindexList; QPtrList oldColor; for(frame=selectedFrames.first(); frame != 0; frame=selectedFrames.next() ) { frame=KWFrameSet::settingsFrame(frame); FrameIndex *index=new FrameIndex( frame ); frameindexList.append(index); QBrush *_color=new QBrush(frame->backgroundColor()); oldColor.append(_color); if (frame->frameSet() && frame->frameSet()->type()!=FT_PICTURE && frame->frameSet()->type()!=FT_PART && _backColor!=frame->backgroundColor()) { colorChanged=true; frame->setBackgroundColor(_backColor); } } if(colorChanged) { KWFrameBackGroundColorCommand *cmd=new KWFrameBackGroundColorCommand(i18n("Change Frame Background Color"),frameindexList,oldColor,_backColor); m_doc->addCommand(cmd); m_doc->repaintAllViews(); } else { frameindexList.setAutoDelete(true); oldColor.setAutoDelete(true); } } void KWCanvas::editFrameProperties( KWFrameSet * frameset ) { KWFrameDia *frameDia; KWFrame *frame = frameset->frame(0); frameDia = new KWFrameDia( this, frame ); frameDia->exec(); delete frameDia; } void KWCanvas::editFrameProperties() { QPtrList frames=m_doc->getSelectedFrames(); if(frames.count()==0) return; KWFrameDia *frameDia; if(frames.count()==1) { KWFrame *frame = frames.first(); frameDia = new KWFrameDia( this, frame ); } else { // multi frame dia. frameDia = new KWFrameDia( this, frames ); } frameDia->exec(); delete frameDia; } bool KWCanvas::selectAllFrames( bool select ) { bool ret = false; QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWFrameSet * fs = fit.current(); if(! fs->isVisible()) continue; QPtrListIterator frameIt = fs->frameIterator(); for ( ; frameIt.current(); ++frameIt ) { KWFrame * frame = frameIt.current(); if ( frame->isSelected() != select ) { frame->setSelected( select ); ret = true; } } } return ret; } void KWCanvas::selectFrame( KWFrame * frame, bool select ) { if ( frame->isSelected() != select ) frame->setSelected( select ); } void KWCanvas::cutSelectedFrames() { copySelectedFrames(); m_gui->getView()->deleteFrame(false); } void KWCanvas::copySelectedFrames() { QDomDocument domDoc( "SELECTION" ); QDomElement topElem = domDoc.createElement( "SELECTION" ); domDoc.appendChild( topElem ); bool foundOne = false; QPtrList embeddedObjects; KoStoreDrag *kd = new KoStoreDrag( "application/x-kword", 0L ); QDragObject* dragObject = kd; QByteArray arr; QBuffer buffer(arr); KoStore* store = KoStore::createStore( &buffer, KoStore::Write, "application/x-kword" ); QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWFrameSet * fs = fit.current(); if ( fs->isVisible() && fs->type() == FT_PART && fs->frameIterator().getFirst()->isSelected() ) { foundOne = true; embeddedObjects.append( static_cast(fs)->getChild() ); } } // Save internal embedded objects first, since it might change their URL int i = 0; QValueList savePictures; QPtrListIterator chl( embeddedObjects ); for( ; chl.current(); ++chl ) { KoDocument* childDoc = chl.current()->document(); if ( childDoc && !childDoc->isStoredExtern() ) (void) childDoc->saveToStore( store, QString::number( i++ ) ); } // We really need a selected-frames-list ! fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWFrameSet * fs = fit.current(); if ( fs->isVisible() ) { bool isTable = ( fs->type() == FT_TABLE ); if ( fs->type() == FT_PART ) continue; QPtrListIterator frameIt = fs->frameIterator(); KWFrame * firstFrame = frameIt.current(); for ( ; frameIt.current(); ++frameIt ) { KWFrame * frame = frameIt.current(); if ( frame->isSelected() ) { // Two cases to be distinguished here // If it's the first frame of a frameset, then copy the frameset (with that frame) // Otherwise copy only the frame information QDomElement parentElem = topElem; if ( frame == firstFrame || isTable ) { parentElem = fs->toXML( parentElem, isTable ? true : false ); // We'll save the frame inside that frameset tag } if ( !isTable ) { // Save the frame information QDomElement frameElem = parentElem.ownerDocument().createElement( "FRAME" ); parentElem.appendChild( frameElem ); frame->save( frameElem ); if ( frame != firstFrame ) { // Frame saved alone -> remember which frameset it's part of frameElem.setAttribute( "parentFrameset", fs->getName() ); } if ( fs->type() == FT_PICTURE ) { KoPictureKey key = static_cast( fs )->key(); if ( !savePictures.contains( key ) ) savePictures.append( key ); } } foundOne = true; if ( isTable ) // Copy tables only once, even if they have many cells selected break; } } } } if ( !foundOne ) { delete store; delete kd; return; } if ( !embeddedObjects.isEmpty() ) m_doc->saveEmbeddedObjects( topElem, embeddedObjects ); if ( !savePictures.isEmpty() ) { // Save picture list at the end of the main XML topElem.appendChild( m_doc->pictureCollection()->saveXML( KoPictureCollection::CollectionPicture, domDoc, savePictures ) ); // Save the actual picture data into the store m_doc->pictureCollection()->saveToStore( KoPictureCollection::CollectionPicture, store, savePictures ); // Single image -> put it in dragobject too if ( savePictures.count() == 1 ) { KoPicture pic = m_doc->pictureCollection()->findPicture( savePictures.first() ); QDragObject* picDrag = pic.dragObject( 0L ); kdDebug() << k_funcinfo << "picDrag=" << picDrag << endl; if ( picDrag ) { KMultipleDrag* multipleDrag = new KMultipleDrag( 0L ); multipleDrag->addDragObject( kd ); multipleDrag->addDragObject( picDrag ); dragObject = multipleDrag; kdDebug() << k_funcinfo << "multiple" << endl; } } } if ( store->open( "root" ) ) { QCString s = domDoc.toCString(); // this is already Utf8! kdDebug(32001) << "KWCanvas::copySelectedFrames: " << s << endl; (void)store->write( s.data(), s.size()-1 ); store->close(); } // Maybe we need to also save styles, framestyles and tablestyles. delete store; kd->setEncodedData( arr ); QApplication::clipboard()->setData( dragObject ); } void KWCanvas::pasteFrames() { QMimeSource *data = QApplication::clipboard()->data(); QByteArray arr = data->encodedData( KoStoreDrag::mimeType( "application/x-kword" ) ); if ( !arr.size() ) return; QBuffer buffer( arr ); KoStore* store = KoStore::createStore( &buffer, KoStore::Read ); if ( !store->bad() ) { if ( store->open( "root" ) ) { QString errorMsg; int errorLine; int errorColumn; QDomDocument domDoc; if ( !domDoc.setContent( store->device(), &errorMsg, &errorLine, &errorColumn ) ) { kdError (30003) << "Parsing Error! Aborting! (in KWCanvas::pasteFrames)" << endl << " Line: " << errorLine << " Column: " << errorColumn << endl << " Message: " << errorMsg << endl; delete store; return; } kdDebug() << domDoc.toCString() << endl; QDomElement topElem = domDoc.documentElement(); KMacroCommand * macroCmd = new KMacroCommand( i18n( "Paste Frames" ) ); m_doc->pasteFrames( topElem, macroCmd ); m_doc->loadPictureMap( topElem ); store->close(); m_doc->loadImagesFromStore( store ); m_doc->insertEmbedded( store, topElem, macroCmd, 20.0 ); m_doc->completePasting(); m_doc->addCommand( macroCmd ); } } delete store; } KWTableFrameSet *KWCanvas::getTable() { if( !m_currentFrameSetEdit) return 0L; if(m_currentFrameSetEdit->frameSet()->type() == FT_TABLE) return static_cast (m_currentFrameSetEdit->frameSet()); return 0L; } void KWCanvas::editFrameSet( KWFrameSet * frameSet, bool onlyText ) { if ( selectAllFrames( false ) ) emit frameSelectedChanged(); bool emitChanged = false; KWTableFrameSet *table = frameSet->getGroupManager(); emitChanged = checkCurrentEdit( table ? table : frameSet, onlyText ); if ( emitChanged ) // emitted after mousePressEvent [for tables] emit currentFrameSetEditChanged(); emit updateRuler(); } -void KWCanvas::editTextFrameSet( KWFrameSet * fs, KoTextParag* parag, int index , bool forceEdit) +void KWCanvas::editTextFrameSet( KWFrameSet * fs, KoTextParag* parag, int index ) { if ( selectAllFrames( false ) ) emit frameSelectedChanged(); //active header/footer when it's possible if ( fs->isAHeader() && !m_doc->isHeaderVisible() && !(viewMode()->type()=="ModeText")) m_doc->setHeaderVisible( true ); if ( fs->isAFooter() && !m_doc->isFooterVisible() && !(viewMode()->type()=="ModeText")) m_doc->setFooterVisible( true ); if ( !fs->isVisible( viewMode() ) ) return; setMouseMode( MM_EDIT ); KWTableFrameSet *table = fs->getGroupManager(); bool emitChanged = checkCurrentEdit( table ? table : fs ); - if ( emitChanged || forceEdit) { // emitted after mousePressEvent [for tables] - if ( m_currentFrameSetEdit && m_currentFrameSetEdit->frameSet()->type()==FT_TEXT ) { - if ( !parag ) - { - KWTextDocument *tmp = static_cast(m_currentFrameSetEdit->frameSet())->kwTextDocument(); - parag = tmp->firstParag(); - } - static_cast( m_currentFrameSetEdit )->setCursor( parag, index ); - - // The _new_ cursor position must be visible. - KWTextFrameSetEdit *textedit=dynamic_cast(m_currentFrameSetEdit->currentTextEdit()); - if ( textedit ) - textedit->ensureCursorVisible(); + if ( m_currentFrameSetEdit && m_currentFrameSetEdit->frameSet()->type()==FT_TEXT ) { + if ( !parag ) + { + KWTextDocument *tmp = static_cast(m_currentFrameSetEdit->frameSet())->kwTextDocument(); + parag = tmp->firstParag(); + } + // The _new_ cursor position must be visible. + KWTextFrameSetEdit *textedit=dynamic_cast(m_currentFrameSetEdit->currentTextEdit()); + if ( textedit ) { + textedit->hideCursor(); + textedit->setCursor( parag, index ); + textedit->showCursor(); + textedit->ensureCursorVisible(); } - emit currentFrameSetEditChanged(); } + if ( emitChanged ) + emit currentFrameSetEditChanged(); emit updateRuler(); } bool KWCanvas::checkCurrentEdit( KWFrameSet * fs , bool onlyText ) { bool emitChanged = false; if ( fs && m_currentFrameSetEdit && m_currentFrameSetEdit->frameSet() != fs ) { KWTextFrameSet * tmp = dynamic_cast(fs ); if ( tmp && tmp->protectContent() && !m_doc->cursorInProtectedArea() ) return false; KWTextFrameSetEdit *edit=dynamic_cast(m_currentFrameSetEdit->currentTextEdit()); if(edit && onlyText) { // Don't use terminateCurrentEdit here, we want to emit changed only once //don't remove selection in dnd m_currentFrameSetEdit->terminate(false); } else m_currentFrameSetEdit->terminate(); delete m_currentFrameSetEdit; m_currentFrameSetEdit = 0L; emitChanged = true; } // Edit the frameset "fs" if ( fs && !m_currentFrameSetEdit ) { KWTextFrameSet * tmp = dynamic_cast(fs ); if ( tmp && tmp->protectContent() && !m_doc->cursorInProtectedArea() ) return false; //just text frameset if(fs->type()==FT_TABLE || fs->type()==FT_TEXT || !onlyText) { m_currentFrameSetEdit = fs->createFrameSetEdit( this ); } // Display page number in statusbar. gui()->getView()->updatePageInfo(); emitChanged = true; } return emitChanged; } void KWCanvas::terminateCurrentEdit() { m_currentFrameSetEdit->terminate(); delete m_currentFrameSetEdit; m_currentFrameSetEdit = 0L; emit currentFrameSetEditChanged(); repaintAll(); } void KWCanvas::terminateEditing( KWFrameSet *fs ) { if ( m_currentFrameSetEdit && m_currentFrameSetEdit->frameSet() == fs ) terminateCurrentEdit(); // Also deselect the frames from this frameset QPtrListIterator frameIt = fs->frameIterator(); for ( ; frameIt.current(); ++frameIt ) if ( frameIt.current()->isSelected() ) frameIt.current()->setSelected( false ); } void KWCanvas::setMouseMode( MouseMode newMouseMode ) { if ( m_mouseMode != newMouseMode ) { if ( selectAllFrames( false ) ) emit frameSelectedChanged(); if ( newMouseMode != MM_EDIT ) { // Terminate edition of current frameset if ( m_currentFrameSetEdit ) terminateCurrentEdit(); } } m_mouseMode = newMouseMode; emit currentMouseModeChanged(m_mouseMode); switch ( m_mouseMode ) { case MM_EDIT: { QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() ); QPoint normalPoint = m_viewMode->viewToNormal( mousep ); viewport()->setCursor( m_doc->getMouseCursor( normalPoint, false /*....*/ ) ); } break; case MM_CREATE_TEXT: case MM_CREATE_PIX: case MM_CREATE_TABLE: case MM_CREATE_FORMULA: case MM_CREATE_PART: viewport()->setCursor( crossCursor ); break; } } void KWCanvas::insertPicture( const KoPicture& newPicture, QSize pixmapSize, bool _keepRatio ) { setMouseMode( MM_CREATE_PIX ); m_kopicture = newPicture; m_pixmapSize = pixmapSize; if ( pixmapSize.isEmpty() ) m_pixmapSize = newPicture.getOriginalSize(); m_keepRatio = _keepRatio; } void KWCanvas::insertPart( const KoDocumentEntry &entry ) { m_partEntry = entry; if ( m_partEntry.isEmpty() ) { setMouseMode( MM_EDIT ); return; } setMouseMode( MM_CREATE_PART ); } void KWCanvas::contentsDragEnterEvent( QDragEnterEvent *e ) { bool providesImage, providesKWordText, providesKWord, providesFormula; KWView::checkClipboard( e, providesImage, providesKWordText, providesKWord, providesFormula ); if ( providesImage ) { m_imageDrag = true; e->acceptAction(); } else { m_imageDrag = false; if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->dragEnterEvent( e ); } } void KWCanvas::contentsDragMoveEvent( QDragMoveEvent *e ) { if ( !m_imageDrag /*&& m_currentFrameSetEdit*/ ) { QPoint normalPoint = m_viewMode->viewToNormal( e->pos() ); KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); KWFrame * frame = m_doc->frameUnderMouse( normalPoint ); KWFrameSet * fs = frame ? frame->frameSet() : 0L; bool emitChanged = false; if ( fs ) { KWTableFrameSet *table = fs->getGroupManager(); //kdDebug()<<"table :"<dragMoveEvent( e, normalPoint, docPoint ); if ( emitChanged ) // emitted after mousePressEvent [for tables] emit currentFrameSetEditChanged(); } } } void KWCanvas::contentsDragLeaveEvent( QDragLeaveEvent *e ) { if ( !m_imageDrag && m_currentFrameSetEdit ) m_currentFrameSetEdit->dragLeaveEvent( e ); } void KWCanvas::contentsDropEvent( QDropEvent *e ) { QPoint normalPoint = m_viewMode->viewToNormal( e->pos() ); KoPoint docPoint = m_doc->unzoomPoint( normalPoint ); if ( m_imageDrag ) { pasteImage( e, docPoint ); } else if ( m_currentFrameSetEdit ) { m_currentFrameSetEdit->dropEvent( e, normalPoint, docPoint ); } m_mousePressed = false; m_imageDrag = false; } void KWCanvas::pasteImage( QMimeSource *e, const KoPoint &docPoint ) { QImage i; QImageDrag::decode(e, i); KTempFile tmpFile( QString::null, ".png"); tmpFile.setAutoDelete( true ); i.save(tmpFile.name(), "PNG"); m_pixmapSize = i.size(); // Prepare things for mrCreatePixmap KoPictureKey key; key.setKeyFromFile( tmpFile.name() ); m_kopicture.setKey( key ); m_kopicture.loadFromFile( tmpFile.name() ); m_insRect = KoRect( docPoint.x(), docPoint.y(), m_doc->unzoomItX( i.width() ), m_doc->unzoomItY( i.height() ) ); m_keepRatio = true; mrCreatePixmap(); } void KWCanvas::doAutoScroll() { if ( !m_mousePressed ) { m_scrollTimer->stop(); return; } // This code comes from khtml QPoint pos( mapFromGlobal( QCursor::pos() ) ); pos = QPoint(pos.x() - viewport()->x(), pos.y() - viewport()->y()); if ( (pos.y() < 0) || (pos.y() > visibleHeight()) || (pos.x() < 0) || (pos.x() > visibleWidth()) ) { int xm, ym; viewportToContents(pos.x(), pos.y(), xm, ym); if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->focusOutEvent(); // Hide cursor if ( m_deleteMovingRect ) deleteMovingRect(); ensureVisible( xm, ym, 0, 5 ); if ( m_currentFrameSetEdit ) m_currentFrameSetEdit->focusInEvent(); // Show cursor } } void KWCanvas::slotContentsMoving( int cx, int cy ) { //QPoint nPointTop = m_viewMode->viewToNormal( QPoint( cx, cy ) ); QPoint nPointBottom = m_viewMode->viewToNormal( QPoint( cx + visibleWidth(), cy + visibleHeight() ) ); //kdDebug() << "KWCanvas::slotContentsMoving cx=" << cx << " cy=" << cy << endl; //kdDebug() << " visibleWidth()=" << visibleWidth() << " visibleHeight()=" << visibleHeight() << endl; // Update our "formatted paragraphs needs" in the text framesets ///////////////// TODO: use allTextFramesets for nested text framesets QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { if(! fit.current()->isVisible()) continue; KWTextFrameSet * fs = dynamic_cast(fit.current()); if ( fs ) { fs->updateViewArea( this, m_viewMode, nPointBottom ); } } // cx and cy contain the future values for contentsx and contentsy, so we need to // pass them to updateRulerOffsets. updateRulerOffsets( cx, cy ); } void KWCanvas::slotMainTextHeightChanged() { // Check that the viewmode is a KWViewModeText, and that the rulers have been built already if ( dynamic_cast(m_viewMode) && m_gui->getHorzRuler() ) { slotNewContentsSize(); m_viewMode->setPageLayout( m_gui->getHorzRuler(), m_gui->getVertRuler(), KoPageLayout() /*unused*/ ); emit updateRuler(); } } void KWCanvas::slotNewContentsSize() { QSize size = m_viewMode->contentsSize(); if ( size != QSize( contentsWidth(), contentsHeight() ) ) { //kdDebug() << "KWCanvas::slotNewContentsSize " << size.width() << "x" << size.height() << endl; resizeContents( size.width(), size.height() ); } } void KWCanvas::resizeEvent( QResizeEvent *e ) { slotContentsMoving( contentsX(), contentsY() ); QScrollView::resizeEvent( e ); } void KWCanvas::scrollToOffset( const KoPoint & d ) { kdDebug() << "KWCanvas::scrollToOffset " << d.x() << "," << d.y() << endl; #if 0 bool blinking = blinkTimer.isActive(); if ( blinking ) stopBlinkCursor(); #endif QPoint nPoint = m_doc->zoomPoint( d ); QPoint cPoint = m_viewMode->normalToView( nPoint ); setContentsPos( cPoint.x(), cPoint.y() ); #if 0 if ( blinking ) startBlinkCursor(); #endif } void KWCanvas::updateRulerOffsets( int cx, int cy ) { if ( cx == -1 && cy == -1 ) { cx = contentsX(); cy = contentsY(); } // The offset is usually just the scrollview offset // But we also need to offset to the current page, for the graduations QPoint pc = m_viewMode->pageCorner(this); //kdDebug() << "KWCanvas::updateRulerOffsets contentsX=" << cx << ", contentsY=" << cy << endl; m_gui->getHorzRuler()->setOffset( cx - pc.x(), 0 ); m_gui->getVertRuler()->setOffset( 0, cy - pc.y() ); } bool KWCanvas::eventFilter( QObject *o, QEvent *e ) { if ( !o || !e ) return TRUE; if ( o == this || o == viewport() ) { if(m_currentFrameSetEdit) { // Pass event to auto-hide-cursor code (see kcursor.h for details) KCursor::autoHideEventFilter( o, e ); } switch ( e->type() ) { case QEvent::FocusIn: // kdDebug() << "KWCanvas::eventFilter QEvent::FocusIn" << endl; if ( m_currentFrameSetEdit && !m_printing ) m_currentFrameSetEdit->focusInEvent(); return TRUE; case QEvent::FocusOut: // kdDebug() << "KWCanvas::eventFilter QEvent::FocusOut" << endl; if ( m_currentFrameSetEdit && !m_printing ) m_currentFrameSetEdit->focusOutEvent(); if ( m_scrollTimer->isActive() ) m_scrollTimer->stop(); m_mousePressed = false; return TRUE; case QEvent::KeyPress: { // kdDebug() << " KeyPress m_currentFrameSetEdit=" << m_currentFrameSetEdit << " isRW="<isReadWrite() << endl; // kdDebug() << " m_printing=" << m_printing << " mousemode=" << m_mouseMode << " (MM_EDIT=" << MM_EDIT<<")"<(e); #ifndef NDEBUG // Debug keys if ( ( keyev->state() & ControlButton ) && ( keyev->state() & ShiftButton ) ) { switch ( keyev->key() ) { case Key_P: // 'P' -> paragraph debug printRTDebug( 0 ); break; case Key_V: // 'V' -> verbose parag debug printRTDebug( 1 ); break; case Key_F: // 'F' -> frames debug m_doc->printDebug(); kdDebug(32002) << "Current framesetedit: " << m_currentFrameSetEdit << " " << ( m_currentFrameSetEdit ? m_currentFrameSetEdit->frameSet()->className() : "" ) << endl; break; case Key_S: // 'S' -> styles debug m_doc->printStyleDebug(); break; default: break; }; // For some reason 'T' doesn't work (maybe kxkb) } #endif // By default PgUp and PgDown move the scrollbars and not the caret anymore - this is done here if ( !m_doc->pgUpDownMovesCaret() && ( (keyev->state() & ShiftButton) == 0 ) && ( keyev->key() == Key_PageUp || keyev->key() == Key_PageDown ) ) { if ( keyev->key() == Key_PageUp ) setContentsPos( contentsX(), contentsY() - visibleHeight() ); else // Key_PageDown setContentsPos( contentsX(), contentsY() + visibleHeight() ); } else if ( keyev->key() == Key_Escape && m_mouseMode != MM_EDIT ) { // Abort frame creation setMouseMode( MM_EDIT ); } else // normal key processing if ( m_currentFrameSetEdit && m_mouseMode == MM_EDIT && m_doc->isReadWrite() && !m_printing ) { KWTextFrameSetEdit *edit = dynamic_cast(m_currentFrameSetEdit ); if ( edit ) { if ( !edit->textFrameSet()->textObject()->protectContent() || (keyev->text().length() == 0)) m_currentFrameSetEdit->keyPressEvent( keyev ); else if(keyev->text().length() > 0) KMessageBox::information(this, i18n("Read-only content cannot be changed. No modifications will be accepted.")); } else m_currentFrameSetEdit->keyPressEvent( keyev ); return TRUE; } // Because of the dependency on the control key, we need to update the mouse cursor here if ( keyev->key() == Key_Control ) { QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() ); QPoint normalPoint = m_viewMode->viewToNormal( mousep ); viewport()->setCursor( m_doc->getMouseCursor( normalPoint, true ) ); } else if ( (keyev->key() == Key_Delete || keyev->key() ==Key_Backspace ) && m_doc->getFirstSelectedFrame() && !m_printing ) { m_gui->getView()->editDeleteFrame(); } } break; case QEvent::KeyRelease: { QKeyEvent * keyev = static_cast(e); if ( keyev->key() == Key_Control ) { QPoint mousep = mapFromGlobal(QCursor::pos()) + QPoint( contentsX(), contentsY() ); QPoint normalPoint = m_viewMode->viewToNormal( mousep ); viewport()->setCursor( m_doc->getMouseCursor( normalPoint, false ) ); } if ( m_currentFrameSetEdit && m_mouseMode == MM_EDIT && m_doc->isReadWrite() && !m_printing ) { m_currentFrameSetEdit->keyReleaseEvent( keyev ); return TRUE; } } break; default: break; } } return QScrollView::eventFilter( o, e ); } bool KWCanvas::focusNextPrevChild( bool ) { return TRUE; // Don't allow to go out of the canvas widget by pressing "Tab" } void KWCanvas::updateCurrentFormat() { KWTextFrameSetEdit * edit = dynamic_cast(m_currentFrameSetEdit); if ( edit ) edit->updateUI( true, true ); } void KWCanvas::emitFrameSelectedChanged() { emit frameSelectedChanged(); } #ifndef NDEBUG void KWCanvas::printRTDebug( int info ) { KWTextFrameSet * textfs = 0L; if ( m_currentFrameSetEdit ) textfs = dynamic_cast(m_currentFrameSetEdit->frameSet()); if ( !textfs ) textfs = dynamic_cast(m_doc->frameSet( 0 )); if ( textfs ) textfs->textObject()->printRTDebug( info ); } #endif void KWCanvas::setXimPosition( int x, int y, int w, int h ) { QWidget::setMicroFocusHint( x - contentsX(), y - contentsY(), w, h ); } void KWCanvas::inlinePictureStarted() { m_frameInline=true; m_frameInlineType=FT_PICTURE; } #include "kwcanvas.moc" diff --git a/kword/kwcanvas.h b/kword/kwcanvas.h index 3bdd4eda18..4bdfe25762 100644 --- a/kword/kwcanvas.h +++ b/kword/kwcanvas.h @@ -1,345 +1,347 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Reginald Stadlbauer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef KWCANVAS_H #define KWCANVAS_H #include #include #include #include #include #include #include #include "kwtextparag.h" #include "kwframe.h" #include class KWDocument; class KWFrame; class KWFrameSet; class KWFrameSetEdit; class KWTextFrameSet; class KWTableFrameSet; class KWFrameMoveCommand; class KWViewMode; class KoTextCursor; class KoTextParag; class KoTextFormat; class KoTextDocument; class QTimer; class KWGUI; class KWStyle; class KWAnchor; class KWTableTemplate; /** * Class: KWCanvas * This class is responsible for the rendering of the frames to * the screen as well as the interaction with the user via mouse * and keyboard. There is one per view. */ class KWCanvas : public QScrollView { Q_OBJECT public: KWCanvas(KWViewMode* viewMode, QWidget *parent, KWDocument *d, KWGUI *lGui); virtual ~KWCanvas(); KWDocument * kWordDocument() const { return m_doc; } KWGUI * gui() const { return m_gui; } KWFrameSetEdit *currentFrameSetEdit() const { return m_currentFrameSetEdit; } void switchViewMode( KWViewMode * newViewMode ); KWViewMode *viewMode() const { return m_viewMode; } void repaintAll( bool erase = false ); /** * Only repaint the frameset @p fs. * @p resetChanged should only be true for the last view * (see KWFrameSet::drawContents) */ void repaintChanged( KWFrameSet * fs, bool resetChanged ); void print( QPainter *painter, KPrinter *printer ); bool eventFilter( QObject *o, QEvent *e ); bool focusNextPrevChild( bool ); /** * set frame border. Sets frame border to newBorder, or to 0 if on==false. */ KCommand *setLeftFrameBorder( KoBorder newBorder, bool on ); KCommand *setRightFrameBorder( KoBorder newBorder, bool on ); KCommand *setTopFrameBorder( KoBorder newBorder, bool on ); KCommand *setBottomFrameBorder( KoBorder newBorder, bool on ); void setFrameBackgroundColor( const QBrush &backColor ); void editFrameProperties(); void editFrameProperties( KWFrameSet * frameset ); void copySelectedFrames(); void cutSelectedFrames(); void pasteFrames(); // Mouse press void mpEditFrame( QMouseEvent *e, const QPoint& nPoint, MouseMeaning meaning ); void mpCreate( const QPoint& normalPoint ); void mpCreatePixmap( const QPoint& normalPoint ); // Mouse move void mmEditFrameResize( bool top, bool bottom, bool left, bool right, bool noGrid ); void mmEditFrameMove( const QPoint &normalPoint, bool shiftPressed ); void mmCreate( const QPoint& normalPoint, bool shiftPressed ); // Mouse release void mrEditFrame( QMouseEvent *e, const QPoint &nPoint ); void mrCreateText(); void mrCreatePixmap(); void mrCreatePart(); void mrCreateFormula(); void mrCreateTable(); enum MouseMode { MM_EDIT = 0, MM_CREATE_TEXT = 2, MM_CREATE_PIX = 3, MM_CREATE_TABLE = 5, MM_CREATE_FORMULA = 6, MM_CREATE_PART = 7 }; void setMouseMode( MouseMode _mm ); MouseMode mouseMode()const { return m_mouseMode; } void insertPicture( const KoPicture& newPicture, QSize pixmapSize, bool _keepRatio ); void insertPart( const KoDocumentEntry &entry ); void pasteImage( QMimeSource *e, const KoPoint &docPoint ); void updateCurrentFormat(); void updateFrameFormat(); // Table creation support - methods used by KWView to reuse the last settings unsigned int tableRows() const { return m_table.rows; } void setTableRows( unsigned int rows ) { m_table.rows=rows; } unsigned int tableCols() const { return m_table.cols; } void setTableCols( unsigned int cols ) { m_table.cols=cols; } int tableWidthMode()const { return m_table.width; } int tableHeightMode()const { return m_table.height; } bool tableIsFloating()const { return m_table.floating; } int tableFormat()const { return m_table.format;} void setTableFormat(int _nb){ m_table.format=_nb;} unsigned int splitCellRows()const{return m_tableSplit.nbRows;} unsigned int splitCellCols()const{return m_tableSplit.nbCols;} void setSplitCellRows(unsigned int _nb){ m_tableSplit.nbRows=_nb;} void setSplitCellCols(unsigned int _nb){ m_tableSplit.nbCols=_nb;} QString tableTemplateName()const { return m_table.tableTemplateName;} void setTableTemplateName(const QString &_name) { m_table.tableTemplateName=_name;} void setPictureInline( bool _inline) { m_picture.pictureInline = _inline;} bool pictureInline() const { return m_picture.pictureInline; } void setPictureKeepRatio( bool _keep) { m_picture.keepRatio = _keep;} bool pictureKeepRatio() const { return m_picture.keepRatio; } void createTable( unsigned int rows, unsigned int cols, int /*KWTableFrameSet::CellSize*/ wid, int /*KWTableFrameSet::CellSize*/ hei, bool isFloating, KWTableTemplate *tt=0L, int format=31 ); KWTableFrameSet * getTable(); KWTableFrameSet *getCurrentTable()const { return curTable; } //move canvas to show point dPoint (in doc coordinates) void scrollToOffset( const KoPoint & dPoint ); //for KWTextFrameSetEdit void dragStarted() { m_mousePressed = false; } void emitFrameSelectedChanged(); void setXimPosition( int x, int y, int w, int h ); void updateRulerOffsets( int cx = -1, int cy = -1 ); void inlinePictureStarted(); - void editFrameSet( KWFrameSet * frameSet,bool onlyText = false ); - // forceEdit : necessary otherwise we can move cursor into - //a frame which is edited - void editTextFrameSet( KWFrameSet * fs, KoTextParag* parag, int index, bool forceEdit=false ); - bool checkCurrentEdit( KWFrameSet * fs , bool onlyText = false); + void editFrameSet( KWFrameSet * frameSet, bool onlyText = false ); + /** + * Starting editing @p fs if we're not yet doing it. + * In all cases, position the cursor at @p parag and @p index. + */ + void editTextFrameSet( KWFrameSet * fs, KoTextParag* parag, int index ); + bool checkCurrentEdit( KWFrameSet * fs, bool onlyText = false); NoteType footNoteType()const{return m_footEndNote.noteType;} KWFootNoteVariable::Numbering numberingFootNoteType() const { return m_footEndNote.numberingType;} void setFootNoteType( NoteType _type ) { m_footEndNote.noteType = _type; } void setNumberingFootNoteType(KWFootNoteVariable::Numbering _type) { m_footEndNote.numberingType = _type; } bool selectAllFrames( bool select ); KCommand * createTextBox(const KoRect & rect ); protected: void applyGrid( KoPoint &p ); void applyAspectRatio( double ratio, KoRect& insRect ); /** * Reimplemented from QScrollView, to draw the contents of the canvas */ virtual void drawContents( QPainter *p, int cx, int cy, int cw, int ch ); /** * The main drawing method. * @param painter guess * @param crect the area to be repainted, in contents coordinates * @param viewMode the view mode to be used (usually m_viewMode, except when printing) */ void drawDocument( QPainter *painter, const QRect &crect, KWViewMode* viewMode ); /** * Draw page borders, but also clear up the space between the frames and the page borders, * draw the page shadow, and the gray area. */ void drawPageBorders( QPainter * painter, const QRect & crect, const QRegion & emptySpaceRegion ); virtual void keyPressEvent( QKeyEvent *e ); virtual void contentsMousePressEvent( QMouseEvent *e ); virtual void contentsMouseMoveEvent( QMouseEvent *e ); virtual void contentsMouseReleaseEvent( QMouseEvent *e ); virtual void contentsMouseDoubleClickEvent( QMouseEvent *e ); virtual void contentsDragEnterEvent( QDragEnterEvent *e ); virtual void contentsDragMoveEvent( QDragMoveEvent *e ); virtual void contentsDragLeaveEvent( QDragLeaveEvent *e ); virtual void contentsDropEvent( QDropEvent *e ); virtual void resizeEvent( QResizeEvent *e ); void selectFrame( KWFrame* frame, bool select ); KWTableFrameSet * createTable(); // uses m_insRect and m_table to create the table void terminateCurrentEdit(); bool insertInlineTable(); signals: // Emitted when the current frameset edit changes void currentFrameSetEditChanged(); // Emitted by the current frameset edit when its selection changes void selectionChanged( bool hasSelection ); // Emitted when Mouse Mode changed void currentMouseModeChanged(int newMouseMode); // Emitted when frames have been selected or unselected (to disable/enable the UI in kwview) void frameSelectedChanged(); // Emitted when the document structure has changed // ### DF: IMHO this should be only emitted by KWDocument (e.g. addFrameSet) void docStructChanged(int _type); void updateRuler(); private slots: void slotContentsMoving( int, int ); void slotNewContentsSize(); void slotMainTextHeightChanged(); void doAutoScroll(); //Terminate editing this frameset, if we were editing it. void terminateEditing( KWFrameSet *fs ); private: /** * Draw the contents of one frameset * @param resetChanged whether the changed flag should be reset to false while redrawing */ void drawFrameSet( KWFrameSet * frameset, QPainter * painter, const QRect & crect, bool onlyChanged, bool resetChanged, KWViewMode* viewMode ); void drawMovingRect( QPainter & p ); void deleteMovingRect(); #ifndef NDEBUG void printRTDebug( int ); #endif KWDocument *m_doc; KWFrameSetEdit *m_currentFrameSetEdit; KWGUI *m_gui; QTimer *m_scrollTimer; bool m_mousePressed; bool m_printing; bool m_imageDrag; //define type of frame (for set inline frame) bool m_frameInline; FrameSetType m_frameInlineType; // Warning: the viewmode is stored here for good design ;) // but it's owned by the document, since we currently have one viewmode for all views. KWViewMode *m_viewMode; // Frame stuff MouseMode m_mouseMode; MouseMeaning m_mouseMeaning; // set by mousePress, used by mouseMove KoRect m_resizedFrameInitialSize; // when resizing a frame KoRect m_insRect; // when creating a new frame KoRect m_boundingRect; // when moving frame(s) KoPoint m_hotSpot; // when moving frame(s) bool m_deleteMovingRect, m_frameMoved, m_frameResized; bool m_ctrlClickOnSelectedFrame; KoPicture m_kopicture; // The picture QSize m_pixmapSize; // size when inserting a picture (not necessaraly the size of the picture) bool m_keepRatio;//when inserting a picture KoDocumentEntry m_partEntry; // when inserting a part // Table creation support. // Having this as a member variable allows to remember and reuse the last settings struct { unsigned int cols; unsigned int rows; int format; int /*KWTableFrameSet::CellSize*/ width; int /*KWTableFrameSet::CellSize*/ height; bool floating; QString tableTemplateName; KWTableTemplate *tt; } m_table; KWTableFrameSet *curTable; KWFrameMoveCommand *cmdMoveFrame; // Split cell in table struct { unsigned int nbCols; unsigned int nbRows; }m_tableSplit; struct { NoteType noteType; KWFootNoteVariable::Numbering numberingType; } m_footEndNote; struct { bool pictureInline; bool keepRatio; }m_picture; }; #endif diff --git a/kword/kwdoc.cc b/kword/kwdoc.cc index 8f2249e705..9e7a2f9cbd 100644 --- a/kword/kwdoc.cc +++ b/kword/kwdoc.cc @@ -1,4888 +1,4887 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Reginald Stadlbauer This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include #include // for KDE_VERSION #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "KWordDocIface.h" #include "defs.h" #include "kwbgspellcheck.h" #include "kwcanvas.h" #include "kwcommand.h" #include "kwdoc.h" #include "kwframelayout.h" #include "kwpartframeset.h" #include "kwtableframeset.h" #include "kwtablestyle.h" #include "kwtabletemplate.h" #include "kwtextimage.h" #include "kwvariable.h" #include "kwview.h" #include "kwviewmode.h" #include "mailmerge.h" #include #include #include "kocommandhistory.h" #ifdef HAVE_LIBASPELL #include #endif #define DEBUG_PAGES //#define DEBUG_SPEED // Make sure an appropriate DTD is available in www/koffice/DTD if changing this value static const char * CURRENT_DTD_VERSION = "1.2"; /******************************************************************/ /* Class: KWChild */ /******************************************************************/ KWChild::KWChild( KWDocument *_wdoc, const QRect& _rect, KoDocument *_doc ) : KoDocumentChild( _wdoc, _doc, _rect ), m_partFrameSet( 0L ) { } KWChild::KWChild( KWDocument *_wdoc ) : KoDocumentChild( _wdoc ), m_partFrameSet( 0L ) { } KWChild::~KWChild() { } KoDocument* KWChild::hitTest( const QPoint& p, const QWMatrix& _matrix ) { Q_ASSERT( m_partFrameSet ); if ( isDeleted() ) { //kdDebug() << k_funcinfo << "is deleted!" << endl; return 0L; } // Only activate when it's already selected. if ( !m_partFrameSet->frame(0)->isSelected() ) { //kdDebug() << k_funcinfo << " is not selected" << endl; return 0L; } // And only if CTRL isn't pressed. Window root; Window child; int root_x, root_y, win_x, win_y; uint keybstate; XQueryPointer( qt_xdisplay(), qt_xrootwin(), &root, &child, &root_x, &root_y, &win_x, &win_y, &keybstate ); if ( keybstate & ControlMask ) return 0L; return KoDocumentChild::hitTest( p, _matrix ); } /******************************************************************/ /* Class: KWCommandHistory */ /******************************************************************/ class KWCommandHistory : public KoCommandHistory { public: KWCommandHistory( KWDocument * doc ) : KoCommandHistory( doc->actionCollection(), true ), m_pDoc( doc ) {} public /*slots*/: // They are already slots in the parent. Running moc on the inherited class shouldn't be necessary AFAICS. virtual void undo(); virtual void redo(); private: KWDocument * m_pDoc; }; void KWCommandHistory::undo() { m_pDoc->clearUndoRedoInfos(); KoCommandHistory::undo(); } void KWCommandHistory::redo() { m_pDoc->clearUndoRedoInfos(); KoCommandHistory::redo(); } void KWDocument::clearUndoRedoInfos() { QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWTextFrameSet *fs = dynamic_cast( fit.current() ); if ( fs ) fs->clearUndoRedoInfo(); } } /** * Temporary storage for the initial edition info * (activeFrameset, cursorParagraph and cursorIndex attributes of the XML */ class KWDocument::InitialEditing { public: QString m_initialFrameSet; int m_initialCursorParag; int m_initialCursorIndex; }; KWBookMark::KWBookMark(const QString &_name) : m_name(_name), m_startParag(0L), m_endParag(0L), m_frameSet(0L), m_startIndex( 0 ), m_endIndex( 0) { } KWBookMark::KWBookMark(const QString &_name, KWTextParag *_startParag, KWTextParag *_endParag,KWFrameSet *_frameSet, int _pos, int _end) : m_name(_name), m_startParag(_startParag), m_endParag(_endParag), m_frameSet(_frameSet), m_startIndex( _pos ), m_endIndex( _end ) { } KWBookMark::~KWBookMark() { m_startParag=0L; m_endParag=0L; m_frameSet=0L; } /******************************************************************/ /* Class: KWDocument */ /******************************************************************/ const int KWDocument::CURRENT_SYNTAX_VERSION = 2; KWDocument::KWDocument(QWidget *parentWidget, const char *widgetName, QObject* parent, const char* name, bool singleViewMode ) : KoDocument( parentWidget, widgetName, parent, name, singleViewMode ), m_unit( KoUnit::U_MM ), m_urlIntern() { dcop = 0; m_tabStop = MM_TO_POINT( 15.0 ); bgFrameSpellChecked = 0L; m_processingType = WP; m_lstViews.setAutoDelete( false ); m_lstChildren.setAutoDelete( true ); // varFormats.setAutoDelete(true); m_lstFrameSet.setAutoDelete( true ); // m_textImageRequests does not create or delete the KWTextImage classes m_textImageRequests.setAutoDelete(false); m_bookmarkList.setAutoDelete( true ); m_styleColl=new KoStyleCollection(); m_frameStyleColl = new KWFrameStyleCollection(); m_tableStyleColl = new KWTableStyleCollection(); m_tableTemplateColl = new KWTableTemplateCollection(); m_personalExpressionPath = KWFactory::global()->dirs()->resourceDirs("expression"); m_picturePath= KGlobalSettings::documentPath(); m_horizontalLinePath = KWFactory::global()->dirs()->resourceDirs("horizontalLine"); setInstance( KWFactory::global(), false ); m_gridX = m_gridY = 10.0; m_indent = MM_TO_POINT( 10.0 ); m_iNbPagePerRow = 4; m_maxRecentFiles = 10; m_defaultColumnSpacing=3; m_bShowRuler = true; m_footNoteSeparatorLinePos=SLP_LEFT; //by default it's 1/5 m_iFootNoteSeparatorLineLength = 20; m_footNoteSeparatorLineWidth = 2.0; m_footNoteSeparatorLineType = SLT_SOLID; m_viewFormattingChars = false; m_viewFormattingEndParag = true; m_viewFormattingSpace = true; m_viewFormattingTabs = true; m_viewFormattingBreak = true; m_viewFrameBorders = true; m_repaintAllViewsPending = false; m_recalcFramesPending = -1; m_bShowDocStruct = true; m_bShowRuler = true; m_bDontCheckUpperWord = false; m_bDontCheckTitleCase = false; m_bShowStatusBar = true; m_bAllowAutoFormat = true; m_pgUpDownMovesCaret = false; m_bShowScrollBar = true; m_cursorInProtectectedArea = true; m_bHasEndNotes = false; m_bInsertDirectCursor=false; m_globalLanguage = KGlobal::locale()->language(); m_lastViewMode="ModeNormal"; m_viewMode = 0; m_commandHistory = new KWCommandHistory( this ); connect( m_commandHistory, SIGNAL( documentRestored() ), this, SLOT( slotDocumentRestored() ) ); connect( m_commandHistory, SIGNAL( commandExecuted() ), this, SLOT( slotCommandExecuted() ) ); setEmpty(); setModified(false); //styleMask = U_FONT_FAMILY_ALL_SIZE | U_COLOR | U_BORDER | U_INDENT | // U_NUMBERING | U_ALIGN | U_TABS | U_SMART; m_headerVisible = false; m_footerVisible = false; m_pasteFramesetsMap = 0L; m_initialEditing = 0L; m_bufPixmap = 0L; m_varFormatCollection = new KoVariableFormatCollection; m_varColl=new KWVariableCollection(new KWVariableSettings() ); m_autoFormat = new KoAutoFormat(this,m_varColl,m_varFormatCollection ); m_bgSpellCheck = new KWBgSpellCheck(this); m_formulaDocument = 0L; // created on demand m_slDataBase = new KWMailMergeDataBase( this ); slRecordNum = -1; m_syntaxVersion = CURRENT_SYNTAX_VERSION; m_pKSpellConfig=0; #ifdef HAVE_LIBASPELL m_pKOSpellConfig = 0; #endif m_hasTOC=false; initConfig(); // Get default font from the KWord config file KConfig *config = KWFactory::global()->config(); config->setGroup("Document defaults" ); QString defaultFontname=config->readEntry("DefaultFont"); if ( !defaultFontname.isEmpty() ) m_defaultFont.fromString( defaultFontname ); // If not found, we automatically fallback to the application font (the one from KControl's font module) // Try to force a scalable font. m_defaultFont.setStyleStrategy( QFont::ForceOutline ); //kdDebug() << "Default font: requested family: " << m_defaultFont.family() << endl; //kdDebug() << "Default font: real family: " << QFontInfo(m_defaultFont).family() << endl; int ptSize = m_defaultFont.pointSize(); if ( ptSize == -1 ) // specified with a pixel size ? ptSize = QFontInfo(m_defaultFont).pointSize(); // Some simple import filters don't define any style, // so let's have a Standard style at least KWStyle * standardStyle = new KWStyle( "Standard" ); // This gets translated later on //kdDebug() << "KWDocument::KWDocument creating standardStyle " << standardStyle << endl; standardStyle->format().setFont( m_defaultFont ); m_styleColl->addStyleTemplate( standardStyle ); // And let's do the same for framestyles KWFrameStyle * standardFrameStyle = new KWFrameStyle( "Plain" ); standardFrameStyle->setBackgroundColor(QColor("white")); standardFrameStyle->setTopBorder(KoBorder(QColor("black"),KoBorder::SOLID,0)); standardFrameStyle->setRightBorder(KoBorder(QColor("black"),KoBorder::SOLID,0)); standardFrameStyle->setLeftBorder(KoBorder(QColor("black"),KoBorder::SOLID,0)); standardFrameStyle->setBottomBorder(KoBorder(QColor("black"),KoBorder::SOLID,0)); m_frameStyleColl->addFrameStyleTemplate( standardFrameStyle ); // And let's do the same for tablestyles KWTableStyle *standardTableStyle = new KWTableStyle( "Plain", standardStyle, standardFrameStyle ); m_tableStyleColl->addTableStyleTemplate( standardTableStyle ); if ( name ) dcopObject(); connect(m_varColl,SIGNAL(repaintVariable()),this,SLOT(slotRepaintVariable())); // It's important to call this to have the kformula actions created. getFormulaDocument(); } /*==============================================================*/ DCOPObject* KWDocument::dcopObject() { if ( !dcop ) dcop = new KWordDocIface( this ); return dcop; } KWDocument::~KWDocument() { //don't save config when kword is embedded into konqueror if(isReadWrite()) saveConfig(); // formula frames have to be deleted before m_formulaDocument m_lstFrameSet.clear(); m_bookmarkList.clear(); m_tmpBookMarkList.clear(); delete m_autoFormat; delete m_formulaDocument; delete m_commandHistory; delete m_varColl; delete m_varFormatCollection; delete m_slDataBase; delete dcop; delete m_bgSpellCheck; delete m_styleColl; delete m_frameStyleColl; delete m_tableStyleColl; delete m_tableTemplateColl; delete m_pKSpellConfig; #ifdef HAVE_LIBASPELL delete m_pKOSpellConfig; #endif delete m_viewMode; delete m_bufPixmap; } void KWDocument::initConfig() { KConfig *config = KWFactory::global()->config(); KSpellConfig ksconfig; #ifdef HAVE_LIBASPELL KOSpellConfig kosconfig; #endif if( config->hasGroup("KSpell kword" ) ) { config->setGroup( "KSpell kword" ); ksconfig.setNoRootAffix(config->readNumEntry ("KSpell_NoRootAffix", 0)); ksconfig.setRunTogether(config->readNumEntry ("KSpell_RunTogether", 0)); ksconfig.setDictionary(config->readEntry ("KSpell_Dictionary", "")); ksconfig.setDictFromList(config->readNumEntry ("KSpell_DictFromList", FALSE)); ksconfig.setEncoding(config->readNumEntry ("KSpell_Encoding", KS_E_ASCII)); ksconfig.setClient(config->readNumEntry ("KSpell_Client", KS_CLIENT_ISPELL)); #ifdef HAVE_LIBASPELL kosconfig.setNoRootAffix(config->readNumEntry ("KSpell_NoRootAffix", 0)); kosconfig.setRunTogether(config->readNumEntry ("KSpell_RunTogether", 0)); kosconfig.setDictionary(config->readEntry ("KSpell_Dictionary", "")); kosconfig.setDictFromList(config->readNumEntry ("KSpell_DictFromList", FALSE)); kosconfig.setEncoding(config->readNumEntry ("KSpell_Encoding", KS_E_ASCII)); setKOSpellConfig( kosconfig ); #endif setKSpellConfig(ksconfig); setDontCheckUpperWord(config->readBoolEntry("KSpell_dont_check_upper_word",false)); setDontCheckTitleCase(config->readBoolEntry("KSpell_dont_check_title_case",false)); // Default is false for spellcheck, but the spell-check config dialog // should write out "true" when the user configures spell checking. if ( isReadWrite() ) m_bgSpellCheck->enableBackgroundSpellCheck(config->readBoolEntry( "SpellCheck", false )); else m_bgSpellCheck->enableBackgroundSpellCheck( false ); } if(config->hasGroup("Interface" ) ) { config->setGroup( "Interface" ); setGridY(QMAX( config->readDoubleNumEntry("GridY",10.0), 0.1)); setGridX(QMAX( config->readDoubleNumEntry("GridX",10.0), 0.1)); setCursorInProtectedArea( config->readBoolEntry( "cursorInProtectArea", true )); // Config-file value in mm, default 10 pt double indent = config->readDoubleNumEntry("Indent", MM_TO_POINT(10.0) ) ; setIndentValue(indent); setShowRuler(config->readBoolEntry("Rulers",true)); int defaultAutoSave = KoDocument::defaultAutoSave()/60; // in minutes setAutoSave(config->readNumEntry("AutoSave",defaultAutoSave)*60); // read key in minutes, call setAutoSave(seconds) setBackupFile( config->readNumEntry("BackupFile", true)); setNbPagePerRow(config->readNumEntry("nbPagePerRow",4)); m_maxRecentFiles = config->readNumEntry( "NbRecentFile", 10 ); m_viewFormattingChars = config->readBoolEntry( "ViewFormattingChars", false ); m_viewFormattingBreak = config->readBoolEntry( "ViewFormattingBreaks", true ); m_viewFormattingSpace = config->readBoolEntry( "ViewFormattingSpace", true ); m_viewFormattingEndParag = config->readBoolEntry( "ViewFormattingEndParag", true ); m_viewFormattingTabs = config->readBoolEntry( "ViewFormattingTabs", true ); m_viewFrameBorders = config->readBoolEntry( "ViewFrameBorders", true ); m_zoom = config->readNumEntry( "Zoom", 100 ); m_bShowDocStruct = config->readBoolEntry( "showDocStruct", true ); m_lastViewMode = config->readEntry( "viewmode", "ModeNormal" ); setShowStatusBar( config->readBoolEntry( "ShowStatusBar" , true ) ); setAllowAutoFormat( config->readBoolEntry( "AllowAutoFormat" , true ) ); setShowScrollBar( config->readBoolEntry( "ShowScrollBar", true ) ); if ( isEmbedded() ) m_bShowDocStruct = false; // off by default for embedded docs, but still toggleable m_pgUpDownMovesCaret = config->readBoolEntry( "PgUpDownMovesCaret", false ); m_bInsertDirectCursor= config->readBoolEntry( "InsertDirectCursor", false ); m_globalLanguage=config->readEntry("language", KGlobal::locale()->language()); } else m_zoom = 100; int undo=30; if(config->hasGroup("Misc" ) ) { config->setGroup( "Misc" ); undo=config->readNumEntry("UndoRedo",-1); } if(undo!=-1) setUndoRedoLimit(undo); setZoomAndResolution( m_zoom, QPaintDevice::x11AppDpiX(), QPaintDevice::x11AppDpiY() ); //text mode view is not a good default for a readonly document... if ( !isReadWrite() && m_lastViewMode =="ModeText" ) m_lastViewMode= "ModeNormal"; m_viewMode = KWViewMode::create( m_lastViewMode, this ); if(config->hasGroup("Kword Path" ) ) { config->setGroup( "Kword Path" ); m_personalExpressionPath=config->readListEntry( "expression path"/*,KWFactory::global()->dirs()->resourceDirs("expression")*/ ); m_horizontalLinePath=config->readListEntry( "horizontal line path"/*,KWFactory::global()->dirs()->resourceDirs("expression")*/ ); m_picturePath=config->readEntry( "picture path",KGlobalSettings::documentPath()); setBackupPath(config->readEntry( "backup path", QString::null )); } } void KWDocument::saveConfig() { if ( isEmbedded() || !isReadWrite() ) return; // Only save the config that is manipulated by the UI directly. // The config from the config dialog is saved by the dialog itself. KConfig *config = KWFactory::global()->config(); config->setGroup( "Interface" ); config->writeEntry( "ViewFormattingChars", m_viewFormattingChars ); config->writeEntry( "ViewFormattingBreaks", m_viewFormattingBreak ); config->writeEntry( "ViewFormattingEndParag", m_viewFormattingEndParag ); config->writeEntry( "ViewFormattingTabs", m_viewFormattingTabs ); config->writeEntry( "ViewFormattingSpace", m_viewFormattingSpace ); config->writeEntry( "ViewFrameBorders", m_viewFrameBorders ); config->writeEntry( "Zoom", m_zoom ); config->writeEntry( "showDocStruct", m_bShowDocStruct); config->writeEntry( "Rulers", m_bShowRuler); config->writeEntry( "viewmode", m_lastViewMode); config->writeEntry( "AllowAutoFormat", m_bAllowAutoFormat ); } void KWDocument::setZoomAndResolution( int zoom, int dpiX, int dpiY ) { KoZoomHandler::setZoomAndResolution( zoom, dpiX, dpiY ); if ( m_formulaDocument ) m_formulaDocument->setZoomAndResolution( zoom, dpiX, dpiY ); } KWTextFrameSet * KWDocument::textFrameSet ( unsigned int _num ) const { unsigned int i=0; QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { if(fit.current()->isDeleted()) continue; if(fit.current()->type()==FT_TEXT) { if(i==_num) return static_cast(fit.current()); i++; } } return static_cast(m_lstFrameSet.getFirst()); } void KWDocument::newZoomAndResolution( bool updateViews, bool forPrint ) { if ( m_formulaDocument ) m_formulaDocument->newZoomAndResolution( updateViews,forPrint ); #if 0 QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) fit.current()->zoom( forPrint ); #endif layout(); updateAllFrames(); if ( updateViews ) { emit newContentsSize(); repaintAllViews( true ); } } bool KWDocument::initDoc() { m_pages = 1; m_pageColumns.columns = 1; m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; m_pageHeaderFooter.header = HF_SAME; m_pageHeaderFooter.footer = HF_SAME; m_pageHeaderFooter.ptHeaderBodySpacing = 10; m_pageHeaderFooter.ptFooterBodySpacing = 10; m_pageHeaderFooter.ptFootNoteBodySpacing = 10; QString _template; bool ok = FALSE; KoTemplateChooseDia::ReturnType ret = KoTemplateChooseDia::choose( KWFactory::global(), _template, "application/x-kword", "*.kwd", i18n("KWord"), KoTemplateChooseDia::Everything, "kword_template"); if ( ret == KoTemplateChooseDia::Template ) { QFileInfo fileInfo( _template ); QString fileName( fileInfo.dirPath( TRUE ) + "/" + fileInfo.baseName() + ".kwt" ); resetURL(); ok = loadNativeFormat( fileName ); initUnit(); setEmpty(); } else if ( ret == KoTemplateChooseDia::File ) { KURL url( _template); //kdDebug() << "KWDocument::initDoc opening URL " << url.prettyURL() << endl; ok = openURL( url ); } else if ( ret == KoTemplateChooseDia::Empty ) { QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::global() ) ); resetURL(); ok = loadNativeFormat( fileName ); initUnit(); setEmpty(); } setModified( FALSE ); return ok; } void KWDocument::initUnit() { //load unit config after we load file. //load it for new file or empty file KConfig *config = KWFactory::global()->config(); if(config->hasGroup("Misc") ) { config->setGroup( "Misc" ); setUnit(KoUnit::unit( config->readEntry("Units",KoUnit::unitName(KoUnit::U_MM )))); setDefaultColumnSpacing( config->readDoubleNumEntry("ColumnSpacing", 3.0) ); } m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; } void KWDocument::initEmpty() { m_pages = 1; m_pageColumns.columns = 1; m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; m_pageHeaderFooter.header = HF_SAME; m_pageHeaderFooter.footer = HF_SAME; m_pageHeaderFooter.ptHeaderBodySpacing = 10; m_pageHeaderFooter.ptFooterBodySpacing = 10; m_pageHeaderFooter.ptFootNoteBodySpacing = 10; QString fileName( locate( "kword_template", "Normal/.source/PlainText.kwt" , KWFactory::global() ) ); /*bool ok = */loadNativeFormat( fileName ); resetURL(); setModified( FALSE ); setEmpty(); } KoPageLayout KWDocument::pageLayout() const { return m_pageLayout; } void KWDocument::setPageLayout( const KoPageLayout& _layout, const KoColumns& _cl, const KoKWHeaderFooter& _hf, bool updateViews ) { if ( m_processingType == WP ) { int numPages = m_pages; //kdDebug() << "KWDocument::setPageLayout WP" << endl; m_pageLayout = _layout; m_pageColumns = _cl; m_pageHeaderFooter = _hf; if ( updateViews ) { // Fix things up, when we change the orientation we might accidentally change the number of pages // (and frames of the main textframeset might just remain un-moved...) KWFrameSet *frameset = m_lstFrameSet.getFirst(); KWFrame* lastFrame = frameset->frame( frameset->getNumFrames() - 1 ); if ( lastFrame && lastFrame->pageNum() + 1 < numPages ) { kdDebug(32002) << "KWDocument::setPageLayout ensuring that recalcFrames will consider " << numPages << " pages." << endl; // All that matters is that it's on numPages so that all pages will be recalc-ed. // If the text layout then wants to remove some pages, no problem. lastFrame->setY( numPages * ptPaperHeight() + ptTopBorder() ); } } } else { //kdDebug() << "KWDocument::setPageLayout NON-WP" << endl; m_pageLayout = _layout; m_pageLayout.ptLeft = 0; m_pageLayout.ptRight = 0; m_pageLayout.ptTop = 0; m_pageLayout.ptBottom = 0; m_pageHeaderFooter = _hf; } recalcFrames(); updateAllFrames(); if ( updateViews ) { // Invalidate document layout, for proper repaint layout(); emit pageLayoutChanged( m_pageLayout ); updateResizeHandles(); updateContentsSize(); } } double KWDocument::ptColumnWidth() const { return ( ptPaperWidth() - ptLeftBorder() - ptRightBorder() - ptColumnSpacing() * ( m_pageColumns.columns - 1 ) ) / m_pageColumns.columns; } class KWFootNoteFrameSetList : public QPtrList { public: KWFootNoteFrameSetList( bool reversed ) : m_reversed( reversed ) {} protected: // Compare the order of the associated variables virtual int compareItems(QPtrCollection::Item a, QPtrCollection::Item b) { KWFootNoteFrameSet* fsa = ((KWFootNoteFrameSet *)a); KWFootNoteFrameSet* fsb = ((KWFootNoteFrameSet *)b); Q_ASSERT( fsa->footNoteVariable() ); Q_ASSERT( fsb->footNoteVariable() ); if ( fsa->footNoteVariable() && fsb->footNoteVariable() ) { int numa = fsa->footNoteVariable()->num(); int numb = fsb->footNoteVariable()->num(); if (numa == numb) return 0; if (numa > numb) return m_reversed ? -1 : 1; return m_reversed ? 1 : -1; } return -1; // whatever } private: bool m_reversed; }; /* append headers and footers if needed, and create enough pages for all the existing frames */ void KWDocument::recalcFrames( int fromPage, int toPage /*-1 for all*/ ) { if ( m_lstFrameSet.isEmpty() ) return; //printDebug(); kdDebug(32002) << "KWDocument::recalcFrames from=" << fromPage << " to=" << toPage << endl; KWFrameSet *frameset = m_lstFrameSet.getFirst(); if ( m_processingType == WP ) { // In WP mode the pages are created automatically. In DTP not... KWTextFrameSet *firstHeader = 0L, *evenHeader = 0L, *oddHeader = 0L; KWTextFrameSet *firstFooter = 0L, *evenFooter = 0L, *oddFooter = 0L; // Lookup the various header / footer framesets into the variables above // [Done in all cases, in order to hide unused framesets] KWFootNoteFrameSetList footnotesList( true ); // Reversed, we want footnotes from bottom to top KWFootNoteFrameSetList endnotesList( false ); // Endnotes are in top to bottom order QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWFrameSet * fs = fit.current(); switch ( fs->frameSetInfo() ) { case KWFrameSet::FI_FIRST_HEADER: if ( isHeaderVisible() ) { firstHeader = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_ODD_HEADER: if ( isHeaderVisible() ) { oddHeader = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_EVEN_HEADER: if ( isHeaderVisible() ) { evenHeader = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_FIRST_FOOTER: if ( isFooterVisible() ) { firstFooter = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_ODD_FOOTER: if ( isFooterVisible() ) { oddFooter = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } break; case KWFrameSet::FI_EVEN_FOOTER: if ( isFooterVisible() ) { evenFooter = dynamic_cast( fs ); } else { fs->setVisible( false ); fs->deleteAllCopies(); } case KWFrameSet::FI_FOOTNOTE: { KWFootNoteFrameSet* fnfs = dynamic_cast(fs); if ( fnfs && fnfs->isVisible() ) // not visible is when the footnote has been deleted { if ( fnfs->isFootNote() ) footnotesList.append( fnfs ); else if ( fnfs->isEndNote() ) { endnotesList.append( fnfs ); m_bHasEndNotes = true; } } } break; default: break; } } // This allocation each time might slow things down a bit. // TODO KWHeaderFooterFrameSet : public KWTextFrameSet, and store the HeaderFooterFrameset data into there. // ... hmm, and then KWFootNoteFrameSet needs to inherit KWHeaderFooterFrameSet QPtrList headerFooterList; headerFooterList.setAutoDelete( true ); // Now hide & forget the unused header/footer framesets (e.g. 'odd pages' if we are in 'all the same' mode etc.) if ( isHeaderVisible() ) { Q_ASSERT( firstHeader ); Q_ASSERT( oddHeader ); Q_ASSERT( evenHeader ); switch ( getHeaderType() ) { case HF_SAME: oddHeader->setVisible( true ); evenHeader->setVisible( false ); evenHeader->deleteAllCopies(); firstHeader->setVisible( false ); firstHeader->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 0, -1, m_pageHeaderFooter.ptHeaderBodySpacing ) ); break; case HF_FIRST_EO_DIFF: // added for koffice-1.2-beta2 firstHeader->setVisible( true ); oddHeader->setVisible( true ); evenHeader->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstHeader, 0, 0, m_pageHeaderFooter.ptHeaderBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 2, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenHeader, 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; case HF_FIRST_DIFF: oddHeader->setVisible( true ); evenHeader->setVisible( false ); evenHeader->deleteAllCopies(); firstHeader->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstHeader, 0, 0, m_pageHeaderFooter.ptHeaderBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing ) ); break; case HF_EO_DIFF: oddHeader->setVisible( true ); evenHeader->setVisible( true ); firstHeader->setVisible( false ); firstHeader->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddHeader, 0, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenHeader, 1, -1, m_pageHeaderFooter.ptHeaderBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; } } if ( isFooterVisible() ) { Q_ASSERT( firstFooter ); Q_ASSERT( oddFooter ); Q_ASSERT( evenFooter ); switch ( getFooterType() ) { case HF_SAME: oddFooter->setVisible( true ); evenFooter->setVisible( false ); evenFooter->deleteAllCopies(); firstFooter->setVisible( false ); firstFooter->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 0, -1, m_pageHeaderFooter.ptFooterBodySpacing ) ); break; case HF_FIRST_EO_DIFF: // added for koffice-1.2-beta2 firstFooter->setVisible( true ); oddFooter->setVisible( true ); evenFooter->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstFooter, 0, 0, m_pageHeaderFooter.ptFooterBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 2, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenFooter, 1, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; case HF_FIRST_DIFF: oddFooter->setVisible( true ); evenFooter->setVisible( false ); evenFooter->deleteAllCopies(); firstFooter->setVisible( true ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( firstFooter, 0, 0, m_pageHeaderFooter.ptFooterBodySpacing ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 1, -1, m_pageHeaderFooter.ptFooterBodySpacing ) ); break; case HF_EO_DIFF: oddFooter->setVisible( true ); evenFooter->setVisible( true ); firstFooter->setVisible( false ); firstFooter->deleteAllCopies(); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( oddFooter, 0, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Odd ) ); headerFooterList.append( new KWFrameLayout::HeaderFooterFrameset( evenFooter, 1, -1, m_pageHeaderFooter.ptFooterBodySpacing, KWFrameLayout::HeaderFooterFrameset::Even ) ); break; } } // The frameset order _on screen_ is: // Header // Main text frame (if WP) // Footnote_s_ // Footer // In the list it will have to be from top and from bottom: // Header, Footer, Footnote from bottom to top QPtrList footnotesHFList; footnotesHFList.setAutoDelete( true ); footnotesList.sort(); QPtrListIterator fnfsIt( footnotesList ); // fnfs == "footnote frameset" for ( ; fnfsIt.current() ; ++fnfsIt ) { KWFootNoteFrameSet* fnfs = fnfsIt.current(); int pageNum = -42; //fnfs->footNoteVariable()->pageNum(); // determined by KWFrameLayout KWFrameLayout::HeaderFooterFrameset* hff = new KWFrameLayout::HeaderFooterFrameset( fnfs, pageNum, pageNum, m_pageHeaderFooter.ptFootNoteBodySpacing, KWFrameLayout::HeaderFooterFrameset::All ); // With other kind of framesets, the height is simply frame->height. // But for footnotes, the height to pass to KWFrameLayout is the sum of the frame heights. hff->m_height = 0; for (QPtrListIterator f = fnfs->frameIterator(); f.current() ; ++f ) hff->m_height += f.current()->height(); footnotesHFList.append( hff ); } // Endnotes, however are laid out from top to bottom. QPtrList endnotesHFList; endnotesHFList.setAutoDelete( true ); endnotesList.sort(); QPtrListIterator enfsIt( endnotesList ); // enfs == "endnote frameset" for ( ; enfsIt.current() ; ++enfsIt ) { KWFootNoteFrameSet* enfs = enfsIt.current(); KWFrameLayout::HeaderFooterFrameset* hff = new KWFrameLayout::HeaderFooterFrameset( enfs, -42, -42, // determined by KWFrameLayout m_pageHeaderFooter.ptFootNoteBodySpacing, KWFrameLayout::HeaderFooterFrameset::All ); // The height to pass to KWFrameLayout is the sum of the frame heights. hff->m_height = 0; for (QPtrListIterator f = enfs->frameIterator(); f.current() ; ++f ) hff->m_height += f.current()->height(); endnotesHFList.append( hff ); } int oldPages = m_pages; unsigned int frms = frameset->getNumFrames(); // Determine number of pages - first from the text frames // - BUT NOT from the number of frames. Some people manage to end up with // multiple frames of textframeset1 on the same page(!) //m_pages = static_cast( ceil( static_cast( frms ) / static_cast( m_pageColumns.columns ) ) ); #ifdef DEBUG_PAGES //kdDebug(32002) << "KWDocument::recalcFrames frms(" << frms << ") / columns(" << m_pageColumns.columns << ") = " << m_pages << endl; #endif m_pages = frameset->frame( frms - 1 )->pageNum() + 1; // Then from the other frames ( framesetNum > 0 ) double maxBottom = 0; for (int m = getNumFrameSets() - 1; m > 0; m-- ) { KWFrameSet *fs=frameSet(m); if ( fs->isVisible() && !fs->isAHeader() && !fs->isAFooter() && !fs->isFloating() && !fs->isFootEndNote() ) { for (int n = fs->getNumFrames()-1; n >= 0 ; n--) { //if ( n == fs->getNumFrames()-1 ) #ifdef DEBUG_PAGES kdDebug(32002) << "KWDocument::recalcFrames frameset number " << m << " '" << fs->getName() << "' frame " << n << " bottom=" << fs->frame(n)->bottom() << endl; #endif maxBottom = QMAX(maxBottom, fs->frame(n)->bottom()); } } } int pages2 = static_cast( ceil( maxBottom / ptPaperHeight() ) ); #ifdef DEBUG_PAGES kdDebug(32002) << "KWDocument::recalcFrames, WP, m_pages=" << m_pages << " pages2=" << pages2 << " (coming from maxBottom=" << maxBottom << " and ptPaperHeight=" << ptPaperHeight() << ")" << endl; #endif m_pages = QMAX( pages2, m_pages ); if ( toPage == -1 ) toPage = m_pages - 1; if ( fromPage > toPage ) // this can happen with "endnotes only" pages :) fromPage = toPage; // ie. start at the last real page KWFrameLayout frameLayout( this, headerFooterList, footnotesHFList, endnotesHFList ); frameLayout.layout( frameset, m_pageColumns.columns, fromPage, toPage ); // If the number of pages changed, update views and variables etc. // (now that the frame layout has been done) if ( m_pages != oldPages ) { // Very much like the end of appendPage, but we don't want to call recalcFrames ;) emit newContentsSize(); emit pageNumChanged(); recalcVariables( VT_PGNUM ); } } else { // DTP mode: calculate the number of pages from the frames. double maxBottom=0; for (QPtrListIterator fit = framesetsIterator(); fit.current() ; ++fit ) { if(fit.current()->isDeleted()) continue; if(fit.current()->frameSetInfo()==KWFrameSet::FI_BODY && !fit.current()->isFloating()) { KWFrameSet * fs = fit.current(); for (QPtrListIterator f = fs->frameIterator(); f.current() ; ++f ) { kdDebug() << " fs=" << fs->getName() << " bottom=" << f.current()->bottom() << endl; maxBottom=QMAX(maxBottom, f.current()->bottom()); } } } m_pages = static_cast( ceil( maxBottom / ptPaperHeight() ) ); #ifdef DEBUG_PAGES kdDebug(32002) << "DTP mode: pages = maxBottom("< it( children() ); for( ; it.current(); ++it ) { if ( !it.current()->loadDocument( _store ) ) return FALSE; } return TRUE; } void KWDocument::loadPictureMap ( QDomElement& domElement ) { m_pictureMap.clear(); // QDomElement picturesElem = domElement.namedItem( "PICTURES" ).toElement(); if ( !picturesElem.isNull() ) { m_pictureCollection.readXML( picturesElem, m_pictureMap ); } // QDomElement pixmapsElem = domElement.namedItem( "PIXMAPS" ).toElement(); if ( !pixmapsElem.isNull() ) { m_pictureCollection.readXML( pixmapsElem, m_pictureMap ); } // QDomElement clipartsElem = domElement.namedItem( "CLIPARTS" ).toElement(); if ( !clipartsElem.isNull() ) { m_pictureCollection.readXML( pixmapsElem, m_pictureMap ); } } bool KWDocument::loadXML( QIODevice *, const QDomDocument & doc ) { QTime dt; dt.start(); emit sigProgress( 0 ); //kdDebug(32001) << "KWDocument::loadXML" << endl; m_pictureMap.clear(); m_textImageRequests.clear(); m_pictureRequests.clear(); m_anchorRequests.clear(); m_footnoteVarRequests.clear(); m_spellListIgnoreAll.clear(); m_pageColumns.columns = 1; m_pageColumns.ptColumnSpacing = m_defaultColumnSpacing; m_pageHeaderFooter.header = HF_SAME; m_pageHeaderFooter.footer = HF_SAME; m_pageHeaderFooter.ptHeaderBodySpacing = 10; m_pageHeaderFooter.ptFooterBodySpacing = 10; m_pageHeaderFooter.ptFootNoteBodySpacing = 10; m_varFormatCollection->clear(); m_pages = 1; m_bHasEndNotes = false; KoPageLayout __pgLayout; KoColumns __columns; __columns.columns = 1; __columns.ptColumnSpacing = m_defaultColumnSpacing; KoKWHeaderFooter __hf; __hf.header = HF_SAME; __hf.footer = HF_SAME; __hf.ptHeaderBodySpacing = 10.0; __hf.ptFooterBodySpacing = 10.0; __hf.ptFootNoteBodySpacing = 10.0; QString value; QDomElement word = doc.documentElement(); value = KWDocument::getAttribute( word, "mime", QString::null ); if ( value.isEmpty() ) { kdError(32001) << "No mime type specified!" << endl; setErrorMessage( i18n( "Invalid document. No mimetype specified." ) ); return false; } else if ( value != "application/x-kword" && value != "application/vnd.kde.kword" ) { kdError(32001) << "Unknown mime type " << value << endl; setErrorMessage( i18n( "Invalid document. Expected mimetype application/x-kword or application/vnd.kde.kword, got %1" ).arg( value ) ); return false; } m_syntaxVersion = KWDocument::getAttribute( word, "syntaxVersion", 0 ); if ( m_syntaxVersion > CURRENT_SYNTAX_VERSION ) { int ret = KMessageBox::warningContinueCancel( 0, i18n("This document was created with a newer version of KWord (syntax version: %1)\n" "Opening it in this version of KWord will lose some information.").arg(m_syntaxVersion), i18n("File format mismatch"), i18n("Continue") ); if ( ret == KMessageBox::Cancel ) { setErrorMessage( "USER_CANCELED" ); return false; } } // Looks like support for the old way of naming images internally, // see completeLoading. value = KWDocument::getAttribute( word, "url", QString::null ); if ( value != QString::null ) { m_urlIntern = KURL( value ).path(); } emit sigProgress(5); // QDomElement paper = word.namedItem( "PAPER" ).toElement(); if ( !paper.isNull() ) { __pgLayout.format = static_cast( KWDocument::getAttribute( paper, "format", 0 ) ); __pgLayout.orientation = static_cast( KWDocument::getAttribute( paper, "orientation", 0 ) ); __pgLayout.ptWidth = getAttribute( paper, "width", 0.0 ); __pgLayout.ptHeight = getAttribute( paper, "height", 0.0 ); __hf.header = static_cast( KWDocument::getAttribute( paper, "hType", 0 ) ); __hf.footer = static_cast( KWDocument::getAttribute( paper, "fType", 0 ) ); __hf.ptHeaderBodySpacing = getAttribute( paper, "spHeadBody", 0.0 ); __hf.ptFooterBodySpacing = getAttribute( paper, "spFootBody", 0.0 ); __hf.ptFootNoteBodySpacing = getAttribute( paper, "spFootNoteBody", 10.0 ); m_iFootNoteSeparatorLineLength = getAttribute( paper, "slFootNoteLength", 20); m_footNoteSeparatorLineWidth = getAttribute( paper, "slFootNoteWidth",2.0); m_footNoteSeparatorLineType = static_cast(getAttribute( paper, "slFootNoteType",0)); if ( paper.hasAttribute("slFootNotePosition")) { QString tmp =paper.attribute("slFootNotePosition"); if ( tmp =="centered" ) m_footNoteSeparatorLinePos = SLP_CENTERED; else if ( tmp =="right") m_footNoteSeparatorLinePos = SLP_RIGHT; else if ( tmp =="left" ) m_footNoteSeparatorLinePos = SLP_LEFT; } __columns.columns = KWDocument::getAttribute( paper, "columns", 1 ); __columns.ptColumnSpacing = KWDocument::getAttribute( paper, "columnspacing", 0.0 ); // Now part of the app config //m_zoom = KWDocument::getAttribute( paper, "zoom", 100 ); //if(m_zoom!=100) // setZoomAndResolution( m_zoom, QPaintDevice::x11AppDpiX(), QPaintDevice::x11AppDpiY(), false, false ); // Support the undocumented syntax actually used by KDE 2.0 for some of the above (:-(). // Do not add anything to this block! if ( __pgLayout.ptWidth == 0.0 ) __pgLayout.ptWidth = getAttribute( paper, "ptWidth", 0.0 ); if ( __pgLayout.ptHeight == 0.0 ) __pgLayout.ptHeight = getAttribute( paper, "ptHeight", 0.0 ); if ( __hf.ptHeaderBodySpacing == 0.0 ) __hf.ptHeaderBodySpacing = getAttribute( paper, "ptHeadBody", 0.0 ); if ( __hf.ptFooterBodySpacing == 0.0 ) __hf.ptFooterBodySpacing = getAttribute( paper, "ptFootBody", 0.0 ); if ( __columns.ptColumnSpacing == 0.0 ) __columns.ptColumnSpacing = getAttribute( paper, "ptColumnspc", 0.0 ); // QDomElement paperborders = paper.namedItem( "PAPERBORDERS" ).toElement(); if ( !paperborders.isNull() ) { __pgLayout.ptLeft = getAttribute( paperborders, "left", 0.0 ); __pgLayout.ptTop = getAttribute( paperborders, "top", 0.0 ); __pgLayout.ptRight = getAttribute( paperborders, "right", 0.0 ); __pgLayout.ptBottom = getAttribute( paperborders, "bottom", 0.0 ); // Support the undocumented syntax actually used by KDE 2.0 for some of the above (:-(). if ( __pgLayout.ptLeft == 0.0 ) __pgLayout.ptLeft = getAttribute( paperborders, "ptLeft", 0.0 ); if ( __pgLayout.ptTop == 0.0 ) __pgLayout.ptTop = getAttribute( paperborders, "ptTop", 0.0 ); if ( __pgLayout.ptRight == 0.0 ) __pgLayout.ptRight = getAttribute( paperborders, "ptRight", 0.0 ); if ( __pgLayout.ptBottom == 0.0 ) __pgLayout.ptBottom = getAttribute( paperborders, "ptBottom", 0.0 ); } } else kdWarning() << "No tag! This is a mandatory tag! Expect weird page sizes..." << endl; // QDomElement attributes = word.namedItem( "ATTRIBUTES" ).toElement(); QString unitName; if ( !attributes.isNull() ) { m_processingType = static_cast( KWDocument::getAttribute( attributes, "processing", 0 ) ); //KWDocument::getAttribute( attributes, "standardpage", QString::null ); m_headerVisible = static_cast( KWDocument::getAttribute( attributes, "hasHeader", 0 ) ); m_footerVisible = static_cast( KWDocument::getAttribute( attributes, "hasFooter", 0 ) ); unitName = KWDocument::getAttribute( attributes, "unit", "pt" ); m_hasTOC = static_cast(KWDocument::getAttribute( attributes,"hasTOC", 0 ) ); m_tabStop = KWDocument::getAttribute( attributes, "tabStopValue", MM_TO_POINT(15) ); m_initialEditing = new InitialEditing(); m_initialEditing->m_initialFrameSet = attributes.attribute( "activeFrameset" ); m_initialEditing->m_initialCursorParag = attributes.attribute( "cursorParagraph" ).toInt(); m_initialEditing->m_initialCursorIndex = attributes.attribute( "cursorIndex" ).toInt(); } else { m_processingType = WP; m_headerVisible = false; m_footerVisible = false; unitName = "pt"; m_hasTOC = false; m_tabStop = MM_TO_POINT(15); delete m_initialEditing; m_initialEditing = 0L; } m_unit = KoUnit::unit( unitName ); setPageLayout( __pgLayout, __columns, __hf, false ); getVariableCollection()->variableSetting()->load(word ); //by default display real variable value if ( !isReadWrite()) getVariableCollection()->variableSetting()->setDisplayFiedCode(false); emit sigProgress(10); QDomElement mailmerge = word.namedItem( "MAILMERGE" ).toElement(); if (mailmerge!=QDomElement()) { m_slDataBase->load(mailmerge); } emit sigProgress(15); // Load all styles before the corresponding paragraphs try to use them! QDomElement stylesElem = word.namedItem( "STYLES" ).toElement(); if ( !stylesElem.isNull() ) loadStyleTemplates( stylesElem ); emit sigProgress(17); QDomElement frameStylesElem = word.namedItem( "FRAMESTYLES" ).toElement(); if ( !frameStylesElem.isNull() ) loadFrameStyleTemplates( frameStylesElem ); else // load default styles loadDefaultFrameStyleTemplates(); emit sigProgress(18); QDomElement tableStylesElem = word.namedItem( "TABLESTYLES" ).toElement(); if ( !tableStylesElem.isNull() ) loadTableStyleTemplates( tableStylesElem ); else // load default styles loadDefaultTableStyleTemplates(); emit sigProgress(19); loadDefaultTableTemplates(); emit sigProgress(20); QDomElement bookmark = word.namedItem( "BOOKMARKS" ).toElement(); if( !bookmark.isNull() ) { QDomElement bookmarkitem=word.namedItem("BOOKMARKS").toElement(); bookmarkitem=bookmarkitem.firstChild().toElement(); while ( !bookmarkitem.isNull() ) { if ( bookmarkitem.tagName()=="BOOKMARKITEM" ) { bookMark *tmp=new bookMark; tmp->bookname=bookmarkitem.attribute("name"); tmp->cursorStartIndex=bookmarkitem.attribute("cursorIndexStart").toInt(); tmp->frameSetName=bookmarkitem.attribute("frameset"); tmp->paragStartIndex = bookmarkitem.attribute("startparag").toInt(); tmp->paragEndIndex = bookmarkitem.attribute("endparag").toInt(); tmp->cursorEndIndex = bookmarkitem.attribute("cursorIndexEnd").toInt(); m_tmpBookMarkList.append(tmp); } bookmarkitem=bookmarkitem.nextSibling().toElement(); } } QDomElement spellCheckIgnore = word.namedItem( "SPELLCHECKIGNORELIST" ).toElement(); if( !spellCheckIgnore.isNull() ) { QDomElement spellWord=word.namedItem("SPELLCHECKIGNORELIST").toElement(); spellWord=spellWord.firstChild().toElement(); while ( !spellWord.isNull() ) { if ( spellWord.tagName()=="SPELLCHECKIGNOREWORD" ) { m_spellListIgnoreAll.append(spellWord.attribute("word")); } spellWord=spellWord.nextSibling().toElement(); } } m_bgSpellCheck->addIgnoreWordAllList( m_spellListIgnoreAll ); emit sigProgress(25); QDomElement framesets = word.namedItem( "FRAMESETS" ).toElement(); if ( !framesets.isNull() ) loadFrameSets( framesets ); emit sigProgress(85); loadPictureMap( word ); emit sigProgress(90); // loadEmbeddedObjects( word ); emit sigProgress(100); // the rest is only processing, not loading bool _first_footer = FALSE, _even_footer = FALSE, _odd_footer = FALSE; bool _first_header = FALSE, _even_header = FALSE, _odd_header = FALSE; QPtrListIterator fit = framesetsIterator(); for ( ; fit.current() ; ++fit ) { switch( fit.current()->frameSetInfo() ) { case KWFrameSet::FI_FIRST_HEADER: _first_header = TRUE; break; case KWFrameSet::FI_ODD_HEADER: _odd_header = TRUE; break; case KWFrameSet::FI_EVEN_HEADER: _even_header = TRUE; break; case KWFrameSet::FI_FIRST_FOOTER: _first_footer = TRUE; break; case KWFrameSet::FI_ODD_FOOTER: _odd_footer = TRUE; break; case KWFrameSet::FI_EVEN_FOOTER: _even_footer = TRUE; break; case KWFrameSet::FI_FOOTNOTE: if ( fit.current()->isEndNote() ) m_bHasEndNotes = true; break; default: break; } } // create defaults if they were not in the input file. if ( !_first_header ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "First Page Header" ) ); //kdDebug(32001) << "KWDocument::loadXML KWTextFrameSet created " << fs << endl; fs->setFrameSetInfo( KWFrameSet::FI_FIRST_HEADER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptTopBorder(), ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); //kdDebug(32001) << "KWDocument::loadXML KWFrame created " << frame << endl; frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_odd_header ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Odd Pages Header" ) ); fs->setFrameSetInfo( KWFrameSet::FI_ODD_HEADER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptTopBorder(), ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_even_header ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Even Pages Header" ) ); fs->setFrameSetInfo( KWFrameSet::FI_EVEN_HEADER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptTopBorder(), ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_first_footer ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "First Page Footer" ) ); fs->setFrameSetInfo( KWFrameSet::FI_FIRST_FOOTER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptPaperHeight() - ptTopBorder() - 20, ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_odd_footer ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Odd Pages Footer" ) ); fs->setFrameSetInfo( KWFrameSet::FI_ODD_FOOTER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptPaperHeight() - ptTopBorder() - 20, ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } if ( !_even_footer ) { KWTextFrameSet *fs = new KWTextFrameSet( this, i18n( "Even Pages Footer" ) ); fs->setFrameSetInfo( KWFrameSet::FI_EVEN_FOOTER ); KWFrame *frame = new KWFrame(fs, ptLeftBorder(), ptPaperHeight() - ptTopBorder() - 20, ptPaperWidth() - ptLeftBorder() - ptRightBorder(), 20 ); frame->setFrameBehavior( KWFrame::AutoExtendFrame ); frame->setNewFrameBehavior( KWFrame::Copy ); fs->addFrame( frame ); m_lstFrameSet.append( fs ); } // do some sanity checking on document. for (int i = getNumFrameSets()-1; i>-1; i--) { KWFrameSet *fs = frameSet(i); if(!fs) { kdWarning() << "frameset " << i << " is NULL!!" << endl; m_lstFrameSet.remove(i); } else if( fs->type()==FT_TABLE) { static_cast( fs )->validate(); } else if(!fs->getNumFrames()) { kdWarning () << "frameset " << i << " has no frames" << endl; removeFrameSet(fs); if ( fs->type() == FT_PART ) delete static_cast(fs)->getChild(); delete fs; } else if (fs->type() == FT_TEXT) { for (int f=fs->getNumFrames()-1; f>=0; f--) { KWFrame *frame = fs->frame(f); if(frame->height() < static_cast (minFrameHeight)) { kdWarning() << "frame height is so small no text will fit, adjusting (was: " << frame->height() << " is: " << minFrameHeight << ")" << endl; frame->setHeight(minFrameHeight); } if(frame->width() < static_cast (minFrameWidth)) { kdWarning() << "frame width is so small no text will fit, adjusting (was: " << frame->width() << " is: " << minFrameWidth << ")" << endl; frame->setWidth(minFrameWidth); } } } } emit sigProgress(-1); //kdDebug(32001) << "KWDocument::loadXML done" << endl; setModified( false ); // Connect to notifications from main text-frameset KWTextFrameSet *frameset = dynamic_cast( m_lstFrameSet.getFirst() ); if ( frameset ) { connect( frameset->textObject(), SIGNAL( chapterParagraphFormatted( KoTextParag * ) ), SLOT( slotChapterParagraphFormatted( KoTextParag * ) ) ); connect( frameset, SIGNAL( mainTextHeightChanged() ), SIGNAL( mainTextHeightChanged() ) ); } kdDebug(32001) << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl; return true; } void KWDocument::startBackgroundSpellCheck() { //don't start bg spell checking if if(backgroundSpellCheckEnabled() && isReadWrite()) { m_bgSpellCheck->objectForSpell(textFrameSet(0)); m_bgSpellCheck->startBackgroundSpellCheck(); } } void KWDocument::loadEmbeddedObjects( QDomElement& word ) { QDomNodeList listEmbedded = word.elementsByTagName ( "EMBEDDED" ); for (unsigned int item = 0; item < listEmbedded.count(); item++) { QDomElement embedded = listEmbedded.item( item ).toElement(); loadEmbedded( embedded ); } } void KWDocument::loadEmbedded( const QDomElement &embedded ) { QDomElement object = embedded.namedItem( "OBJECT" ).toElement(); if ( !object.isNull() ) { KWChild *ch = new KWChild( this ); ch->load( object, true ); insertChild( ch ); QDomElement settings = embedded.namedItem( "SETTINGS" ).toElement(); QString name; if ( !settings.isNull() ) name = settings.attribute( "name" ); KWPartFrameSet *fs = new KWPartFrameSet( this, ch, name ); m_lstFrameSet.append( fs ); if ( !settings.isNull() ) { kdDebug(32001) << "KWDocument::loadXML loading embedded object" << endl; fs->load( settings ); } else kdError(32001) << "No tag in EMBEDDED" << endl; emit sig_insertObject( ch, fs ); } else kdError(32001) << "No tag in EMBEDDED" << endl; } void KWDocument::loadStyleTemplates( const QDomElement &stylesElem ) { QValueList followingStyles; QDomNodeList listStyles = stylesElem.elementsByTagName( "STYLE" ); if( listStyles.count() > 0) { // we are going to import at least one style. KWStyle *s = m_styleColl->findStyle("Standard"); //kdDebug(32001) << "KWDocument::loadStyleTemplates looking for Standard, to delete it. Found " << s << endl; if(s) // delete the standard style. m_styleColl->removeStyleTemplate(s); } for (unsigned int item = 0; item < listStyles.count(); item++) { QDomElement styleElem = listStyles.item( item ).toElement(); KWStyle *sty = new KWStyle( QString::null ); // Load the paraglayout from the