diff --git a/kword/kwformulaframe.cc b/kword/kwformulaframe.cc index 6709bd9048..12b143bf7c 100644 --- a/kword/kwformulaframe.cc +++ b/kword/kwformulaframe.cc @@ -1,551 +1,518 @@ /* This file is part of the KDE project Copyright (C) 2003 Ulrich Kuettler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "kwdoc.h" #include "kwview.h" #include "kwviewmode.h" #include "kwcanvas.h" #include "kwcommand.h" #include "kwframe.h" #include "defs.h" #include "kwtextframeset.h" #include "kwtableframeset.h" #include "kwanchor.h" #include "resizehandles.h" #include // for customItemChar! #include #include #include #include #include #include #include #include #include #include #include "KWordFrameSetIface.h" #include #include "qdrawutil.h" #include "KWordTextFrameSetEditIface.h" #include "KWordFormulaFrameSetIface.h" #include "KWordFormulaFrameSetEditIface.h" #include "KWordPictureFrameSetIface.h" #include "KWordHorizontalLineFrameSetIface.h" #include "kwformulaframe.h" #include // #ifdef __GNUC__ // #undef k_funcinfo // #define k_funcinfo "[\033[36m" << __PRETTY_FUNCTION__ << "\033[m] " // #endif /******************************************************************/ /* Class: KWFormulaFrameSet */ /******************************************************************/ KWFormulaFrameSet::KWFormulaFrameSet( KWDocument *_doc, const QString & name ) : KWFrameSet( _doc ), m_changed( false ), m_edit( 0 ) { kdDebug() << k_funcinfo << endl; // The newly created formula is not yet part of the formula // document. It will be added when a frame is created. formula = _doc->getFormulaDocument()->createFormula( -1, false ); // With the new drawing scheme (drawFrame being called with translated painter) // there is no need to move the KFormulaContainer anymore, it remains at (0,0). formula->moveTo( 0, 0 ); connect( formula, SIGNAL( formulaChanged( double, double ) ), this, SLOT( slotFormulaChanged( double, double ) ) ); connect( formula, SIGNAL( errorMsg( const QString& ) ), this, SLOT( slotErrorMessage( const QString& ) ) ); if ( name.isEmpty() ) m_name = _doc->generateFramesetName( i18n( "Formula %1" ) ); else m_name = name; /* if ( isFloating() ) { // we need to look for the anchor every time, don't cache this value. // undo/redo creates/deletes anchors KWAnchor * anchor = findAnchor( 0 ); if ( anchor ) { KoTextFormat * format = anchor->format(); formula->setFontSize( format->pointSize() ); } } */ QRect rect = formula->boundingRect(); slotFormulaChanged(rect.width(), rect.height()); } KWordFrameSetIface* KWFormulaFrameSet::dcopObject() { if ( !m_dcop ) m_dcop = new KWordFormulaFrameSetIface( this ); return m_dcop; } KWFormulaFrameSet::~KWFormulaFrameSet() { kdDebug() << k_funcinfo << endl; delete formula; } void KWFormulaFrameSet::addFrame( KWFrame *_frame, bool recalc ) { kdDebug() << k_funcinfo << endl; if ( formula ) { _frame->setWidth( formula->width() ); _frame->setHeight( formula->height() ); } KWFrameSet::addFrame( _frame, recalc ); if ( formula ) { formula->registerFormula(); } } void KWFormulaFrameSet::delFrame( unsigned int _num, bool remove, bool recalc ) { kdDebug() << k_funcinfo << endl; assert( _num == 0 ); KWFrameSet::delFrame( _num, remove, recalc ); formula->unregisterFormula(); } void KWFormulaFrameSet::moveFrame( KWFrame* frame ) { formula->setDocumentPosition( frame->x(), frame->y()+formula->baseline() ); } KWFrameSetEdit* KWFormulaFrameSet::createFrameSetEdit(KWCanvas* canvas,bool) { return new KWFormulaFrameSetEdit(this, canvas); } void KWFormulaFrameSet::drawFrameContents( KWFrame* /*frame*/, QPainter* painter, const QRect& crect, const QColorGroup& cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit */*edit*/, KWViewMode * ) { if ( m_changed || !onlyChanged ) { if ( resetChanged ) m_changed = false; bool printing = painter->device()->devType() == QInternal::Printer; bool clipping = true; QPainter *p; QPixmap* pix = 0L; if ( printing ) { p = painter; clipping = painter->hasClipping(); // That's unfortunate for formulas wider than the page. // However it helps a lot with ordinary formulas. painter->setClipping( false ); } else { pix = doubleBufferPixmap( crect.size() ); p = new QPainter( pix ); p->translate( -crect.x(), -crect.y() ); } if ( m_edit ) { //KWFormulaFrameSetEdit * formulaEdit = static_cast(edit); if ( m_edit->getFormulaView() ) { m_edit->getFormulaView()->draw( *p, crect, cg ); } else { formula->draw( *p, crect, cg ); } } else { formula->draw( *p, crect, cg ); } if ( !printing ) { p->end(); delete p; painter->drawPixmap( crect.topLeft(), *pix ); } else { painter->setClipping( clipping ); } } } void KWFormulaFrameSet::slotFormulaChanged( double width, double height ) { if ( frames.isEmpty() ) return; double oldWidth = frames.first()->width(); double oldHeight = frames.first()->height(); frames.first()->setWidth( width ); frames.first()->setHeight( height ); updateFrames(); kWordDocument()->layout(); if ( ( oldWidth != width ) || ( oldHeight != height ) ) { kWordDocument()->repaintAllViews( false ); kWordDocument()->updateRulerFrameStartEnd(); } m_changed = true; if ( !m_edit ) { // A change without a FrameSetEdit! This must be the result of // an undo. We need to evaluate. formula->startEvaluation(); } } void KWFormulaFrameSet::slotErrorMessage( const QString& msg ) { KMessageBox::error( /*m_widget*/ 0, msg ); } MouseMeaning KWFormulaFrameSet::getMouseMeaningInsideFrame( const KoPoint& ) { return MEANING_MOUSE_INSIDE_TEXT; } QDomElement KWFormulaFrameSet::save(QDomElement& parentElem, bool saveFrames) { if ( frames.isEmpty() ) // Deleted frameset -> don't save return QDomElement(); QDomElement framesetElem = parentElem.ownerDocument().createElement("FRAMESET"); parentElem.appendChild(framesetElem); KWFrameSet::saveCommon(framesetElem, saveFrames); QDomElement formulaElem = parentElem.ownerDocument().createElement("FORMULA"); framesetElem.appendChild(formulaElem); formula->save(formulaElem); return framesetElem; } void KWFormulaFrameSet::saveOasis(KoXmlWriter&, KoSavingContext&) const { // TODO } void KWFormulaFrameSet::load(QDomElement& attributes, bool loadFrames) { KWFrameSet::load(attributes, loadFrames); QDomElement formulaElem = attributes.namedItem("FORMULA").toElement(); paste( formulaElem ); } void KWFormulaFrameSet::paste( QDomNode& formulaElem ) { if (!formulaElem.isNull()) { if (formula == 0) { formula = m_doc->getFormulaDocument()->createFormula( -1, false ); connect(formula, SIGNAL(formulaChanged(double, double)), this, SLOT(slotFormulaChanged(double, double))); connect( formula, SIGNAL( errorMsg( const QString& ) ), this, SLOT( slotErrorMessage( const QString& ) ) ); } if ( !formula->load( formulaElem.firstChild().toElement() ) ) { kdError(32001) << "Error loading formula" << endl; } } else { kdError(32001) << "Missing FORMULA tag in FRAMESET" << endl; } } void KWFormulaFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position ) { kdDebug() << k_funcinfo << endl; KWFrameSet::moveFloatingFrame( frameNum, position ); if ( !frames.isEmpty() ) { formula->setDocumentPosition( position.x(), position.y()+formula->baseline() ); } } int KWFormulaFrameSet::floatingFrameBaseline( int /*frameNum*/ ) { if ( !frames.isEmpty() ) { return m_doc->ptToLayoutUnitPixY( formula->baseline() ); } return -1; } void KWFormulaFrameSet::setAnchorFormat( KoTextFormat* format, int /*frameNum*/ ) { if ( !frames.isEmpty() ) { formula->setFontSizeDirect( format->pointSize() ); } } void KWFormulaFrameSet::showPopup( KWFrame *, KWView *view, const QPoint &point ) { QPopupMenu * popup = view->popupMenu("Formula"); Q_ASSERT(popup); if (popup) popup->popup( point ); } QPixmap* KWFormulaFrameSet::m_bufPixmap = 0; // stolen from KWDocument // However, I don't see if a formula frame can be an underlying // frame. That is why I use my own buffer. QPixmap* KWFormulaFrameSet::doubleBufferPixmap( const QSize& s ) { if ( !m_bufPixmap ) { int w = QABS( s.width() ); int h = QABS( s.height() ); m_bufPixmap = new QPixmap( w, h ); } else { if ( m_bufPixmap->width() < s.width() || m_bufPixmap->height() < s.height() ) { m_bufPixmap->resize( QMAX( s.width(), m_bufPixmap->width() ), QMAX( s.height(), m_bufPixmap->height() ) ); } } return m_bufPixmap; } KWFormulaFrameSetEdit::KWFormulaFrameSetEdit(KWFormulaFrameSet* fs, KWCanvas* canvas) : KWFrameSetEdit(fs, canvas) { formulaView = new KFormula::View( fs->getFormula() ); connect( formulaView, SIGNAL( cursorChanged( bool, bool ) ), this, SLOT( cursorChanged( bool, bool ) ) ); connect( fs->getFormula(), SIGNAL( leaveFormula( Container*, FormulaCursor*, int ) ), this, SLOT( slotLeaveFormula( Container*, FormulaCursor*, int ) ) ); fs->m_edit = this; m_canvas->gui()->getView()->showFormulaToolbar(true); focusInEvent(); dcop=0; } DCOPObject* KWFormulaFrameSetEdit::dcopObject() { if ( !dcop ) dcop = new KWordFormulaFrameSetEditIface( this ); return dcop; } KWFormulaFrameSetEdit::~KWFormulaFrameSetEdit() { formulaFrameSet()->m_edit = 0; focusOutEvent(); // this causes a core dump on quit m_canvas->gui()->getView()->showFormulaToolbar(false); delete formulaView; formulaView = 0; formulaFrameSet()->getFormula()->startEvaluation(); formulaFrameSet()->setChanged(); m_canvas->repaintChanged( formulaFrameSet(), true ); delete dcop; } const KFormula::View* KWFormulaFrameSetEdit::getFormulaView() const { return formulaView; } KFormula::View* KWFormulaFrameSetEdit::getFormulaView() { return formulaView; } void KWFormulaFrameSetEdit::keyPressEvent( QKeyEvent* event ) { //kdDebug(32001) << "KWFormulaFrameSetEdit::keyPressEvent" << endl; formulaView->keyPressEvent( event ); } void KWFormulaFrameSetEdit::mousePressEvent( QMouseEvent* event, const QPoint&, const KoPoint& pos ) { // [Note that this method is called upon RMB and MMB as well, now] KoPoint tl = m_currentFrame->topLeft(); formulaView->mousePressEvent( event, pos-tl ); } void KWFormulaFrameSetEdit::mouseMoveEvent( QMouseEvent* event, const QPoint&, const KoPoint& pos ) { KoPoint tl = m_currentFrame->topLeft(); formulaView->mouseMoveEvent( event, pos-tl ); } void KWFormulaFrameSetEdit::mouseReleaseEvent( QMouseEvent* event, const QPoint&, const KoPoint& pos ) { KoPoint tl = m_currentFrame->topLeft(); formulaView->mouseReleaseEvent( event, pos-tl ); } void KWFormulaFrameSetEdit::focusInEvent() { //kdDebug(32001) << "KWFormulaFrameSetEdit::focusInEvent" << endl; if ( formulaView != 0 ) { formulaView->focusInEvent(0); } } void KWFormulaFrameSetEdit::focusOutEvent() { //kdDebug(32001) << "KWFormulaFrameSetEdit::focusOutEvent" << //endl; if ( formulaView != 0 ) { formulaView->focusOutEvent(0); } } void KWFormulaFrameSetEdit::copy() { formulaView->getDocument()->copy(); } void KWFormulaFrameSetEdit::cut() { formulaView->getDocument()->cut(); } void KWFormulaFrameSetEdit::paste() { formulaView->getDocument()->paste(); } void KWFormulaFrameSetEdit::selectAll() { formulaView->slotSelectAll(); } void KWFormulaFrameSetEdit::moveHome() { formulaView->moveHome( KFormula::WordMovement ); } void KWFormulaFrameSetEdit::moveEnd() { formulaView->moveEnd( KFormula::WordMovement ); } -void KWFormulaFrameSetEdit::exitLeft() -{ - if ( formulaFrameSet()->isFloating() ) { - KWAnchor* anchor = formulaFrameSet()->findAnchor( 0 ); - int index = anchor->index(); - KoTextParag *parag = static_cast( anchor->paragraph() ); - m_canvas->editTextFrameSet( formulaFrameSet()->anchorFrameset(), parag, index ); - } -} - -void KWFormulaFrameSetEdit::exitRight() -{ - if ( formulaFrameSet()->isFloating() ) { - KWAnchor* anchor = formulaFrameSet()->findAnchor( 0 ); - int index = anchor->index(); - KoTextParag *parag = static_cast( anchor->paragraph() ); - m_canvas->editTextFrameSet( formulaFrameSet()->anchorFrameset(), parag, index+1 ); - } -} - - -void KWFormulaFrameSetEdit::exitAbove() -{ - exitLeft(); -} - - -void KWFormulaFrameSetEdit::exitBelow() -{ - exitRight(); -} - - void KWFormulaFrameSetEdit::removeFormula() { if ( formulaFrameSet()->isFloating() ) { KWCanvas* canvas = m_canvas; // This call will destroy us! We cannot use 'this' afterwards! exitRight(); QKeyEvent keyEvent( QEvent::KeyPress, Key_Backspace, 0, 0 ); canvas->currentFrameSetEdit()->keyPressEvent( &keyEvent ); } } void KWFormulaFrameSetEdit::cursorChanged( bool visible, bool /*selecting*/ ) { if ( visible ) { if ( m_currentFrame ) { // Add the cursor position to the (zoomed) frame position QPoint nPoint = frameSet()->kWordDocument()->zoomPoint( m_currentFrame->topLeft() ); nPoint += formulaView->getCursorPoint(); // Apply viewmode conversion QPoint p = m_canvas->viewMode()->normalToView( nPoint ); m_canvas->ensureVisible( p.x(), p.y() ); } } formulaFrameSet()->setChanged(); m_canvas->repaintChanged( formulaFrameSet(), true ); } void KWFormulaFrameSetEdit::slotLeaveFormula( KFormula::Container*, KFormula::FormulaCursor* cursor, int cmd ) { kdDebug() << k_funcinfo << endl; if ( cursor == formulaView->getCursor() ) { switch ( cmd ) { case KFormula::Container::EXIT_LEFT: exitLeft(); break; case KFormula::Container::EXIT_RIGHT: exitRight(); break; case KFormula::Container::EXIT_ABOVE: - exitAbove(); + exitLeft(); break; case KFormula::Container::EXIT_BELOW: - exitBelow(); + exitRight(); break; case KFormula::Container::REMOVE_FORMULA: removeFormula(); break; } } } #include "kwformulaframe.moc" diff --git a/kword/kwformulaframe.h b/kword/kwformulaframe.h index 52eb6191ee..4e50413eaf 100644 --- a/kword/kwformulaframe.h +++ b/kword/kwformulaframe.h @@ -1,181 +1,172 @@ /* This file is part of the KDE project Copyright (C) 2003 Ulrich Kuettler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef KWFORMULAFRAME_H #define KWFORMULAFRAME_H #include "kwframe.h" namespace KFormula { class FormulaCursor; class Container; class View; } /******************************************************************/ /* Class: KWFormulaFrameSet */ /******************************************************************/ // needed for signals & slots ;( using KFormula::Container; using KFormula::FormulaCursor; using KFormula::View; class KWFormulaFrameSet : public KWFrameSet { Q_OBJECT public: KWFormulaFrameSet( KWDocument *_doc, const QString & name ); virtual ~KWFormulaFrameSet(); virtual KWordFrameSetIface* dcopObject(); /** The type of frameset. Use this to differentiate between different instantiations of * the framesets. Each implementation will return a different frameType. */ virtual FrameSetType type() { return FT_FORMULA; } virtual void addFrame( KWFrame *_frame, bool recalc = true ); /** * Delete a frame from the set of frames this frameSet has. * @param num The frameNumber to be removed. * @param remove passing true means that there can not be an undo of the action. * @param recalc do an updateFrames() */ virtual void delFrame( unsigned int _num, bool remove = true, bool recalc = true ); virtual void moveFrame( KWFrame* frame ); virtual KWFrameSetEdit* createFrameSetEdit(KWCanvas*,bool); virtual MouseMeaning getMouseMeaningInsideFrame( const KoPoint& ); /** * Paint this frameset */ virtual void drawFrameContents(KWFrame *, QPainter*, const QRect&, const QColorGroup&, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode); virtual QDomElement save( QDomElement &parentElem, bool saveFrames = true ); virtual void load( QDomElement &attributes, bool loadFrames = true ); virtual void saveOasis(KoXmlWriter&, KoSavingContext&) const; void paste( QDomNode& formulaElem ); KFormula::Container* getFormula() const { return formula; } void setChanged() { m_changed = true; } virtual void moveFloatingFrame( int frameNum, const KoPoint &position ); virtual int floatingFrameBaseline( int /*frameNum*/ ); virtual void setAnchorFormat( KoTextFormat* format, int /*frameNum*/ ); void showPopup( KWFrame *, KWView *view, const QPoint &point ); // TODO support for protecting the formula's contents virtual void setProtectContent ( bool ) {} virtual bool protectContent() const { return false; } protected slots: void slotFormulaChanged( double width, double height ); void slotErrorMessage( const QString& msg ); private: static QPixmap* doubleBufferPixmap( const QSize& s ); static QPixmap* m_bufPixmap; friend class KWFormulaFrameSetEdit; KFormula::Container* formula; bool m_changed; KWFormulaFrameSetEdit* m_edit; }; class KWFormulaFrameSetEdit : public QObject, public KWFrameSetEdit { Q_OBJECT public: KWFormulaFrameSetEdit(KWFormulaFrameSet* fs, KWCanvas* canvas); virtual ~KWFormulaFrameSetEdit(); KWFormulaFrameSet* formulaFrameSet() const { return static_cast(frameSet()); } const KFormula::View* getFormulaView() const; KFormula::View* getFormulaView(); virtual DCOPObject* dcopObject(); // Events forwarded by the canvas (when being in "edit" mode) virtual void keyPressEvent(QKeyEvent*); virtual void mousePressEvent(QMouseEvent*, const QPoint & n, const KoPoint & d ); virtual void mouseMoveEvent(QMouseEvent*, const QPoint & n, const KoPoint & d); // only called if button is pressed virtual void mouseReleaseEvent(QMouseEvent*, const QPoint & n, const KoPoint & d); //virtual void mouseDoubleClickEvent( QMouseEvent *, const QPoint & n, const KoPoint & d ) {} //virtual void dragEnterEvent( QDragEnterEvent * ) {} //virtual void dragMoveEvent( QDragMoveEvent *, const QPoint &, const KoPoint & ) {} //virtual void dragLeaveEvent( QDragLeaveEvent * ) {} //virtual void dropEvent( QDropEvent *, const QPoint &, const KoPoint & ) {} virtual void focusInEvent(); virtual void focusOutEvent(); virtual void copy(); virtual void cut(); virtual void paste(); virtual void selectAll(); /** Moves the cursor to the first position */ void moveHome(); /** Moves the cursor to the last position */ void moveEnd(); - /** Gets called if the cursor ties to leave the formula at its begin. */ - void exitLeft(); - - /** Gets called if the cursor ties to leave the formula at its end. */ - void exitRight(); - - void exitAbove(); - void exitBelow(); - void removeFormula(); protected slots: /** * Make sure the cursor can be seen at its new position. */ void cursorChanged( bool visible, bool selecting ); void slotLeaveFormula( Container*, FormulaCursor*, int ); private: KFormula::View* formulaView; DCOPObject *dcop; }; #endif diff --git a/kword/kwframe.cc b/kword/kwframe.cc index 6457c2bfed..f7218d65db 100644 --- a/kword/kwframe.cc +++ b/kword/kwframe.cc @@ -1,2418 +1,2444 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 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 "kwdoc.h" #include "kwview.h" #include "kwviewmode.h" #include "kwcanvas.h" #include "kwcommand.h" #include "kwframe.h" #include "kwtextframeset.h" #include "kwtableframeset.h" #include "kwanchor.h" #include "resizehandles.h" #include "KWordFrameSetIface.h" #include "KWordTextFrameSetEditIface.h" #include "KWordFormulaFrameSetIface.h" #include "KWordFormulaFrameSetEditIface.h" #include "KWordPictureFrameSetIface.h" #include "KWordHorizontalLineFrameSetIface.h" #include #include #include #include #include #include // for customItemChar! #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_DRAW /******************************************************************/ /* Class: KWFrameList */ /******************************************************************/ int KWFrameList::compareItems(QPtrCollection::Item a, QPtrCollection::Item b) { int za = ((KWFrame *)a)->zOrder(); int zb = ((KWFrame *)b)->zOrder(); if (za == zb) return 0; if (za < zb) return -1; return 1; } /******************************************************************/ /* Class: KWFrame */ /******************************************************************/ KWFrame::KWFrame(KWFrame * frame) { handles.setAutoDelete(true); m_selected = false; m_runAround = RA_NO; //kdDebug(32001) << "KWFrame::KWFrame this=" << this << " frame=" << frame << endl; copySettings( frame ); m_minFrameHeight=0; } KWFrame::KWFrame(KWFrameSet *fs, double left, double top, double width, double height, RunAround _ra ) : KoRect( left, top, width, height ), // Initialize member vars here. This ensures they are all initialized, since it's // easier to compare this list with the member vars list (compiler ensures order). m_sheetSide( AnySide ), m_runAround( _ra ), m_frameBehavior( AutoExtendFrame ), m_newFrameBehavior( ( fs && fs->type() == FT_TEXT ) ? Reconnect : NoFollowup ), m_runAroundLeft( 1.0 ), m_runAroundRight( 1.0 ), m_runAroundTop( 1.0 ), m_runAroundBottom( 1.0 ), m_paddingLeft( 0 ), m_paddingRight( 0 ), m_paddingTop( 0 ), m_paddingBottom( 0 ), m_minFrameHeight( 0 ), m_internalY( 0 ), m_zOrder( 0 ), m_bCopy( false ), m_selected( false ), m_drawFootNoteLine( false ), m_backgroundColor( (fs && (fs->type() == FT_PICTURE || fs->type() == FT_PART)) ? QBrush( QColor(), Qt::NoBrush) : QBrush( QColor() ) ), // valid brush with invalid color ( default ) m_borderLeft( QColor(), KoBorder::SOLID, 0 ), m_borderRight( QColor(), KoBorder::SOLID, 0 ), m_borderTop( QColor(), KoBorder::SOLID, 0 ), m_borderBottom( QColor(), KoBorder::SOLID, 0 ), handles(), m_framesOnTop(), m_framesBelow(), m_frameSet( fs ) { //kdDebug(32001) << "KWFrame::KWFrame " << this << " left=" << left << " top=" << top << endl; handles.setAutoDelete(true); } KWFrame::~KWFrame() { //kdDebug(32001) << "KWFrame::~KWFrame " << this << endl; if (m_selected) removeResizeHandles(); } void KWFrame::setBackgroundColor( const QBrush &_color ) { m_backgroundColor = _color; } int KWFrame::pageNum() const { Q_ASSERT( m_frameSet ); if ( !m_frameSet ) { kdDebug() << k_funcinfo << this << " has no frameset!" << endl; return 0; } return pageNum( m_frameSet->kWordDocument() ); } int KWFrame::pageNum( KWDocument* doc ) const { if ( y() < 0.1 ) return 0; // ### This kind of calculation will break the day we introduce sections // (with different page sizes and orientation). int page = static_cast(y() / doc->ptPaperHeight()); return page; // Circular dependency. KWDoc uses pageNum to calculate the number of pages! //return KMIN( page, doc->numPages()-1 ); } MouseMeaning KWFrame::getMouseMeaning( const KoPoint & docPoint, MouseMeaning defaultMeaning ) { if ( !m_selected ) return defaultMeaning; double hs = 6; // horizontal snap zone (in pt) double vs = 6; // vertical snap zone (in pt) if ( width() < 18 ) hs = width() / 3; // frame is not wide enough -> leave some room to click inside it if ( height() < 18 ) vs = height() / 3; // same thing if frame is not high enough // Maybe we should calculate the area a bit differently // (on both sides of the line), and allow resizing without selecting. double mx = docPoint.x(); double my = docPoint.y(); // Corners if ( mx >= x() && my >= y() && mx <= x() + hs && my <= y() + vs ) return MEANING_TOPLEFT; if ( mx >= x() && my >= y() + height() - vs && mx <= x() + hs && my <= y() + height() ) return MEANING_BOTTOMLEFT; if ( mx >= x() + width() - hs && my >= y() && mx <= x() + width() && my <= y() + vs ) return MEANING_TOPRIGHT; if ( mx >= x() + width() - hs && my >= y() + height() - vs && mx <= x() + width() && my <= y() + height() ) return MEANING_BOTTOMRIGHT; // Middle of edges if ( mx >= x() && my >= y() + height() / 2 - vs/2 && mx <= x() + hs && my <= y() + height() / 2 + vs/2 ) return MEANING_LEFT; if ( mx >= x() + width() / 2 - hs/2 && my >= y() && mx <= x() + width() / 2 + hs/2 && my <= y() + vs ) return MEANING_TOP; if ( mx >= x() + width() / 2 - hs/2 && my >= y() + height() - vs && mx <= x() + width() / 2 + hs/2 && my <= y() + height() ) return MEANING_BOTTOM; if ( mx >= x() + width() - hs && my >= y() + height() / 2 - vs/2 && mx <= x() + width() && my <= y() + height() / 2 + vs/2 ) return MEANING_RIGHT; return defaultMeaning; } KWFrame *KWFrame::getCopy() { /* returns a deep copy of self */ return new KWFrame(this); } void KWFrame::invalidateParentFrameset() { if (frameSet()->isFloating()) frameSet()->anchorFrameset()->invalidate(); } void KWFrame::copySettings(KWFrame *frm) { setFrameSet( frm->frameSet() ); // do this first in case of debug output in the methods below setRect(frm->x(), frm->y(), frm->width(), frm->height()); // Keep order identical as member var order (and init in ctor) setSheetSide(frm->sheetSide()); setRunAround(frm->runAround()); setRunAroundSide(frm->runAroundSide()); setFrameBehavior(frm->frameBehavior()); setNewFrameBehavior(frm->newFrameBehavior()); setRunAroundGap(frm->runAroundLeft(), frm->runAroundRight(), frm->runAroundTop(), frm->runAroundBottom()); setPaddingLeft(frm->paddingLeft()); setPaddingRight(frm->paddingRight()); setPaddingTop(frm->paddingTop()); setPaddingBottom(frm->paddingBottom()); setMinFrameHeight(frm->minFrameHeight()); m_internalY = 0; // internal Y is recalculated setZOrder(frm->zOrder()); setCopy(frm->isCopy()); setSelected( false );// don't copy this attribute [shouldn't be an attribute of KWFrame] m_drawFootNoteLine = false; // recalculated setBackgroundColor( frm->backgroundColor() ); setLeftBorder(frm->leftBorder()); setRightBorder(frm->rightBorder()); setTopBorder(frm->topBorder()); setBottomBorder(frm->bottomBorder()); } // Insert all resize handles void KWFrame::createResizeHandles() { removeResizeHandles(); QPtrList pages = frameSet()->kWordDocument()->getAllViews(); for (int i=pages.count() -1; i >= 0; i--) createResizeHandlesForPage(pages.at(i)->getGUI()->canvasWidget()); } // Insert 8 resize handles which will be drawn in param canvas void KWFrame::createResizeHandlesForPage(KWCanvas *canvas) { removeResizeHandlesForPage(canvas); for (unsigned int i=0; i < 8; i++) { KWResizeHandle * h = new KWResizeHandle( canvas, (KWResizeHandle::Direction)i, this ); handles.append( h ); } } // remove all the resize handles which will be drawn in param canvas void KWFrame::removeResizeHandlesForPage(KWCanvas *canvas) { for( unsigned int i=0; i < handles.count(); i++) { if(handles.at ( i )->getCanvas() == canvas) { handles.remove(i--); } } } // remove all resizeHandles void KWFrame::removeResizeHandles() { //kdDebug(32001) << this << " KWFrame::removeResizeHandles " << handles.count() << " handles" << endl; handles.clear(); } // move the resizehandles to current location of frame void KWFrame::updateResizeHandles() { for (unsigned int i=0; i< handles.count(); i++) { handles.at(i)->updateGeometry(); } } void KWFrame::repaintResizeHandles() { for (unsigned int i=0; i< handles.count(); i++) { handles.at(i)->repaint(); } } void KWFrame::updateCursorType() { for (unsigned int i=0; i< handles.count(); i++) { handles.at(i)->applyCursorType(); } } void KWFrame::frameBordersChanged() { invalidateParentFrameset(); if (isSelected()) { updateResizeHandles(); } } void KWFrame::updateRulerHandles(){ if(isSelected()) updateResizeHandles(); else { KWDocument *doc = frameSet()->kWordDocument(); if(doc) doc->updateRulerFrameStartEnd(); } } void KWFrame::setSelected( bool _selected ) { //kdDebug(32001) << this << " KWFrame::setSelected " << _selected << endl; bool s = m_selected; m_selected = _selected; if ( m_selected ) createResizeHandles(); else if ( s ) removeResizeHandles(); } QRect KWFrame::outerRect( KWViewMode* viewMode ) const { KWDocument *doc = m_frameSet->kWordDocument(); QRect outerRect( doc->zoomRect( *this ) ); if ( viewMode && !m_frameSet->getGroupManager() ) { int minBorder = viewMode->drawFrameBorders() ? 1 : 0; KWFrame* settingsFrame = m_frameSet->settingsFrame( this ); outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, minBorder ); outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, minBorder ); outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, minBorder ); outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, minBorder ); } return outerRect; } KoRect KWFrame::outerKoRect() const { KoRect outerRect = *this; KWDocument *doc = m_frameSet->kWordDocument(); KWFrame* settingsFrame = m_frameSet->settingsFrame( this ); outerRect.rLeft() -= KoBorder::zoomWidthX( settingsFrame->leftBorder().width(), doc, 1 ) / doc->zoomedResolutionX(); outerRect.rTop() -= KoBorder::zoomWidthY( settingsFrame->topBorder().width(), doc, 1 ) / doc->zoomedResolutionY(); outerRect.rRight() += KoBorder::zoomWidthX( settingsFrame->rightBorder().width(), doc, 1 ) / doc->zoomedResolutionX(); outerRect.rBottom() += KoBorder::zoomWidthY( settingsFrame->bottomBorder().width(), doc, 1 ) / doc->zoomedResolutionY(); return outerRect; } KoRect KWFrame::runAroundRect() const { KoRect raRect = outerKoRect(); raRect.rLeft() -= m_runAroundLeft; raRect.rRight() += m_runAroundRight; raRect.rTop() -= m_runAroundTop; raRect.rBottom() += m_runAroundBottom; return raRect; } void KWFrame::save( QDomElement &frameElem ) { // setAttribute( double ) uses a default precision of 6, and this seems // to be 6 digits, even like '123.123' ! frameElem.setAttribute( "left", QString::number( left(), 'g', DBL_DIG ) ); frameElem.setAttribute( "top", QString::number( top(), 'g', DBL_DIG ) ); frameElem.setAttribute( "right", QString::number( right(), 'g', DBL_DIG ) ); frameElem.setAttribute( "bottom", QString::number( bottom(), 'g', DBL_DIG ) ); if ( minFrameHeight() > 0 ) frameElem.setAttribute( "min-height", QString::number( minFrameHeight(), 'g', DBL_DIG ) ); if(runAround()!=RA_NO) { frameElem.setAttribute( "runaround", static_cast( runAround() ) ); if (runAround() == RA_BOUNDINGRECT) { if (runAroundSide()==RA_LEFT) frameElem.setAttribute( "runaroundSide", "left" ); else if (runAroundSide()==RA_RIGHT) frameElem.setAttribute( "runaroundSide", "right" ); else frameElem.setAttribute( "runaroundSide", "biggest" ); } } if(runAroundLeft()!=0 || runAroundRight()!=0 || runAroundTop()!=0 || runAroundBottom()!=0) { frameElem.setAttribute( "runaroundLeft", m_runAroundLeft ); frameElem.setAttribute( "runaroundRight", m_runAroundRight ); frameElem.setAttribute( "runaroundTop", m_runAroundTop ); frameElem.setAttribute( "runaroundBottom", m_runAroundBottom ); // The old file format had only one value, keep compat double runAroundGap = QMAX( QMAX( m_runAroundLeft, m_runAroundRight ), QMAX( m_runAroundTop, m_runAroundBottom ) ); frameElem.setAttribute( "runaroundGap", runAroundGap ); } if(leftBorder().penWidth()!=0) frameElem.setAttribute( "lWidth", leftBorder().penWidth() ); if(leftBorder().color.isValid()) { frameElem.setAttribute( "lRed", leftBorder().color.red() ); frameElem.setAttribute( "lGreen", leftBorder().color.green() ); frameElem.setAttribute( "lBlue", leftBorder().color.blue() ); } if(leftBorder().getStyle() != KoBorder::SOLID) frameElem.setAttribute( "lStyle", static_cast( leftBorder().getStyle()) ); if(rightBorder().penWidth()!=0) frameElem.setAttribute( "rWidth", rightBorder().penWidth() ); if(rightBorder().color.isValid()) { frameElem.setAttribute( "rRed", rightBorder().color.red() ); frameElem.setAttribute( "rGreen", rightBorder().color.green() ); frameElem.setAttribute( "rBlue", rightBorder().color.blue() ); } if(rightBorder().getStyle() != KoBorder::SOLID) frameElem.setAttribute( "rStyle", static_cast( rightBorder().getStyle() ) ); if(topBorder().penWidth()!=0) frameElem.setAttribute( "tWidth", topBorder().penWidth() ); if(topBorder().color.isValid()) { frameElem.setAttribute( "tRed", topBorder().color.red() ); frameElem.setAttribute( "tGreen", topBorder().color.green() ); frameElem.setAttribute( "tBlue", topBorder().color.blue() ); } if(topBorder().getStyle() != KoBorder::SOLID) frameElem.setAttribute( "tStyle", static_cast( topBorder().getStyle() ) ); if(bottomBorder().penWidth()!=0) { frameElem.setAttribute( "bWidth", bottomBorder().penWidth() ); } if(bottomBorder().color.isValid()) { frameElem.setAttribute( "bRed", bottomBorder().color.red() ); frameElem.setAttribute( "bGreen", bottomBorder().color.green() ); frameElem.setAttribute( "bBlue", bottomBorder().color.blue() ); } if(bottomBorder().getStyle() != KoBorder::SOLID) frameElem.setAttribute( "bStyle", static_cast( bottomBorder().getStyle() ) ); if(backgroundColor().color().isValid()) { frameElem.setAttribute( "bkRed", backgroundColor().color().red() ); frameElem.setAttribute( "bkGreen", backgroundColor().color().green() ); frameElem.setAttribute( "bkBlue", backgroundColor().color().blue() ); frameElem.setAttribute( "bkStyle", (int)backgroundColor().style ()); } if(paddingLeft() != 0) frameElem.setAttribute( "bleftpt", paddingLeft() ); if(paddingRight()!=0) frameElem.setAttribute( "brightpt", paddingRight() ); if(paddingTop()!=0) frameElem.setAttribute( "btoppt", paddingTop() ); if(paddingBottom()!=0) frameElem.setAttribute( "bbottompt", paddingBottom() ); if(frameBehavior()!=AutoCreateNewFrame) frameElem.setAttribute( "autoCreateNewFrame", static_cast( frameBehavior()) ); //if(newFrameBehavior()!=Reconnect) // always save this one, since the default value depends on the type of frame, etc. frameElem.setAttribute( "newFrameBehavior", static_cast( newFrameBehavior()) ); //same reason frameElem.setAttribute( "copy", static_cast( m_bCopy ) ); if(sheetSide()!= AnySide) frameElem.setAttribute( "sheetSide", static_cast( sheetSide()) ); frameElem.setAttribute( "z-index", zOrder() ); } void KWFrame::load( QDomElement &frameElem, KWFrameSet* frameSet, int syntaxVersion ) { m_minFrameHeight = KWDocument::getAttribute( frameElem, "min-height", 0.0 ); m_runAround = static_cast( KWDocument::getAttribute( frameElem, "runaround", RA_NO ) ); QString str = frameElem.attribute( "runaroundSide" ); if ( str == "left" ) setRunAroundSide( RA_LEFT ); else if ( str == "right" ) setRunAroundSide( RA_RIGHT ); // default case: RA_BIGGEST, since it's 0 double runAroundGap = ( frameElem.hasAttribute( "runaroundGap" ) ) ? frameElem.attribute( "runaroundGap" ).toDouble() : frameElem.attribute( "runaGapPT" ).toDouble(); setRunAroundGap( KWDocument::getAttribute( frameElem, "runaroundLeft", runAroundGap ), KWDocument::getAttribute( frameElem, "runaroundRight", runAroundGap ), KWDocument::getAttribute( frameElem, "runaroundTop", runAroundGap ), KWDocument::getAttribute( frameElem, "runaroundBottom", runAroundGap ) ); m_sheetSide = static_cast( KWDocument::getAttribute( frameElem, "sheetSide", AnySide ) ); m_frameBehavior = static_cast( KWDocument::getAttribute( frameElem, "autoCreateNewFrame", AutoCreateNewFrame ) ); // Old documents had no "NewFrameBehavior" for footers/headers -> default to Copy. NewFrameBehavior defaultValue = frameSet->isHeaderOrFooter() ? Copy : Reconnect; // for old document we used the British spelling (newFrameBehaviour), so this is for backwards compatibility. defaultValue = static_cast( KWDocument::getAttribute( frameElem, "newFrameBehaviour", defaultValue ) ); m_newFrameBehavior = static_cast( KWDocument::getAttribute( frameElem, "newFrameBehavior", defaultValue ) ); if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet m_newFrameBehavior = NoFollowup; KoBorder l, r, t, b; l.setPenWidth( KWDocument::getAttribute( frameElem, "lWidth", 0.0 )); r.setPenWidth(KWDocument::getAttribute( frameElem, "rWidth", 0.0 )); t.setPenWidth(KWDocument::getAttribute( frameElem, "tWidth", 0.0 )); b.setPenWidth(KWDocument::getAttribute( frameElem, "bWidth", 0.0 )); if ( frameElem.hasAttribute("lRed") ) l.color.setRgb( KWDocument::getAttribute( frameElem, "lRed", 0 ), KWDocument::getAttribute( frameElem, "lGreen", 0 ), KWDocument::getAttribute( frameElem, "lBlue", 0 ) ); if ( frameElem.hasAttribute("rRed") ) r.color.setRgb( KWDocument::getAttribute( frameElem, "rRed", 0 ), KWDocument::getAttribute( frameElem, "rGreen", 0 ), KWDocument::getAttribute( frameElem, "rBlue", 0 ) ); if ( frameElem.hasAttribute("tRed") ) t.color.setRgb( KWDocument::getAttribute( frameElem, "tRed", 0 ), KWDocument::getAttribute( frameElem, "tGreen", 0 ), KWDocument::getAttribute( frameElem, "tBlue", 0 ) ); if ( frameElem.hasAttribute("bRed") ) b.color.setRgb( KWDocument::getAttribute( frameElem, "bRed", 0 ), KWDocument::getAttribute( frameElem, "bGreen", 0 ), KWDocument::getAttribute( frameElem, "bBlue", 0 ) ); l.setStyle(static_cast( KWDocument::getAttribute( frameElem, "lStyle", KoBorder::SOLID ) )); r.setStyle(static_cast( KWDocument::getAttribute( frameElem, "rStyle", KoBorder::SOLID ) )); t.setStyle(static_cast( KWDocument::getAttribute( frameElem, "tStyle", KoBorder::SOLID ) )); b.setStyle( static_cast( KWDocument::getAttribute( frameElem, "bStyle", KoBorder::SOLID ) )); QColor c; if ( frameElem.hasAttribute("bkRed") ) c.setRgb( KWDocument::getAttribute( frameElem, "bkRed", 0 ), KWDocument::getAttribute( frameElem, "bkGreen", 0 ), KWDocument::getAttribute( frameElem, "bkBlue", 0 ) ); if ( syntaxVersion < 2 ) // Activate old "white border == no border" conversion { if(c==l.color && l.penWidth()==1 && l.getStyle()==0 ) l.setPenWidth(0); if(c==r.color && r.penWidth()==1 && r.getStyle()==0) r.setPenWidth(0); if(c==t.color && t.penWidth()==1 && t.getStyle()==0 ) t.setPenWidth(0); if(c==b.color && b.penWidth()==1 && b.getStyle()==0 ) b.setPenWidth(0); } m_borderLeft = l; m_borderRight = r; m_borderTop = t; m_borderBottom = b; m_backgroundColor = QBrush( c ); if( frameElem.hasAttribute("bkStyle")) m_backgroundColor.setStyle (static_cast(KWDocument::getAttribute( frameElem, "bkStyle", Qt::SolidPattern ))); m_paddingLeft = frameElem.attribute( "bleftpt" ).toDouble(); m_paddingRight = frameElem.attribute( "brightpt" ).toDouble(); m_paddingTop = frameElem.attribute( "btoppt" ).toDouble(); m_paddingBottom = frameElem.attribute( "bbottompt" ).toDouble(); m_bCopy = KWDocument::getAttribute( frameElem, "copy", frameSet->isHeaderOrFooter() /* default to true for h/f */ ); m_zOrder = frameElem.attribute( "z-index" ).toInt(); } void KWFrame::loadCommonOasisProperties( KoOasisContext& context, KWFrameSet* frameSet ) { KoStyleStack& styleStack = context.styleStack(); styleStack.setTypeProperties( "graphic" ); // padding. fo:padding for 4 values or padding-left/right/top/bottom (3.11.29 p228) m_paddingLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "left" ) ); m_paddingRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "right" ) ); m_paddingTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "top" ) ); m_paddingBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "padding", "bottom" ) ); #if 0 // not allowed in the current OASIS spec // margins, i.e. runAroundGap. fo:margin for 4 values or padding-left/right/top/bottom m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "left" ) ); m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "right" ) ); m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "top" ) ); m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin", "bottom" ) ); #endif // margins, i.e. runAroundGap. fo:margin-left/right/top/bottom m_runAroundLeft = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-left" ) ); m_runAroundRight = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-right" ) ); m_runAroundTop = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-top" ) ); m_runAroundBottom = KoUnit::parseValue( styleStack.attributeNS( KoXmlNS::fo, "margin-bottom" ) ); // background color (3.11.25) if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-color" ) ) { QString color = styleStack.attributeNS( KoXmlNS::fo, "background-color" ); if ( color == "transparent" ) m_backgroundColor = QBrush( QColor(), Qt::NoBrush ); else { m_backgroundColor = QBrush( QColor( color ) /*, brush style is a dead feature, ignored */ ); } } // OOo compatibility: it uses background-transparency=100% instead of background-color="transparent" if ( styleStack.hasAttributeNS( KoXmlNS::fo, "background-transparency" ) ) { QString transp = styleStack.attributeNS( KoXmlNS::fo, "background-transparency" ); if ( transp == "100%" ) m_backgroundColor.setStyle( Qt::NoBrush ); } // borders (3.11.27) // can be none/hidden, solid and double. General form is the XSL/FO "width|style|color" { m_borderLeft.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "left") ); m_borderRight.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "right") ); m_borderTop.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "top") ); m_borderBottom.loadFoBorder( styleStack.attributeNS( KoXmlNS::fo, "border", "bottom") ); } // TODO more refined border spec for double borders (3.11.28) // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering // of existing documents, only editing (and only KWord has this kind of option until now). const QCString frameBehaviorOnNewPage = styleStack.attributeNS( KoXmlNS::style, "frame-behavior-on-new-page" ).latin1(); if ( frameBehaviorOnNewPage == "followup" ) m_newFrameBehavior = Reconnect; else if ( frameBehaviorOnNewPage == "copy" ) m_newFrameBehavior = Copy; else if ( frameBehaviorOnNewPage == "none" ) m_newFrameBehavior = NoFollowup; else { // Defaults for OASIS documents not created by KWord m_newFrameBehavior = frameSet->isHeaderOrFooter() ? Copy : NoFollowup; if ( !frameBehaviorOnNewPage.isEmpty() ) kdWarning(32001) << "Unknown value for style:frame-behavior-on-new-page: " << frameBehaviorOnNewPage << endl; } // Footnotes and endnotes are handled in a special way. if ( frameSet->isFootEndNote() ) // note that isFootNote/isEndNote are not possible yet m_newFrameBehavior = NoFollowup; KWFrame::RunAround runAround = KWFrame::RA_BOUNDINGRECT; KWFrame::RunAroundSide runAroundSide = KWFrame::RA_BIGGEST; const QCString oowrap = styleStack.attributeNS( KoXmlNS::style, "wrap" ).latin1(); if ( oowrap == "none" ) // 'no wrap' means 'avoid horizontal space' runAround = KWFrame::RA_SKIP; else if ( oowrap == "left" ) runAroundSide = KWFrame::RA_LEFT; else if ( oowrap == "right" ) runAroundSide= KWFrame::RA_RIGHT; else if ( oowrap == "run-through" ) runAround = KWFrame::RA_NO; //if ( oowrap == "biggest" ) // OASIS extension // ->( KWFrame::RA_BOUNDINGRECT, KWFrame::RA_BIGGEST ), already set above //if ( oowrap == "parallel" || oowrap == "dynamic" ) // dynamic is called "optimal" in the OO GUI. It's different from biggest because it can lead to parallel. // Those are not supported in KWord, let's use biggest instead setRunAround( runAround ); setRunAroundSide( runAroundSide ); } void KWFrame::startOasisFrame( KoXmlWriter &writer, KoGenStyles& mainStyles ) const { writer.startElement( "draw:frame" ); writer.addAttribute( "draw:name", frameSet()->getName() ); // ### framesets are named, not frames... writer.addAttribute( "draw:style-name", saveOasisFrameStyle( mainStyles ) ); if ( !frameSet()->isFloating() ) { // non-inline frame, anchored to page int pgNum = pageNum(); double yInPage = top() - pgNum * frameSet()->kWordDocument()->ptPaperHeight(); writer.addAttributePt( "svg:x", left() ); writer.addAttributePt( "svg:y", yInPage ); writer.addAttribute( "text:anchor-type", "page" ); writer.addAttribute( "text:anchor-page-number", pgNum + 1 ); // OASIS starts at 1 writer.addAttribute( "draw:z-index", zOrder() ); } writer.addAttributePt( "svg:width", width() ); writer.addAttributePt( "svg:height", height() ); // the caller fills in the child element, then closes draw:frame } QString KWFrame::saveOasisFrameStyle( KoGenStyles& mainStyles ) const { KoGenStyle frameStyle( KWDocument::STYLE_FRAME, "graphic" ); QString protect; if ( frameSet()->protectContent() ) protect = "content"; if ( frameSet()->isProtectSize() ) // ## should be moved for frame { if ( !protect.isEmpty() ) protect+=" "; protect+="size"; } if ( !protect.isEmpty() ) frameStyle.addProperty( "style:protect", protect ); // Background: color and transparency // OOo seems to use style:background-transparency="100%", but the schema allows background-color=transparent if ( m_backgroundColor.style() == Qt::NoBrush ) frameStyle.addProperty( "fo:background-color", "transparent" ); else if ( m_backgroundColor.color().isValid() ) frameStyle.addProperty( "fo:background-color", m_backgroundColor.color().name() ); // Borders if ( ( m_borderLeft == m_borderRight ) && ( m_borderLeft == m_borderTop ) && ( m_borderLeft == m_borderBottom ) ) { frameStyle.addProperty( "fo:border", m_borderLeft.saveFoBorder() ); } else { frameStyle.addProperty( "fo:border-left", m_borderLeft.saveFoBorder() ); frameStyle.addProperty( "fo:border-right", m_borderRight.saveFoBorder() ); frameStyle.addProperty( "fo:border-top", m_borderTop.saveFoBorder() ); frameStyle.addProperty( "fo:border-bottom", m_borderBottom.saveFoBorder() ); } if ( m_paddingLeft != 0 && ( ( m_paddingLeft == m_paddingRight ) && ( m_paddingLeft == m_paddingTop ) && ( m_paddingLeft == m_paddingBottom ) ) ) frameStyle.addPropertyPt( "fo:padding", m_paddingLeft ); else { if ( m_paddingLeft != 0 ) frameStyle.addPropertyPt( "fo:padding-left", m_paddingLeft ); if ( m_paddingRight != 0 ) frameStyle.addPropertyPt( "fo:padding-right", m_paddingRight ); if ( m_paddingTop != 0 ) frameStyle.addPropertyPt( "fo:padding-top", m_paddingTop ); if ( m_paddingBottom != 0 ) frameStyle.addPropertyPt( "fo:padding-bottom", m_paddingBottom ); } #if 0 // not allowed in the current OASIS spec if ( m_runAroundLeft != 0 && ( ( m_runAroundLeft == m_runAroundRight ) && ( m_runAroundLeft == m_runAroundTop ) && ( m_runAroundLeft == m_runAroundBottom ) ) ) frameStyle.addPropertyPt( "fo:margin", m_runAroundLeft ); else { #endif if ( m_runAroundLeft != 0 ) frameStyle.addPropertyPt( "fo:margin-left", m_runAroundLeft ); if ( m_runAroundRight != 0 ) frameStyle.addPropertyPt( "fo:margin-right", m_runAroundRight ); if ( m_runAroundTop != 0 ) frameStyle.addPropertyPt( "fo:margin-top", m_runAroundTop ); if ( m_runAroundBottom != 0 ) frameStyle.addPropertyPt( "fo:margin-bottom", m_runAroundBottom ); #if 0 // not allowed in the current OASIS spec } #endif if ( runAround() == KWFrame::RA_SKIP ) frameStyle.addProperty( "style:wrap", "none" ); else if ( runAround() == KWFrame::RA_NO ) frameStyle.addProperty( "style:wrap", "run-through" ); else // RA_BOUNDINGRECT { if ( runAroundSide() == KWFrame::RA_LEFT ) frameStyle.addProperty( "style:wrap", "left" ); else if ( runAroundSide() == KWFrame::RA_RIGHT ) frameStyle.addProperty( "style:wrap", "right" ); else if ( runAroundSide() == KWFrame::RA_BIGGEST ) frameStyle.addProperty( "style:wrap", "biggest" ); } // This attribute isn't part of the OASIS spec. Doesn't matter since it doesn't affect rendering // of existing documents, only editing (and only KWord has this kind of option until now). NewFrameBehavior defaultNfb = frameSet()->isHeaderOrFooter() ? Copy : NoFollowup; if ( m_newFrameBehavior != defaultNfb ) { const char* value; if ( m_newFrameBehavior == Reconnect ) value = "followup"; else if ( m_newFrameBehavior == Copy ) value = "copy"; else if ( m_newFrameBehavior == NoFollowup ) value = "none"; frameStyle.addProperty( "style:frame-behavior-on-new-page", value ); } // The loading code for this one is in kwtextframeset, maybe this should be moved there too const char* frameBehav = 0; if ( m_frameBehavior == KWFrame::Ignore ) frameBehav = "clip"; else if ( m_frameBehavior == KWFrame::AutoCreateNewFrame ) frameBehav = "auto-create-new-frame"; // the third case, AutoExtendFrame is handled by min-height if ( frameBehav ) frameStyle.addProperty( "style:overflow-behavior", frameBehav ); return mainStyles.lookup( frameStyle, "fr" ); } bool KWFrame::frameAtPos( const QPoint& point, bool borderOfFrameOnly) { // Forwarded to KWFrameSet to make it virtual return frameSet()->isFrameAtPos( this, point, borderOfFrameOnly ); } KoRect KWFrame::innerRect() const { KoRect inner( this->normalize()); inner.moveBy( paddingLeft(), paddingTop() ); inner.setWidth( innerWidth() ); inner.setHeight( innerHeight() ); return inner; } double KWFrame::innerWidth() const { return KMAX( 0.0, width() - m_paddingLeft - m_paddingRight ); } double KWFrame::innerHeight() const { return KMAX( 0.0, height() - m_paddingTop - m_paddingBottom ); } void KWFrame::setFramePadding( double _left, double _top, double _right, double _bottom) { m_paddingLeft = _left; m_paddingTop = _top; m_paddingRight = _right; m_paddingBottom = _bottom; } void KWFrame::setMinFrameHeight(double h) { //kdDebug() << k_funcinfo << m_frameSet->getName() << " " << this << " " << h << endl; m_minFrameHeight = h; } /******************************************************************/ /* Class: KWFrameSet */ /******************************************************************/ KWFrameSet::KWFrameSet( KWDocument *doc ) : m_doc( doc ), frames(), m_framesInPage(), m_firstPage( 0 ), m_emptyList(), m_info( FI_BODY ), grpMgr( 0L ), m_removeableHeader( false ), m_visible( true ), m_protectSize( false ), m_anchorTextFs( 0L ), m_dcop( 0L ) { // Send our "repaintChanged" signals to the document. connect( this, SIGNAL( repaintChanged( KWFrameSet * ) ), doc, SLOT( slotRepaintChanged( KWFrameSet * ) ) ); frames.setAutoDelete( true ); m_framesInPage.setAutoDelete( true ); // autodelete the lists in the array (not the frames;) } KWordFrameSetIface* KWFrameSet::dcopObject() { if ( !m_dcop ) m_dcop = new KWordFrameSetIface( this ); return m_dcop; } KWFrameSet::~KWFrameSet() { delete m_dcop; } void KWFrameSet::addFrame( KWFrame *_frame, bool recalc ) { if ( frames.findRef( _frame ) != -1 ) return; //kdDebug(32001) << k_funcinfo << getName() << " adding frame" << _frame << " recalc=" << recalc << endl; frames.append( _frame ); _frame->setFrameSet(this); if(recalc) updateFrames(); } void KWFrameSet::delFrame( unsigned int _num, bool remove, bool recalc ) { //kdDebug(32001) << k_funcinfo << getName() << " deleting frame" << _num << " remove=" << remove << " recalc=" << recalc << kdBacktrace(); KWFrame *frm = frames.at( _num ); Q_ASSERT( frm ); frames.take( _num ); if ( !remove ) { if (frm->isSelected()) // get rid of the resize handles frm->setSelected(false); frm->setFrameSet(0L); } else { // ###### should something similar be done when just removing a frame from the list? frameDeleted( frm, recalc ); // inform kwtableframeset if necessary delete frm; //kdDebug(32001) << k_funcinfo << frm << " deleted. Now I have " << frames.count() << " frames" << endl; } if ( recalc ) updateFrames(); } void KWFrameSet::delFrame( KWFrame *frm, bool remove, bool recalc ) { //kdDebug(32001) << "KWFrameSet::delFrame " << frm << " remove=" << remove << endl; int _num = frames.findRef( frm ); Q_ASSERT( _num != -1 ); if ( _num == -1 ) return; delFrame( _num, remove, recalc ); } void KWFrameSet::deleteAllFrames() { if ( !frames.isEmpty() ) { frames.clear(); updateFrames(); } } void KWFrameSet::deleteAllCopies() { if ( frames.count() > 1 ) { KWFrame * firstFrame = frames.first()->getCopy(); frames.clear(); frames.append( firstFrame ); updateFrames(); } } void KWFrameSet::createEmptyRegion( const QRect & crect, QRegion & emptyRegion, KWViewMode *viewMode ) { int paperHeight = m_doc->paperHeight(); //kdDebug(32001) << "KWFrameSet::createEmptyRegion " << getName() << endl; QPtrListIterator frameIt = frameIterator(); for ( ; frameIt.current(); ++frameIt ) { QRect outerRect( viewMode->normalToView( frameIt.current()->outerRect(viewMode) ) ); //kdDebug(32001) << "KWFrameSet::createEmptyRegion outerRect=" << outerRect << " crect=" << crect << endl; outerRect &= crect; // This is important, to avoid calling subtract with a Y difference > 65536 if ( !outerRect.isEmpty() ) { emptyRegion = emptyRegion.subtract( outerRect ); //kdDebug(32001) << "KWFrameSet::createEmptyRegion emptyRegion now: " << endl; DEBUGREGION( emptyRegion ); } if ( crect.bottom() + paperHeight < outerRect.top() ) return; // Ok, we're far below the crect, abort. } } void KWFrameSet::drawPadding( KWFrame *frame, QPainter *p, const QRect &crect, const QColorGroup &, KWViewMode *viewMode ) { QRect outerRect( viewMode->normalToView( frame->outerRect(viewMode) ) ); //kdDebug(32001) << "KWFrameSet::drawPadding frame: " << frameFromPtr( frame ) // << " outerRect: " << outerRect // << " crect: " << crect << endl; if ( !crect.intersects( outerRect ) ) { #ifdef DEBUG_DRAW kdDebug(32001) << "KWFrameSet::drawPadding no intersection with " << crect << endl; #endif return; } QRect frameRect( viewMode->normalToView( m_doc->zoomRect( *frame ) ) ); p->save(); QBrush bgBrush( frame->backgroundColor() ); bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), p ) ); p->setBrush( bgBrush ); int leftMargin = m_doc->zoomItX(frame->paddingLeft()); int topMargin = m_doc->zoomItY(frame->paddingTop()); int rightMargin = m_doc->zoomItX(frame->paddingRight()); int bottomMargin = m_doc->zoomItY(frame->paddingBottom()); //kdDebug(32001) << "KWFrameSet::drawPadding leftMargin=" << leftMargin << " topMargin=" << topMargin << " rightMargin=" << rightMargin << " bottomMargin=" << bottomMargin << endl; if ( topMargin != 0 ) { QRect r( frameRect.left(), frameRect.top(), frameRect.width(), topMargin ); p->fillRect( r, bgBrush ); } if ( leftMargin != 0 ) { QRect r( frameRect.left(), frameRect.top(), leftMargin, frameRect.height() ); p->fillRect( r, bgBrush ); } if ( rightMargin != 0 ) { QRect r( frameRect.right()-rightMargin, frameRect.top(), rightMargin, frameRect.height() ); p->fillRect( r, bgBrush ); } if ( bottomMargin != 0 ) { QRect r( frameRect.left(), frameRect.bottom()-bottomMargin, frameRect.width(), bottomMargin ); p->fillRect( r, bgBrush ); } p->restore(); } void KWFrameSet::drawFrameBorder( QPainter *painter, KWFrame *frame, KWFrame *settingsFrame, const QRect &crect, KWViewMode *viewMode ) { QRect outerRect( viewMode->normalToView( frame->outerRect( viewMode ) ) ); //kdDebug(32001) << "KWFrameSet::drawFrameBorder frame: " << frameFromPtr( frame ) // << " outerRect: " << outerRect << endl; if ( !crect.intersects( outerRect ) ) { //kdDebug(32001) << "KWFrameSet::drawFrameBorder no intersection with " << crect << endl; return; } QRect frameRect( viewMode->normalToView( m_doc->zoomRect( *frame ) ) ); painter->save(); QBrush bgBrush( settingsFrame->backgroundColor() ); //bool defaultColor = !bgBrush.color().isValid(); bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), painter ) ); painter->setBrush( bgBrush ); // Draw default borders using view settings... QPen viewSetting( QApplication::palette().color( QPalette::Active, QColorGroup::Mid ) ); int minBorder = 1; // ...except when printing, or embedded doc, or disabled. if ( !viewMode || !viewMode->drawFrameBorders() ) { viewSetting = NoPen; minBorder = 0; } // Draw borders either as the user defined them, or using the view settings. // Borders should be drawn _outside_ of the frame area // otherwise the frames will erase the border when painting themselves. KoBorder::drawBorders( *painter, m_doc, frameRect, settingsFrame->leftBorder(), settingsFrame->rightBorder(), settingsFrame->topBorder(), settingsFrame->bottomBorder(), minBorder, viewSetting ); painter->restore(); } void KWFrameSet::setFloating() { // Find main text frame QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { KWTextFrameSet * frameSet = dynamic_cast( fit.current() ); if ( !frameSet || frameSet->frameSetInfo() != FI_BODY ) continue; KoTextParag* parag = 0L; int index = 0; KoPoint dPoint( frames.first()->topLeft() ); kdDebug(32001) << "KWFrameSet::setFloating looking for pos at " << dPoint.x() << " " << dPoint.y() << endl; frameSet->findPosition( dPoint, parag, index ); // Create anchor. TODO: refcount the anchors! setAnchored( frameSet, parag, index ); frameSet->layout(); frames.first()->updateResizeHandles(); m_doc->frameChanged( frames.first() ); return; } } void KWFrameSet::setAnchored( KWTextFrameSet* textfs, int paragId, int index, bool placeHolderExists /* = false */, bool repaint ) { KWTextParag * parag = static_cast( textfs->textDocument()->paragAt( paragId ) ); Q_ASSERT( parag ); if ( parag ) setAnchored( textfs, parag, index, placeHolderExists, repaint ); } void KWFrameSet::setAnchored( KWTextFrameSet* textfs, KoTextParag* parag, int index, bool placeHolderExists /* = false */, bool repaint ) { kdDebug(32001) << "KWFrameSet::setAnchored " << textfs << " " << parag->paragId() << " " << index << " " << placeHolderExists << endl; Q_ASSERT( textfs ); Q_ASSERT( parag ); if ( isFloating() ) deleteAnchors(); m_anchorTextFs = textfs; if ( parag ) createAnchors( parag, index, placeHolderExists, repaint ); if ( !placeHolderExists ) // i.e. not while loading { m_doc->updateAllFrames(); // We just became floating, so we need to be removed from "frames on top/below". // TODO pass page number to updateAllFrames - hmm, we could have several frames in theory } } void KWFrameSet::setAnchored( KWTextFrameSet* textfs ) { m_anchorTextFs = textfs; m_doc->updateAllFrames(); // We just became floating, so we need to be removed from "frames on top/below". // TODO pass page number - hmm, we could have several frames in theory } // Find where our anchor is ( if we are anchored ). // We can't store a pointers to anchors, because over time we might change anchors // (Especially, undo/redo of insert/delete can reuse an old anchor and forget a newer one etc.) KWAnchor * KWFrameSet::findAnchor( int frameNum ) { Q_ASSERT( m_anchorTextFs ); // Yes, a linear search, but only among all customitems of the correct textdoc, // whose number is assumed to be quite small. QPtrListIterator cit( m_anchorTextFs->textDocument()->allCustomItems() ); for ( ; cit.current() ; ++cit ) { KWAnchor * anchor = dynamic_cast( cit.current() ); if ( anchor && !anchor->isDeleted() && anchor->frameSet() == this && anchor->frameNum() == frameNum ) return anchor; } kdWarning() << "KWFrameSet::findAnchor anchor not found (frameset='" << getName() << "' frameNum=" << frameNum << ")" << endl; return 0L; } void KWFrameSet::setFixed() { kdDebug(32001) << "KWFrameSet::setFixed" << endl; if ( isFloating() ) deleteAnchors(); m_anchorTextFs = 0L; // make sure the frames are on top // (their z-order didn't matter when they were inline) QPtrListIterator frameIt = frameIterator(); for ( ; frameIt.current(); ++frameIt ) frameIt.current()->setZOrder( m_doc->maxZOrder( frameIt.current()->pageNum(m_doc) ) + 1 ); } KWAnchor * KWFrameSet::createAnchor( KoTextDocument *txt, int frameNum ) { KWAnchor * anchor = new KWAnchor( txt, this, frameNum ); return anchor; } void KWFrameSet::createAnchors( KoTextParag * parag, int index, bool placeHolderExists /*= false */ /*only used when loading*/, bool repaint ) { kdDebug(32001) << "KWFrameSet::createAnchors" << endl; Q_ASSERT( m_anchorTextFs ); QPtrListIterator frameIt = frameIterator(); for ( ; frameIt.current(); ++frameIt, ++index ) { //if ( ! frameIt.current()->anchor() ) { // Anchor this frame, after the previous one KWAnchor * anchor = createAnchor( m_anchorTextFs->textDocument(), frameFromPtr( frameIt.current() ) ); if ( !placeHolderExists ) parag->insert( index, KoTextObject::customItemChar() ); parag->setCustomItem( index, anchor, 0 ); } } parag->setChanged( true ); if ( repaint ) emit repaintChanged( m_anchorTextFs ); } void KWFrameSet::deleteAnchor( KWAnchor * anchor ) { // Simple deletion, no undo/redo KoTextCursor c( m_anchorTextFs->textDocument() ); c.setParag( anchor->paragraph() ); c.setIndex( anchor->index() ); anchor->setDeleted( true ); // this sets m_anchorTextFs to 0L static_cast(c.parag())->removeCustomItem(c.index()); c.remove(); // This deletes the character where the anchor was // We don't delete the anchor since it might be in a customitemmap in a text-insert command // TODO: refcount the anchors c.parag()->setChanged( true ); } void KWFrameSet::deleteAnchors() { kdDebug(32002) << "KWFrameSet::deleteAnchors" << endl; KWTextFrameSet * textfs = m_anchorTextFs; Q_ASSERT( textfs ); if ( !textfs ) return; //QPtrListIterator frameIt = frameIterator(); int frameNum = 0; // At the moment there's only one anchor per frameset // With tables the loop below will be wrong anyway... //for ( ; frameIt.current(); ++frameIt, ++frameNum ) { /* if ( frameIt.current()->anchor() ) deleteAnchor( frameIt.current()->anchor() ); frameIt.current()->setAnchor( 0L ); */ KWAnchor * anchor = findAnchor( frameNum ); deleteAnchor( anchor ); } emit repaintChanged( textfs ); } void KWFrameSet::moveFloatingFrame( int frameNum, const KoPoint &position ) { KWFrame * frame = frames.at( frameNum ); Q_ASSERT( frame ); if ( !frame ) return; KoPoint pos( position ); // position includes the border, we need to adjust accordingly pos.rx() += frame->leftBorder().width(); pos.ry() += frame->topBorder().width(); if ( frame->topLeft() != pos ) { kdDebug(32002) << "KWFrameSet::moveFloatingFrame " << pos.x() << "," << pos.y() << endl; int oldPageNum = frame->pageNum(); frame->moveTopLeft( pos ); updateFrames(); kWordDocument()->updateFramesOnTopOrBelow( frame->pageNum() ); if ( oldPageNum != frame->pageNum() ) kWordDocument()->updateFramesOnTopOrBelow( oldPageNum ); if ( frame->isSelected() ) frame->updateResizeHandles(); } invalidate(); } KoRect KWFrameSet::floatingFrameRect( int frameNum ) { KWFrame * frame = frames.at( frameNum ); Q_ASSERT( frame ); Q_ASSERT( isFloating() ); KWAnchor* anchor = findAnchor( frameNum ); Q_ASSERT( anchor ); QRect paragRect = anchor->paragraph()->rect(); int x = anchor->x() + paragRect.x(); // in LU int y = anchor->y() + paragRect.y(); // in LU KoPoint topLeft( m_doc->layoutUnitToPixelX( x ), m_doc->layoutUnitToPixelY( y ) ); return KoRect( topLeft, frame->outerKoRect().size() ); } KoSize KWFrameSet::floatingFrameSize( int frameNum ) { KWFrame * frame = frames.at( frameNum ); Q_ASSERT( frame ); return frame->outerKoRect().size(); } KCommand * KWFrameSet::anchoredObjectCreateCommand( int frameNum ) { KWFrame * frame = frames.at( frameNum ); Q_ASSERT( frame ); return new KWCreateFrameCommand( QString::null, frame ); } KCommand * KWFrameSet::anchoredObjectDeleteCommand( int frameNum ) { KWFrame * frame = frames.at( frameNum ); Q_ASSERT( frame ); return new KWDeleteFrameCommand( QString::null, frame ); } KWFrame * KWFrameSet::frameByBorder( const QPoint & nPoint ) { QPtrListIterator frameIt = frameIterator(); for ( ; frameIt.current(); ++frameIt ) { if(frameIt.current()->frameAtPos(nPoint, true)) return frameIt.current(); } return 0L; } KWFrame * KWFrameSet::frameAtPos( double _x, double _y ) { KoPoint docPoint( _x, _y ); QPtrListIterator frameIt = frameIterator(); for ( ; frameIt.current(); ++frameIt ) if ( frameIt.current()->contains( docPoint ) ) return frameIt.current(); return 0L; } KWFrame *KWFrameSet::frame( unsigned int _num ) { return frames.at( _num ); } int KWFrameSet::frameFromPtr( KWFrame *frame ) { return frames.findRef( frame ); } KWFrame * KWFrameSet::settingsFrame( const KWFrame* frame ) { QPtrListIterator frameIt( frame->frameSet()->frameIterator() ); if ( !frame->isCopy() ) return const_cast( frame ); KWFrame* lastRealFrame=0L; for ( ; frameIt.current(); ++frameIt ) { KWFrame *curFrame = frameIt.current(); if( curFrame == frame ) return lastRealFrame ? lastRealFrame : const_cast( frame ); if ( !lastRealFrame || !curFrame->isCopy() ) lastRealFrame = curFrame; } return const_cast( frame ); //fallback, should never happen } void KWFrameSet::updateFrames( int flags ) { if ( frames.isEmpty() ) return; // No frames. This happens when the frameset is deleted (still exists for undo/redo) // Not visible ? Don't bother then. if ( !isVisible() ) return; //kdDebug(32001) << "KWFrameSet::updateFrames " << this << " " << getName() << endl; if ( flags & UpdateFramesInPage ) { // For each of our frames, clear old list of frames on top, and grab min/max page nums m_firstPage = frames.first()->pageNum(); // we know frames is not empty here int lastPage = m_firstPage; QPtrListIterator fIt( frameIterator() ); for ( ; fIt.current(); ++fIt ) { int pg = fIt.current()->pageNum(); m_firstPage = KMIN( m_firstPage, pg ); lastPage = KMAX( lastPage, pg ); } //kdDebug(32001) << "firstPage=" << m_firstPage << " lastPage=" << lastPage << endl; // Prepare the m_framesInPage structure int oldSize = m_framesInPage.size(); m_framesInPage.resize( lastPage - m_firstPage + 1 ); // Clear the old elements int oldElements = KMIN( oldSize, (int)m_framesInPage.size() ); for ( int i = 0 ; i < oldElements ; ++i ) m_framesInPage[i]->clear(); // Initialize the new elements. for ( int i = oldElements ; i < (int)m_framesInPage.size() ; ++i ) m_framesInPage.insert( i, new QPtrList() ); // Iterate over frames again, to fill the m_framesInPage array fIt.toFirst(); for ( ; fIt.current(); ++fIt ) { int pg = fIt.current()->pageNum(); Q_ASSERT( pg <= lastPage ); m_framesInPage[pg - m_firstPage]->append( fIt.current() ); } } if ( isFloating() ) { //kdDebug(32001) << "KWFrameSet::updateFrames " << getName() << " is floating" << endl; QPtrListIterator frameIt = frameIterator(); int frameNum = 0; // At the moment there's only one anchor per frameset //for ( ; frameIt.current(); ++frameIt, ++frameNum ) { KWAnchor * anchor = findAnchor( frameNum ); //kdDebug(32001) << "KWFrameSet::updateFrames anchor=" << anchor << endl; if ( anchor ) anchor->resize(); } } } bool KWFrameSet::isPaintedBy( KWFrameSet* fs ) const { if ( fs == this ) return true; if ( isFloating() ) { KWFrameSet* parentFs = anchorFrameset(); if ( parentFs && parentFs->isPaintedBy( fs ) ) return true; } if ( getGroupManager() ) { if ( getGroupManager()->isPaintedBy( fs ) ) return true; } return false; } const QPtrList & KWFrameSet::framesInPage( int pageNum ) const { if ( pageNum < m_firstPage || pageNum >= (int)m_framesInPage.size() + m_firstPage ) { #ifdef DEBUG_DTI kdWarning(32002) << getName() << " framesInPage called for pageNum=" << pageNum << ". " << " Min value: " << m_firstPage << " Max value: " << m_framesInPage.size() + m_firstPage - 1 << endl; #endif return m_emptyList; // QPtrList() doesn't work, it's a temporary } return * m_framesInPage[pageNum - m_firstPage]; } void KWFrameSet::drawContents( QPainter *p, const QRect & crect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode ) { #ifdef DEBUG_DRAW kdDebug(32001) << "\nKWFrameSet::drawContents " << this << " " << getName() << " onlyChanged=" << onlyChanged << " resetChanged=" << resetChanged << " crect= " << crect << endl; #endif if ( !viewMode->isTextModeFrameset( this ) ) { QPtrListIterator frameIt( frameIterator() ); KWFrame * lastRealFrame = 0L; //double lastRealFrameTop = 0; //double totalHeight = 0; // in pt, to avoid accumulating rounding errors for ( ; frameIt.current(); ) { KWFrame *frame = frameIt.current(); ++frameIt; // Point to the next one, to detect "last copy" // The settings come from this frame KWFrame * settingsFrame = ( frame->isCopy() && lastRealFrame ) ? lastRealFrame : frame; bool lastCopy = !frameIt.current() || !frameIt.current()->isCopy(); drawFrameAndBorders( frame, p, crect, cg, onlyChanged, // Only reset the changed flag in the last copy of a given frame (#60678) resetChanged && lastCopy, edit, viewMode, settingsFrame, true /*transparency & double-buffering*/ ); if ( !lastRealFrame || !frame->isCopy() ) { lastRealFrame = frame; //lastRealFrameTop = totalHeight; } //totalHeight += frame->innerHeight(); } } else { // Text view mode drawFrame( 0L /*frame*/, p, crect, crect, QPoint(0,0), 0L /*settingsFrame*/, cg, onlyChanged, resetChanged, edit, viewMode, true ); } } void KWFrameSet::drawFrameAndBorders( KWFrame *frame, QPainter *painter, const QRect &crect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode, KWFrame *settingsFrame, bool drawUnderlyingFrames ) { if ( !frame->isValid() ) { kdDebug(32002) << "KWFrameSet::drawFrameAndBorders " << getName() << " frame " << frameFromPtr( frame ) << " " << frame << " isn't valid" << endl; return; } QRect normalOuterFrameRect( frame->outerRect( viewMode ) ); QRect outerFrameRect( viewMode->normalToView( normalOuterFrameRect ) ); QRect outerCRect = crect.intersect( outerFrameRect ); #ifdef DEBUG_DRAW kdDebug(32001) << "KWFrameSet::drawFrameAndBorders " << getName() << " frame " << frameFromPtr( frame ) << " " << *frame << endl; kdDebug(32001) << " (outer) normalFrameRect=" << normalOuterFrameRect << " frameRect=" << outerFrameRect << endl; kdDebug(32001) << " crect=" << crect << " intersec=" << outerCRect << " todraw=" << !outerCRect.isEmpty() << endl; #endif if ( !outerCRect.isEmpty() ) { // Determine settingsFrame if not passed (for speedup) if ( !settingsFrame ) settingsFrame = this->settingsFrame( frame ); QRect normalInnerFrameRect( m_doc->zoomRect( frame->innerRect() ) ); QRect innerFrameRect( viewMode->normalToView( normalInnerFrameRect ) ); // This translates the coordinates in the document contents // ( frame and r are up to here in this system ) // into the frame's own coordinate system. int offsetX = normalInnerFrameRect.left(); int offsetY = normalInnerFrameRect.top() - m_doc->zoomItY( frame->internalY() ); QRect innerCRect = outerCRect.intersect( innerFrameRect ); QRect fcrect = viewMode->viewToNormal( innerCRect ); #ifdef DEBUG_DRAW kdDebug(32001) << " (inner) normalFrameRect=" << normalInnerFrameRect << " frameRect=" << innerFrameRect << endl; //kdDebug(32001) << " crect after view-to-normal:" << fcrect << "." << " Will move by (" << -offsetX << ", -(" << normalInnerFrameRect.top() << "-" << m_doc->zoomItY(frame->internalY()) << ") == " << -offsetY << ")." << endl; #endif fcrect.moveBy( -offsetX, -offsetY ); Q_ASSERT( fcrect.x() >= 0 ); Q_ASSERT( fcrect.y() >= 0 ); // fcrect is now the portion of the frame to be drawn, // in the frame's coordinates and in pixels #ifdef DEBUG_DRAW kdDebug(32001) << "KWFrameSet::drawFrameAndBorders in frame coords:" << fcrect << ". Will translate painter by intersec-fcrect: " << innerCRect.x()-fcrect.x() << "," << innerCRect.y()-fcrect.y() << "." << endl; #endif QRegion reg; if ( drawUnderlyingFrames ) reg = frameClipRegion( painter, frame, outerCRect, viewMode ); else // false means we are being drawn _as_ an underlying frame, so no clipping! reg = painter->xForm( outerCRect ); if ( !reg.isEmpty() ) { painter->save(); painter->setClipRegion( reg ); drawFrame( frame, painter, fcrect, outerCRect, innerCRect.topLeft() - fcrect.topLeft(), // This assume that viewToNormal() is only a translation settingsFrame, cg, onlyChanged, resetChanged, edit, viewMode, drawUnderlyingFrames ); if( !getGroupManager() ) // not for table cells drawFrameBorder( painter, frame, settingsFrame, outerCRect, viewMode ); painter->restore(); } } } void KWFrameSet::drawFrame( KWFrame *frame, QPainter *painter, const QRect &fcrect, const QRect &outerCRect, const QPoint& translationOffset, KWFrame *settingsFrame, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode* viewMode, bool drawUnderlyingFrames ) { // In this method the painter is NOT translated yet. It's still in view coordinates. if ( outerCRect.isEmpty() ) return; #ifdef DEBUG_DRAW kdDebug(32001) << "\nKWFrameSet::drawFrame " << getName() << " outerCRect=" << outerCRect << " frameCrect=" << fcrect << " drawUnderlyingFrames=" << drawUnderlyingFrames << endl; #endif QColorGroup frameColorGroup( cg ); if ( settingsFrame ) // 0L in text viewmode { QBrush bgBrush( settingsFrame->backgroundColor() ); bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), painter ) ); frameColorGroup.setBrush( QColorGroup::Base, bgBrush ); } if ( drawUnderlyingFrames && frame && !frame->framesBelow().isEmpty() ) { // Double-buffering - not when printing QPainter* doubleBufPainter = painter; QPixmap* pix = 0L; if ( painter->device()->devType() != QInternal::Printer ) { pix = m_doc->doubleBufferPixmap( outerCRect.size() ); doubleBufPainter = new QPainter; doubleBufPainter->begin( pix ); // Initialize the pixmap to the page background color // (if the frame is over the page margins, no underlying frame will paint anything there) doubleBufPainter->fillRect( 0, 0, outerCRect.width(), outerCRect.height(), QApplication::palette().active().brush( QColorGroup::Base ) ); // The double-buffer pixmap has (0,0) at outerCRect.topLeft(), so we need to // translate the double-buffer painter; drawFrameAndBorders will draw using view coordinates. doubleBufPainter->translate( -outerCRect.x(), -outerCRect.y() ); #ifdef DEBUG_DRAW // kdDebug(32001) << " ... using double buffering. Portion covered: " << outerCRect << endl; #endif } // Transparency handling #ifdef DEBUG_DRAW kdDebug(32001) << " frame->framesBelow(): " << frame->framesBelow().count() << endl; #endif QPtrListIterator it( frame->framesBelow() ); for ( ; it.current() ; ++it ) { KWFrame* f = it.current(); #ifdef DEBUG_DRAW kdDebug(32001) << " looking at frame below us: " << f->frameSet()->getName() << " frame " << frameFromPtr( frame ) << endl; #endif QRect viewFrameCRect = outerCRect.intersect( viewMode->normalToView( f->outerRect( viewMode ) ) ); if ( !viewFrameCRect.isEmpty() ) { #ifdef DEBUG_DRAW kdDebug(32001) << " viewFrameRect=" << viewFrameCRect << " calling drawFrameAndBorders." << endl; #endif f->frameSet()->drawFrameAndBorders( f, doubleBufPainter, viewFrameCRect, cg, false, resetChanged, edit, viewMode, 0L, false ); } } if ( frame->paddingLeft() || frame->paddingTop() || frame->paddingRight() || frame->paddingBottom() ) drawPadding( frame, doubleBufPainter, outerCRect, cg, viewMode ); doubleBufPainter->save(); #ifdef DEBUG_DRAW kdDebug(32001) << " translating by " << translationOffset.x() << ", " << translationOffset.y() << " before drawFrameContents" << endl; #endif doubleBufPainter->translate( translationOffset.x(), translationOffset.y() ); // This assume that viewToNormal() is only a translation // We can't "repaint changed parags only" if we just drew the underlying frames, hence the "false" drawFrameContents( frame, doubleBufPainter, fcrect, frameColorGroup, false, resetChanged, edit, viewMode ); doubleBufPainter->restore(); if ( painter->device()->devType() != QInternal::Printer ) { doubleBufPainter->end(); #ifdef DEBUG_DRAW kdDebug(32001) << " painting double-buf pixmap at position " << outerCRect.topLeft() << " (real painter pos:" << painter->xForm( outerCRect.topLeft() ) << ")" << endl; #endif painter->drawPixmap( outerCRect.topLeft(), *pix ); delete doubleBufPainter; } } else { if ( frame && (frame->paddingLeft() || frame->paddingTop() || frame->paddingRight() || frame->paddingBottom()) ) drawPadding( frame, painter, outerCRect, cg, viewMode ); painter->save(); painter->translate( translationOffset.x(), translationOffset.y() ); //painter->setBrushOrigin( painter->brushOrigin() + translationOffset ); drawFrameContents( frame, painter, fcrect, frameColorGroup, onlyChanged, resetChanged, edit, viewMode ); painter->restore(); } } void KWFrameSet::drawFrameContents( KWFrame *, QPainter *, const QRect &, const QColorGroup &, bool, bool, KWFrameSetEdit*, KWViewMode * ) { kdWarning() << "Default implementation of drawFrameContents called for " << className() << " " << this << " " << getName() << kdBacktrace(); } bool KWFrameSet::contains( double mx, double my ) { QPtrListIterator frameIt = frameIterator(); for ( ; frameIt.current(); ++frameIt ) if ( frameIt.current()->contains( KoPoint( mx, my ) ) ) return true; return false; } MouseMeaning KWFrameSet::getMouseMeaning( const QPoint &nPoint, int keyState ) { if ( grpMgr ) // Cells forward the call to the table return grpMgr->getMouseMeaning( nPoint, keyState ); bool canMove = isMoveable(); KoPoint docPoint = m_doc->unzoomPoint( nPoint ); MouseMeaning defaultCursor = canMove ? MEANING_MOUSE_MOVE : MEANING_MOUSE_SELECT; // See if we're over a frame border KWFrame * frame = frameByBorder( nPoint ); if ( frame ) { return frame->getMouseMeaning( docPoint, defaultCursor ); } // TODO there's a case where we're over a frame resize-handle // but not over the frame border, we miss to see that here. // Proper fix: hmm, why are resize handles widgets anyway? frame = frameAtPos( docPoint.x(), docPoint.y() ); if ( frame == 0L ) { return MEANING_NONE; } // Found a frame under the cursor // Ctrl -> move or select if ( keyState & ControlButton ) return defaultCursor; // Shift _and_ at least a frame is selected already // (shift + no frame selected is used to select text) if ( (keyState & ShiftButton) && (m_doc->getFirstSelectedFrame() != 0L) ) return defaultCursor; return getMouseMeaningInsideFrame( docPoint ); } MouseMeaning KWFrameSet::getMouseMeaningInsideFrame( const KoPoint& ) { return isMoveable() ? MEANING_MOUSE_MOVE : MEANING_MOUSE_SELECT; } void KWFrameSet::saveCommon( QDomElement &parentElem, bool saveFrames ) { if ( frames.isEmpty() ) // Deleted frameset -> don't save return; // Save all the common attributes for framesets. if (m_doc->specialOutputFlag()==KoDocument::SaveAsKOffice1dot1) { parentElem.setAttribute( "frameType", static_cast( typeAsKOffice1Dot1() ) ); } else { parentElem.setAttribute( "frameType", static_cast( type() ) ); } parentElem.setAttribute( "frameInfo", static_cast( m_info ) ); parentElem.setAttribute( "name", m_name ); parentElem.setAttribute( "visible", static_cast( m_visible ) ); parentElem.setAttribute( "protectSize", static_cast( m_protectSize ) ); if ( saveFrames ) { QPtrListIterator frameIt = frameIterator(); for ( ; frameIt.current(); ++frameIt ) { KWFrame *frame = frameIt.current(); QDomElement frameElem = parentElem.ownerDocument().createElement( "FRAME" ); parentElem.appendChild( frameElem ); frame->save( frameElem ); if(m_doc->processingType() == KWDocument::WP) { // Assume that all header/footer frames in the same frameset are // perfect copies. This might not be the case some day though. if(frameSetInfo() == FI_FIRST_HEADER || frameSetInfo() == FI_EVEN_HEADER || frameSetInfo() == FI_ODD_HEADER || frameSetInfo() == FI_FIRST_FOOTER || frameSetInfo() == FI_EVEN_FOOTER || frameSetInfo() == FI_ODD_FOOTER || frameSetInfo() == FI_FOOTNOTE) break; } } } } // // This function is intended as a helper for all the derived classes. It reads // in all the attributes common to all framesets and loads all frames. // void KWFrameSet::load( QDomElement &framesetElem, bool loadFrames ) { m_info = static_cast( KWDocument::getAttribute( framesetElem, "frameInfo", KWFrameSet::FI_BODY ) ); m_visible = static_cast( KWDocument::getAttribute( framesetElem, "visible", true ) ); if ( framesetElem.hasAttribute( "removeable" ) ) m_removeableHeader = static_cast( KWDocument::getAttribute( framesetElem, "removeable", false ) ); else m_removeableHeader = static_cast( KWDocument::getAttribute( framesetElem, "removable", false ) ); m_protectSize=static_cast( KWDocument::getAttribute( framesetElem, "protectSize", false ) ); if ( loadFrames ) { // QDomElement frameElem = framesetElem.firstChild().toElement(); for ( ; !frameElem.isNull() ; frameElem = frameElem.nextSibling().toElement() ) { if ( frameElem.tagName() == "FRAME" ) { KoRect rect; rect.setLeft( KWDocument::getAttribute( frameElem, "left", 0.0 ) ); rect.setTop( KWDocument::getAttribute( frameElem, "top", 0.0 ) ); rect.setRight( KWDocument::getAttribute( frameElem, "right", 0.0 ) ); rect.setBottom( KWDocument::getAttribute( frameElem, "bottom", 0.0 ) ); KWFrame * frame = new KWFrame(this, rect.x(), rect.y(), rect.width(), rect.height() ); frame->load( frameElem, this, m_doc->syntaxVersion() ); addFrame( frame, false ); m_doc->progressItemLoaded(); } } } } KWFrame* KWFrameSet::loadOasisFrame( const QDomElement& tag, KoOasisContext& context ) { double width = 100; if ( tag.hasAttributeNS( KoXmlNS::svg, "width" ) ) { // fixed width // TODO handle percentage (of enclosing table/frame/page) width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "width", QString::null ) ); } else if ( tag.hasAttributeNS( KoXmlNS::fo, "min-width" ) ) { // min-width is not supported in KWord. Let's use it as a fixed width. width = KoUnit::parseValue( tag.attributeNS( KoXmlNS::fo, "min-width", QString::null ) ); } else { kdWarning(32001) << "Error in frame " << tag.tagName() << " " << tag.attributeNS( KoXmlNS::draw, "name", QString::null ) << " : neither width nor min-width specified!" << endl; } double height = 100; if ( tag.hasAttributeNS( KoXmlNS::svg, "height" ) ) { // fixed height // TODO handle percentage (of enclosing table/frame/page) height = KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "height", QString::null ) ); } //kdDebug(32001) << k_funcinfo << "width=" << width << " height=" << height << " pt" << endl; KWFrame * frame = new KWFrame(this, KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "x", QString::null ) ), KoUnit::parseValue( tag.attributeNS( KoXmlNS::svg, "y", QString::null ) ), width, height ); frame->setZOrder( tag.attributeNS( KoXmlNS::draw, "z-index", QString::null ).toInt() ); // Copy-frames. OASIS extension requested on 29/03/2004. // We currently ignore the value of the copy-of attribute. It probably needs to // be handled like chain-next-name (kwtextframeset.cc) but for all types of frameset. frame->setCopy( tag.hasAttributeNS( KoXmlNS::draw, "copy-of" ) ); frame->loadCommonOasisProperties( context, this ); addFrame( frame, false ); // Protect (OASIS 14.27.7, also in OO-1.1) // A frame with protected contents means that the frameset is protected (makes sense) // A frame with protected size means that the frameset is size-protected (hmm, kword did it that way) // TODO implement position protection QString protectList = context.styleStack().attributeNS( KoXmlNS::style, "protect" ); if ( protectList.contains( "content" ) ) setProtectContent( true ); if ( protectList.contains( "size" ) ) m_protectSize = true; // TODO m_visible ? User-toggeable or internal? return frame; } bool KWFrameSet::hasSelectedFrame() { for ( unsigned int i = 0; i < frames.count(); i++ ) { if ( frames.at( i )->isSelected() ) return true; } return false; } void KWFrameSet::setVisible( bool v ) { m_visible = v; if ( m_visible ) // updateFrames was disabled while we were invisible updateFrames(); } bool KWFrameSet::isVisible( KWViewMode* viewMode ) const { if ( !m_visible || frames.isEmpty() ) return false; if ( isAHeader() && !m_doc->isHeaderVisible() ) return false; if ( isAFooter() && !m_doc->isFooterVisible() ) return false; if ( viewMode && !viewMode->isFrameSetVisible(this) ) return false; if ( isFloating() && !anchorFrameset()->isVisible( viewMode ) ) return false; KoHFType ht = m_doc->getHeaderType(); KoHFType ft = m_doc->getFooterType(); switch( m_info ) { case FI_FIRST_HEADER: return ( ht == HF_FIRST_DIFF || ht == HF_FIRST_EO_DIFF ); case FI_ODD_HEADER: return true; case FI_EVEN_HEADER: return ( ht == HF_EO_DIFF || ht == HF_FIRST_EO_DIFF ); case FI_FIRST_FOOTER: return ( ft == HF_FIRST_DIFF || ft == HF_FIRST_EO_DIFF ); case FI_ODD_FOOTER: return true; case FI_EVEN_FOOTER: return ( ft == HF_EO_DIFF || ft == HF_FIRST_EO_DIFF ); default: return true; } } bool KWFrameSet::isAHeader() const { return ( m_info == FI_FIRST_HEADER || m_info == FI_ODD_HEADER || m_info == FI_EVEN_HEADER ); } bool KWFrameSet::isAFooter() const { return ( m_info == FI_FIRST_FOOTER || m_info == FI_ODD_FOOTER || m_info == FI_EVEN_FOOTER ); } bool KWFrameSet::isFootEndNote() const { return m_info == FI_FOOTNOTE; } bool KWFrameSet::isMainFrameset() const { return ( m_doc->processingType() == KWDocument::WP && m_doc->frameSet( 0 ) == this ); } bool KWFrameSet::isMoveable() const { if ( isHeaderOrFooter() ) return false; return !isMainFrameset() && !isFloating(); } void KWFrameSet::finalize() { //kdDebug(32001) << "KWFrameSet::finalize ( calls updateFrames + zoom ) " << this << endl; updateFrames(); } QRegion KWFrameSet::frameClipRegion( QPainter * painter, KWFrame *frame, const QRect & crect, KWViewMode * viewMode ) { KWDocument * doc = kWordDocument(); QRect rc = painter->xForm( crect ); KoRect clipKoRect = doc->unzoomRect(viewMode->viewToNormal(crect)); #ifdef DEBUG_DRAW //kdDebug(32002) << "KWFrameSet::frameClipRegion rc initially " << rc << endl; #endif Q_ASSERT( frame ); #if 0 // done later if ( clipFrame ) { rc &= painter->xForm( viewMode->normalToView( doc->zoomRect( (*frame) ) ) ); // intersect #ifdef DEBUG_DRAW kdDebug(32002) << "KWFrameSet::frameClipRegion frame=" << *frame << " clip region rect=" << rc << " rc.isEmpty()=" << rc.isEmpty() << endl; #endif } #endif if ( !rc.isEmpty() ) { QRegion reg( rc ); // This breaks when a frame is under another one, it still appears if !onlyChanged. // cvs log says this is about frame borders... hmm. /// ### if ( onlyChanged ) QPtrListIterator fIt( frame->framesOnTop() ); for ( ; fIt.current() ; ++fIt ) { QRect r = painter->xForm( viewMode->normalToView( (*fIt)->outerRect( viewMode ) ) ); #ifdef DEBUG_DRAW //kdDebug(32002) << "frameClipRegion subtract rect "<< r << endl; #endif reg -= r; // subtract } #ifdef DEBUG_DRAW //kdDebug(32002) << "KWFrameSet::frameClipRegion result:" << reg << endl; #endif return reg; } else return QRegion(); } bool KWFrameSet::canRemovePage( int num ) { QPtrListIterator frameIt( frameIterator() ); for ( ; frameIt.current(); ++frameIt ) { KWFrame * frame = frameIt.current(); if ( frame->pageNum() == num ) // ## TODO: use framesInPage, see KWTextFrameSet { // Ok, so we have a frame on that page -> we can't remove it unless it's a copied frame if ( ! ( frame->isCopy() && frameIt.current() != frames.first() ) ) { //kdDebug(32001) << "KWFrameSet::canRemovePage " << getName() << " frame on page " << num << " -> false" << endl; return false; } } } return true; } void KWFrameSet::showPopup( KWFrame *, KWView *view, const QPoint &point ) { QPopupMenu * popup = view->popupMenu("frame_popup"); Q_ASSERT(popup); if (popup) popup->popup( point ); } void KWFrameSet::setFrameBehavior( KWFrame::FrameBehavior fb ) { for(KWFrame *f=frames.first();f;f=frames.next()) f->setFrameBehavior(fb); } void KWFrameSet::setNewFrameBehavior( KWFrame::NewFrameBehavior nfb ) { for(KWFrame *f=frames.first();f;f=frames.next()) f->setNewFrameBehavior(nfb); } void KWFrameSet::resizeFrameSetCoords( KWFrame* frame, double newLeft, double newTop, double newRight, double newBottom, bool finalSize ) { frame->setLeft( newLeft ); frame->setTop( newTop ); resizeFrame( frame, newRight - newLeft, newBottom - newTop, finalSize ); } void KWFrameSet::resizeFrame( KWFrame* frame, double newWidth, double newHeight, bool /*finalSize*/ ) { frame->setWidth( newWidth ); frame->setHeight( newHeight ); if ( frame->frameBehavior() == KWFrame::AutoExtendFrame ) frame->setMinFrameHeight( newHeight ); } bool KWFrameSet::isFrameAtPos( KWFrame* frame, const QPoint& point, bool borderOfFrameOnly) { QRect outerRect( frame->outerRect( m_doc->viewMode() ) ); // Give the user a bit of margin for clicking on it :) const int margin = 2; outerRect.rLeft() -= margin; outerRect.rTop() -= margin; outerRect.rRight() += margin; outerRect.rBottom() += margin; if ( outerRect.contains( point ) ) { if(borderOfFrameOnly) { QRect innerRect( m_doc->zoomRect( *frame ) ); innerRect.rLeft() += margin; innerRect.rTop() += margin; innerRect.rRight() -= margin; innerRect.rBottom() -= margin; return (!innerRect.contains(point) ); } return true; } return false; } void KWFrameSet::setZOrder() { //kdDebug(32001) << "KWFrameSet::setZOrder (to max) " << getName() << endl; QPtrListIterator fit = frameIterator(); for ( ; fit.current() ; ++fit ) fit.current()->setZOrder( m_doc->maxZOrder( fit.current()->pageNum(m_doc) ) + 1 ); } void KWFrameSet::setName( const QString &_name ) { m_name = _name; m_doc->updateFrameStatusBarItem(); } #ifndef NDEBUG void KWFrameSet::printDebug() { static const char * typeFrameset[] = { "base", "txt", "picture", "part", "formula", "clipart", "6", "7", "8", "9", "table", "ERROR" }; static const char * infoFrameset[] = { "body", "first header", "even headers", "odd headers", "first footer", "even footers", "odd footers", "footnote", "ERROR" }; static const char * frameBh[] = { "AutoExtendFrame", "AutoCreateNewFrame", "Ignore", "ERROR" }; static const char * newFrameBh[] = { "Reconnect", "NoFollowup", "Copy" }; static const char * runaround[] = { "No Runaround", "Bounding Rect", "Skip", "ERROR" }; static const char * runaroundSide[] = { "Biggest", "Left", "Right", "ERROR" }; kdDebug() << " | Visible: " << isVisible() << endl; kdDebug() << " | Type: " << typeFrameset[ type() ] << endl; kdDebug() << " | Info: " << infoFrameset[ frameSetInfo() ] << endl; kdDebug() << " | Floating: " << isFloating() << endl; kdDebug() << " | Frames in page array: " << endl; for ( uint i = 0 ; i < m_framesInPage.size() ; ++i ) { QPtrListIterator it( *m_framesInPage[i] ); int pgNum = i + m_firstPage; for ( ; it.current() ; ++it ) kdDebug() << " | " << pgNum << ": " << it.current() << " " << *it.current() << " internalY=" << it.current()->internalY() << "pt " << " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->internalY() ) << ")" << " innerHeight=" << it.current()->innerHeight() << " (in LU pix:" << m_doc->ptToLayoutUnitPixY( it.current()->innerHeight() ) << ")" << endl; } QPtrListIterator frameIt = frameIterator(); for ( unsigned int j = 0; frameIt.current(); ++frameIt, ++j ) { KWFrame * frame = frameIt.current(); QCString copy = frame->isCopy() ? "[copy]" : ""; kdDebug() << " +-- Frame " << j << " of "<< getNumFrames() << " (" << frame << ") " << copy << endl; printDebug( frame ); kdDebug() << " Rectangle : " << frame->x() << "," << frame->y() << " " << frame->width() << "x" << frame->height() << endl; kdDebug() << " RunAround: "<< runaround[ frame->runAround() ] << " side:" << runaroundSide[ frame->runAroundSide() ]<< endl; kdDebug() << " FrameBehavior: "<< frameBh[ frame->frameBehavior() ] << endl; kdDebug() << " NewFrameBehavior: "<< newFrameBh[ frame->newFrameBehavior() ] << endl; QColor col = frame->backgroundColor().color(); kdDebug() << " BackgroundColor: "<< ( col.isValid() ? col.name().latin1() : "(default)" ) << endl; kdDebug() << " SheetSide "<< frame->sheetSide() << endl; kdDebug() << " Z Order: " << frame->zOrder() << endl; kdDebug() << " Frames below: " << frame->framesBelow().count() << " frames on top: " << frame->framesOnTop().count() << endl; kdDebug() << " minFrameHeight "<< frame->minFrameHeight() << endl; if(frame->isSelected()) kdDebug() << " * Page "<< frame->pageNum() << endl; else kdDebug() << " Page "<< frame->pageNum() << endl; } } void KWFrameSet::printDebug( KWFrame * ) { } #endif KWFrameSetEdit::KWFrameSetEdit( KWFrameSet * fs, KWCanvas * canvas ) : m_fs(fs), m_canvas(canvas), m_currentFrame( fs->frame(0) ) { } void KWFrameSetEdit::drawContents( QPainter *p, const QRect &crect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWViewMode *viewMode ) { //kdDebug(32001) << "KWFrameSetEdit::drawContents " << frameSet()->getName() << endl; frameSet()->drawContents( p, crect, cg, onlyChanged, resetChanged, this, viewMode ); } void KWFrameSetEdit::showPopup( KWFrame* frame, KWView* view, const QPoint & _point ) { frame->frameSet()->showPopup( frame, view, _point ); } +bool KWFrameSetEdit::exitLeft() +{ + if ( m_fs->isFloating() ) { + KWAnchor* anchor = m_fs->findAnchor( 0 ); + int index = anchor->index(); + KoTextParag *parag = anchor->paragraph(); + // This call deletes "this"! + m_canvas->editTextFrameSet( m_fs->anchorFrameset(), parag, index ); + return true; + } + return false; +} + +bool KWFrameSetEdit::exitRight() +{ + if ( m_fs->isFloating() ) { + KWAnchor* anchor = m_fs->findAnchor( 0 ); + int index = anchor->index(); + KoTextParag *parag = anchor->paragraph(); + // This call deletes "this"! + m_canvas->editTextFrameSet( m_fs->anchorFrameset(), parag, index+1 ); + return true; + } + return false; +} + /******************************************************************/ /* Class: KWPictureFrameSet */ /******************************************************************/ KWPictureFrameSet::KWPictureFrameSet( KWDocument *_doc, const QString & name ) : KWFrameSet( _doc ), m_keepAspectRatio( true ), m_finalSize( false ), m_protectContent( false ) { if ( name.isEmpty() ) m_name = _doc->generateFramesetName( i18n( "Picture %1" ) ); else m_name = name; } KWPictureFrameSet::KWPictureFrameSet( KWDocument* doc, const QDomElement& frame, const QDomElement& imageTag, KoOasisContext& context ) : KWFrameSet( doc ), m_keepAspectRatio( true ), m_finalSize( false ) { m_name = frame.attributeNS( KoXmlNS::draw, "name", QString::null ); if ( doc->frameSetByName( m_name ) ) // already exists! m_name = doc->generateFramesetName( m_name + " %1" ); loadOasis( frame, imageTag, context ); } KWPictureFrameSet::~KWPictureFrameSet() { } KWordFrameSetIface* KWPictureFrameSet::dcopObject() { if ( !m_dcop ) m_dcop = new KWordPictureFrameSetIface( this ); return m_dcop; } void KWPictureFrameSet::loadPicture( const QString & fileName ) { KoPictureCollection *collection = m_doc->pictureCollection(); m_picture = collection->loadPicture( fileName ); } void KWPictureFrameSet::insertPicture( const KoPicture& picture ) { KoPictureCollection *collection = m_doc->pictureCollection(); m_picture = collection->insertPicture( picture.getKey(), picture ); } void KWPictureFrameSet::reloadPicture( const KoPictureKey& key ) { KoPictureCollection *collection = m_doc->pictureCollection(); // If the picture is not already in the collection, then it gives a blank picture m_picture = collection->insertPicture( key, KoPicture() ); } void KWPictureFrameSet::setSize( const QSize & /*_imgSize*/ ) { // Do nothing as KoPicture needs a size only at drawing time } void KWPictureFrameSet::resizeFrame( KWFrame* frame, double newWidth, double newHeight, bool finalSize ) { KWFrameSet::resizeFrame( frame, newWidth, newHeight, finalSize ); //QSize newSize = kWordDocument()->zoomSize( frame->innerRect().size() ); m_finalSize=finalSize; // Cache the value for drawing time! } QDomElement KWPictureFrameSet::save( QDomElement & parentElem, bool saveFrames ) { if ( frames.isEmpty() ) // Deleted frameset -> don't save return QDomElement(); QDomElement framesetElem = parentElem.ownerDocument().createElement( "FRAMESET" ); parentElem.appendChild( framesetElem ); KWFrameSet::saveCommon( framesetElem, saveFrames ); QDomElement imageElem; if (m_doc->specialOutputFlag()==KoDocument::SaveAsKOffice1dot1) { // KWord 1.1 file format QString strElementName=m_picture.isClipartAsKOffice1Dot1() ? QString( "CLIPART" ) : QString( "IMAGE" ); imageElem = parentElem.ownerDocument().createElement( strElementName ); framesetElem.appendChild( imageElem ); if ( !m_picture.isClipartAsKOffice1Dot1() ) { // KWord 1.1 does not save keepAspectRaio for a clipart imageElem.setAttribute( "keepAspectRatio", m_keepAspectRatio ? "true" : "false" ); } } else { // KWord 1.3 file format imageElem = parentElem.ownerDocument().createElement( "PICTURE" ); framesetElem.appendChild( imageElem ); imageElem.setAttribute( "keepAspectRatio", m_keepAspectRatio ? "true" : "false" ); } QDomElement elem = parentElem.ownerDocument().createElement( "KEY" ); imageElem.appendChild( elem ); m_picture.getKey().saveAttributes( elem ); return framesetElem; } void KWPictureFrameSet::load( QDomElement &attributes, bool loadFrames ) { KWFrameSet::load( attributes, loadFrames ); QString defaultRatio="true"; // QDomNode node=attributes.namedItem( "PICTURE" ); if ( node.isNull() ) { node=attributes.namedItem( "IMAGE" ); if ( node.isNull() ) { node=attributes.namedItem( "CLIPART" ); defaultRatio="false"; } } QDomElement image = node.toElement(); if ( !image.isNull() ) { m_keepAspectRatio = image.attribute( "keepAspectRatio", defaultRatio ) == "true"; // QDomElement keyElement = image.namedItem( "KEY" ).toElement(); if ( !keyElement.isNull() ) { KoPictureKey key; key.loadAttributes( keyElement ); m_picture.clear(); m_picture.setKey( key ); m_doc->addPictureRequest( this ); } else { // (old format, up to KWord-1.1-beta2) QDomElement filenameElement = image.namedItem( "FILENAME" ).toElement(); if ( !filenameElement.isNull() ) { QString filename = filenameElement.attribute( "value" ); m_picture.clear(); m_picture.setKey( KoPictureKey( filename ) ); m_doc->addPictureRequest( this ); } else { kdError(32001) << "Missing KEY tag in IMAGE" << endl; } } } else { kdError(32001) << "Missing PICTURE/IMAGE/CLIPART tag in FRAMESET" << endl; } } void KWPictureFrameSet::saveOasis( KoXmlWriter& writer, KoSavingContext& context ) const { if( frames.isEmpty() ) // Deleted frameset -> don't save return; KWFrame* frame = frames.getFirst(); frame->startOasisFrame( writer, context.mainStyles() ); // draw:frame writer.startElement( "draw:image" ); writer.addAttribute( "xlink:type", "simple" ); writer.addAttribute( "xlink:show", "embed" ); writer.addAttribute( "xlink:actuate", "onLoad" ); if ( context.savingMode() == KoSavingContext::Store ) writer.addAttribute( "xlink:href", m_doc->pictureCollection()->getOasisFileName(m_picture) ); else { writer.startElement( "office:binary-data" ); m_picture.saveAsBase64( writer ); writer.endElement(); } writer.endElement(); writer.endElement(); // draw:frame } void KWPictureFrameSet::loadOasis( const QDomElement& frame, const QDomElement& tag, KoOasisContext& context ) { kdDebug() << k_funcinfo << endl; KoPictureKey key; QDomNode binaryData = KoDom::namedItemNS( tag, KoXmlNS::office, "binary-data" ); if ( !binaryData.isNull() ) { QCString data = binaryData.toElement().text().latin1(); m_picture.loadFromBase64( data ); key = KoPictureKey("nofile", QDateTime::currentDateTime(Qt::UTC)); m_picture.setKey(key); } else { const QString href( tag.attributeNS( KoXmlNS::xlink, "href", QString::null) ); if ( !href.isEmpty() /*&& href[0] == '#'*/ ) { QString strExtension; const int result=href.findRev("."); if (result>=0) { strExtension=href.mid(result+1); // As we are using KoPicture, the extension should be without the dot. } QString filename(href/*.mid(1)*/); key = KoPictureKey(filename, QDateTime::currentDateTime(Qt::UTC)); m_picture.setKey(key); KoStore* store = context.store(); assert( store ); if ( store->open( filename ) ) { KoStoreDevice dev(store); if ( !m_picture.load( &dev, strExtension ) ) kdWarning(32001) << "Cannot load picture: " << filename << " " << href << endl; store->close(); } } } m_doc->pictureCollection()->insertPicture( key, m_picture ); context.styleStack().save(); context.fillStyleStack( frame, KoXmlNS::draw, "style-name" ); // get the style for the graphics element loadOasisFrame( frame, context ); context.styleStack().restore(); } void KWPictureFrameSet::drawFrameContents( KWFrame *frame, QPainter *painter, const QRect &crect, const QColorGroup &, bool, bool, KWFrameSetEdit *, KWViewMode * ) { #ifdef DEBUG_DRAW kdDebug(32001) << "KWPictureFrameSet::drawFrameContents crect=" << crect << " size=" << kWordDocument()->zoomItX( frame->innerWidth() ) << "x" << kWordDocument()->zoomItY( frame->innerHeight() ) << endl; #endif m_picture.draw( *painter, 0, 0, kWordDocument()->zoomItX( frame->innerWidth() ), kWordDocument()->zoomItY( frame->innerHeight() ), crect.x(), crect.y(), crect.width(), crect.height(), !m_finalSize); } FrameSetType KWPictureFrameSet::type( void ) { return FT_PICTURE; } FrameSetType KWPictureFrameSet::typeAsKOffice1Dot1( void ) { return m_picture.isClipartAsKOffice1Dot1()?FT_CLIPART:FT_PICTURE; } bool KWPictureFrameSet::keepAspectRatio() const { return m_keepAspectRatio; } void KWPictureFrameSet::setKeepAspectRatio( bool b ) { m_keepAspectRatio = b; } #ifndef NDEBUG void KWPictureFrameSet::printDebug( KWFrame *frame ) { KWFrameSet::printDebug( frame ); if ( !isDeleted() ) { kdDebug(32001) << "Image: key=" << m_picture.getKey().toString() << endl; } } #endif #if 0 // KWORD_HORIZONTAL_LINE /******************************************************************/ /* Class: KWHorzLineFrameSet */ /******************************************************************/ KWHorzLineFrameSet::KWHorzLineFrameSet( KWDocument *_doc, const QString & name ) : KWPictureFrameSet( _doc, "none" /*don't generate name in kwpictureframeset*/) { kdDebug(32001) << "KWHorzLineFrameSet::KWHorzLineFrameSet" << endl; if ( name.isEmpty() ) m_name = _doc->generateFramesetName( i18n( "Horizontal line %1" ) ); else m_name = name; } KWHorzLineFrameSet::~KWHorzLineFrameSet() { //todo } FrameSetType KWHorzLineFrameSet::type( void ) { return FT_HORZLINE; } bool KWHorzLineFrameSet::ownLine() const { return TRUE; } KWordFrameSetIface* KWHorzLineFrameSet::dcopObject() { if ( !m_dcop ) m_dcop = new KWHorizontalLineFrameSetIface( this ); return m_dcop; } void KWHorzLineFrameSet::drawFrameContents( KWFrame *frame, QPainter *painter, const QRect &crect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode * viewmode) { if ( !m_picture.isNull()) KWPictureFrameSet::drawFrameContents( frame, painter, crect, cg, onlyChanged, resetChanged, edit, viewmode); else { if ( painter->device()->devType() == QInternal::Printer ) { QPen oldPen = painter->pen(); painter->setPen( QPen( cg.text(), crect.height()/8 ) ); painter->drawLine( crect.left()-1, crect.y() + crect.height() / 2, crect.right() + 1, crect.y() + crect.height() / 2 ); painter->setPen( oldPen ); } else { QColorGroup g( cg ); g.setColor( QColorGroup::Dark, Qt::red ); qDrawShadeLine( painter, crect.left() - 1, crect.y() + crect.height() / 2, crect.right() + 1, crect.y() + crect.height() / 2, g, TRUE, crect.height() / 8 ); } } } #endif #include "kwframe.moc" diff --git a/kword/kwframe.h b/kword/kwframe.h index 509a54318f..024afa04cc 100644 --- a/kword/kwframe.h +++ b/kword/kwframe.h @@ -1,960 +1,967 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 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 frame_h #define frame_h #include #include "defs.h" #include #include #include #include #include #include "kwstyle.h" #include "koborder.h" class KCommand; class KWAnchor; class KWCanvas; class KWChild; class KWDocument; class KWFrame; class KWFrameSet; class KWTextFrameSet; class KWResizeHandle; class KWTableFrameSet; class KWTextDocument; class KWTextParag; class KWView; class KWViewMode; class QCursor; class QPainter; class QPoint; class QRegion; class QSize; class QProgressDialog; class KWTextFrameSet; class KWFramePartMoveCommand; class KWordFrameSetIface; class DCOPObject; class KoXmlWriter; class KoSavingContext; /** * small utility class representing a sortable (by z-order) list of frames * you can use sort() and inSort(item) **/ class KWFrameList: public QPtrList { protected: virtual int compareItems(QPtrCollection::Item a, QPtrCollection::Item b); }; /** * This class represents a single frame. * A frame belongs to a frameset which states its contents. * A frame does NOT have contents, the frameset stores that. * A frame is really just a square that is used to place the content * of a frameset. */ class KWFrame : public KoRect { public: /** Runaround types * RA_NO = No run around, all text is just printed. * RA_BOUNDINGRECT = run around the square of this frame. * RA_SKIP = stop running text on the whole horizontal space this frame occupies. */ enum RunAround { RA_NO = 0, RA_BOUNDINGRECT = 1, RA_SKIP = 2 }; /** Runaround side - only meaningful when RA_BOUNDINGRECT is used */ enum RunAroundSide { RA_BIGGEST = 0, RA_LEFT = 1, RA_RIGHT = 2 }; /** * Constructor * @param fs parent frameset * @param left, top, width, height coordinates of the frame * The page number will be automatically determined from the position of the frame. * @param ra the "runaround" setting, i.e. whether text should flow below the frame, * around the frame, or avoiding the frame on the whole horizontal band. */ KWFrame(KWFrameSet *fs, double left, double top, double width, double height, RunAround ra = RA_BOUNDINGRECT); KWFrame(KWFrame * frame); /** Destructor */ virtual ~KWFrame(); /** a frame can be selected by the user clicking on it. The frame * remembers if it is selected * - which is actually pretty bad in terms of doc/view design (DF) */ void setSelected( bool _selected ); bool isSelected()const { return m_selected; } MouseMeaning getMouseMeaning( const KoPoint& docPoint, MouseMeaning defaultMeaning ); double runAroundLeft() const { return m_runAroundLeft; } double runAroundRight() const { return m_runAroundRight; } double runAroundTop() const { return m_runAroundTop; } double runAroundBottom() const { return m_runAroundBottom; } void setRunAroundGap( double left, double right, double top, double bottom ) { m_runAroundLeft = left; m_runAroundRight = right; m_runAroundTop = top; m_runAroundBottom = bottom; } // Don't look at the implementation, it's about saving one byte ;) RunAround runAround()const { return (RunAround)(m_runAround & 0x0f); } void setRunAround( RunAround _ra ) { m_runAround = 16 * runAroundSide() + _ra; } RunAroundSide runAroundSide() const { return (RunAroundSide)(m_runAround / 16); } void setRunAroundSide( RunAroundSide rs ) { m_runAround = 16 * rs + runAround(); } /** what should happen when the frame is full */ enum FrameBehavior { AutoExtendFrame=0 , AutoCreateNewFrame=1, Ignore=2 }; FrameBehavior frameBehavior()const { return (FrameBehavior)m_frameBehavior; } void setFrameBehavior( FrameBehavior fb ) { m_frameBehavior = fb; } /* Frame duplication properties */ /** This frame will only be copied to: * AnySide, OddSide or EvenSide */ enum SheetSide { AnySide=0, OddSide=1, EvenSide=2}; SheetSide sheetSide()const { return (SheetSide)m_sheetSide; } void setSheetSide( SheetSide ss ) { m_sheetSide = ss; } /** What happens on new page * (create a new frame and reconnect, no followup, make copy) */ enum NewFrameBehavior { Reconnect=0, NoFollowup=1, Copy=2 }; NewFrameBehavior newFrameBehavior()const { return (NewFrameBehavior)m_newFrameBehavior; } void setNewFrameBehavior( NewFrameBehavior nfb ) { m_newFrameBehavior = nfb; } /** Drawing property: if isCopy, this frame is a copy of the previous frame in the frameset */ bool isCopy()const { return m_bCopy; } void setCopy( bool copy ) { m_bCopy = copy; } /** Data stucture methods */ KWFrameSet *frameSet() const { return m_frameSet; } void setFrameSet( KWFrameSet *fs ) { m_frameSet = fs; } /** The page on which this frame is (0 based) */ int pageNum() const; /** Same as pageNum(), but works if the frame hasn't been added to a frameset yet */ int pageNum( KWDocument* doc ) const; /** The z-order of the frame, relative to the other frames on the same page */ void setZOrder( int z ) { m_zOrder = z; } int zOrder() const { return m_zOrder; } /** For KWFrameSet::updateFrames only. Clear list of frames on top of this one. */ void clearFramesOnTop() { m_framesOnTop.clear(); } void clearFramesBelow() { m_framesBelow.clear(); } /** For KWFrameSet::updateFrames only. Add a frame on top of this one. * Note that order doesn't matter in that list, it's for clipping only. */ void addFrameOnTop( KWFrame* fot ) { m_framesOnTop.append( fot ); } /** * order DOES matter for this one tho. this one is for transparency & selection. **/ void addFrameBelow( KWFrame* fbl ) { m_framesBelow.append( fbl ); } void sortFramesBelow() { m_framesBelow.sort(); } const QPtrList& framesOnTop() const { return m_framesOnTop; } const QPtrList& framesBelow() const { return m_framesBelow; } /** All borders can be custom drawn with their own colors etc. */ const KoBorder &leftBorder() const { return m_borderLeft; } const KoBorder &rightBorder() const { return m_borderRight; } const KoBorder &topBorder() const { return m_borderTop; } const KoBorder &bottomBorder() const { return m_borderBottom; } void setLeftBorder( KoBorder _brd ) { m_borderLeft = _brd; } void setRightBorder( KoBorder _brd ) { m_borderRight = _brd; } void setTopBorder( KoBorder _brd ) { m_borderTop = _brd; } void setBottomBorder( KoBorder _brd ) { m_borderBottom = _brd; } void invalidateParentFrameset(); /** Return the _zoomed_ rectangle for this frame, including the border - for drawing * @param viewMode needed to know if borders are visible or not */ QRect outerRect( KWViewMode* viewMode ) const; /** Return the unzoomed rectangle, including the border, for the frames-on-top list. * The default border of size 1-pixel that is drawn on screen is _not_ included here * [since it depends on the zoom] */ KoRect outerKoRect() const; /** Return the rectangle for this frame including the border and the runaround gap. * This is the rectangle that the surrounding text must run around. */ KoRect runAroundRect() const; /** Resize handles (in kwcanvas.h) are the dots that are drawn on selected frames, this creates and deletes them */ void createResizeHandles(); void createResizeHandlesForPage(KWCanvas *canvas); void removeResizeHandlesForPage(KWCanvas *canvas); void removeResizeHandles(); void frameBordersChanged(); void updateResizeHandles(); void repaintResizeHandles(); void updateRulerHandles(); void updateCursorType(); QBrush backgroundColor() const { return m_backgroundColor; } void setBackgroundColor( const QBrush &_color ); KoRect innerRect() const; double innerWidth() const; double innerHeight() const; /** The "internal Y" is the offset (in pt) of the real frame showed in this one * ("real" means "the last that isn't a copy") * This offset in pt is the sum of the height of the frames before that one. * For text frames, this is equivalent to the layout units (after multiplication). */ void setInternalY( double y ) { m_internalY = y; } double internalY() const { return m_internalY; } /// set left padding (distance between frame contents and frame border) void setPaddingLeft( double b ) { m_paddingLeft = b; } /// set right padding void setPaddingRight( double b ) { m_paddingRight = b; } /// set top padding void setPaddingTop( double b ) { m_paddingTop = b; } /// set bottom padding void setPaddingBottom( double b ) { m_paddingBottom = b; } /// get left padding double paddingLeft() const { return m_paddingLeft; } /// get right padding double paddingRight() const { return m_paddingRight; } /// get top padding double paddingTop() const { return m_paddingTop; } /// get bottom padding double paddingBottom() const { return m_paddingBottom; } void setFramePadding( double _left, double _top, double right, double bottom); /** returns a copy of self */ KWFrame *getCopy(); void copySettings(KWFrame *frm); /** create XML to describe yourself */ void save( QDomElement &frameElem ); /** read attributes from XML. @p headerOrFooter if true some defaults are different */ void load( QDomElement &frameElem, KWFrameSet* frameSet, int syntaxVersion ); void loadCommonOasisProperties( KoOasisContext& context, KWFrameSet* frameSet ); QString saveOasisFrameStyle( KoGenStyles& mainStyles ) const; void startOasisFrame( KoXmlWriter &xmlWriter, KoGenStyles& mainStyles ) const; void setMinFrameHeight(double h); double minFrameHeight(void)const {return m_minFrameHeight;} /** Return if the point is on the frame. @param point the point in normal coordinates. @param borderOfFrameOnly when true an additional check is done if the point is on the border. */ bool frameAtPos( const QPoint& nPoint, bool borderOfFrameOnly=false ); /** * Only applicable to frames of the main text frameset. * Set to true by KWFrameLayout if the "footnote line" should be * drawn under this frame. */ void setDrawFootNoteLine( bool b ) { m_drawFootNoteLine = b; } bool drawFootNoteLine()const { return m_drawFootNoteLine; } private: char /*SheetSide*/ m_sheetSide; char /*RunAroundSide*/ m_runAround; // includes runaround side char /*FrameBehavior*/ m_frameBehavior; char /*NewFrameBehavior*/ m_newFrameBehavior; double m_runAroundLeft, m_runAroundRight, m_runAroundTop, m_runAroundBottom; double m_paddingLeft, m_paddingRight, m_paddingTop, m_paddingBottom; double m_minFrameHeight; double m_internalY; int m_zOrder; bool m_bCopy; bool m_selected; bool m_drawFootNoteLine; QBrush m_backgroundColor; KoBorder m_borderLeft, m_borderRight, m_borderTop, m_borderBottom; QPtrList handles; KWFrameList m_framesOnTop; ///< List of frames on top of us, those we shouldn't overwrite KWFrameList m_framesBelow; ///< List of frames below us. needed for selection code & transparency KWFrameSet *m_frameSet; /** Prevent operator= */ KWFrame &operator=( const KWFrame &_frame ); /** Prevent copy constructor */ KWFrame ( const KWFrame &_frame ); }; /** * This object is created to edit a particular frameset in a particular view * The view's canvas creates it, and destroys it. */ class KWFrameSetEdit { public: KWFrameSetEdit( KWFrameSet * fs, KWCanvas * canvas ); virtual ~KWFrameSetEdit() {} KWFrameSet * frameSet() const { return m_fs; } KWCanvas * canvas() const { return m_canvas; } KWFrame * currentFrame() const { return m_currentFrame; } /** * Return the current most-low-level text edit object */ virtual KWFrameSetEdit* currentTextEdit() { return 0L; } /** * Called before destruction, when terminating edition - use to e.g. hide cursor */ virtual void terminate(bool /*removeselection*/ = true) {} /** * Paint this frameset in "has focus" mode (e.g. with a cursor) * See KWFrameSet for explanation about the arguments. * Most framesets don't need to reimplement that (the KWFrameSetEdit gets passed to drawFrame) */ virtual void drawContents( QPainter *, const QRect &, const QColorGroup &, bool onlyChanged, bool resetChanged, KWViewMode *viewMode ); // Events forwarded by the canvas (when being in "edit" mode) virtual void keyPressEvent( QKeyEvent * ) {} virtual void keyReleaseEvent( QKeyEvent * ) {} virtual void imStartEvent( QIMEvent * ) {} virtual void imComposeEvent( QIMEvent * ) {} virtual void imEndEvent( QIMEvent * ) {} virtual void mousePressEvent( QMouseEvent *, const QPoint &, const KoPoint & ) {} virtual void mouseMoveEvent( QMouseEvent *, const QPoint &, const KoPoint & ) {} // only called if button is pressed virtual void mouseReleaseEvent( QMouseEvent *, const QPoint &, const KoPoint & ) {} virtual void mouseDoubleClickEvent( QMouseEvent *, const QPoint &, const KoPoint & ) {} virtual void dragEnterEvent( QDragEnterEvent * ) {} virtual void dragMoveEvent( QDragMoveEvent *, const QPoint &, const KoPoint & ) {} virtual void dragLeaveEvent( QDragLeaveEvent * ) {} virtual void dropEvent( QDropEvent *, const QPoint &, const KoPoint & ) {} virtual void focusInEvent() {} virtual void focusOutEvent() {} virtual void copy() {} virtual void cut() {} virtual void paste() {} virtual void selectAll() {} /** Show a popup menu - called when right-clicking inside a frame of this frameset. * The default implementation calls the frameset's showPopup. * @param frame the frame which was clicked. * @param view the view - we use it to get the popupmenu by name * @param point the mouse position (at which to show the menu) */ virtual void showPopup( KWFrame* frame, KWView* view, const QPoint & _point ); + /// Called if the cursor tries to leave the frameset at its beginning. + /// Returns true if the frameset was inline, and we did exit into another frameset. + bool exitLeft(); + /// Called if the cursor tries to leave the frameset at its end. + /// Returns true if the frameset was inline, and we did exit into another frameset. + bool exitRight(); + protected: KWFrameSet * m_fs; KWCanvas * m_canvas; /** * The Frameset-Edit implementation is responsible for updating that one * (to the frame where the current "cursor" is) */ KWFrame * m_currentFrame; }; /** * Class: KWFrameSet * Base type, a frameset holds content as well as frames to show that * content. * The different types of content are implemented in the different * types of frameSet implementations (see below) * @see KWTextFrameSet, KWPartFrameSet, KWPictureFrameSet, * KWFormulaFrameSet, KWTableFrameSet */ class KWFrameSet : public QObject { Q_OBJECT public: /// constructor KWFrameSet( KWDocument *doc ); /// destructor virtual ~KWFrameSet(); virtual KWordFrameSetIface* dcopObject(); /** The type of frameset. Use this to differentiate between different instantiations of * the framesets. Each implementation will return a different frameType. */ virtual FrameSetType type() { return FT_BASE; } /** * Return the type of FrameSet that would have been used in KWord 1.1 */ virtual FrameSetType typeAsKOffice1Dot1(void) { return type(); } virtual void addTextFrameSets( QPtrList & /*lst*/, bool /*onlyReadWrite*/ = false ) {}; virtual bool ownLine() const { return FALSE;} /** The different types of textFramesets (that TEXT is important here!) * FI_BODY = normal text frames.
* FI_FIRST_HEADER = Header on page 1
* FI_EVEN_HEADER = header on any even page
* FI_ODD_HEADER = header on any odd page (can be including page 1)
* FI_FIRST_FOOTER = footer on page 1
* FI_EVEN_FOOTER = footer on any even page
* FI_ODD_FOOTER = footer on any odd page (can be including page 1)
* FI_FOOTNOTE = a footnote frame. */ enum Info { FI_BODY = 0, FI_FIRST_HEADER = 1, FI_EVEN_HEADER = 2, FI_ODD_HEADER = 3, FI_FIRST_FOOTER = 4, FI_EVEN_FOOTER = 5, FI_ODD_FOOTER = 6, FI_FOOTNOTE = 7 }; /** Returns the type of TextFrameSet this is */ Info frameSetInfo()const { return m_info; } /** Set the type of TextFrameSet this is */ void setFrameSetInfo( Info fi ) { m_info = fi; } bool isAHeader() const; bool isAFooter() const; bool isHeaderOrFooter() const { return isAHeader() || isAFooter(); } bool isFootEndNote() const; virtual bool isFootNote() const { return false; } virtual bool isEndNote() const { return false; } bool isMainFrameset() const; bool isMoveable() const; // frame management virtual void addFrame( KWFrame *_frame, bool recalc = true ); /** Delete a frame from the set of frames this frameSet has. * @param num The frameNumber to be removed. * @param remove passing true means that there can not be an undo of the action. * @param recalc do an updateFrames() */ virtual void delFrame( unsigned int _num, bool remove = true, bool recalc = true ); /** Delete a frame from the set of frames this frameSet has. * @param frm. The frame that should be deleted * @param remove passing true means that there can not be an undo of the action. * @param recalc do an updateFrames() */ void delFrame( KWFrame *frm, bool remove = true, bool recalc = true ); // calls the virtual one /// Called by delFrame when it really deletes a frame (remove=true), to remove it from the table too virtual void frameDeleted( KWFrame* /*frm*/, bool /*recalc*/ ) {} void deleteAllFrames(); void deleteAllCopies(); /// \note for headers/footers only /** retrieve frame from x and y coords (unzoomed coords) */ KWFrame *frameAtPos( double _x, double _y ); /** Return if the point is on the frame. @param point the point in normal coordinates. @param borderOfFrameOnly when true an additional check is done if the point is on the border. */ bool isFrameAtPos( KWFrame* frame, const QPoint& nPoint, bool borderOfFrameOnly=false ); /** return a frame if nPoint in on one of its borders */ KWFrame *frameByBorder( const QPoint & nPoint ); /** get a frame by number */ KWFrame *frame( unsigned int _num ); /** get the frame whose settings apply for @p frame (usually @p frame, but can also be the real frame if frame is a copy) */ static KWFrame * settingsFrame( const KWFrame* frame ); /** Iterator over the child frames */ const QPtrList &frameIterator() const { return frames; } /** Get frame number */ int frameFromPtr( KWFrame *frame ); /** Get number of child frames */ unsigned int getNumFrames() const { return frames.count(); } /** Called when the user resizes a frame. Calls resizeFrame. */ void resizeFrameSetCoords( KWFrame* frame, double newLeft, double newTop, double newRight, double newBottom, bool finalSize ); /** Called when the user resizes a frame. Reimplemented by KWPictureFrameSet. */ virtual void resizeFrame( KWFrame* frame, double newWidth, double newHeight, bool finalSize ); /** Called when the user moves a frame. */ virtual void moveFrame( KWFrame* ) {} /** True if the frameset was deleted (but not destroyed, since it's in the undo/redo) */ bool isDeleted() const { return frames.isEmpty(); } /** Create a framesetedit object to edit this frameset in @p canvas */ virtual KWFrameSetEdit * createFrameSetEdit( KWCanvas *, bool /*temp*/ = false ) { return 0L; } /** * @param emptyRegion The region is modified to subtract the areas painted, thus * allowing the caller to determine which areas remain to be painted. * Framesets that can be transparent should reimplement this and make it a no-op, * so that the background is painted below the transparent frame. */ virtual void createEmptyRegion( const QRect & crect, QRegion & emptyRegion, KWViewMode *viewMode ); /** * Paint this frameset * @param painter The painter in which to draw the contents of the frameset * @param crect The rectangle (in scrollview "contents coordinates", i.e. "view coords") * to be painted * @param cg The colorgroup from which to get the colors * @param onlyChanged If true, only redraw what has changed (see KWCanvas::repaintChanged) * @param resetChanged If true, set the changed flag to false after drawing. * @param edit If set, this frameset is being edited, so a cursor is needed. * @param viewMode For coordinate conversion, always set. * @param canvas For view settings. WARNING: canvas can be 0 (e.g. in embedded documents). * * The way this "onlyChanged/resetChanged" works is: when something changes, * all views are asked to redraw themselves with onlyChanged=true. * But all views except the last one shouldn't reset the changed flag to false, * otherwise the other views wouldn't repaint anything. * So resetChanged is called with "false" for all views except the last one, * and with "true" for the last one, so that it resets the flag. * * Framesets shouldn't reimplement this one in theory [but KWTableFrameSet has to]. */ virtual void drawContents( QPainter *painter, const QRect &crect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode ); /** * This one is called by drawContents for each frame. * It sets up clip rect and painter translation, and calls drawFrame, drawFrameBorder and drawMargins * * @param drawUnderlyingFrames if the frame implements it, then it should draw underlying frames. * This is set to false by the default drawFrame implementation, so that the frames under a * transparent frame are simply drawn, without transparency handling (nor their own * double-buffering). */ void drawFrameAndBorders( KWFrame *frame, QPainter *painter, const QRect &crect, const QColorGroup &cg, bool, bool, KWFrameSetEdit *edit, KWViewMode *viewMode, KWFrame *settingsFrame, bool drawUnderlyingFrames ); /** * Paint the borders for one frame of this frameset. * @param painter The painter in which to draw the contents of the frameset * @param frame The frame to be drawn * @param settingsFrame The frame from which we take the settings (usually @p frame, but not with Copy behaviour) * @param crect The rectangle (in "contents coordinates") to be painted */ void drawFrameBorder( QPainter *painter, KWFrame *frame, KWFrame *settingsFrame, const QRect &crect, KWViewMode *viewMode ); /** * Draw a particular frame of this frameset. * This is called by drawContents and is what framesets must reimplement. * @param fcrect rectangle to be repainted, in the _frame_'s coordinate system, in pixels. * Doesn't include padding. * * @param crect rectangle to be repainted, in view coordinates. Includes padding. * Default implementation does double-buffering and calls drawFrameContents. */ virtual void drawFrame( KWFrame *frame, QPainter *painter, const QRect &fcrect, const QRect &crect, const QPoint& translationOffset, KWFrame *settingsFrame, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode, bool drawUnderlyingFrames ); /** * Implement this one instead of drawFrame to benefit from double-buffering * AND transparency handling (painting frames below this one) automatically. * You MUST reimplement one or the other, or you'll get infinite recursion ;) * * In this method, the painter has been translated to the frame's coordinate system * @param fcrect rectangle to be repainted, in the _frame_'s coordinate system, in pixels. * Doesn't include padding. */ virtual void drawFrameContents( KWFrame * frame, QPainter *painter, const QRect& fcrect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit * edit, KWViewMode *viewMode ); /** * Draw the padding area inside of a specific frame of this frameSet */ virtual void drawPadding( KWFrame *frame, QPainter *p, const QRect &fcrect, const QColorGroup &cg, KWViewMode *viewMode); enum UpdateFramesFlags { UpdateFramesInPage = 1, SortFrames = 2 ///< kwtextframeset only // next one is 4, not 3 ;) }; /** * Called when our frames change, or when another frameset's frames change. * Framesets can reimplement it, but should always call the parent method. */ virtual void updateFrames( int flags = 0xff ); /** Return list of frames in page @p pageNum. * This is fast since it uses the m_framesInPage array.*/ const QPtrList & framesInPage( int pageNum ) const; /** Allows to detect that updateFrames() hasn't been called yet (e.g. on loading) */ bool hasFramesInPageArray() const { return !m_framesInPage.isEmpty(); } /** relayout text in frames, so that it flows correctly around other frames */ virtual void layout() {} virtual void invalidate() {} /** returns true if we have a frame occupying that position */ virtual bool contains( double mx, double my ); /** * Return "what it means" to have the mouse at position nPoint, * (which kwdoc tests to be over one of our frames). * The meaning is "what will happen when clicking". */ virtual MouseMeaning getMouseMeaning( const QPoint &nPoint, int keyState ); /** * Return the meaning of clicking inside the frame (when neither Ctrl nor Shift is pressed) */ virtual MouseMeaning getMouseMeaningInsideFrame( const KoPoint& ); /** Show a popup menu - called when right-clicking inside a frame of this frameset. * The default implementation shows "frame_popup". * @param frame the frame which was clicked. Always one of ours. * @param view the view - we use it to get the popupmenu by name * @param point the mouse position (at which to show the menu) */ virtual void showPopup( KWFrame *frame, KWView *view, const QPoint &point ); /// save to XML - when saving virtual QDomElement save( QDomElement &parentElem, bool saveFrames = true ) = 0; /// save to XML - when copying to clipboard virtual QDomElement toXML( QDomElement &parentElem, bool saveFrames = true ) { return save( parentElem, saveFrames ); } /// Save to OASIS format virtual void saveOasis( KoXmlWriter& writer, KoSavingContext& context ) const = 0; /// load from XML - when loading virtual void load( QDomElement &framesetElem, bool loadFrames = true ); KWFrame* loadOasisFrame( const QDomElement& tag, KoOasisContext& context ); /// load from XML - when pasting from clipboard virtual void fromXML( QDomElement &framesetElem, bool loadFrames = true, bool /*useNames*/ = true ) { load( framesetElem, loadFrames ); } virtual QString toPlainText() const { return QString::null; } //virtual void preparePrinting( QPainter *, QProgressDialog *, int & ) { } /** Called once the frameset has been completely loaded or constructed. * The default implementation calls updateFrames() and zoom(). Call the parent :) */ virtual void finalize(); virtual int paragraphs() { return 0; } virtual int paragraphsSelected() { return 0; } virtual bool statistics( QProgressDialog */*progress*/, ulong & /*charsWithSpace*/, ulong & /*charsWithoutSpace*/, ulong & /*words*/, ulong & /*sentences*/, ulong & /*syllables*/, ulong & /*lines*/, bool /*process only selected */ ) { return true; } KWDocument* kWordDocument() const { return m_doc; } /// Return true if page @p num can be removed, as far as this frameset is concerned virtual bool canRemovePage( int num ); //Note: none of those floating-frameset methods creates undo/redo //They are _called_ by the undo/redo commands. /// Make this frameset floating (anchored), as close to its current position as possible. void setFloating(); /** * Make this frameset anchored, with the anchor at @p paragId,@p index in the text frameset @p textfs. * Also used during OASIS loading (placeHolderExists=true) */ void setAnchored( KWTextFrameSet* textfs, KoTextParag* parag, int index, bool placeHolderExists = false, bool repaint = true ); /** Make this frameset floating, with the anchor at @p paragId,@p index in the text frameset @p textfs. * \deprecated */ void setAnchored( KWTextFrameSet* textfs, int paragId, int index, bool placeHolderExists = false, bool repaint = true ); /** Note that this frameset has been made floating already, and store anchor position */ void setAnchored( KWTextFrameSet* textfs ); /// Make this frameset fixed, i.e. not anchored void setFixed(); /// Return true if this frameset is floating (inline), false if it's fixed bool isFloating() const { return m_anchorTextFs; } /// Return the frameset in which our anchor is - assuming isFloating() KWTextFrameSet * anchorFrameset() const { return m_anchorTextFs; } /// Sets the frameset in which we are about to become inline. Used for OASIS loading. void setAnchorFrameset(KWTextFrameSet * textfs) { m_anchorTextFs = textfs; } /// Return the anchor object for this frame number KWAnchor * findAnchor( int frameNum ); /// Tell this frame the format of it's anchor virtual void setAnchorFormat( KoTextFormat* /*format*/, int /*frameNum*/ ) {} /// Create an anchor for the floating frame identified by frameNum virtual KWAnchor * createAnchor( KoTextDocument *txt, int frameNum ); /** Move the frame frameNum to the given position - this is called when the frame is anchored and the anchor moves (see KWAnchor). */ virtual void moveFloatingFrame( int frameNum, const KoPoint &position ); /** Get the size of the "floating frame" identified by frameNum. By default a real frame but not for tables. */ virtual KoSize floatingFrameSize( int frameNum = 0 ); /** Get the rect of the "floating frame" identified by frameNum, in coordinates RELATIVE TO THE PARENT FRAMESET. This is especially important for multi-parent inline frames. */ KoRect floatingFrameRect( int frameNum = 0 ); /** Get the 'baseline' to use for the "floating frame" identified by frameNum. -1 means same as the height (usual case) */ virtual int floatingFrameBaseline( int /*frameNum*/ ) { return -1; } /// Store command for creating an anchored object virtual KCommand * anchoredObjectCreateCommand( int frameNum ); /// Store command for deleting an anchored object virtual KCommand * anchoredObjectDeleteCommand( int frameNum ); /** make this frameset part of a groupmanager * @see KWTableFrameSet */ void setGroupManager( KWTableFrameSet *gm ) { grpMgr = gm; } /** returns the groupManager this frameset belongs to. A Groupmanager is better known as a table */ KWTableFrameSet *getGroupManager()const { return grpMgr; } /** table headers can created by the groupmanager, we store the fact that this is one in here. */ void setIsRemoveableHeader( bool h ) { m_removeableHeader = h; } bool isRemoveableHeader()const { return m_removeableHeader; } /// returns if one of our frames has been selected. bool hasSelectedFrame(); bool isProtectSize()const { return m_protectSize; } void setProtectSize( bool _b) { m_protectSize = _b;} /** * Returns true if the frameset is visible. * A frameset is visible if setVisible(false) wasn't called, * but also, for a header frameset, if m_doc->isHeaderVisible is true, etc. * For an "even pages header" frameset, the corresponding headerType setting * must be selected (i.e. different headers for even and odd pages). * @param viewMode pass the current viewmode when using this method for any visual * stuff (drawing, handling input etc.). Frameset visibility depends on the viewmode. */ bool isVisible( KWViewMode* viewMode = 0L ) const; /// set the visibility of the frameset. virtual void setVisible( bool v ); /// get/set frameset name. For tables in particular, this _must_ be unique QString getName() const { return m_name; } void setName( const QString &_name ); /// set frameBehavior on all frames, see KWFrame for specifics void setFrameBehavior( KWFrame::FrameBehavior fb ); /// set newFrameBehavior on all frames, see KWFrame for specifics void setNewFrameBehavior( KWFrame::NewFrameBehavior nfb ); #ifndef NDEBUG virtual void printDebug(); virtual void printDebug( KWFrame * ); #endif virtual KWTextFrameSet* nextTextObject( KWFrameSet * ) { return 0L;} bool isPaintedBy( KWFrameSet* fs ) const; /// set z-order for all frames virtual void setZOrder(); virtual void setProtectContent ( bool protect ) = 0; virtual bool protectContent() const = 0; signals: /// Emitted when something has changed in this frameset, /// so that all views repaint it. KWDocument connects to it, /// and KWCanvas connects to KWDocument. void repaintChanged( KWFrameSet * frameset ); protected: /// save the common attributes for the frameset void saveCommon( QDomElement &parentElem, bool saveFrames ); /**Determine the clipping rectangle for drawing the contents of @p frame with @p painter * in the rectangle delimited by @p crect. * This determines where to clip the painter to draw the contents of a given frame */ QRegion frameClipRegion( QPainter * painter, KWFrame *frame, const QRect & crect, KWViewMode * viewMode ); void deleteAnchor( KWAnchor * anchor ); virtual void deleteAnchors(); virtual void createAnchors( KoTextParag * parag, int index, bool placeHolderExists = false, bool repaint = true ); KWDocument *m_doc; // Document QPtrList frames; // Our frames // Cached info for optimization /// This array provides a direct access to the frames on page N QPtrVector< QPtrList > m_framesInPage; /// always equal to m_framesInPage[0].first()->pageNum() :) int m_firstPage; /// always empty, for convenience in @ref framesInPage QPtrList m_emptyList; // ## make static pointer to save memory ? Info m_info; KWTableFrameSet *grpMgr; bool m_removeableHeader, m_visible; bool m_protectSize; QString m_name; KWTextFrameSet * m_anchorTextFs; KWordFrameSetIface *m_dcop; }; /******************************************************************/ /* Class: KWPictureFrameSet */ /******************************************************************/ class KWPictureFrameSet : public KWFrameSet { public: KWPictureFrameSet( KWDocument *_doc, const QString & name ); /// Used for OASIS loading KWPictureFrameSet( KWDocument* doc, const QDomElement& frame, const QDomElement& imageTag, KoOasisContext& context ); virtual ~KWPictureFrameSet(); virtual KWordFrameSetIface* dcopObject(); /** * The type of frameset. Use this to differentiate between different instantiations of * the framesets. Each implementation will return a different frameType. */ virtual FrameSetType type( void ); virtual FrameSetType typeAsKOffice1Dot1( void ); void setPicture( const KoPicture &picture ) { m_picture = picture; } KoPicture picture() const { return m_picture; } KoPictureKey key() const { return m_picture.getKey(); } void loadPicture( const QString &fileName ); void insertPicture( const KoPicture& picture ); /** * Reload a picture, which already exists in the picture collection * (if not, it gives a defaulft KoPicture() ) */ void reloadPicture( const KoPictureKey& key ); /** * @deprecated * The size of the image is now only needed at drawing time, not before anymore. * However at drawing time, it is the frame's size that matters. */ void setSize( const QSize & _imgSize ); /** * Called when the user resizes a frame. */ virtual void resizeFrame( KWFrame* frame, double newWidth, double newHeight, bool finalSize ); virtual QDomElement save( QDomElement &parentElem, bool saveFrames = true ); virtual void load( QDomElement &attributes, bool loadFrames = true ); virtual void saveOasis( KoXmlWriter& writer, KoSavingContext& context ) const; virtual void drawFrameContents( KWFrame * frame, QPainter *painter, const QRect & crect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit * edit, KWViewMode *viewMode ); /// Pixmaps can be transparent virtual void createEmptyRegion( const QRect &, QRegion &, KWViewMode * ) { } #ifndef NDEBUG virtual void printDebug( KWFrame* frame ); #endif bool keepAspectRatio() const; void setKeepAspectRatio( bool b ); virtual void setProtectContent ( bool protect ) { m_protectContent = protect; } virtual bool protectContent() const { return m_protectContent; } protected: void loadOasis( const QDomElement& frame, const QDomElement& imageTag, KoOasisContext& context ); /// The picture KoPicture m_picture; bool m_keepAspectRatio; /// Cache the finalSize parameter of the method resizeFrame for drawFrame bool m_finalSize; bool m_protectContent; }; #if 0 // KWORD_HORIZONTAL_LINE // MOC_SKIP_BEGIN /******************************************************************/ /* Class: KWHorzLineFrameSet */ /******************************************************************/ class KWHorzLineFrameSet : public KWPictureFrameSet { public: KWHorzLineFrameSet( KWDocument *_doc, const QString & name ); virtual ~KWHorzLineFrameSet(); virtual KWordFrameSetIface* dcopObject(); /** * The type of frameset. Use this to differentiate between different instantiations of * the framesets. Each implementation will return a different frameType. */ virtual FrameSetType type( void ); virtual bool ownLine() const; void drawFrameContents( KWFrame *frame, QPainter *painter, const QRect &crect, const QColorGroup &, bool, bool, KWFrameSetEdit *, KWViewMode * ); }; // MOC_SKIP_END #endif #endif diff --git a/kword/kwtextframeset.cc b/kword/kwtextframeset.cc index c81e3169b1..8228d60ca7 100644 --- a/kword/kwtextframeset.cc +++ b/kword/kwtextframeset.cc @@ -1,4089 +1,4100 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 Reginald Stadlbauer Copyright (C) 2001 David Faure 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 "kwtextframeset.h" #include "kwtableframeset.h" #include "kwdoc.h" #include "kwview.h" #include "kwviewmode.h" #include "kwcanvas.h" #include "kwanchor.h" #include "kwcommand.h" #include "kwdrag.h" #include "kwformulaframe.h" #include "kwbgspellcheck.h" #include "KWordTextFrameSetIface.h" #include "KWordTextFrameSetEditIface.h" #include "KWordFootNoteFrameSetIface.h" #include "KWordFrameSetIface.h" #include "kwloadinginfo.h" #include "contents.h" #include "mailmerge.h" #include "kwbookmark.h" #include "kwvariable.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_MARGINS //#define DEBUG_FORMATVERTICALLY //#define DEBUG_FORMATS //#define DEBUG_FORMAT_MORE //#define DEBUG_VIEWAREA //#define DEBUG_CURSOR //#define DEBUG_DTI //#define DEBUG_ITD /** * KWord's text formatter. * It derives from KoTextFormatter and simply forwards formatVertically to KWTextFrameSet, * since only KWTextFrameSet knows about page-breaking, overlapping frames etc. */ class KWTextFormatter : public KoTextFormatter { public: KWTextFormatter( KWTextFrameSet *textfs ) : m_textfs( textfs ) {} virtual ~KWTextFormatter() {} virtual int formatVertically( KoTextDocument*, KoTextParag* parag ) { return m_textfs->formatVertically( parag, parag->rect() ); } virtual void postFormat( KoTextParag* parag ) { m_textfs->fixParagWidth( static_cast( parag ) ); } private: KWTextFrameSet *m_textfs; }; KWTextFrameSet::KWTextFrameSet( KWDocument *_doc, const QString & name ) : KWFrameSet( _doc ) { //kdDebug() << "KWTextFrameSet::KWTextFrameSet " << this << endl; if ( name.isEmpty() ) m_name = _doc->generateFramesetName( i18n( "Text Frameset %1" ) ); else m_name = name; QObject::setName( m_name.utf8() ); // store name in the QObject, for DCOP users init(); } KWTextFrameSet::KWTextFrameSet( KWDocument* doc, const QDomElement& tag, KoOasisContext& /*context*/ ) : KWFrameSet( doc ) { m_name = tag.attributeNS( KoXmlNS::draw, "name", QString::null ); if ( doc->frameSetByName( m_name ) ) // already exists! m_name = doc->generateFramesetName( m_name + " %1" ); init(); // Note that we don't call loadOasis here. The caller wants to do it, // to get the frame it returns. } void KWTextFrameSet::init() { m_currentViewMode = 0L; m_currentDrawnFrame = 0L; m_lastTextDocHeight = 0; // Create the text document to set in the text object KWTextDocument* textdoc = new KWTextDocument( this, new KoTextFormatCollection( m_doc->defaultFont(), QColor(), m_doc->globalLanguage(), m_doc->globalHyphenation() ), new KWTextFormatter( this ) ); textdoc->setFlow( this ); textdoc->setPageBreakEnabled( true ); // get verticalBreak to be called if ( m_doc->tabStopValue() != -1 ) textdoc->setTabStops( m_doc->ptToLayoutUnitPixX( m_doc->tabStopValue() )); m_textobj = new KoTextObject( textdoc, m_doc->styleCollection()->findStyle( "Standard" ), this, (m_name+"-textobj").utf8() ); #ifdef HAVE_LIBKSPELL2 m_doc->backSpeller()->registerNewTextObject( m_textobj ); #endif connect( m_textobj, SIGNAL( availableHeightNeeded() ), SLOT( slotAvailableHeightNeeded() ) ); connect( m_textobj, SIGNAL( afterFormatting( int, KoTextParag*, bool* ) ), SLOT( slotAfterFormatting( int, KoTextParag*, bool* ) ) ); //connect( m_textobj, SIGNAL( formattingFirstParag() ), // SLOT( slotFormattingFirstParag() ) ); //connect( m_textobj, SIGNAL( chapterParagraphFormatted( KoTextParag * ) ), // SLOT( slotChapterParagraphFormatted( KoTextParag * ) ) ); connect( m_textobj, SIGNAL( newCommand( KCommand * ) ), SLOT( slotNewCommand( KCommand * ) ) ); connect( m_textobj, SIGNAL( repaintChanged( KoTextObject* ) ), SLOT( slotRepaintChanged() ) ); connect( m_textobj, SIGNAL( paragraphDeleted( KoTextParag*) ), SLOT( slotParagraphDeleted(KoTextParag*) )); connect( m_textobj, SIGNAL( paragraphCreated( KoTextParag*) ), SLOT( slotParagraphCreated(KoTextParag*) )); connect( m_textobj, SIGNAL( paragraphModified( KoTextParag*, int, int, int) ), SLOT( slotParagraphModified(KoTextParag*, int, int, int) )); } void KWTextFrameSet::slotParagraphModified(KoTextParag* _parag, int /*KoTextParag::ParagModifyType*/ _type, int start, int lenght) { kWordDocument()->paragraphModified(_parag, _type, start, lenght); } void KWTextFrameSet::slotParagraphCreated(KoTextParag* /*_parag*/) { //todo } void KWTextFrameSet::slotParagraphDeleted(KoTextParag*_parag) { kWordDocument()->paragraphDeleted( _parag, this); } KWordFrameSetIface* KWTextFrameSet::dcopObject() { if ( !m_dcop ) m_dcop = new KWordTextFrameSetIface( this ); return m_dcop; } KWFrameSetEdit * KWTextFrameSet::createFrameSetEdit( KWCanvas * canvas, bool temp ) { return new KWTextFrameSetEdit( this, canvas, temp ); } KoTextDocument * KWTextFrameSet::textDocument() const { return m_textobj->textDocument(); } KWTextDocument * KWTextFrameSet::kwTextDocument() const { return static_cast(m_textobj->textDocument()); } void KWTextFrameSet::slotAvailableHeightNeeded() { Q_ASSERT( isVisible() ); kdDebug() << "KWTextFrameSet::slotAvailableHeightNeeded " << getName() << endl; updateFrames( 0 ); // only do the available-height determination } KWFrame * KWTextFrameSet::documentToInternal( const KoPoint &dPoint, QPoint &iPoint ) const { #ifdef DEBUG_DTI kdDebug() << "KWTextFrameSet::documentToInternal dPoint:" << dPoint.x() << "," << dPoint.y() << endl; #endif if ( !m_doc->viewMode()->hasFrames() ) { // text viewmode iPoint = QPoint( m_doc->ptToLayoutUnitPixX( dPoint.x() ), m_doc->ptToLayoutUnitPixY( dPoint.y() ) ); return frames.getFirst(); } // Find the frame that contains dPoint. To go fast, we look them up by page number. int pageNum = static_cast( dPoint.y() / m_doc->ptPaperHeight() ); QPtrListIterator frameIt( framesInPage( pageNum ) ); for ( ; frameIt.current(); ++frameIt ) { KWFrame *theFrame = frameIt.current(); if ( theFrame->contains( dPoint ) ) { iPoint.setX( m_doc->ptToLayoutUnitPixX( dPoint.x() - theFrame->innerRect().x() ) ); iPoint.setY( m_doc->ptToLayoutUnitPixY( dPoint.y() - theFrame->innerRect().y() + theFrame->internalY() ) ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: returning " << iPoint.x() << "," << iPoint.y() << " internalY=" << theFrame->internalY() << " because frame=" << theFrame << " contains dPoint:" << dPoint.x() << "," << dPoint.y() << endl; #endif return theFrame; } #ifdef DEBUG_DTI //else // kdDebug() << "DTI: " << frameRect // << " doesn't contain nPoint:" << nPoint.x() << "," << nPoint.y() << endl; #endif } // Not found. This means the mouse isn't over any frame, in the page pageNum. iPoint = m_doc->ptToLayoutUnitPix( dPoint ); // bah return 0; } KWFrame * KWTextFrameSet::documentToInternalMouseSelection( const KoPoint &dPoint, QPoint &iPoint, RelativePosition& relPos ) const { #ifdef DEBUG_DTI kdDebug() << "KWTextFrameSet::documentToInternalMouseSelection dPoint:" << dPoint.x() << "," << dPoint.y() << endl; #endif if ( !m_doc->viewMode()->hasFrames() ) { // text viewmode relPos = InsideFrame; iPoint = QPoint( m_doc->ptToLayoutUnitPixX( dPoint.x() ), m_doc->ptToLayoutUnitPixY( dPoint.y() ) ); return frames.getFirst(); } // Find the frame that contains dPoint. To go fast, we look them up by page number. int pageNum = static_cast( dPoint.y() / m_doc->ptPaperHeight() ); QPtrListIterator frameIt( framesInPage( pageNum ) ); for ( ; frameIt.current(); ++frameIt ) { KWFrame *theFrame = frameIt.current(); if ( theFrame->contains( dPoint ) ) { iPoint.setX( m_doc->ptToLayoutUnitPixX( dPoint.x() - theFrame->innerRect().x() ) ); iPoint.setY( m_doc->ptToLayoutUnitPixY( dPoint.y() - theFrame->innerRect().y() + theFrame->internalY() ) ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: returning InsideFrame " << iPoint.x() << "," << iPoint.y() << " internalY=" << theFrame->internalY() << " because frame=" << theFrame << " contains dPoint:" << dPoint.x() << "," << dPoint.y() << endl; #endif relPos = InsideFrame; return theFrame; } } frameIt.toFirst(); for ( ; frameIt.current(); ++frameIt ) { KWFrame *theFrame = frameIt.current(); KoRect openLeftRect( theFrame->innerRect() ); openLeftRect.setLeft( theFrame->paddingLeft() ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: openLeftRect=" << openLeftRect << endl; #endif if ( openLeftRect.contains( dPoint ) ) { // We are at the left of this frame (and not in any other frame of this frameset) iPoint.setX( m_doc->ptToLayoutUnitPixX(theFrame->innerRect().left() )); iPoint.setY( m_doc->ptToLayoutUnitPixY( dPoint.y() - theFrame->top() + theFrame->internalY() ) ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: returning LeftOfFrame " << iPoint.x() << "," << iPoint.y() << " internalY=" << theFrame->internalY() << " because openLeftRect=" << openLeftRect << " contains dPoint:" << dPoint.x() << "," << dPoint.y() << endl; #endif relPos = LeftOfFrame; return theFrame; } KoRect openTopRect( KoPoint( 0, 0 ), theFrame->innerRect().bottomRight() ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: openTopRect=" << openTopRect << endl; #endif if ( openTopRect.contains( dPoint ) ) { // We are at the top of this frame (...) iPoint.setX( m_doc->ptToLayoutUnitPixX( dPoint.x() - theFrame->innerRect().left() ) ); iPoint.setY( m_doc->ptToLayoutUnitPixY( theFrame->internalY() ) ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: returning " << iPoint.x() << "," << iPoint.y() << " internalY=" << theFrame->internalY() << " because openTopRect=" << openTopRect << " contains dPoint:" << dPoint.x() << "," << dPoint.y() << endl; #endif relPos = TopOfFrame; return theFrame; } } // Not found. This means we are under (or at the right of), the frames in pageNum. // In that case, go for the first frame in the next page. if ( pageNum + 1 >= (int)m_framesInPage.size() + m_firstPage ) { // Under last frame of last page! KWFrame *theFrame = frames.getLast(); iPoint.setX( m_doc->ptToLayoutUnitPixX( theFrame->innerWidth() ) ); iPoint.setY( m_doc->ptToLayoutUnitPixY( theFrame->innerHeight() ) ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: returning AtEnd " << iPoint.x() << "," << iPoint.y() << " because we are under all frames of the last page" << endl; #endif relPos = AtEnd; return theFrame; } else { QPtrListIterator frameIt( framesInPage( pageNum + 1 ) ); if ( frameIt.current() ) { // There is a frame on the next page KWFrame *theFrame = frameIt.current(); KoRect openTopRect( theFrame->innerRect() ); openTopRect.setTop( 0 ); if ( openTopRect.contains( dPoint ) ) // We are at the top of this frame iPoint.setX( m_doc->ptToLayoutUnitPixX( dPoint.x() - theFrame->left() ) ); else iPoint.setX( 0 ); // We are, hmm, on the left or right of the frames iPoint.setY( m_doc->ptToLayoutUnitPixY( theFrame->internalY() ) ); #ifdef DEBUG_DTI kdDebug() << "documentToInternal: returning TopOfFrame " << iPoint.x() << "," << iPoint.y() << " because we are under all frames of page " << pageNum << endl; #endif relPos = TopOfFrame; return theFrame; } // else there is a gap (no frames on that page, but on some other further down) // This case isn't handled (and should be VERY rare I think) } iPoint = m_doc->ptToLayoutUnitPix( dPoint ); // bah #ifdef DEBUG_DTI kdDebug() << "documentToInternal: returning not found for " << iPoint.x() << "," << iPoint.y() << endl; #endif return 0; } KWFrame * KWTextFrameSet::internalToDocumentWithHint( const QPoint &iPoint, KoPoint &dPoint, const KoPoint &hintDPoint ) const { #ifdef DEBUG_ITD kdDebug() << "KWTextFrameSet::internalToDocumentWithHint hintDPoint: " << hintDPoint.x() << "," << hintDPoint.y() << endl; #endif if ( !m_doc->viewMode()->hasFrames() ) { // text viewmode dPoint = m_doc->layoutUnitPtToPt( m_doc->pixelToPt( iPoint ) ); return frames.getFirst(); } KWFrame *lastFrame = 0L; QPtrListIterator frameIt( frameIterator() ); for ( ; frameIt.current(); ++frameIt ) { KWFrame *theFrame = frameIt.current(); QRect r( 0, m_doc->ptToLayoutUnitPixY( theFrame->internalY() ), m_doc->ptToLayoutUnitPixX( theFrame->innerWidth() )+1, m_doc->ptToLayoutUnitPixY( theFrame->innerHeight() )+1 ); #ifdef DEBUG_ITD kdDebug() << "ITD: r=" << r << " iPoint=" << iPoint.x() << "," << iPoint.y() << endl; #endif // r is the frame in qrt coords if ( r.contains( iPoint ) ) // both r and p are in layout units (aka internal) { dPoint = internalToDocumentKnowingFrame( iPoint, theFrame ); #ifdef DEBUG_ITD kdDebug() << "copy: " << theFrame->isCopy() << " hintDPoint.y()=" << hintDPoint.y() << " dPoint.y()=" << dPoint.y() << endl; #endif // First test: No "hintDPoint" specified, go for the first match // Second test: hintDPoint specified, check if we are far enough if ( hintDPoint.isNull() || hintDPoint.y() <= dPoint.y() ) return theFrame; // Remember that this frame matched, in case we find no further frame that matches lastFrame = theFrame; } else if ( lastFrame ) { return lastFrame; } } // This happens when the parag is on a not-yet-created page (formatMore will notice afterwards) // So it doesn't matter much what happens here, we'll redo it anyway. #ifdef DEBUG_ITD kdDebug(32002) << "KWTextFrameSet::internalToDocumentWithHint " << iPoint.x() << "," << iPoint.y() << " not in any frame of " << (void*)this << endl; #endif dPoint = m_doc->layoutUnitPtToPt( m_doc->pixelToPt( iPoint ) ); // bah return 0L; } // relPoint is in relative coordinates (pt) KoPoint KWTextFrameSet::internalToDocumentKnowingFrame( const KoPoint &relPoint, KWFrame* theFrame ) const { // It's ok to have theFrame == 0 in the text viewmode, but not in other modes if ( m_doc->viewMode()->hasFrames() ) Q_ASSERT( theFrame ); if ( theFrame ) return KoPoint( relPoint.x() + theFrame->innerRect().x(), relPoint.y() - theFrame->internalY() + theFrame->innerRect().y() ); else return relPoint; } KoPoint KWTextFrameSet::internalToDocumentKnowingFrame( const QPoint &iPoint, KWFrame* theFrame ) const { // Convert LU to relative coordinates (pt), then call the real internalToDocumentKnowingFrame(). return internalToDocumentKnowingFrame( m_doc->layoutUnitPtToPt( m_doc->pixelToPt( iPoint ) ), theFrame ); } QPoint KWTextFrameSet::moveToPage( int currentPgNum, short int direction ) const { if ( !isVisible() || frames.isEmpty() ) return QPoint(); //kdDebug() << "KWTextFrameSet::moveToPage currentPgNum=" << currentPgNum << " direction=" << direction << endl; int num = currentPgNum + direction; int pages = m_doc->numPages(); for ( ; num >= 0 && num < pages ; num += direction ) { //kdDebug() << "KWTextFrameSet::moveToPage num=" << num << " pages=" << pages << endl; // Find the first frame on page num if ( num < m_firstPage || num >= (int)m_framesInPage.size() + m_firstPage ) continue; // No frame on that page //kdDebug() << "KWTextFrameSet::moveToPage ok for first frame in page " << num << endl; QPtrListIterator frameIt( framesInPage( num ) ); return QPoint( 0, m_doc->ptToLayoutUnitPixY( frameIt.current()->internalY() ) + 2 ); // found, ok. } // Not found. Go to top of first frame or bottom of last frame, depending on direction if ( direction < 0 ) return QPoint( 0, m_doc->ptToLayoutUnitPixY( frames.getFirst()->internalY() ) + 2 ); else { KWFrame * theFrame = frames.getLast(); return QPoint( 0, m_doc->ptToLayoutUnitPixY( theFrame->internalY() + theFrame->innerHeight() ) ); } } void KWTextFrameSet::drawContents( QPainter *p, const QRect & crect, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode ) { m_currentViewMode = viewMode; KWFrameSet::drawContents( p, crect, cg, onlyChanged, resetChanged, edit, viewMode ); // Main textframeset: draw the footnote line if there are footnotes if ( isMainFrameset() && viewMode->hasFrames() ) { // We stored the info "there's a footnote in this page" in the frame[s] // of the maintextframeset for that page. Usually one, but could be more // if there are columns. However we want to draw the line only once, so we // do it here and not in drawFrame (we'd have problems with cliprect anyway). if ( m_doc->footNoteSeparatorLineWidth() ==0.0) return; int pages = m_doc->numPages(); double left = m_doc->ptLeftBorder(); double pageWidth = m_doc->ptPaperWidth() - m_doc->ptRightBorder() - left ; double width = pageWidth * m_doc->footNoteSeparatorLineLength() / 100.0; int numColumns = m_doc->numColumns(); for ( int pageNum = 0; pageNum < pages; pageNum++ ) { //if ( viewMode->isPageVisible( pageNum ) ) { uint frameNum = pageNum * numColumns /*+ col 0 here*/; if ( frameNum < getNumFrames() ) // not true on the "endnotes-only" page { KWFrame* frame = this->frame( frameNum ); // ## or use framesInPage ? //kdDebug() << " Footnote line: page " << pageNum << " found frame " << frameNum << " drawFootNoteLine=" << frame->drawFootNoteLine() << endl; if ( frame->drawFootNoteLine() ) { double y = frame->bottomLeft().y() + m_doc->headerFooterInfo().ptFootNoteBodySpacing / 2; KoRect rect( left, y, width, 0 ); // this rect is flat switch( m_doc->footNoteSeparatorLinePosition()) { case SLP_LEFT: break; case SLP_CENTERED: rect = KoRect( pageWidth/2.0+left-width/2.0, y,width,0); break; case SLP_RIGHT: rect = KoRect( pageWidth+left-width, y,width,0); break; } QRect flatRect = viewMode->normalToView( m_doc->zoomRect( rect ) ); //kdDebug() << " KWTextFrameSet::drawContents rect=" << rect << " zoomed:" << flatRect << endl; flatRect.setBottom( flatRect.top() + 1 ); // #!@!@!& QRect.... if ( flatRect.intersects( crect ) ) { p->save(); QPen pen( KoTextFormat::defaultTextColor( p ), // always in default fg color (and black when printing) KoBorder::zoomWidthY( m_doc->footNoteSeparatorLineWidth(), m_doc, 1 ) ); // penwidth = zoomIt( 2 pt ) switch( m_doc->footNoteSeparatorLineType()) { case SLT_SOLID: pen.setStyle( SolidLine ); break; case SLT_DASH: pen.setStyle( DashLine ); break; case SLT_DOT: pen.setStyle( DotLine ); break; case SLT_DASH_DOT: pen.setStyle( DashDotLine ); break; case SLT_DASH_DOT_DOT: pen.setStyle( DashDotDotLine ); break; } p->setPen( pen ); p->drawLine( flatRect.left(), flatRect.top(), flatRect.right(), flatRect.top() ); //kdDebug() << " drawLine( " << flatRect.left() << ", " << flatRect.top() << ", " << flatRect.right() << ", " << flatRect.top() << endl; p->restore(); } } } } } } } void KWTextFrameSet::drawFrame( KWFrame *theFrame, QPainter *painter, const QRect &fcrect, const QRect &crect, const QPoint& translationOffset, KWFrame *settingsFrame, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode, bool drawUnderlyingFrames ) { // Detect if text frame needs transparency painting, to save time if it's using SolidPattern // In theory this code should be in kwFrameSet, but currently only text frames obey m_backgroundColor. if ( theFrame ) { bool transparent = theFrame->backgroundColor().style() != Qt::SolidPattern; drawUnderlyingFrames &= transparent; } KWFrameSet::drawFrame( theFrame, painter, fcrect, crect, translationOffset, settingsFrame, cg, onlyChanged, resetChanged, edit, viewMode, drawUnderlyingFrames ); } void KWTextFrameSet::drawFrameContents( KWFrame *theFrame, QPainter *painter, const QRect &r, const QColorGroup &cg, bool onlyChanged, bool resetChanged, KWFrameSetEdit *edit, KWViewMode *viewMode ) { // In this method the painter is translated to the frame's coordinate system // (in the first frame (0,0) will be its topleft, in the second frame it will be (0,internalY) etc. //kdDebug(32001) << "KWTextFrameSet::drawFrameContents " << getName() << "(frame " << frameFromPtr( theFrame ) << ") crect(r)=" << r << " onlyChanged=" << onlyChanged << endl; m_currentDrawnFrame = theFrame; if ( theFrame ) // 0L in the text viewmode { // Update variables for each frame (e.g. for page-number) // If more than KWPgNumVariable need this functionality, create an intermediary base class QPtrListIterator cit( textDocument()->allCustomItems() ); for ( ; cit.current() ; ++cit ) { KWPgNumVariable * var = dynamic_cast( cit.current() ); if ( var && !var->isDeleted() ) { QSize oldSize( var->width, var->height ); switch ( var->subType() ) { case KWPgNumVariable::VST_PGNUM_CURRENT: //kdDebug() << "KWTextFrameSet::drawFrame updating pgnum variable to " << theFrame->pageNum()+1 // << " and invalidating parag " << var->paragraph() << endl; var->setPgNum( theFrame->pageNum() + kWordDocument()->getVariableCollection()->variableSetting()->startingPage()); break; case KWPgNumVariable::VST_CURRENT_SECTION: var->setSectionTitle( kWordDocument()->sectionTitle( theFrame->pageNum() ) ); break; case KWPgNumVariable::VST_PGNUM_PREVIOUS: var->setPgNum( QMAX(theFrame->pageNum()-1,0) + kWordDocument()->getVariableCollection()->variableSetting()->startingPage()); break; case KWPgNumVariable::VST_PGNUM_NEXT: var->setPgNum( QMIN(theFrame->pageNum()+1, theFrame->pageNum()+1) + kWordDocument()->getVariableCollection()->variableSetting()->startingPage()); break; } var->resize(); QSize newSize( var->width, var->height ); if ( oldSize != newSize ) var->paragraph()->invalidate( 0 ); // size has changed -> need reformatting ! var->paragraph()->setChanged( true ); } } } // Do we draw a cursor ? bool drawCursor = edit!=0L; // Only if it will blink, i.e. not in a 'copy frame' that's not the current one if ( drawCursor && viewMode->hasFrames() && edit->currentFrame() != theFrame /*always true if currentFrame()==0 */ ) drawCursor = false; KoTextCursor * cursor = edit ? (dynamic_cast(edit) ? static_cast(edit)->cursor() : 0) : 0; uint drawingFlags = 0; if ( viewMode->drawSelections() ) drawingFlags |= KoTextDocument::DrawSelections; if ( m_doc->backgroundSpellCheckEnabled() ) drawingFlags |= KoTextDocument::DrawMisspelledLine; if ( m_doc->viewFormattingChars() ) drawingFlags |= KoTextDocument::DrawFormattingChars; //kdDebug(32001) << "KWTextFrameSet::drawFrame calling drawWYSIWYG. cg base color:" << cg.brush( QColorGroup::Base) << endl; KoTextParag * lastFormatted = textDocument()->drawWYSIWYG( painter, r.x(), r.y(), r.width(), r.height(), cg, kWordDocument(), onlyChanged, drawCursor, cursor, resetChanged, drawingFlags ); // The last paragraph of this frame might have a bit in the next frame too. // In that case, and if we're only drawing changed paragraphs, (and resetting changed), // we have to set changed to true again, to draw the bottom of the parag in the next frame. if ( onlyChanged && resetChanged ) { // Finding the "last parag of the frame" is a bit tricky. // It's usually the one before lastFormatted, except if it's actually lastParag :} [see KoTextDocument::draw] KoTextParag * lastDrawn = lastFormatted->prev(); if ( lastFormatted == textDocument()->lastParag() && ( !lastDrawn || m_doc->layoutUnitToPixelY( lastDrawn->rect().bottom() ) < r.bottom() ) ) lastDrawn = lastFormatted; //kdDebug(32002) << "KWTextFrameSet::drawFrame drawn. onlyChanged=" << onlyChanged << " resetChanged=" << resetChanged << " lastDrawn=" << lastDrawn->paragId() << " lastDrawn's bottom:" << lastDrawn->rect().bottom() << " r.bottom=" << r.bottom() << endl; if ( lastDrawn && m_doc->layoutUnitToPixelY( lastDrawn->rect().bottom() ) > r.bottom() ) { //kdDebug(32002) << "KWTextFrameSet::drawFrame setting lastDrawn " << lastDrawn->paragId() << " to changed" << endl; lastDrawn->setChanged( true ); } } // NOTE: QTextView sets m_lastFormatted to lastFormatted here // But when scrolling up, this causes to reformat a lot of stuff for nothing. // And updateViewArea takes care of formatting things before we even arrive here. // Blank area under the very last paragraph - QRT draws it up to textdoc->height, // we have to draw it from there up to the bottom of the last frame. if ( ( !lastFormatted || lastFormatted == textDocument()->lastParag() ) ) { // This is drawing code, so we convert everything to pixels int docHeight = textDocument()->lastParag()->pixelRect(m_doc).bottom() + 1; //QRect frameRect = m_doc->zoomRect( (theFrame->innerRect()) ); QSize availSize = viewMode->availableSizeForText( this ); QRect blank( 0, docHeight, availSize.width(), availSize.height() /*+ frameRect.height() ?? */ - docHeight ); //kdDebug(32002) << this << " Blank area: " << blank << endl; painter->fillRect( blank, cg.brush( QColorGroup::Base ) ); // for debugging :) //painter->setPen( QPen(Qt::blue, 1, DashLine) ); painter->drawRect( blank ); } m_currentDrawnFrame = 0L; } void KWTextFrameSet::drawCursor( QPainter *p, KoTextCursor *cursor, bool cursorVisible, KWCanvas *canvas, KWFrame *theFrame ) { // This redraws the paragraph where the cursor is - with a small clip region around the cursor KWViewMode *viewMode = canvas->viewMode(); bool hasFrames = viewMode->hasFrames(); m_currentViewMode = viewMode; m_currentDrawnFrame = theFrame; QRect normalFrameRect; if (hasFrames) normalFrameRect = m_doc->zoomRect( theFrame->innerRect() ); else normalFrameRect = QRect( QPoint(0, 0), viewMode->contentsSize() ); KoTextParag* parag = cursor->parag(); QPoint topLeft = parag->rect().topLeft(); // in QRT coords int lineY; // Cursor height, in pixels int cursorHeight = m_doc->layoutUnitToPixelY( topLeft.y(), parag->lineHeightOfChar( cursor->index(), 0, &lineY ) ); QPoint iPoint( topLeft.x() + cursor->x(), topLeft.y() + lineY ); #ifdef DEBUG_CURSOR kdDebug() << "KWTextFrameSet::drawCursor topLeft=" << topLeft.x() << "," << topLeft.y() << " x=" << cursor->x() << " y=" << lineY << endl; kdDebug() << "KWTextFrameSet::drawCursor iPoint=" << iPoint.x() << "," << iPoint.y() << " cursorHeight=" << cursorHeight << endl; #endif KoPoint dPoint; KoPoint hintDPoint = theFrame ? theFrame->innerRect().topLeft() : KoPoint(); if ( internalToDocumentWithHint( iPoint, dPoint, hintDPoint ) ) { #ifdef DEBUG_CURSOR kdDebug() << " dPoint(doc, pts)=" << dPoint.x() << "," << dPoint.y() << endl; QPoint debugPt = m_doc->zoomPoint( dPoint ); kdDebug() << " zoomed dPoint(doc, pixels)=" << debugPt.x() << "," << debugPt.y() << endl; #endif QPoint vPoint = viewMode->normalToView( m_doc->zoomPoint( dPoint ) ); // from doc to view contents #ifdef DEBUG_CURSOR kdDebug() << " vPoint(view, pixels)=" << vPoint.x() << "," << vPoint.y() << endl; #endif // from now on, iPoint will be in pixels iPoint = m_doc->layoutUnitToPixel( iPoint ); //int xadj = parag->at( cursor->index() )->pixelxadj; #ifdef DEBUG_CURSOR //kdDebug() << " iPoint in pixels : " << iPoint.x() << "," << iPoint.y() << " will add xadj=" << xadj << endl; #endif //iPoint.rx() += xadj; //vPoint.rx() += xadj; // very small clipping around the cursor QRect clip( vPoint.x() - 5, vPoint.y(), 10, cursorHeight ); #ifdef DEBUG_CURSOR kdDebug() << " clip(view, before intersect)=" << clip << endl; #endif QRect viewFrameRect = viewMode->normalToView( normalFrameRect ); clip &= viewFrameRect; // clip to frame #ifdef DEBUG_CURSOR kdDebug() << "KWTextFrameSet::drawCursor normalFrameRect=" << normalFrameRect << " clip(view, after intersect)=" << clip << endl; #endif QRegion reg; if ( hasFrames ) { reg = frameClipRegion( p, theFrame, clip, viewMode ); if ( !isFloating() ) // problem with multiparent inline frames reg &= p->xForm( viewFrameRect ); } if ( !hasFrames || !reg.isEmpty() ) { #ifdef DEBUG_CURSOR // for debug only! //p->fillRect( clip, QBrush( Qt::red, QBrush::Dense3Pattern ) ); #endif p->save(); QColorGroup cg = QApplication::palette().active(); if ( hasFrames ) { p->setClipRegion( reg ); // translate to qrt coords - after setting the clip region ! // see internalToDocumentWithHint int translationX = viewFrameRect.left(); int translationY = viewFrameRect.top() - m_doc->zoomItY( theFrame->internalY() ); #ifdef DEBUG_CURSOR kdDebug() << " translating Y by viewFrameRect.top()-internalY in pixelY= " << viewFrameRect.top() << "-" << m_doc->zoomItY( theFrame->internalY() ) << "=" << viewFrameRect.top() - m_doc->zoomItY( theFrame->internalY() ) << endl; #endif p->translate( translationX, translationY ); p->setBrushOrigin( p->brushOrigin().x() + translationX, p->brushOrigin().y() + translationY ); // The settings come from this frame KWFrame * settings = settingsFrame( theFrame ); QBrush bgBrush( settings->backgroundColor() ); bgBrush.setColor( KWDocument::resolveBgColor( bgBrush.color(), p ) ); cg.setBrush( QColorGroup::Base, bgBrush ); } QPixmap *pix = 0; uint drawingFlags = KoTextDocument::DrawSelections; if ( m_doc->backgroundSpellCheckEnabled() ) drawingFlags |= KoTextDocument::DrawMisspelledLine; if ( m_doc->viewFormattingChars() ) drawingFlags |= KoTextDocument::DrawFormattingChars; // To force the drawing to happen: bool wasChanged = parag->hasChanged(); int oldLineChanged = parag->lineChanged(); int line; // line number parag->lineStartOfChar( cursor->index(), 0, &line ); parag->setChanged( false ); // not all changed, only from a given line parag->setLineChanged( line ); textDocument()->drawParagWYSIWYG( p, parag, QMAX(0, iPoint.x() - 5), // negative values create problems iPoint.y(), clip.width(), clip.height(), pix, cg, m_doc, // TODO view's zoom handler cursorVisible, cursor, FALSE /*resetChanged*/, drawingFlags ); if ( wasChanged ) // Maybe we have more changes to draw, than those in the small cliprect parag->setLineChanged( oldLineChanged ); // -1 = all else parag->setChanged( false ); p->restore(); //XIM Position QPoint ximPoint = vPoint; canvas->setXimPosition( ximPoint.x(), ximPoint.y(), 0, cursorHeight - parag->lineSpacing( line ) ); } } m_currentDrawnFrame = 0L; } void KWTextFrameSet::layout() { invalidate(); // Get the thing going though, repainting doesn't call formatMore m_textobj->formatMore( 2 ); } void KWTextFrameSet::invalidate() { //kdDebug() << "KWTextFrameSet::invalidate " << getName() << endl; m_textobj->setLastFormattedParag( textDocument()->firstParag() ); textDocument()->invalidate(); // lazy layout, real update follows upon next repaint } void KWTextFrameSet::slotRepaintChanged() { emit repaintChanged( this ); } int KWTextFrameSet::paragraphs() { int paragraphs = 0; KoTextParag * parag = textDocument()->firstParag(); for ( ; parag ; parag = parag->next() ) paragraphs++; return paragraphs; } int KWTextFrameSet::paragraphsSelected() { int paragraphs = 0; KoTextParag *parag = textDocument()->firstParag(); for ( ; parag ; parag = parag->next() ) { if ( parag->hasSelection( KoTextDocument::Standard ) ) paragraphs++; } return paragraphs; } bool KWTextFrameSet::statistics( QProgressDialog *progress, ulong & charsWithSpace, ulong & charsWithoutSpace, ulong & words, ulong & sentences, ulong & syllables, ulong & lines, bool selected ) { return m_textobj->statistics( progress, charsWithSpace, charsWithoutSpace, words, sentences, syllables, lines, selected ); } // Only interested in the body textframeset, not in header/footer #define kdDebugBody(area) if ( frameSetInfo() == FI_BODY ) kdDebug(area) // Helper for adjust*. There are 3 ways to use this method. // 1) marginLeft and marginRight set -> determination of left and right margins for adjustMargins // 2) marginRight set -> determination of right margin for adjustRMargin // 3) breakBegin, breakEnd set -> check whether we should jump over some frames // [when there is not enough space besides them] // reqMinWidth is the width that the formatter wants to use (current char/item) // validHeight is set to the height where marginLeft/marginRight applies (TODO) void KWTextFrameSet::getMargins( int yp, int h, int reqMinWidth, int* marginLeft, int* marginRight, int* pageWidth, int* validHeight, int* breakBegin, int* breakEnd, KoTextParag* parag ) { // paragLeftMargin will be used as the minimum width needed for the parag, // to "see" the parag. // So we only apply the first line margin if it increases that width, i.e. if > 0. // Otherwise only the first line might be visible, in a narrow passage. int paragLeftMargin = parag ? parag->leftMargin() : 0; if ( parag && !parag->string()->isRightToLeft() && parag->firstLineMargin() > 0 ) paragLeftMargin += parag->firstLineMargin(); #ifdef DEBUG_MARGINS kdDebugBody(32002) << " KWTextFrameSet " << this << "(" << getName() << ") getMargins yp=" << yp << " h=" << h << " called by " << (marginLeft && marginRight ? "adjustMargins" : "formatVertically") << " paragLeftMargin=" << paragLeftMargin << endl; // Both or none... if (breakBegin) assert(breakEnd); if (breakEnd) assert(breakBegin); // Idem if ( marginLeft ) { assert( marginRight ); assert( pageWidth ); } #endif KoPoint pt; // The +h in here is a hack, for the case where this line is going to // be moved down by formatVertically. We anticipate, and look at the bottom of the // line rather than the top of it, in order to find the bottom frame (the one // in which we'll end up). See TODO file for a real solution. // ## This hack breaks layouting of a big char in two connected frames where // the first one is very small (we don't notice the width being too small) int yUsedForFrame = yp + h; // Workaround: look at bottom in adjustMargins, look at top in formatVertically if ( breakBegin ) yUsedForFrame = yp; KWFrame * theFrame = internalToDocument( QPoint(0, yUsedForFrame), pt ); if (!theFrame) { #ifdef DEBUG_MARGINS kdDebug(32002) << " getMargins: internalToDocument returned frame=0L for y=" << yUsedForFrame << " ->aborting with 0 margins" << endl; #endif // frame == 0 happens when the parag is under the last frame. // On an auto-resizable frame, we know the frame will grow so we can go ahead // and use its width. if ( !frames.isEmpty() && frames.last()->frameBehavior() == KWFrame::AutoExtendFrame ) { theFrame = frames.last(); } else { // On auto-create-new-frame, this means the parag is on a not-yet-created page // (formatMore will notice afterwards) // Abort then, no need to return precise values // We also abort in the third case (Ignore) if ( validHeight ) *validHeight = 0; return; } } #ifdef DEBUG_MARGINS else kdDebugBody(32002) << " getMargins: internalToDocument returned frame=" << *theFrame << " and pt=" << pt.x() << "," << pt.y() << endl; #endif if ( validHeight ) *validHeight = h; // TODO // Everything from there is in layout units // Note: it is very important that this method works in internal coordinates. // Otherwise, parags broken at the line-level (e.g. between two columns) are seen // as still in one piece, and we miss the frames in the 2nd column. int from = 0; int to = m_doc->ptToLayoutUnitPixX( theFrame->innerWidth() ); if ( pageWidth ) *pageWidth = to; bool init = false; #ifdef DEBUG_MARGINS kdDebugBody(32002) << " getMargins: looking for frames between " << yp << " and " << yp+h << " (internal coords)" << endl; #endif if ( m_doc->viewMode()->shouldAdjustMargins() ) { // Principle: for every frame on top at this height, we'll move from and to // towards each other. The text flows between 'from' and 'to' QPtrListIterator fIt( theFrame->framesOnTop() ); for ( ; fIt.current() && from < to ; ++fIt ) { if ( (*fIt)->runAround() == KWFrame::RA_BOUNDINGRECT ) { KoRect rectOnTop = theFrame->intersect( (*fIt)->runAroundRect() ); #ifdef DEBUG_MARGINS kdDebugBody(32002) << " getMargins found rect-on-top at (normal coords) " << rectOnTop << endl; #endif QPoint iTop, iBottom; // top and bottom of intersection in internal coordinates if ( documentToInternal( rectOnTop.topLeft(), iTop ) && iTop.y() <= yp + h && // optimization documentToInternal( rectOnTop.bottomRight(), iBottom ) ) { #ifdef DEBUG_MARGINS kdDebugBody(32002) << " in internal coords: " << QRect(iTop,iBottom) << endl; #endif // Look for intersection between yp -- yp+h and iTop -- iBottom if ( QMAX( yp, iTop.y() ) <= QMIN( yp+h, iBottom.y() ) ) { #ifdef DEBUG_MARGINS kdDebugBody(32002) << " getMargins iTop=" << iTop.x() << "," << iTop.y() << " iBottom=" << iBottom.x() << "," << iBottom.y() << endl; #endif int availLeft = QMAX( 0, iTop.x() - from ); int availRight = QMAX( 0, to - iBottom.x() ); #ifdef DEBUG_MARGINS kdDebugBody(32002) << " getMargins availLeft=" << availLeft << " availRight=" << availRight << endl; #endif bool chooseLeft = false; switch ( (*fIt)->runAroundSide() ) { case KWFrame::RA_LEFT: chooseLeft = true; break; case KWFrame::RA_RIGHT: break; // chooseLeft remains false case KWFrame::RA_BIGGEST: chooseLeft = ( availLeft > availRight ); // choose the max }; if ( chooseLeft ) // flow text at the left of the frame to = QMIN( to, from + availLeft - 1 ); // can only go left -> QMIN else // flow text at the right of the frame from = QMAX( from, to - availRight + 1 ); // can only go right -> QMAX #ifdef DEBUG_MARGINS kdDebugBody(32002) << " getMargins from=" << from << " to=" << to << endl; #endif // If the available space is too small, give up on it if ( to - from < reqMinWidth + paragLeftMargin ) { #ifdef DEBUG_MARGINS kdDebugBody(32002) << " smaller than minimum=" << m_doc->ptToLayoutUnitPixX( 15 ) + paragLeftMargin << endl; #endif from = to; } if ( breakEnd && from == to ) // no-space case { if ( !init ) // first time { init = true; *breakBegin = iTop.y(); *breakEnd = iBottom.y(); } else { *breakBegin = QMIN( *breakBegin, iTop.y() ); *breakEnd = QMAX( *breakEnd, iBottom.y() ); } #ifdef DEBUG_MARGINS kdDebugBody(32002) << " getMargins iBottom.y=" << iBottom.y() << " breakBegin=" << *breakBegin << " breakEnd=" << *breakEnd << endl; #endif } } // else no intersection }// else we got a 0L, or the iTop.y()<=yp+h test didn't work - wrong debug output // kdDebugBody(32002) << " gerMargins: normalToInternal returned 0L" << endl; } } } if ( marginLeft /*&& marginRight && pageWidth -- implicit*/ ) { #ifdef DEBUG_MARGINS kdDebugBody(32002) << " getMargins done. from=" << from << " to=" << to << endl; #endif if ( from == to ) { from = 0; to = *pageWidth; } if ( marginLeft ) *marginLeft += from; if ( marginRight ) { #ifdef DEBUG_MARGINS kdDebug(32002) << " getMargins " << getName() << " page width=" << *pageWidth << " to=" << to << endl; #endif *marginRight += *pageWidth - to; } } } void KWTextFrameSet::adjustMargins( int yp, int h, int reqMinWidth, int& leftMargin, int& rightMargin, int& pageWidth, KoTextParag* parag ) { int validHeight; // currently ignored (TODO) getMargins( yp, h, reqMinWidth, &leftMargin, &rightMargin, &pageWidth, &validHeight, 0L, 0L, parag ); #ifdef DEBUG_MARGINS kdDebugBody(32002) << "KWTextFrameSet::adjustMargins(yp=" << yp << " h=" << h << " reqMinWidth=" << reqMinWidth << " returning" << " leftMargin=" << leftMargin << " rightMargin=" << rightMargin << " valid from " << yp << " to " << yp+validHeight << endl; #endif } // helper for formatVertically bool KWTextFrameSet::checkVerticalBreak( int & yp, int & hp, KoTextParag * parag, bool linesTogether, int breakBegin, int breakEnd ) { // We need the "+1" here because when skipping a frame on top, we want to be _under_ // its bottom. Without the +1, we hit the frame again on the next adjustLMargin call. // Check for intersection between the parag (yp -- yp+hp) and the break area (breakBegin -- breakEnd) if ( QMAX( yp, breakBegin ) <= QMIN( yp+hp, breakEnd ) ) { if ( !parag || linesTogether ) // Paragraph-level breaking { #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << "checkVerticalBreak ADJUSTING yp=" << yp << " hp=" << hp << " breakEnd+2 [new value for yp]=" << breakEnd+2 << endl; #endif yp = breakEnd + 1; return true; } else // Line-level breaking { QMap& lineStarts = parag->lineStartList(); #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << "checkVerticalBreak parag " << parag->paragId() << ". lineStarts has " << lineStarts.count() << " items" << endl; #endif int dy = 0; int line = 0; QMap::Iterator it = lineStarts.begin(); for ( ; it != lineStarts.end() ; ++it, ++line ) { KoTextParagLineStart * ls = it.data(); Q_ASSERT( ls ); int y = parag->rect().y() + ls->y; #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << "checkVerticalBreak parag " << parag->paragId() << " line " << line << " ls->y=" << ls->y << " ls->h=" << ls->h << " y=" << y << " breakBegin=" << breakBegin << " breakEnd=" << breakEnd << endl; #endif if ( !dy ) { if ( QMAX( y, breakBegin ) <= QMIN( y + ls->h, breakEnd ) ) { if ( line == 0 ) // First line ? It's like a paragraph breaking then { #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << "checkVerticalBreak parag " << parag->paragId() << " BREAKING first line -> parag break" << endl; #endif yp = breakEnd + 1; return true; } dy = breakEnd + 1 - y; ls->y = breakEnd + 1 - parag->rect().y(); #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << "checkVerticalBreak parag " << parag->paragId() << " BREAKING at line " << line << " dy=" << dy << " Setting ls->y to " << ls->y << ", y=" << breakEnd << endl; #endif } } else { ls->y += dy; #ifdef DEBUG_FORMATVERTICALLY if ( dy ) kdDebug(32002) << " moving down to position ls->y=" << ls->y << endl; #endif } } parag->setMovedDown( true ); parag->setHeight( hp + dy ); #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << "Paragraph height set to " << hp+dy << endl; #endif hp += dy; return true; } // End of line-level breaking } return false; } int KWTextFrameSet::formatVertically( KoTextParag * _parag, const QRect& paragRect ) { // WARNING: in this whole method parag can be 0. See adjustFlow() KWTextParag *parag = static_cast( _parag ); if ( !m_doc->viewMode()->shouldFormatVertically() ) { return 0; } int yp = paragRect.y(); int hp = paragRect.height(); int oldHeight = hp; int oldY = yp; // This is called by KoTextFormatter to apply "vertical breaks". // End of frames/pages lead to those "vertical breaks". // What we do, is adjust the Y accordingly, // to implement page-break at the paragraph level and at the line level. // It's cumulative (the space of one break will be included in the further // paragraph's y position), which makes it easy to implement. // But don't forget that formatVertically is called twice for every parag, since the formatting // is re-done after moving down. bool linesTogether = parag ? parag->linesTogether() : true; bool hardFrameBreak = parag ? parag->hardFrameBreakBefore() : false; if ( !hardFrameBreak && parag && parag->prev() ) hardFrameBreak = static_cast(parag->prev())->hardFrameBreakAfter(); #ifdef DEBUG_FORMATVERTICALLY kdDebugBody(32002) << "KWTextFrameSet::formatVertically parag=" << parag << " linesTogether=" << linesTogether << " hardFrameBreak=" << hardFrameBreak << " yp=" << yp << " hp=" << hp << endl; #endif int totalHeight = 0; QPtrListIterator frameIt( frameIterator() ); for ( ; frameIt.current(); ++frameIt ) { int frameHeight = kWordDocument()->ptToLayoutUnitPixY( frameIt.current()->innerHeight() ); int bottom = totalHeight + frameHeight; // Only skip bottom of frame if there is a next one or if there'll be another one created. // ( Not for header/footer, for instance. ) bool check = frameIt.atLast() && frameIt.current()->frameBehavior() == KWFrame::AutoCreateNewFrame; if ( !check ) { // ## TODO optimize this [maybe we should simply start from the end in the main loop?] // Or cache the attribute ( e.g. "frame->hasCopy()" ). QPtrListIterator nextFrame( frameIt ); while ( !check && !nextFrame.atLast() ) { ++nextFrame; if ( !nextFrame.current()->isCopy() ) check = true; // Found a frame after us that isn't a copy => we have somewhere for our overflow } } if ( check ) { if ( hardFrameBreak && yp > totalHeight && yp < bottom && !parag->wasMovedDown() ) { // The paragraph wants a frame break before it, and is in the current frame // The last check is for whether we did the frame break already // (formatVertically is called twice for each paragraph, if a break was done) yp = bottom /*+ 2*/; #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << "KWTextFrameSet::formatVertically -> HARD FRAME BREAK" << endl; kdDebug(32002) << "KWTextFrameSet::formatVertically yp now " << yp << endl; #endif break; } #ifdef DEBUG_FORMATVERTICALLY kdDebug(32002) << " formatVertically: frameHeight=" << frameHeight << " bottom=" << bottom << endl; #endif // don't move down parags that have only one line and are bigger than the page (e.g. floating tables) if ( hp < frameHeight || ( parag && parag->lineStartList().count() > 1 ) ) { // breakBegin==breakEnd==bottom, since the next frame's top is the same as bottom, in QRT coords. (void) checkVerticalBreak( yp, hp, parag, linesTogether, bottom, bottom ); // Some people write a single paragraph over 3 frames! So we have to keep looking, that's why we ignore the return value } } if ( yp+hp < bottom ) break; // we've been past the parag, so stop here totalHeight = bottom; } // Another case for a vertical break is frames with the RA_SKIP flag // Currently looking at all frames on top of all of our frames... maybe optimize better frameIt.toFirst(); for ( ; frameIt.current(); ++frameIt ) { QPtrListIterator fIt( frameIt.current()->framesOnTop() ); for ( ; fIt.current() ; ++fIt ) { if ( (*fIt)->runAround() == KWFrame::RA_SKIP ) { KoRect rectOnTop = frameIt.current()->intersect( (*fIt)->runAroundRect() ); QPoint iTop, iBottom; // top and bottom in internal coordinates if ( documentToInternal( rectOnTop.topLeft(), iTop ) && iTop.y() <= yp + hp && documentToInternal( rectOnTop.bottomLeft(), iBottom ) && checkVerticalBreak( yp, hp, parag, linesTogether, iTop.y(), iBottom.y() ) ) { kdDebug(32002) << "KWTextFrameSet::formatVertically breaking around RA_SKIP frame yp="<string()->at( 0 ).width : 0; getMargins( yp, hp, reqMinWidth, 0L, 0L, 0L, 0L, &breakBegin, &breakEnd, parag ); if ( breakEnd ) { kdDebug(32002) << "KWTextFrameSet("<setHeight( hp ); if ( yp != oldY ) { QRect r = parag->rect(); r.moveBy( 0, yp - oldY ); parag->setRect( r ); parag->setMovedDown( true ); } } #ifdef DEBUG_FORMATVERTICALLY kdDebug() << "KWTextFrameSet::formatVertically returning " << ( yp + hp ) - ( oldY + oldHeight ) << endl; #endif return ( yp + hp ) - ( oldY + oldHeight ); } // adjustFlow is called e.g. to break the "top margin" of a paragraph. // There is no parag pointer in that case. int KWTextFrameSet::adjustFlow( int y, int w, int h ) { QRect r( 0, y, w, h ); return formatVertically( 0L, r ); } void KWTextFrameSet::fixParagWidth( KWTextParag* parag ) { // Fixing the parag rect for the formatting chars (CR and frame break). if ( parag && m_doc->viewFormattingChars() && parag->rect().width() < textDocument()->width() ) { if ( parag->hardFrameBreakAfter() ) { KoTextFormat * lastFormat = parag->at( parag->length() - 1 )->format(); const QFontMetrics& refFontMetrics = lastFormat->refFontMetrics(); // keep in sync with KWTextFrameSet::formatVertically QString str = i18n( "--- Frame Break ---" ); int width = refFontMetrics.width( str ); parag->setWidth( QMIN( parag->rect().width() + width, textDocument()->width() ) ); } else // default KoTextFormatter implementation parag->fixParagWidth( true ); } } KWTextFrameSet::~KWTextFrameSet() { textDocument()->takeFlow(); //kdDebug(32001) << "KWTextFrameSet::~KWTextFrameSet" << endl; m_doc = 0L; delete m_textobj; } // This struct is used for sorting frames. // Since pages are one below the other, simply sorting on (y, x) does what we want. struct FrameStruct { KWFrame * frame; bool operator < ( const FrameStruct & t ) const { return compare(frame, t.frame) < 0; } bool operator <= ( const FrameStruct & t ) const { return compare(frame, t.frame) <= 0; } bool operator > ( const FrameStruct & t ) const { return compare(frame, t.frame) > 0; } /* the sorting of all frames in the same frameset is done as all sorting based on a simple frameOne > frameTwo question. Frame frameOne is greater then frameTwo if the center point lies more down then (the whole of) frame frameTwo. When they are equal, the X position is considered. */ int compare (const KWFrame *frameOne, const KWFrame *frameTwo) const { // The first criteria is the page number though! int pageOne = frameOne->pageNum(); int pageTwo = frameTwo->pageNum(); if ( pageOne > pageTwo ) return 4; // frameOne > frameTwo if ( pageOne < pageTwo ) return -4; // frameOne < frameTwo double centerX = frameOne->left() + (frameOne->width() /2); // reverse the return values of the next two for RTL if ( centerX > frameTwo->right()) return 3; // frameOne > frameTwo if ( centerX < frameTwo->left()) return -3; // frameOne < frameTwo // check the Y position. Y is greater only when it is below the other frame. double centerY = frameOne->top() + (frameOne->height() /2); if ( centerY > frameTwo->bottom() ) return 2; // frameOne > frameTwo if ( centerY < frameTwo->top() ) return -2; // frameOne < frameTwo // the center of frameOne lies inside frameTwo. Lets check the topleft pos. if (frameOne->top() > frameTwo->top()) return 1; return -1; } }; void KWTextFrameSet::updateFrames( int flags ) { // Not visible ? Don't bother then. if ( !isVisible() ) { //kdDebug(32002) << "KWTextFrameSet::updateFrames " << getName() << " not visible" << endl; m_textobj->setVisible(false); return; } m_textobj->setVisible(true); //kdDebug(32002) << "KWTextFrameSet::updateFrames " << getName() << " frame-count=" << frames.count() << endl; // Sort frames of this frameset on (y coord, x coord) // Adjustment on 20-Jun-2002 which does not change the itent of this but moves the // sorting from top-left of frame to the whole frame area. (TZ) QValueList sortedFrames; int width = 0; QPtrListIterator frameIter( frameIterator() ); for ( ; frameIter.current(); ++frameIter ) { // Calculate max width while we're at it //kdDebug(32002) << "KWTextFrameSet::updateFrames frame " << *frameIter.current() << " innerWidth=" << frameIter.current()->innerWidth() << "pt" << endl; width = QMAX( width, m_doc->ptToLayoutUnitPixX( frameIter.current()->innerWidth())); if ( flags & SortFrames ) { FrameStruct str; str.frame = frameIter.current(); sortedFrames.append( str ); } } if ( width != textDocument()->width() ) { //kdDebug(32002) << "KWTextFrameSet::updateFrames setWidth " << width << " LU pixels." << endl; //textDocument()->setMinimumWidth( -1, 0 ); textDocument()->setWidth( width + 1 ); // QRect semantics problem (#32866) } //else kdDebug(32002) << "KWTextFrameSet::updateFrames width already " << width << " LU pixels." << endl; if ( flags & SortFrames ) { qHeapSort( sortedFrames ); // Re-fill the frames list with the frames in the right order frames.setAutoDelete( false ); frames.clear(); QValueList::Iterator it = sortedFrames.begin(); for ( ; it != sortedFrames.end() ; ++it ) frames.append( (*it).frame ); } double availHeight = 0; double internalYpt = 0; double lastRealFrameHeight = 0; bool firstFrame = true; QPtrListIterator frameIt( frames ); for ( ; frameIt.current(); ++frameIt ) { KWFrame* theFrame = frameIt.current(); if ( !theFrame->isCopy() ) internalYpt += lastRealFrameHeight; theFrame->setInternalY( internalYpt ); // Update availHeight with the internal height of this frame - unless it's a copy if ( !theFrame->isCopy() || firstFrame ) { lastRealFrameHeight = theFrame->innerHeight(); availHeight += lastRealFrameHeight; } firstFrame = false; } m_textobj->setAvailableHeight( m_doc->ptToLayoutUnitPixY( availHeight ) ); //kdDebug(32002) << this << " (" << getName() << ") KWTextFrameSet::updateFrames availHeight=" << availHeight // << " (LU: " << m_doc->ptToLayoutUnitPixY( availHeight ) << ")" << endl; frames.setAutoDelete( true ); KWFrameSet::updateFrames( flags ); } int KWTextFrameSet::availableHeight() const { return m_textobj->availableHeight(); } KWFrame * KWTextFrameSet::internalToDocument( const KoPoint &relPoint, KoPoint &dPoint ) const { #ifdef DEBUG_ITD kdDebug() << getName() << " ITD called for relPoint=" << relPoint.x() << "," << relPoint.y() << endl; #endif if ( !m_doc->viewMode()->hasFrames() ) { // text viewmode dPoint = relPoint; return frames.getFirst(); } // This does a binary search in the m_framesInPage array, with internalY as criteria // We only look at the first frame of each page. Refining is done later on. Q_ASSERT( !m_framesInPage.isEmpty() ); int len = m_framesInPage.count(); int n1 = 0; int n2 = len - 1; double internalY = 0.0; int mid = 0; bool found = FALSE; while ( n1 <= n2 ) { double res; mid = (n1 + n2)/2; #ifdef DEBUG_ITD kdDebug() << "ITD: begin. mid=" << mid << endl; #endif Q_ASSERT( m_framesInPage[mid] ); // We have no null items if ( m_framesInPage[mid]->isEmpty() ) res = -1; else { KWFrame * theFrame = m_framesInPage[mid]->first(); internalY = theFrame->internalY(); #ifdef DEBUG_ITD kdDebug() << "ITD: relPoint.y=" << relPoint.y() << " internalY=" << internalY << endl; #endif res = relPoint.y() - internalY; #ifdef DEBUG_ITD kdDebug() << "ITD: res=" << res << endl; #endif // Anything between this internalY (top) and internalY+height (bottom) is fine // (Using the next page's first frame's internalY only works if there is a frame on the next page) if ( res >= 0 ) { double height = theFrame->innerHeight(); #ifdef DEBUG_ITD kdDebug() << "ITD: height=" << height << " -> the bottom is at " << internalY+height << endl; #endif if ( relPoint.y() < internalY + height ) { #ifdef DEBUG_ITD kdDebug() << "ITD: found a match " << mid << endl; #endif found = true; break; } } } // res == 0 can't happen in theory, but in practice it happens when a frame has a height of 0 // (e.g. newly imported table without correct row heights) if ( res < 0 ) n2 = mid - 1; else // if ( res >= 0 ) n1 = mid + 1; #ifdef DEBUG_ITD kdDebug() << "ITD: End of loop. n1=" << n1 << " n2=" << n2 << endl; #endif } if ( !found ) { // Not found (n2 < n1) // We might have missed the frame because n2 has many frames // (and we only looked at the first one). mid = n2; #ifdef DEBUG_ITD kdDebug() << "ITD: Setting mid to n2=" << mid << endl; #endif if ( mid < 0 ) { #ifdef DEBUG_ITD kdDebug(32002) << "KWTextFrameSet::internalToDocument " << relPoint.x() << "," << relPoint.y() << " before any frame of " << (void*)this << endl; #endif dPoint = relPoint; // "bah", I said above :) return 0L; } } // search to first of equal items // This happens with copied frames, which have the same internalY int result = mid; while ( mid - 1 >= 0 ) { mid--; if ( !m_framesInPage[mid]->isEmpty() ) { KWFrame * theFrame = m_framesInPage[mid]->first(); #ifdef DEBUG_ITD kdDebug() << "KWTextFrameSet::internalToDocument going back to page " << mid << " - frame: " << theFrame->internalY() << endl; #endif if ( theFrame->internalY() == internalY ) // same internalY as the frame we found before result = mid; else break; } } // Now iterate over the frames in page 'result' and find the right one QPtrListIterator frameIt( *m_framesInPage[result] ); for ( ; frameIt.current(); ++frameIt ) { KWFrame *theFrame = frameIt.current(); KoRect relRect( 0, theFrame->internalY(), theFrame->innerWidth(), theFrame->innerHeight() ); #ifdef DEBUG_ITD kdDebug() << "KWTextFrameSet::internalToDocument frame's relative rect:" << relRect << endl; #endif if ( relRect.contains( relPoint ) ) // both relRect and relPoint are in "relative coordinates" { dPoint = internalToDocumentKnowingFrame( relPoint, theFrame ); return theFrame; } } #ifdef DEBUG_ITD kdDebug(32002) << "KWTextFrameSet::internalToDocument " << relPoint.x() << "," << relPoint.y() << " not in any frame of " << (void*)this << " (looked on page " << result << ")" << endl; #endif dPoint = relPoint; // bah again return 0L; } // same but with iPoint in LU KWFrame * KWTextFrameSet::internalToDocument( const QPoint &iPoint, KoPoint &dPoint ) const { KoPoint relPoint = m_doc->layoutUnitPtToPt( m_doc->pixelToPt( iPoint ) ); return internalToDocument( relPoint, dPoint ); } #ifndef NDEBUG void KWTextFrameSet::printDebug() { KWFrameSet::printDebug(); if ( !isDeleted() ) { kdDebug() << "KoTextDocument width = " << textDocument()->width() << " height = " << textDocument()->height() << endl; } QPtrListIterator cit( textDocument()->allCustomItems() ); for ( ; cit.current() ; ++cit ) { KWAnchor *anc = dynamic_cast( cit.current() ); if (anc) kdDebug() << "Inline framesets: " << anc->frameSet()->getName() << endl; } } #endif QDomElement KWTextFrameSet::saveInternal( QDomElement &parentElem, bool saveFrames, bool saveAnchorsFramesets ) { if ( frames.isEmpty() ) // Deleted frameset -> don't save return QDomElement(); QDomElement framesetElem = parentElem.ownerDocument().createElement( "FRAMESET" ); parentElem.appendChild( framesetElem ); if ( grpMgr ) { framesetElem.setAttribute( "grpMgr", grpMgr->getName() ); KWTableFrameSet::Cell *cell = (KWTableFrameSet::Cell *)this; framesetElem.setAttribute( "row", cell->firstRow() ); framesetElem.setAttribute( "col", cell->firstCol() ); framesetElem.setAttribute( "rows", cell->rowSpan() ); framesetElem.setAttribute( "cols", cell->colSpan() ); framesetElem.setAttribute( "removable", static_cast( m_removeableHeader ) ); } if ( protectContent() ) framesetElem.setAttribute( "protectContent", static_cast(protectContent())); KWFrameSet::saveCommon( framesetElem, saveFrames ); // Save paragraphs KWTextParag *start = static_cast( textDocument()->firstParag() ); while ( start ) { start->save( framesetElem, saveAnchorsFramesets ); start = static_cast( start->next() ); } return framesetElem; } KWFrame* KWTextFrameSet::loadOasisTextBox( const QDomElement& frameTag, const QDomElement& tag, KoOasisContext& context ) { // Text frame chains. When seeing frame 'B' is chained to this frame A when loading, // we store 'B' -> A, so that when loading B we can add it to A's frameset. // If we load B first, no problem: when loading A we can chain. // This is all made simpler by the fact that we don't have manually configurable order in KWord... // But it's made more complex by the fact that frames don't have names in KWord (framesets do). // Hence the framename temporary storage in KWLoadingInfo KWTextFrameSet* fs = 0; QString frameName = frameTag.attributeNS( KoXmlNS::draw, "name", QString::null ); QString chainNextName = tag.attributeNS( KoXmlNS::draw, "chain-next-name", QString::null ); if ( !chainNextName.isEmpty() ) { // 'B' in the above example kdDebug(32001) << "Loading " << frameName << " : next-in-chain=" << chainNextName << endl; // Check if we already loaded that frame (then we need to go 'before' it) KWFrame* nextFrame = m_doc->loadingInfo()->frameByName( chainNextName ); if ( nextFrame ) { fs = dynamic_cast( nextFrame->frameSet() ); chainNextName = QString::null; // already found, no need to store it kdDebug(32001) << " found " << nextFrame << " -> frameset " << ( fs ? fs->getName() : QString::null ) << endl; } } KWFrame* prevFrame = m_doc->loadingInfo()->chainPrevFrame( frameName ); //kdDebug(32001) << "Loading " << frameName << " : chainPrevFrame=" << prevFrame << endl; if ( prevFrame ) { if ( fs ) // we are between prevFrame and nextFrame. They'd better be for the same fs!! Q_ASSERT( fs == prevFrame->frameSet() ); fs = dynamic_cast( prevFrame->frameSet() ); //kdDebug(32001) << " found " << prevFrame << " -> frameset " << fs->getName() << endl; } KWFrame* frame = 0; if ( !fs ) { fs = new KWTextFrameSet( m_doc, frameTag, context ); m_doc->addFrameSet( fs, false ); frame = fs->loadOasis( frameTag, tag, context ); } else { // Adding frame to existing frameset context.styleStack().save(); context.fillStyleStack( frameTag, KoXmlNS::draw, "style-name" ); // get the style for the graphics element frame = fs->loadOasisTextFrame( frameTag, tag, context ); context.styleStack().restore(); } m_doc->loadingInfo()->storeFrameName( frame, frameName ); if ( !chainNextName.isEmpty() ) { m_doc->loadingInfo()->storeNextFrame( frame, chainNextName ); } return frame; } KWFrame* KWTextFrameSet::loadOasisTextFrame( const QDomElement& frameTag, const QDomElement &tag, KoOasisContext& context ) { context.styleStack().save(); context.fillStyleStack( frameTag, KoXmlNS::draw, "style-name" ); // get the style for the graphics element KWFrame* frame = loadOasisFrame( frameTag, context ); // Load minimum height - only available for text-box bool hasMinHeight = tag.hasAttributeNS( KoXmlNS::fo, "min-height" ); if ( hasMinHeight ) { double height = KoUnit::parseValue( tag.attributeNS( KoXmlNS::fo, "min-height", QString::null ) ); frame->setMinFrameHeight( height ); } // Load overflow behavior (OASIS 14.27.27, not in OO-1.1 DTD). This is here since it's only for text framesets. const QString overflowBehavior = context.styleStack().attributeNS( KoXmlNS::style, "overflow-behavior" ); if ( frame->minFrameHeight() > 0 ) frame->setFrameBehavior( KWFrame::AutoExtendFrame ); else if ( overflowBehavior == "auto-create-new-frame" ) { frame->setFrameBehavior( KWFrame::AutoCreateNewFrame ); frame->setNewFrameBehavior( KWFrame::Reconnect ); // anything else doesn't make sense } else if ( overflowBehavior.isEmpty() || overflowBehavior == "clip" ) frame->setFrameBehavior( KWFrame::Ignore ); else kdWarning(32001) << "Unknown value for style:overflow-behavior: " << overflowBehavior << endl; context.styleStack().restore(); return frame; } void KWTextFrameSet::loadOasisContent( const QDomElement &bodyElem, KoOasisContext& context ) { return m_textobj->loadOasisContent( bodyElem, context, m_doc->styleCollection() ); } KWFrame* KWTextFrameSet::loadOasis( const QDomElement& frameTag, const QDomElement &tag, KoOasisContext& context ) { KWFrame* frame = loadOasisTextFrame( frameTag, tag, context ); loadOasisContent( tag, context ); return frame; } void KWTextFrameSet::saveOasisContent( KoXmlWriter& writer, KoSavingContext& context ) const { if ( frames.isEmpty() ) // Deleted frameset -> don't save return; // TODO save protectContent m_textobj->saveOasisContent( writer, context ); } void KWTextFrameSet::saveOasis( KoXmlWriter& writer, KoSavingContext& context ) const { if ( frames.isEmpty() ) // Deleted frameset -> don't save return; // Save first frame with the whole contents KWFrame* frame = frames.getFirst(); frame->startOasisFrame( writer, context.mainStyles() ); writer.startElement( "draw:text-box" ); if ( frame->frameBehavior() == KWFrame::AutoExtendFrame ) writer.addAttributePt( "fo:min-height", frame->minFrameHeight() ); saveOasisContent( writer, context ); writer.endElement(); writer.endElement(); // draw:frame // TODO: save other frames using chaining // ......... but not when called from KWDocument::saveSelectedFrames } void KWTextFrameSet::load( QDomElement &attributes, bool loadFrames ) { KWFrameSet::load( attributes, loadFrames ); if ( attributes.hasAttribute( "protectContent")) setProtectContent((bool)attributes.attribute( "protectContent" ).toInt()); textDocument()->clear(false); // Get rid of dummy paragraph (and more if any) m_textobj->setLastFormattedParag( 0L ); // no more parags, avoid UMR in next setLastFormattedParag call KWTextParag *lastParagraph = 0L; // QDomElement paragraph = attributes.firstChild().toElement(); for ( ; !paragraph.isNull() ; paragraph = paragraph.nextSibling().toElement() ) { if ( paragraph.tagName() == "PARAGRAPH" ) { KWTextParag *parag = new KWTextParag( textDocument(), lastParagraph ); parag->load( paragraph ); if ( !lastParagraph ) // First parag textDocument()->setFirstParag( parag ); lastParagraph = parag; m_doc->progressItemLoaded(); } } if ( !lastParagraph ) // We created no paragraph { // Create an empty one, then. See KWTextDocument ctor. textDocument()->clear( true ); static_cast( textDocument()->firstParag() )->setStyle( m_doc->styleCollection()->findStyle( "Standard" ) ); } else textDocument()->setLastParag( lastParagraph ); m_textobj->setLastFormattedParag( textDocument()->firstParag() ); //kdDebug(32001) << "KWTextFrameSet::load done" << endl; } void KWTextFrameSet::finalize() { KWFrameSet::finalize(); m_textobj->formatMore( 0 ); // just to get the timer going // This is important in case of auto-resized frames or table cells, // which come from an import filter, which didn't give them the right size. // However it shouldn't start _now_ (so we use 0), because e.g. main frames // don't have the right size yet (KWFrameLayout not done yet). } void KWTextFrameSet::setVisible(bool visible) { setInlineFramesVisible( visible ); KWFrameSet::setVisible( visible ); } void KWTextFrameSet::setInlineFramesVisible(bool visible) { QPtrListIterator cit( textDocument()->allCustomItems() ); for ( ; cit.current() ; ++cit ) { KWAnchor *anc = dynamic_cast( cit.current() ); if (anc) anc->frameSet()->setVisible( visible ); } } #if 0 // Currently not used (since the WYSIWYG switch) void KWTextFrameSet::preparePrinting( QPainter *painter, QProgressDialog *progress, int &processedParags ) { //textDocument()->doLayout( painter, textDocument()->width() ); textDocument()->setWithoutDoubleBuffer( painter != 0 ); textDocument()->formatCollection()->setPainter( painter ); KoTextParag *parag = textDocument()->firstParag(); while ( parag ) { parag->invalidate( 0 ); parag->setPainter( painter, true ); if ( painter ) parag->format(); parag = parag->next(); if ( progress ) progress->setProgress( ++processedParags ); } } #endif void KWTextFrameSet::addTextFrameSets( QPtrList & lst, bool onlyReadWrite ) { if (!textObject()->protectContent() || !onlyReadWrite) lst.append(this); } void KWTextFrameSet::slotNewCommand( KCommand *cmd ) { m_doc->addCommand( cmd ); } void KWTextFrameSet::ensureFormatted( KoTextParag * parag, bool emitAfterFormatting ) { if (!isVisible()) return; m_textobj->ensureFormatted( parag, emitAfterFormatting ); } bool KWTextFrameSet::slotAfterFormattingNeedMoreSpace( int bottom, KoTextParag *lastFormatted ) { int availHeight = availableHeight(); #ifdef DEBUG_FORMAT_MORE if(lastFormatted) kdDebug(32002) << "slotAfterFormatting We need more space in " << getName() << " bottom=" << bottom + lastFormatted->rect().height() << " availHeight=" << availHeight << endl; else kdDebug(32002) << "slotAfterFormatting We need more space in " << getName() << " bottom2=" << bottom << " availHeight=" << availHeight << endl; #endif if ( frames.isEmpty() ) { kdWarning(32002) << "slotAfterFormatting no more space, but no frame !" << endl; return true; // abort } KWFrame::FrameBehavior frmBehavior = frames.last()->frameBehavior(); if ( frmBehavior == KWFrame::AutoExtendFrame && isProtectSize()) frmBehavior = KWFrame::Ignore; if ( frmBehavior == KWFrame::AutoCreateNewFrame ) { KWFrame *theFrame = settingsFrame( frames.last() ); double minHeight = s_minFrameHeight + theFrame->paddingTop() + theFrame->paddingBottom() + 5; if ( availHeight < minHeight ) frmBehavior = KWFrame::Ignore; } int difference = ( bottom + 2 ) - availHeight; // in layout unit pixels #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "AutoExtendFrame bottom=" << bottom << " availHeight=" << availHeight << " => difference = " << difference << endl; #endif if( lastFormatted && bottom + lastFormatted->rect().height() > availHeight ) { #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << " next will be off -> adding " << lastFormatted->rect().height() << endl; #endif difference += lastFormatted->rect().height(); } switch ( frmBehavior ) { case KWFrame::AutoExtendFrame: { if(difference > 0) { // There's no point in resizing a copy, so go back to the last non-copy frame KWFrame *theFrame = settingsFrame( frames.last() ); double wantedPosition = 0; // Footers and footnotes go up if ( theFrame->frameSet()->isAFooter() || theFrame->frameSet()->isFootNote() ) { // The Y position doesn't matter much, recalcFrames will reposition the frame // But the point of this code is set the correct height for the frame. double maxFooterSize = footerHeaderSizeMax( theFrame ); double diffPt = m_doc->layoutUnitPtToPt( m_doc->pixelYToPt( difference ) ); wantedPosition = theFrame->top() - diffPt; #ifdef DEBUG_FORMAT_MORE kdDebug() << " diffPt=" << diffPt << " -> wantedPosition=" << wantedPosition << endl; #endif if ( wantedPosition < 0 ) { m_textobj->setLastFormattedParag( 0 ); return true; // abort } if ( wantedPosition != theFrame->top() && ( theFrame->frameSet()->isFootEndNote() || theFrame->bottom() - maxFooterSize <= wantedPosition ) ) // Apply maxFooterSize for footers only { theFrame->setTop( wantedPosition ); #ifdef DEBUG_FORMAT_MORE kdDebug() << " ok: frame=" << *theFrame << " bottom=" << theFrame->bottom() << " height=" << theFrame->height() << endl; #endif frameResized( theFrame, true ); // We only got room for the next paragraph, we still have to keep the formatting going... return false; // keep going } kdDebug() << "slotAfterFormatting didn't manage to get more space for footer/footnote, aborting" << endl; return true; // abort } // Other frames are resized by the bottom wantedPosition = m_doc->layoutUnitPtToPt( m_doc->pixelYToPt( difference ) ) + theFrame->bottom(); double pageBottom = (double) (theFrame->pageNum()+1) * m_doc->ptPaperHeight(); pageBottom -= m_doc->ptBottomBorder(); double newPosition = QMIN( wantedPosition, pageBottom ); kdDebug(32002) << "wantedPosition=" << wantedPosition << " pageBottom=" << pageBottom << " -> newPosition=" << newPosition << endl; if ( theFrame->frameSet()->isAHeader() ) { double maxHeaderSize=footerHeaderSizeMax( theFrame ); newPosition = QMIN( newPosition, maxHeaderSize + theFrame->top() ); } newPosition = QMAX( newPosition, theFrame->top() ); // avoid negative heights kdDebug(32002) << "newPosition=" << newPosition << endl; bool resized = false; if(theFrame->frameSet()->getGroupManager()) { KWTableFrameSet *table = theFrame->frameSet()->getGroupManager(); #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "is table cell; just setting new minFrameHeight, to " << newPosition - theFrame->top() << endl; #endif double newMinFrameHeight = newPosition - theFrame->top(); resized = QABS( newMinFrameHeight - theFrame->minFrameHeight() ) > 1E-10; if ( resized ) { theFrame->setMinFrameHeight( newMinFrameHeight ); KWTableFrameSet::Cell *cell = (KWTableFrameSet::Cell *)theFrame->frameSet(); table->recalcCols(cell->firstCol(), cell->firstRow()); table->recalcRows(cell->firstCol(), cell->firstRow()); m_doc->delayedRepaintAllViews(); } return true; // abort formatting for now (not sure this is correct) } else { resized = QABS( theFrame->bottom() - newPosition ) > 1E-10; #ifdef DEBUG_FORMAT_MORE kdDebug() << " bottom=" << theFrame->bottom() << " new position:" << newPosition << " wantedPosition=" << wantedPosition << " resized=" << resized << endl; #endif if ( resized ) { #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "slotAfterFormatting changing bottom from " << theFrame->bottom() << " to " << newPosition << endl; #endif theFrame->setBottom(newPosition); frameResized( theFrame, false ); } } if(newPosition < wantedPosition && (theFrame->newFrameBehavior() == KWFrame::Reconnect && !theFrame->frameSet()->isEndNote())) // end notes are handled by KWFrameLayout { wantedPosition = wantedPosition - newPosition + theFrame->top() + m_doc->ptPaperHeight(); #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "Not enough room in this page -> creating new one, with a reconnect frame" << endl; kdDebug(32002) << "new wantedPosition=" << wantedPosition << endl; #endif // fall through to AutoCreateNewFrame } else if(newPosition < wantedPosition && (theFrame->newFrameBehavior() == KWFrame::NoFollowup)) { if ( theFrame->frameSet()->isEndNote() ) // we'll need a new page m_doc->delayedRecalcFrames( theFrame->pageNum() ); m_textobj->setLastFormattedParag( 0 ); return true; // abort } else { if ( resized ) // we managed to resize a frame return false; // keep going return true; // abort } } } case KWFrame::AutoCreateNewFrame: { // We need a new frame in this frameset. return createNewPageAndNewFrame( lastFormatted, difference ); } case KWFrame::Ignore: #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "slotAfterFormatting frame behaviour is Ignore" << endl; #endif m_textobj->setLastFormattedParag( 0 ); return true; // abort } kdWarning() << "NEVERREACHED" << endl; // NEVERREACHED return true; } void KWTextFrameSet::slotAfterFormattingTooMuchSpace( int bottom ) { int availHeight = availableHeight(); // The + 2 here leaves 2 pixels below the last line. Without it we hit // the "break at end of frame" case in formatVertically (!!). int difference = availHeight - ( bottom + 2 ); #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "slotAfterFormatting less text than space (AutoExtendFrame). Frameset " << getName() << " availHeight=" << availHeight << " bottom=" << bottom << " ->difference=" << difference << endl; #endif // There's no point in resizing a copy, so go back to the last non-copy frame KWFrame *theFrame = settingsFrame( frames.last() ); #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << " frame is " << *theFrame << " footer:" << ( theFrame->frameSet()->isAFooter() || theFrame->frameSet()->isFootEndNote() ) << endl; #endif if ( theFrame->frameSet()->isAFooter() || theFrame->frameSet()->isFootEndNote() ) { double wantedPosition = theFrame->top() + m_doc->layoutUnitPtToPt( m_doc->pixelYToPt( difference ) ); Q_ASSERT( wantedPosition < theFrame->bottom() ); if ( wantedPosition != theFrame->top() ) { #ifdef DEBUG_FORMAT_MORE kdDebug() << " top= " << theFrame->top() << " setTop " << wantedPosition << endl; #endif theFrame->setTop( wantedPosition ); #ifdef DEBUG_FORMAT_MORE kdDebug() << " -> the frame is now " << *theFrame << endl; #endif frameResized( theFrame, true ); } } else // header or other frame: resize bottom { double wantedPosition = theFrame->bottom() - m_doc->layoutUnitPtToPt( m_doc->pixelYToPt( difference ) ); #ifdef DEBUG_FORMAT_MORE kdDebug() << "slotAfterFormatting wantedPosition=" << wantedPosition << " top+minheight=" << theFrame->top() + s_minFrameHeight << endl; #endif wantedPosition = QMAX( wantedPosition, theFrame->top() + s_minFrameHeight ); if( theFrame->frameSet()->getGroupManager() ) { if ( wantedPosition != theFrame->bottom()) { KWTableFrameSet *table = theFrame->frameSet()->getGroupManager(); // When a frame can be smaller we don't rescale it if it is a table, since // we don't have the full picture of the change. // We will set the minFrameHeight to the correct value and let the tables code // do the rescaling based on all the frames in the row. (see KWTableFrameSet::recalcRows()) if(wantedPosition != theFrame->top() + theFrame->minFrameHeight()) { theFrame->setMinFrameHeight(wantedPosition - theFrame->top()); #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "is table cell; only setting new minFrameHeight to " << theFrame->minFrameHeight() << ", recalcrows will do the rest" << endl; #endif KWTableFrameSet::Cell *cell = (KWTableFrameSet::Cell *)theFrame->frameSet(); table->recalcCols(cell->firstCol(), cell->firstRow()); table->recalcRows(cell->firstCol(), cell->firstRow()); m_doc->delayedRepaintAllViews(); } } } else { // Also apply the frame's minimum height wantedPosition = QMAX( wantedPosition, theFrame->top() + theFrame->minFrameHeight() ); if ( wantedPosition != theFrame->bottom()) { #ifdef DEBUG_FORMAT_MORE kdDebug() << " the frame was " << *theFrame << endl; kdDebug() << "setBottom " << wantedPosition << endl; #endif theFrame->setBottom( wantedPosition ); #ifdef DEBUG_FORMAT_MORE kdDebug() << " -> the frame is now " << *theFrame << endl; #endif frameResized( theFrame, true ); } } } } void KWTextFrameSet::slotAfterFormatting( int bottom, KoTextParag *lastFormatted, bool* abort ) { int availHeight = availableHeight(); if ( ( bottom > availHeight ) || // this parag is already off page ( lastFormatted && bottom + lastFormatted->rect().height() > availHeight ) ) // or next parag will be off page { *abort = slotAfterFormattingNeedMoreSpace( bottom, lastFormatted ); } // Handle the case where the last frame is empty, so we may want to // remove the last page. else if ( frames.count() > 1 && !lastFormatted && frameSetInfo() == KWFrameSet::FI_BODY && bottom < availHeight - m_doc->ptToLayoutUnitPixY( frames.last()->innerHeight() ) ) { #ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "slotAfterFormatting too much space (bottom=" << bottom << ", availHeight=" << availHeight << ") , trying to remove last frame" << endl; #endif // Remove the empty last frame, if it's an auto-created one (e.g. a // continuation on the next page). Not when the user just created it! if(frames.last()->frameBehavior() == KWFrame::AutoExtendFrame && frames.last()->minFrameHeight() < 1E-10 ) { // i.e. equal to 0 delFrame(frames.last(), true); m_doc->frameChanged( 0L ); } if ( m_doc->processingType() == KWDocument::WP ) { bool removed = m_doc->tryRemovingPages(); // Do all the recalc in one go. Speeds up deleting many pages. if ( removed ) m_doc->afterRemovePages(); } } // Handle the case where the last frame is in AutoExtendFrame mode // and there is less text than space else if ( !lastFormatted && bottom + 2 < availHeight && (frames.last()->frameBehavior() == KWFrame::AutoExtendFrame&& !isProtectSize()) ) { slotAfterFormattingTooMuchSpace( bottom ); *abort = false; } if ( m_doc->processingType() == KWDocument::WP && this == m_doc->frameSet( 0 ) ) { if ( m_lastTextDocHeight != textDocument()->height() ) { m_lastTextDocHeight = textDocument()->height(); emit mainTextHeightChanged(); } } } // This is called when a text frame with behaviour AutoCreateNewFrame // has more text than available frame height, so we need to create a new page // so that a followup frame is created for this one bool KWTextFrameSet::createNewPageAndNewFrame( KoTextParag* lastFormatted, int /*difference*/ ) { KWFrame* lastFrame = frames.last(); // This is only going to help us if the new frame is reconnected. Otherwise bail out. if ( !lastFrame || lastFrame->newFrameBehavior() != KWFrame::Reconnect ) { kdDebug(32002) << getName() << " : frame is AutoCreateNewFrame but not Reconnect !?!? Aborting." << endl; m_textobj->setLastFormattedParag( 0 ); return true; // abort } //#ifdef DEBUG_FORMAT_MORE kdDebug(32002) << "createNewPageAndNewFrame creating new frame in frameset " << getName() << endl; //#endif uint oldCount = frames.count(); kdDebug(32002) << " last frame=" << lastFrame << " pagenum=" << lastFrame->pageNum() << " getpages-1=" << m_doc->numPages()-1 << " frames count=" << oldCount << endl; // First create a new page for it if necessary if ( lastFrame->pageNum() == m_doc->numPages() - 1 ) { // Let's first check if it will give us more space than we // already have left in this page. Otherwise we'll loop infinitely. QPtrList framesToCopy = m_doc->framesToCopyOnNewPage( m_doc->numPages() - 1 ); QPtrListIterator frameIt( framesToCopy ); int heightWeWillGet = 0; // in LU for ( ; frameIt.current(); ++frameIt ) if (frameIt.current()->frameSet() == this && frameIt.current()->newFrameBehavior()==KWFrame::Reconnect) heightWeWillGet += m_doc->ptToLayoutUnitPixY( frameIt.current()->height() ); // This logic doesn't applies to tables though, since they can be broken over multiple pages // TODO: lastFormatted->containsTable() or so (containsPageBreakableItem rather). // "difference" doesn't apply if we're pasting multiple paragraphs. // We want to compare the height of one paragraph, not all the missing height. int paragHeight = lastFormatted ? lastFormatted->rect().height() : 0; kdDebug(32002) << "height we will get in the new page:" << heightWeWillGet << " parag height:" << paragHeight << endl; if ( heightWeWillGet < paragHeight && !grpMgr ) { kdDebug(32002) << "not enough height on the new page, not worth it" << endl; m_textobj->setLastFormattedParag( 0 ); return true; // abort } int num = m_doc->appendPage(); m_doc->afterAppendPage( num ); kdDebug(32002) << "now frames count=" << frames.count() << endl; } // Maybe creating the new page created the frame in this frameset, then we're done // Otherwise let's create it ourselves: if ( frames.count() == oldCount ) { Q_ASSERT( !isMainFrameset() ); // ouch, should have gone to the appendPage case above... // Otherwise, create a new frame on next page kdDebug(32002) << "createNewPageAndNewFrame creating frame on page " << lastFrame->pageNum()+1 << endl; KWFrame *frm = lastFrame->getCopy(); frm->moveBy( 0, m_doc->ptPaperHeight() ); //frm->setPageNum( lastFrame->pageNum()+1 ); addFrame( frm ); } updateFrames(); m_doc->updateFramesOnTopOrBelow( lastFrame->pageNum() ); /// We don't want to start from the beginning every time ! ////m_doc->invalidate(); // Reformat the last paragraph. If it's over the two pages, it will need // the new page (e.g. for inline frames that need internalToDocument to work) if ( lastFormatted ) lastFormatted = lastFormatted->prev(); else lastFormatted = textDocument()->lastParag(); if ( lastFormatted ) { m_textobj->setLastFormattedParag( lastFormatted ); lastFormatted->invalidate( 0 ); //This was a way to format the rest from here (recursively), but it didn't help much ensureCursorVisible() //So instead I fixed formatMore to return formatMore(2) itself. //m_textobj->formatMore( 2 ); return false; // keep going } m_doc->delayedRepaintAllViews(); return false; // all done } double KWTextFrameSet::footNoteSize( KWFrame *theFrame ) { double tmp =0.0; int page = theFrame->pageNum(); QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { if((fit.current()->isFootNote() || fit.current()->isEndNote()) && fit.current()->isVisible()) { KWFrame * frm=fit.current()->frame( 0 ); if(frm->pageNum()==page ) tmp += frm->innerHeight()+m_doc->ptFootnoteBodySpacing(); } } return tmp; } double KWTextFrameSet::footerHeaderSizeMax( KWFrame *theFrame ) { double tmp =m_doc->ptPaperHeight()-m_doc->ptBottomBorder()-m_doc->ptTopBorder()-40;//default min 40 for page size int page = theFrame->pageNum(); bool header=theFrame->frameSet()->isAHeader(); if( header ? m_doc->isHeaderVisible():m_doc->isFooterVisible() ) { QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() ; ++fit ) { bool state = header ? fit.current()->isAFooter():fit.current()->isAHeader(); if(fit.current()->isVisible() && state) { KWFrame * frm=fit.current()->frame( 0 ); if(frm->pageNum()==page ) { return (tmp-frm->innerHeight()-footNoteSize( theFrame )); } } } } if (theFrame->frameSet()->isHeaderOrFooter()) return (tmp-footNoteSize( theFrame )); return tmp; } void KWTextFrameSet::frameResized( KWFrame *theFrame, bool invalidateLayout ) { kdDebug(32002) << "KWTextFrameSet::frameResized " << theFrame << " " << *theFrame << " invalidateLayout=" << invalidateLayout << endl; if ( theFrame->height() < 0 ) return; // safety! KWFrameSet * fs = theFrame->frameSet(); Q_ASSERT( fs == this ); fs->updateFrames(); // update e.g. available height m_doc->updateFramesOnTopOrBelow( theFrame->pageNum() ); theFrame->updateRulerHandles(); // Do a full KWFrameLayout if this will have influence on other frames, i.e.: // * if we resized the last main text frame (the one before the first endnote) // * if we resized an endnote // Delay it though, to get the full height first. if ( fs->isMainFrameset() || fs->isEndNote() ) m_doc->delayedRecalcFrames( theFrame->pageNum() ); // * if we resized a header, footer, or footnote else if ( fs->frameSetInfo() != KWFrameSet::FI_BODY ) m_doc->recalcFrames( theFrame->pageNum(), -1 ); // warning this can delete theFrame! // m_doc->frameChanged( theFrame ); // Warning, can't call layout() (frameChanged calls it) // from here, since it calls formatMore() ! if ( invalidateLayout ) m_doc->invalidate(this); // Can't repaint directly, we might be in a paint event already m_doc->delayedRepaintAllViews(); } bool KWTextFrameSet::isFrameEmpty( KWFrame * theFrame ) { KoTextParag * lastParag = textDocument()->lastParag(); // The problem is that if we format things here, and don't emit afterFormatting, // we won't resize autoresize frames properly etc. (e.g. endnotes) // Testcase for this problem: werner's footnote-1.doc //ensureFormatted( lastParag, false ); // maybe true here would do too? slow if maintextframeset though. if ( !lastParag->isValid() ) return false; // we don't know yet int bottom = lastParag->rect().top() + lastParag->rect().height(); if ( theFrame->frameSet() == this ) // safety check { //kdDebug() << "KWTextFrameSet::isFrameEmpty text bottom=(LU) " << bottom << " theFrame=" << theFrame << " " << *theFrame << " its internalY(LU)=" << m_doc->ptToLayoutUnitPixY( theFrame->internalY() ) << endl; return bottom < m_doc->ptToLayoutUnitPixY( theFrame->internalY() ); } kdWarning() << "KWTextFrameSet::isFrameEmpty called for frame " << theFrame << " which isn't a child of ours!" << endl; if ( theFrame->frameSet()!=0L && theFrame->frameSet()->getName()!=0L) kdDebug() << "(this is " << getName() << " and the frame belongs to " << theFrame->frameSet()->getName() << ")" << endl; return false; } bool KWTextFrameSet::canRemovePage( int num ) { //kdDebug() << "KWTextFrameSet(" << getName() << ")::canRemovePage " << num << endl; // No frame on that page ? ok for us then if ( num < m_firstPage || num >= (int)m_framesInPage.size() + m_firstPage ) { //kdDebug() << "No frame on that page. Number of frames: " << getNumFrames() << endl; return true; } QPtrListIterator frameIt( framesInPage( num ) ); for ( ; frameIt.current(); ++frameIt ) { KWFrame * theFrame = frameIt.current(); //kdDebug() << "canRemovePage: looking at " << theFrame << " pageNum=" << theFrame->pageNum() << endl; Q_ASSERT( theFrame->pageNum() == num ); Q_ASSERT( theFrame->frameSet() == this ); bool isEmpty = isFrameEmpty( theFrame ); //kdDebug() << "KWTextFrameSet(" << getName() << ")::canRemovePage" // << " found a frame on page " << num << " empty:" << isEmpty << endl; // Ok, so we have a frame on that page -> we can't remove it unless it's a copied frame OR it's empty bool isCopy = theFrame->isCopy() && frameIt.current() != frames.first(); if ( !isCopy && !isEmpty ) return false; } return true; } void KWTextFrameSet::delFrame( unsigned int num, bool remove, bool recalc ) { KWFrame *frm = frames.at( num ); kdDebug() << "KWTextFrameSet(" << getName() << ")::delFrame " << frm << " (" << num << ")" << endl; if ( frm ) emit frameDeleted( frm ); KWFrameSet::delFrame( num, remove, recalc ); } void KWTextFrameSet::updateViewArea( QWidget * w, KWViewMode* viewMode, const QPoint & nPointBottom ) { if (!isVisible(viewMode)) return; int ah = availableHeight(); // make sure that it's not -1 #ifdef DEBUG_VIEWAREA kdDebug(32002) << "KWTextFrameSet::updateViewArea " << (void*)w << " " << w->name() << " nPointBottom=" << nPointBottom.x() << "," << nPointBottom.y() << " availHeight=" << ah << " textDocument()->height()=" << textDocument()->height() << endl; #endif // Find last page that is visible int maxPage = ( nPointBottom.y() + m_doc->paperHeight() /*equiv. to ceil()*/ ) / m_doc->paperHeight(); int maxY = 0; if ( maxPage < m_firstPage || maxPage >= (int)m_framesInPage.size() + m_firstPage ) maxY = ah; else { // Find frames on that page, and keep the max bottom, in internal coordinates QPtrListIterator frameIt( framesInPage( maxPage ) ); for ( ; frameIt.current(); ++frameIt ) { maxY = QMAX( maxY, m_doc->ptToLayoutUnitPixY( frameIt.current()->internalY() + frameIt.current()->innerHeight() ) ); } } #ifdef DEBUG_VIEWAREA kdDebug(32002) << "KWTextFrameSet (" << getName() << ")::updateViewArea maxY now " << maxY << endl; #endif m_textobj->setViewArea( w, maxY ); m_textobj->formatMore( 2 ); } KCommand * KWTextFrameSet::setPageBreakingCommand( KoTextCursor * cursor, int pageBreaking ) { if ( !textDocument()->hasSelection( KoTextDocument::Standard ) && static_cast(cursor->parag())->pageBreaking() == pageBreaking ) return 0L; // No change needed. m_textobj->emitHideCursor(); m_textobj->storeParagUndoRedoInfo( cursor ); if ( !textDocument()->hasSelection( KoTextDocument::Standard ) ) { KWTextParag *parag = static_cast( cursor->parag() ); parag->setPageBreaking( pageBreaking ); m_textobj->setLastFormattedParag( cursor->parag() ); } else { KoTextParag *start = textDocument()->selectionStart( KoTextDocument::Standard ); KoTextParag *end = textDocument()->selectionEnd( KoTextDocument::Standard ); m_textobj->setLastFormattedParag( start ); for ( ; start && start != end->next() ; start = start->next() ) static_cast(start)->setPageBreaking( pageBreaking ); } m_textobj->formatMore( 2 ); emit repaintChanged( this ); KoTextObject::UndoRedoInfo & undoRedoInfo = m_textobj->undoRedoInfoStruct(); undoRedoInfo.newParagLayout.pageBreaking = pageBreaking; KoTextParagCommand *cmd = new KoTextParagCommand( textDocument(), undoRedoInfo.id, undoRedoInfo.eid, undoRedoInfo.oldParagLayouts, undoRedoInfo.newParagLayout, KoParagLayout::PageBreaking ); textDocument()->addCommand( cmd ); undoRedoInfo.clear(); m_textobj->emitShowCursor(); m_textobj->emitUpdateUI( true ); m_textobj->emitEnsureCursorVisible(); // ## find a better name for the command return new KoTextCommand( m_textobj, /*cmd, */i18n("Change Paragraph Attribute") ); } KCommand * KWTextFrameSet::pasteOasis( KoTextCursor * cursor, const QByteArray & data, bool removeSelected ) { if (protectContent() ) return 0; kdDebug(32001) << "KWTextFrameSet::pasteOasis data:" << data.size() << " bytes" << endl; KMacroCommand * macroCmd = new KMacroCommand( i18n("Paste") ); if ( removeSelected && textDocument()->hasSelection( KoTextDocument::Standard ) ) macroCmd->addCommand( m_textobj->removeSelectedTextCommand( cursor, KoTextDocument::Standard ) ); m_textobj->emitHideCursor(); m_textobj->setLastFormattedParag( cursor->parag()->prev() ? cursor->parag()->prev() : cursor->parag() ); KWOasisPasteCommand * cmd = new KWOasisPasteCommand( textDocument(), cursor->parag()->paragId(), cursor->index(), data ); textDocument()->addCommand( cmd ); macroCmd->addCommand( new KoTextCommand( m_textobj, /*cmd, */QString::null ) ); *cursor = *( cmd->execute( cursor ) ); // not enough when pasting many pages. We need the cursor's parag to be formatted. //m_textobj->formatMore( 2 ); ensureFormatted( cursor->parag() ); emit repaintChanged( this ); m_textobj->emitEnsureCursorVisible(); m_textobj->emitUpdateUI( true ); m_textobj->emitShowCursor(); m_textobj->selectionChangedNotify(); return macroCmd; } void KWTextFrameSet::insertTOC( KoTextCursor * cursor ) { m_textobj->emitHideCursor(); KMacroCommand * macroCmd = new KMacroCommand( i18n("Insert Table of Contents") ); // Remove old TOC KoTextCursor *cur= KWInsertTOCCommand::removeTOC( this, cursor, macroCmd ); // Insert new TOC KoTextDocCommand * cmd = new KWInsertTOCCommand( this,cur ? cur->parag(): cursor->parag() ); textDocument()->addCommand( cmd ); macroCmd->addCommand( new KoTextCommand( m_textobj, QString::null ) ); *cursor = *( cmd->execute( cursor ) ); m_textobj->setLastFormattedParag( textDocument()->firstParag() ); m_textobj->formatMore( 2 ); emit repaintChanged( this ); m_textobj->emitEnsureCursorVisible(); m_textobj->emitUpdateUI( true ); m_textobj->emitShowCursor(); m_doc->addCommand( macroCmd ); } KNamedCommand* KWTextFrameSet::insertFrameBreakCommand( KoTextCursor *cursor ) { KMacroCommand* macroCmd = new KMacroCommand( QString::null ); macroCmd->addCommand( m_textobj->insertParagraphCommand( cursor ) ); KWTextParag *parag = static_cast( cursor->parag() ); if(parag->prev()) { parag=static_cast (parag->prev()); cursor->setParag( parag ); cursor->setIndex( parag->length() - 1 ); } macroCmd->addCommand( setPageBreakingCommand( cursor, parag->pageBreaking() | KoParagLayout::HardFrameBreakAfter ) ); Q_ASSERT( parag->next() ); if ( parag->next() ) { cursor->setParag( parag->next() ); cursor->setIndex( 0 ); } return macroCmd; } void KWTextFrameSet::insertFrameBreak( KoTextCursor *cursor ) { clearUndoRedoInfo(); m_textobj->emitHideCursor(); KNamedCommand* cmd = insertFrameBreakCommand( cursor ); cmd->setName( i18n( "Insert Break After Paragraph" ) ); m_doc->addCommand( cmd ); m_textobj->setLastFormattedParag( cursor->parag() ); m_textobj->formatMore( 2 ); emit repaintChanged( this ); m_textobj->emitEnsureCursorVisible(); m_textobj->emitUpdateUI( true ); m_textobj->emitShowCursor(); } QRect KWTextFrameSet::paragRect( KoTextParag * parag ) const { // ## Warning. Imagine a paragraph cut in two pieces (at the line-level), // between two columns. A single rect in internal coords, but two rects in // normal coords. QRect( topLeft, bottomRight ) is just plain wrong. // Currently this method is only used for "ensure visible" so that's fine, but // we shouldn't use it for more precise stuff. KoPoint p; (void)internalToDocument( parag->rect().topLeft(), p ); QPoint topLeft = m_doc->zoomPoint( p ); (void)internalToDocument( parag->rect().bottomRight(), p ); QPoint bottomRight = m_doc->zoomPoint( p ); return QRect( topLeft, bottomRight ); } void KWTextFrameSet::findPosition( const KoPoint &dPoint, KoTextParag * & parag, int & index ) { KoTextCursor cursor( textDocument() ); QPoint iPoint; if ( documentToInternal( dPoint, iPoint ) ) { cursor.place( iPoint, textDocument()->firstParag() ); parag = cursor.parag(); index = cursor.index(); } else { // Not found, maybe under everything ? parag = textDocument()->lastParag(); if ( parag ) index = parag->length() - 1; } } bool KWTextFrameSet::minMaxInternalOnPage( int pageNum, int& topLU, int& bottomLU ) const { QPtrListIterator frameIt( framesInPage( pageNum ) ); if ( !frameIt.current() ) return false; // Look at all frames in the page, and keep min and max "internalY" positions double topPt = frameIt.current()->internalY(); double bottomPt = topPt + frameIt.current()->height(); for ( ; frameIt.current(); ++frameIt ) { double y = frameIt.current()->internalY(); topPt = QMIN( topPt, y ); bottomPt = QMAX( bottomPt, y + frameIt.current()->height() ); } // Convert to layout units topLU = m_doc->ptToLayoutUnitPixY( topPt ); bottomLU = m_doc->ptToLayoutUnitPixY( bottomPt ); return true; } KoTextParag* KWTextFrameSet::paragAtLUPos( int yLU ) const { KoTextParag* parag = textDocument()->firstParag(); for ( ; parag ; parag = parag->next() ) { if ( parag->rect().bottom() >= yLU ) return parag; } return 0L; } KCommand * KWTextFrameSet::deleteAnchoredFrame( KWAnchor * anchor ) { kdDebug() << "KWTextFrameSet::deleteAnchoredFrame anchor->index=" << anchor->index() << endl; Q_ASSERT( anchor ); KoTextCursor c( textDocument() ); c.setParag( anchor->paragraph() ); c.setIndex( anchor->index() ); textDocument()->setSelectionStart( KoTextDocument::Temp, &c ); c.setIndex( anchor->index() + 1 ); textDocument()->setSelectionEnd( KoTextDocument::Temp, &c ); KCommand *cmd = m_textobj->removeSelectedTextCommand( &c, KoTextDocument::Temp ); m_doc->repaintAllViews(); return cmd; } bool KWTextFrameSet::hasSelection() const { return m_textobj->hasSelection(); } QString KWTextFrameSet::selectedText() const { return m_textobj->selectedText(); } QString KWTextFrameSet::toPlainText() const { return m_textobj->textDocument()->plainText(); } void KWTextFrameSet::highlightPortion( KoTextParag * parag, int index, int length, KWCanvas * canvas, bool repaint, KDialogBase* dialog ) { Q_ASSERT( isVisible() ); Q_ASSERT( m_textobj->isVisible() ); //kdDebug() << "highlighting in " << getName() << " parag=" << parag->paragId() << " index=" << index << " repaint=" << repaint << endl; m_textobj->highlightPortion( parag, index, length, repaint ); if ( repaint ) { // Position the cursor canvas->editTextFrameSet( this, parag, index ); // Ensure text is fully visible QRect expose = canvas->viewMode()->normalToView( paragRect( parag ) ); canvas->ensureVisible( (expose.left()+expose.right()) / 2, // point = center of the rect (expose.top()+expose.bottom()) / 2, (expose.right()-expose.left()) / 2, // margin = half-width of the rect (expose.bottom()-expose.top()) / 2); if ( dialog ) { //kdDebug() << k_funcinfo << " dialog=" << dialog << " avoiding rect=" << expose << endl; QRect globalRect( expose ); globalRect.moveTopLeft( canvas->mapToGlobal( globalRect.topLeft() ) ); KDialog::avoidArea( dialog, globalRect ); } } } void KWTextFrameSet::removeHighlight( bool repaint ) { m_textobj->removeHighlight( repaint ); } void KWTextFrameSet::clearUndoRedoInfo() { m_textobj->clearUndoRedoInfo(); } void KWTextFrameSet::applyStyleChange( KoStyleChangeDefMap changed ) { m_textobj->applyStyleChange( changed ); } void KWTextFrameSet::showPopup( KWFrame *, KWView *view, const QPoint &point ) { QPopupMenu * popup = view->popupMenu("text_popup"); Q_ASSERT(popup); if (popup) popup->popup( point ); } // KoTextFormatInterface methods KoTextFormat *KWTextFrameSet::currentFormat() const { return m_textobj->currentFormat(); } KCommand *KWTextFrameSet::setChangeCaseOfTextCommand(KoChangeCaseDia::TypeOfCase _type) { KoTextDocument *textdoc = m_textobj->textDocument(); textdoc->selectAll( KoTextDocument::Standard ); KoTextCursor *cursor = new KoTextCursor( textDocument() ); KCommand* cmd = m_textobj->changeCaseOfText(cursor, _type); textdoc->removeSelection( KoTextDocument::Standard ); delete cursor; return cmd; } KCommand *KWTextFrameSet::setFormatCommand( const KoTextFormat * newFormat, int flags, bool zoomFont ) { m_textobj->textDocument()->selectAll( KoTextDocument::Temp ); KCommand *cmd = m_textobj->setFormatCommand( 0L, 0L, newFormat, flags, zoomFont, KoTextDocument::Temp ); m_textobj->textDocument()->removeSelection( KoTextDocument::Temp ); return cmd; } const KoParagLayout * KWTextFrameSet::currentParagLayoutFormat() const { return m_textobj->currentParagLayoutFormat(); } bool KWTextFrameSet::rtl() const { return m_textobj->rtl(); } KCommand *KWTextFrameSet::setParagLayoutFormatCommand( KoParagLayout *newLayout,int flags, int marginIndex) { return m_textobj->setParagLayoutFormatCommand(newLayout, flags, marginIndex); } class KWFootNoteVarList : public QPtrList< KWFootNoteVariable > { protected: virtual int compareItems(QPtrCollection::Item a, QPtrCollection::Item b) { KWFootNoteVariable* vara = ((KWFootNoteVariable *)a); KWFootNoteVariable* varb = ((KWFootNoteVariable *)b); if ( vara->paragraph() == varb->paragraph() ) { // index() is a bit slow. But this is only called when there are // two footnotes in the same paragraph. int indexa = vara->index(); int indexb = varb->index(); return indexa < indexb ? -1 : indexa == indexb ? 0 : 1; } if ( vara->paragraph()->paragId() < varb->paragraph()->paragId() ) return -1; return 1; } }; void KWTextFrameSet::renumberFootNotes( bool repaint ) { KWFootNoteVarList lst; QPtrListIterator cit( textDocument()->allCustomItems() ); for ( ; cit.current() ; ++cit ) { KWFootNoteVariable *fnv = dynamic_cast( cit.current() ); if (fnv && !fnv->isDeleted() && (fnv->frameSet() && !fnv->frameSet()->isDeleted())) lst.append( fnv ); } lst.sort(); short int footNoteVarNumber = 0; // absolute order number [internal, not saved nor displayed] short int endNoteVarNumber = 0; short int footNoteNumDisplay = 1; // the number being displayed short int endNoteNumDisplay = 1; bool needRepaint = false; QPtrListIterator< KWFootNoteVariable > vit( lst ); for ( ; vit.current() ; ++vit ) { KWFootNoteVariable* var = vit.current(); bool endNote = var->noteType() == EndNote; short int & varNumber = endNote ? endNoteVarNumber : footNoteVarNumber; short int & numDisplay = endNote ? endNoteNumDisplay : footNoteNumDisplay; ++varNumber; bool changed = false; if ( varNumber != var->num() ) { changed = true; var->setNum( varNumber ); } if ( var->numberingType()==KWFootNoteVariable::Auto ) { if ( numDisplay != var->numDisplay() ) { changed = true; var->setNumDisplay( numDisplay ); } numDisplay++; } if ( changed ) { if ( var->frameSet() ) //safety { QString fsName = endNote ? i18n("Endnote %1") : i18n("Footnote %1"); if ( var->numberingType()== KWFootNoteVariable::Manual) var->frameSet()->setName( m_doc->generateFramesetName(fsName)); else var->frameSet()->setName( fsName.arg( var->text() ) ); var->frameSet()->setCounterText( var->text() ); } var->resize(); var->paragraph()->invalidate(0); var->paragraph()->setChanged( true ); needRepaint = true; } } if ( needRepaint && repaint ) m_doc->slotRepaintChanged( this ); } KoTextDocCommand *KWTextFrameSet::deleteTextCommand( KoTextDocument *textdoc, int id, int index, const QMemArray & str, const CustomItemsMap & customItemsMap, const QValueList & oldParagLayouts ) { return new KWTextDeleteCommand( textdoc, id, index, str, customItemsMap, oldParagLayouts ); } // Old koffice-1.3 method, to be removed once KWTableFrameSet::convertTableToText is ported QString KWTextFrameSet::copyTextParag( QDomElement & elem, int selectionId ) { KoTextCursor c1 = textDocument()->selectionStartCursor( selectionId ); KoTextCursor c2 = textDocument()->selectionEndCursor( selectionId ); QString text; if ( c1.parag() == c2.parag() ) { text = c1.parag()->toString( c1.index(), c2.index() - c1.index() ); static_cast(c1.parag())->save( elem, c1.index(), c2.index()-1, true ); } else { text += c1.parag()->toString( c1.index() ) + "\n"; static_cast(c1.parag())->save( elem, c1.index(), c1.parag()->length()-2, true ); KoTextParag *p = c1.parag()->next(); while ( p && p != c2.parag() ) { text += p->toString() + "\n"; static_cast(p)->save( elem, 0, p->length()-2, true ); p = p->next(); } text += c2.parag()->toString( 0, c2.index() ); static_cast(c2.parag())->save( elem, 0, c2.index()-1, true ); } return text; } bool KWTextFrameSet::sortText(sortType type) { KoTextCursor c1 = textDocument()->selectionStartCursor(KoTextDocument::Standard ); KoTextCursor c2 = textDocument()->selectionEndCursor( KoTextDocument::Standard ); QString text; if ( c1.parag() == c2.parag() ) return false; else { //create list QMap sortText; QStringList listOfText; QString text = c1.parag()->toString(0); sortText.insert( text, c1.parag()->paragId()); listOfText<next(); while ( p && p != c2.parag() ) { text = p->toString(0); listOfText<paragId()); p = p->next(); } text = c2.parag()->toString(0); listOfText<paragId()); //sort text int nbParag = sortText.count(); QString tmp; for (int pass = 1; pass < nbParag ; pass++) { for (int i = 0; i < nbParag-1; i++) { if ( listOfText[i] > listOfText[i+1] ) { tmp = listOfText[i]; listOfText[i] = listOfText[i+1]; listOfText[i+1] = tmp; } } } //save text ! QDomDocument domDoc( "PARAGRAPHS" ); QDomElement elem = domDoc.createElement( "PARAGRAPHS" ); domDoc.appendChild( elem ); KWTextParag *parag =0L; if ( type ==KW_SORTINCREASE ) { for (unsigned int i =0; i < listOfText.count(); i++) { parag = static_cast(textDocument()->paragAt( sortText.find(listOfText[i]).data() )); parag->save(elem); } } else { for (int i =listOfText.count()-1 ; i >= 0; --i) { parag = static_cast(textDocument()->paragAt( sortText.find(listOfText[i]).data() )); parag->save(elem); } } KWTextDrag *kd = new KWTextDrag( 0L ); kd->setFrameSetNumber( -1 ); kd->setKWord( domDoc.toCString() ); QApplication::clipboard()->setData( kd ); c1.setIndex( 0 ); textDocument()->setSelectionStart( KoTextDocument::Standard, &c1 ); c2.setIndex( c2.parag()->length()-1 ); textDocument()->setSelectionEnd( KoTextDocument::Standard, &c2 ); } return true; } // This is used when loading (KWTextDocument::loadOasisFootnote) // and when inserting from the GUI (KWTextFrameSetEdit::insertFootNote), // so don't add any 'repaint' or 'recalc' code here KWFootNoteFrameSet * KWTextFrameSet::insertFootNote( NoteType noteType, KWFootNoteVariable::Numbering numType, const QString &manualString ) { kdDebug() << "KWTextFrameSetEdit::insertFootNote " << endl; KWDocument * doc = m_doc; KWFootNoteVariable * var = new KWFootNoteVariable( textDocument(), doc->variableFormatCollection()->format( "NUMBER" ), doc->getVariableCollection(), doc ); var->setNoteType( noteType ); var->setNumberingType( numType ); if ( numType == KWFootNoteVariable::Manual ) var->setManualString( manualString ); // Now create text frameset which will hold the variable's contents KWFootNoteFrameSet *fs = new KWFootNoteFrameSet( doc, i18n( "Footnotes" ) ); fs->setFrameSetInfo( KWFrameSet::FI_FOOTNOTE ); doc->addFrameSet( fs ); // Bind the footnote variable and its text frameset var->setFrameSet( fs ); fs->setFootNoteVariable( var ); return fs; } MouseMeaning KWTextFrameSet::getMouseMeaningInsideFrame( const KoPoint& dPoint ) { if (m_doc->getVariableCollection()->variableSetting()->displayLink() && m_doc->getVariableCollection()->variableSetting()->underlineLink() ) { QPoint iPoint; if ( documentToInternal( dPoint, iPoint ) ) { KoLinkVariable* linkVariable = dynamic_cast( textObject()->variableAtPoint( iPoint ) ); if ( linkVariable ) return MEANING_MOUSE_OVER_LINK; } } return MEANING_MOUSE_INSIDE_TEXT; } /////////////////////////////////////////////////////////////////////////////// KWTextFrameSetEdit::KWTextFrameSetEdit( KWTextFrameSet * fs, KWCanvas * canvas, bool temp) : KoTextView( fs->textObject() ), KWFrameSetEdit( fs, canvas ), m_rtl( false ) { //kdDebug(32001) << "KWTextFrameSetEdit::KWTextFrameSetEdit " << fs->getName() << endl; KoTextView::setReadWrite( fs->kWordDocument()->isReadWrite() ); KoTextObject* textobj = fs->textObject(); if (temp) return; connect( textobj, SIGNAL( selectionChanged(bool) ), canvas, SIGNAL( selectionChanged(bool) ) ); connect( fs, SIGNAL( frameDeleted(KWFrame *) ), this, SLOT( slotFrameDeleted(KWFrame *) ) ); connect( textView(), SIGNAL( cut() ), SLOT( cut() ) ); connect( textView(), SIGNAL( copy() ), SLOT( copy() ) ); connect( textView(), SIGNAL( paste() ), SLOT( paste() ) ); updateUI( true, true ); if( canvas->gui() && canvas->gui()->getHorzRuler()) { if ( !textobj->protectContent() ) canvas->gui()->getHorzRuler()->changeFlags(KoRuler::F_INDENTS | KoRuler::F_TABS); else canvas->gui()->getHorzRuler()->changeFlags(0); } } KWTextFrameSetEdit::~KWTextFrameSetEdit() { //kdDebug(32001) << "KWTextFrameSetEdit::~KWTextFrameSetEdit" << endl; //m_canvas->gui()->getHorzRuler()->changeFlags(0); } KoTextViewIface* KWTextFrameSetEdit::dcopObject() { if ( !dcop ) dcop = new KWordTextFrameSetEditIface( this ); return dcop; } void KWTextFrameSetEdit::terminate(bool removeSelection) { disconnect( textView()->textObject(), SIGNAL( selectionChanged(bool) ), m_canvas, SIGNAL( selectionChanged(bool) ) ); textView()->terminate(removeSelection); } void KWTextFrameSetEdit::slotFrameDeleted( KWFrame *frm ) { if ( m_currentFrame == frm ) m_currentFrame = 0L; } void KWTextFrameSetEdit::paste() { QMimeSource *data = QApplication::clipboard()->data(); QCString returnedTypeMime; // Check for any oasis mimetype (we also accept pasting e.g. kpresenter data) if ( KWTextDrag::provides( data, KoTextObject::acceptSelectionMimeType(), returnedTypeMime) ) { kdDebug() << k_funcinfo << "returnedTypeMime=" << returnedTypeMime << endl; QByteArray arr = data->encodedData( returnedTypeMime ); Q_ASSERT( !arr.isEmpty() ); if ( arr.size() ) { KCommand *cmd = textFrameSet()->pasteOasis( cursor(), arr, true ); if ( cmd ) frameSet()->kWordDocument()->addCommand(cmd); } } else { // Note: QClipboard::text() seems to do a better job than encodedData( "text/plain" ) // In particular it handles charsets (in the mimetype). QString text = QApplication::clipboard()->text(); if ( !text.isEmpty() ) textObject()->pasteText( cursor(), text, currentFormat(), true ); } } void KWTextFrameSetEdit::cut() { if ( textDocument()->hasSelection( KoTextDocument::Standard ) ) { copy(); textObject()->removeSelectedText( cursor() ); } } void KWTextFrameSetEdit::copy() { if ( textDocument()->hasSelection( KoTextDocument::Standard ) ) { QDragObject *drag = newDrag( 0 ); QApplication::clipboard()->setData( drag ); } } bool KWTextFrameSetEdit::doIgnoreDoubleSpace(KoTextParag * parag, int index,QChar ch ) { if( textFrameSet()->kWordDocument()->allowAutoFormat()) { KoAutoFormat * autoFormat = textFrameSet()->kWordDocument()->getAutoFormat(); if( autoFormat ) { return autoFormat->doIgnoreDoubleSpace( parag, index,ch ); } } return false; } void KWTextFrameSetEdit::doAutoFormat( KoTextCursor* cursor, KoTextParag *parag, int index, QChar ch ) { if( textFrameSet()->kWordDocument()->allowAutoFormat() ) { KoAutoFormat * autoFormat = textFrameSet()->kWordDocument()->getAutoFormat(); if( autoFormat ) autoFormat->doAutoFormat( cursor, parag, index, ch, textObject()); } } bool KWTextFrameSetEdit::doCompletion( KoTextCursor* cursor, KoTextParag *parag, int index ) { if( textFrameSet()->kWordDocument()->allowAutoFormat() ) { KoAutoFormat * autoFormat = textFrameSet()->kWordDocument()->getAutoFormat(); if( autoFormat ) return autoFormat->doCompletion( cursor, parag, index, textObject()); } return false; } bool KWTextFrameSetEdit::doToolTipCompletion( KoTextCursor* cursor, KoTextParag *parag, int index, int keyPressed ) { if( textFrameSet()->kWordDocument()->allowAutoFormat() ) { KoAutoFormat * autoFormat = textFrameSet()->kWordDocument()->getAutoFormat(); if( autoFormat ) return autoFormat->doToolTipCompletion( cursor, parag, index, textObject(), keyPressed); } return false; } void KWTextFrameSetEdit::showToolTipBox(KoTextParag *parag, int index, QWidget *widget, const QPoint &pos) { if( textFrameSet()->kWordDocument()->allowAutoFormat() ) { KoAutoFormat * autoFormat = textFrameSet()->kWordDocument()->getAutoFormat(); if( autoFormat ) autoFormat->showToolTipBox(parag, index, widget, pos); } } void KWTextFrameSetEdit::removeToolTipCompletion() { if( textFrameSet()->kWordDocument()->allowAutoFormat() ) { KoAutoFormat * autoFormat = textFrameSet()->kWordDocument()->getAutoFormat(); if( autoFormat ) autoFormat->removeToolTipCompletion(); } } void KWTextFrameSetEdit::textIncreaseIndent() { kdDebug(32001) << "Increasing list" << endl; m_canvas->gui()->getView()->textIncreaseIndent(); } bool KWTextFrameSetEdit::textDecreaseIndent() { if (currentLeftMargin()>0) { kdDebug(32001) << "Decreasing list" << endl; m_canvas->gui()->getView()->textDecreaseIndent(); return true; } else return false; } void KWTextFrameSetEdit::startDrag() { textView()->dragStarted(); m_canvas->dragStarted(); QDragObject *drag = newDrag( m_canvas->viewport() ); if ( !frameSet()->kWordDocument()->isReadWrite() ) drag->dragCopy(); else { if ( drag->drag() && QDragObject::target() != m_canvas && QDragObject::target() != m_canvas->viewport() ) { #if 0 //This is when dropping text _out_ of KWord. Since we have Move and Copy //options (Copy being accessed by pressing CTRL), both are possible. //But is that intuitive enough ? Doesn't the user expect a Copy in all cases ? //Losing the selection when dropping out of kword seems quite unexpected to me. //Undecided about this........ textObject()->removeSelectedText( cursor() ); #endif } } } QDragObject * KWTextFrameSetEdit::newDrag( QWidget * parent ) { KWTextFrameSet* fs = textFrameSet(); return fs->kWordDocument()->dragSelected( parent, fs ); } void KWTextFrameSetEdit::ensureCursorVisible() { //kdDebug() << "KWTextFrameSetEdit::ensureCursorVisible paragId=" << cursor()->parag()->paragId() << " cursor->index()=" << cursor()->index() << endl; KoTextParag * parag = cursor()->parag(); int idx = cursor()->index(); textFrameSet()->ensureFormatted( parag ); KoTextStringChar *chr = parag->at( idx ); int cursorHeight = parag->lineHeightOfChar( idx ); int x = parag->rect().x() + cursor()->x(); // this includes +charwidth for an RTL char //kdDebug() << "parag->rect().x()=" << parag->rect().x() << " x=" << cursor()->x() << endl; int y = 0; int dummy; parag->lineHeightOfChar( idx, &dummy, &y ); y += parag->rect().y(); //kdDebug() << "KWTextFrameSetEdit::ensureCursorVisible y=" << y << endl; // make sure one char is visible before, and one after KoTextStringChar *chrLeft = idx > 0 ? chr-1 : chr; // which char is on the left and which one is on the right depends on chr->rightToLeft int areaLeft = chr->rightToLeft ? chr->width : chrLeft->width; int areaRight = chr->rightToLeft ? chrLeft->width : chr->width; KoPoint pt; KoPoint hintDPoint; if ( m_currentFrame ) hintDPoint = m_currentFrame->topLeft(); KWFrame * theFrame = textFrameSet()->internalToDocumentWithHint( QPoint(x, y), pt, hintDPoint ); //kdDebug() << "KWTextFrameSetEdit::ensureCursorVisible frame=" << theFrame << " m_currentFrame=" << m_currentFrame << endl; if ( theFrame && m_currentFrame != theFrame ) { m_currentFrame = theFrame; m_canvas->gui()->getView()->updatePageInfo(); } QPoint cursorPos = textFrameSet()->kWordDocument()->zoomPoint( pt ); cursorPos = m_canvas->viewMode()->normalToView( cursorPos ); areaLeft = textFrameSet()->kWordDocument()->layoutUnitToPixelX( areaLeft ) + 1; areaRight = textFrameSet()->kWordDocument()->layoutUnitToPixelX( areaRight ) + 1; cursorHeight = textFrameSet()->kWordDocument()->layoutUnitToPixelY( cursorHeight ); //kdDebug() << "KWTextFrameSetEdit::ensureCursorVisible pt=" << pt << " cursorPos=" << cursorPos // << " areaLeft=" << areaLeft << " areaRight=" << areaRight << " y=" << y << endl; m_canvas->ensureVisible( cursorPos.x() - areaLeft, cursorPos.y() + cursorHeight / 2, areaLeft + areaRight, cursorHeight / 2 + 2 ); } bool KWTextFrameSetEdit::enterCustomItem( KoTextCustomItem* customItem, bool fromRight ) { KWAnchor* anchor = dynamic_cast( customItem ); if ( anchor ) { KWFrameSet* frameSet = anchor->frameSet(); - if ( frameSet->type() == FT_FORMULA ) { + if ( frameSet->type() == FT_FORMULA || frameSet->type() == FT_TEXT ) { // store the instance variable we need after "delete this" KWCanvas* canvas = m_canvas; // this will "delete this"! m_canvas->editFrameSet( frameSet ); // We assume that `editFrameSet' succeeded. if ( fromRight ) { KWFrameSetEdit* edit = canvas->currentFrameSetEdit(); - static_cast( edit )->moveEnd(); + if ( frameSet->type() == FT_FORMULA ) + static_cast( edit )->moveEnd(); + else + static_cast( edit )->moveCursor( MoveEnd ); } - // A FormulaFrameSetEdit looks a little different from - // a FormulaFrameSet. (Colors) - static_cast( frameSet )->setChanged(); - canvas->repaintChanged( frameSet, true ); + if ( frameSet->type() == FT_FORMULA ) + { + // A FormulaFrameSetEdit looks a little different from + // a FormulaFrameSet. (Colors) + static_cast( frameSet )->setChanged(); + canvas->repaintChanged( frameSet, true ); + } return true; } } return false; } void KWTextFrameSetEdit::keyPressEvent( QKeyEvent* e ) { - // Handle moving into foreign frames (formula frames). + // Handle moving into inline frames (e.g. formula frames). if ( !( e->state() & ControlButton ) && !( e->state() & ShiftButton ) ) { if (e->state() != Qt::NoButton) removeToolTipCompletion(); switch ( e->key() ) { case Key_Left: { KoTextCursor* cursor = textView()->cursor(); KoTextParag* parag = cursor->parag(); int index = cursor->index(); if ( index > 0 ) { KoTextStringChar* ch = parag->at( index-1 ); if ( ch->isCustom() ) { KoTextCustomItem* customItem = ch->customItem(); if ( enterCustomItem( customItem, true ) ) { - removeToolTipCompletion(); + // Don't do anything here, "this" is deleted! return; } } } + if ( index == 0 && !parag->prev() ) + if ( exitLeft() ) + return; break; } case Key_Right: { KoTextCursor* cursor = textView()->cursor(); KoTextParag* parag = cursor->parag(); int index = cursor->index(); - if ( index < parag->length() ) { + if ( index < parag->length() - 1 ) { KoTextStringChar* ch = parag->at( index ); if ( ch->isCustom() ) { KoTextCustomItem* customItem = ch->customItem(); if ( enterCustomItem( customItem, false ) ) { - removeToolTipCompletion(); + // Don't do anything here, "this" is deleted! return; } } - } + } else if ( /*at end, covered by previous if, && */ !parag->next() ) + if ( exitRight() ) + return; break; } } } // Calculate position of tooltip for autocompletion QPoint pos = textFrameSet()->cursorPos( cursor(), m_canvas, m_currentFrame ); textView()->handleKeyPressEvent( e, m_canvas, pos ); } void KWTextFrameSetEdit::keyReleaseEvent( QKeyEvent* e ) { textView()->handleKeyReleaseEvent( e ); } void KWTextFrameSetEdit::imStartEvent( QIMEvent* e ) { textView()->handleImStartEvent( e ); } void KWTextFrameSetEdit::imComposeEvent( QIMEvent* e ) { textView()->handleImComposeEvent( e ); } void KWTextFrameSetEdit::imEndEvent( QIMEvent* e ) { textView()->handleImEndEvent( e ); } void KWTextFrameSetEdit::mousePressEvent( QMouseEvent *e, const QPoint &, const KoPoint & dPoint ) { if ( dPoint.x() < 0 || dPoint.y() < 0 ) return; // Ignore clicks completely outside of the page (e.g. in the gray area, or ruler) textFrameSet()->textObject()->clearUndoRedoInfo(); if ( m_currentFrame ) hideCursor(); // Need to do that with the old m_currentFrame QPoint iPoint; KWTextFrameSet::RelativePosition relPos; KWFrame * theFrame = textFrameSet()->documentToInternalMouseSelection( dPoint, iPoint, relPos ); if ( theFrame && m_currentFrame != theFrame ) { m_currentFrame = theFrame; m_canvas->gui()->getView()->updatePageInfo(); } if ( m_currentFrame ) { // Let KoTextView handle the mousepress event - but don't let it start // a drag if clicking on the left of the text (out of the frame itself) bool addParag = textView()->handleMousePressEvent( e, iPoint, relPos != KWTextFrameSet::LeftOfFrame, frameSet()->kWordDocument()->insertDirectCursor() ); // Clicked on the left of the text -> select the whole paragraph if ( relPos == KWTextFrameSet::LeftOfFrame ) textView()->selectParagUnderCursor( *textView()->cursor() ); if ( addParag ) frameSet()->kWordDocument()->setModified(true ); } // else mightStartDrag = FALSE; necessary? } void KWTextFrameSetEdit::mouseMoveEvent( QMouseEvent * e, const QPoint & nPoint, const KoPoint & ) { if ( textView()->maybeStartDrag( e ) ) return; if ( nPoint.x() < 0 || nPoint.y() < 0 ) return; // Ignore clicks completely outside of the page (e.g. in the gray area, or ruler) QPoint iPoint; KoPoint dPoint = frameSet()->kWordDocument()->unzoomPoint( nPoint ); KWTextFrameSet::RelativePosition relPos; if ( nPoint.y() > 0 && textFrameSet()->documentToInternalMouseSelection( dPoint, iPoint, relPos ) ) { if ( relPos == KWTextFrameSet::LeftOfFrame ) textView()->extendParagraphSelection( iPoint ); else textView()->handleMouseMoveEvent( e, iPoint ); } } bool KWTextFrameSetEdit::openLink( KoLinkVariable* variable ) { KWTextFrameSet* fs = textFrameSet(); KWDocument* doc = fs->kWordDocument(); if ( doc->getVariableCollection()->variableSetting()->displayLink() ) { const QString url = variable->url(); if( url.startsWith("bkm://") ) { KWBookMark* bookmark = doc->bookMarkByName(url.mid(6) ); if ( bookmark ) { cursor()->setParag( bookmark->startParag() ); ensureCursorVisible(); return true; } } KoTextView::openLink( variable ); return true; } return false; } void KWTextFrameSetEdit::openLink() { KoLinkVariable* v = linkVariable(); if ( v ) openLink( v ); } void KWTextFrameSetEdit::mouseReleaseEvent( QMouseEvent *, const QPoint &, const KoPoint & ) { textView()->handleMouseReleaseEvent(); } void KWTextFrameSetEdit::mouseDoubleClickEvent( QMouseEvent *e, const QPoint &, const KoPoint & ) { textView()->handleMouseDoubleClickEvent( e, QPoint() /* Currently unused */ ); } void KWTextFrameSetEdit::dragEnterEvent( QDragEnterEvent * e ) { if ( !frameSet()->kWordDocument()->isReadWrite() || !KWTextDrag::canDecode( e ) ) { e->ignore(); return; } e->acceptAction(); } void KWTextFrameSetEdit::dragMoveEvent( QDragMoveEvent * e, const QPoint &nPoint, const KoPoint & ) { if ( !frameSet()->kWordDocument()->isReadWrite() || !KWTextDrag::canDecode( e ) ) { e->ignore(); return; } QPoint iPoint; KoPoint dPoint = frameSet()->kWordDocument()->unzoomPoint( nPoint ); if ( textFrameSet()->documentToInternal( dPoint, iPoint ) ) { textObject()->emitHideCursor(); placeCursor( iPoint ); textObject()->emitShowCursor(); e->acceptAction(); // here or out of the if ? } } void KWTextFrameSetEdit::dragLeaveEvent( QDragLeaveEvent * ) { } void KWTextFrameSetEdit::dropEvent( QDropEvent * e, const QPoint & nPoint, const KoPoint & ) { if ( frameSet()->kWordDocument()->isReadWrite() && KWTextDrag::canDecode( e ) ) { e->acceptAction(); KoTextCursor dropCursor( textDocument() ); QPoint dropPoint; KoPoint dPoint = frameSet()->kWordDocument()->unzoomPoint( nPoint ); if ( !textFrameSet()->documentToInternal( dPoint, dropPoint ) ) return; // Don't know where to paste KMacroCommand * macroCmd = 0; dropCursor.place( dropPoint, textDocument()->firstParag() ); kdDebug(32001) << "KWTextFrameSetEdit::dropEvent dropCursor at parag=" << dropCursor.parag()->paragId() << " index=" << dropCursor.index() << endl; if ( ( e->source() == m_canvas || e->source() == m_canvas->viewport() ) && e->action() == QDropEvent::Move ) { // TODO move this to the drag() code - drag() returns true when a move was requested // Probably needed: call acceptAction() here and accept() in the other cases const int numberFrameSet = KWTextDrag::decodeFrameSetNumber( e ); //kdDebug()<<"decodeFrameSetNumber( QMimeSource *e ) :"<kWordDocument()->frameSet( numberFrameSet ); KWFrameSet *frameset= frameSet()->kWordDocument()->textFrameSetFromIndex( numberFrameSet, false ); KWTextFrameSet *tmp=dynamic_cast(frameset); tmp=tmp ? tmp:textFrameSet(); if( tmp ) { bool dropInSameObj= ( tmp == textFrameSet()); KCommand *cmd=textView()->dropEvent(tmp->textObject(), dropCursor, dropInSameObj); if(cmd) { macroCmd = new KMacroCommand(i18n("Move Text")); macroCmd->addCommand(cmd); //relayout textframeset after a dnd otherwise autoextend //frameset is not re-layout tmp->layout(); textFrameSet()->layout(); } else { return; } } } else { // drop coming from outside -> forget about current selection textDocument()->removeSelection( KoTextDocument::Standard ); textObject()->selectionChangedNotify(); } QCString returnedTypeMime; if ( KWTextDrag::provides( e, KoTextObject::acceptSelectionMimeType(),returnedTypeMime )) { QByteArray arr = e->encodedData( returnedTypeMime ); if ( arr.size() ) { KCommand *cmd = textFrameSet()->pasteOasis( cursor(), arr, false ); if ( cmd ) { if ( !macroCmd ) macroCmd = new KMacroCommand(i18n("Paste Text")); macroCmd->addCommand(cmd); } } } else { QString text; if ( QTextDrag::decode( e, text ) ) textObject()->pasteText( cursor(), text, currentFormat(), false ); } if ( macroCmd ) frameSet()->kWordDocument()->addCommand(macroCmd); } } void KWTextFrameSetEdit::focusInEvent() { textView()->focusInEvent(); } void KWTextFrameSetEdit::focusOutEvent() { textView()->focusOutEvent(); } void KWTextFrameSetEdit::selectAll() { textObject()->selectAll( true ); } void KWTextFrameSetEdit::drawCursor( bool visible ) { #ifdef DEBUG_CURSOR kdDebug() << "KWTextFrameSetEdit::drawCursor " << visible << endl; #endif KoTextView::drawCursor( visible ); if ( !cursor()->parag() ) return; if ( !cursor()->parag()->isValid() ) textFrameSet()->ensureFormatted( cursor()->parag() ); if ( !frameSet()->kWordDocument()->isReadWrite() ) return; if ( m_canvas->viewMode()->hasFrames() && !m_currentFrame ) return; QPainter p( m_canvas->viewport() ); p.translate( -m_canvas->contentsX(), -m_canvas->contentsY() ); p.setBrushOrigin( -m_canvas->contentsX(), -m_canvas->contentsY() ); textFrameSet()->drawCursor( &p, cursor(), visible, m_canvas, m_currentFrame ); } bool KWTextFrameSetEdit::pgUpKeyPressed() { QRect crect( m_canvas->contentsX(), m_canvas->contentsY(), m_canvas->visibleWidth(), m_canvas->visibleHeight() ); crect = m_canvas->viewMode()->viewToNormal( crect ); // Go up of 90% of crect.height() int h = frameSet()->kWordDocument()->pixelToLayoutUnitY( (int)( (double)crect.height() * 0.9 ) ); KoTextParag *s = textView()->cursor()->parag(); KoTextParag* oldParag = s; int y = s->rect().y(); while ( s ) { if ( y - s->rect().y() >= h ) break; s = s->prev(); } if ( !s ) s = textDocument()->firstParag(); textView()->cursor()->setParag( s ); textView()->cursor()->setIndex( 0 ); if ( s == oldParag ) { m_canvas->viewportScroll( true ); return false; } return true; } bool KWTextFrameSetEdit::pgDownKeyPressed() { QRect crect( m_canvas->contentsX(), m_canvas->contentsY(), m_canvas->visibleWidth(), m_canvas->visibleHeight() ); crect = m_canvas->viewMode()->viewToNormal( crect ); // Go down of 90% of crect.height() int h = frameSet()->kWordDocument()->pixelToLayoutUnitY( (int)( (double)crect.height() * 0.9 ) ); KoTextCursor *cursor = textView()->cursor(); KoTextParag *s = cursor->parag(); KoTextParag* oldParag = s; int y = s->rect().y(); while ( s ) { if ( s->rect().y() - y >= h ) break; s = s->next(); } if ( !s ) { s = textDocument()->lastParag(); cursor->setParag( s ); cursor->setIndex( s->length() - 1 ); } else { cursor->setParag( s ); cursor->setIndex( 0 ); } if ( s == oldParag ) { m_canvas->viewportScroll( false ); return false; } return true; } void KWTextFrameSetEdit::ctrlPgUpKeyPressed() { if ( m_currentFrame ) { QPoint iPoint = textFrameSet()->moveToPage( m_currentFrame->pageNum(), -1 ); if ( !iPoint.isNull() ) placeCursor( iPoint ); } } void KWTextFrameSetEdit::ctrlPgDownKeyPressed() { if ( m_currentFrame ) { QPoint iPoint = textFrameSet()->moveToPage( m_currentFrame->pageNum(), +1 ); if ( !iPoint.isNull() ) placeCursor( iPoint ); } } void KWTextFrameSetEdit::setCursor( KoTextParag* parag, int index ) { cursor()->setParag( parag ); cursor()->setIndex( index ); } void KWTextFrameSetEdit::insertExpression(const QString &_c) { if(textObject()->hasSelection() ) frameSet()->kWordDocument()->addCommand(textObject()->replaceSelectionCommand( cursor(), _c, KoTextDocument::Standard , i18n("Insert Expression"))); else textObject()->insert( cursor(), currentFormat(), _c, false /* no newline */, true, i18n("Insert Expression") ); } void KWTextFrameSetEdit::insertFloatingFrameSet( KWFrameSet * fs, const QString & commandName ) { textObject()->clearUndoRedoInfo(); CustomItemsMap customItemsMap; QString placeHolders; // TODO support for multiple floating items (like multiple-page tables) int frameNumber = 0; int index = 0; bool ownline = false; { // the loop will start here :) KWAnchor * anchor = fs->createAnchor( textFrameSet()->textDocument(), frameNumber ); if ( frameNumber == 0 && anchor->ownLine() && cursor()->index() > 0 ) // enforce start of line - currently unused { kdDebug() << "ownline -> prepending \\n" << endl; placeHolders += QChar('\n'); index++; ownline = true; } placeHolders += KoTextObject::customItemChar(); customItemsMap.insert( index, anchor ); } fs->setAnchored( textFrameSet() ); textObject()->insert( cursor(), currentFormat(), placeHolders, ownline, false, commandName, customItemsMap ); } void KWTextFrameSetEdit::insertLink(const QString &_linkName, const QString & hrefName) { KWDocument * doc = frameSet()->kWordDocument(); KoVariable * var = new KoLinkVariable( textFrameSet()->textDocument(), _linkName, hrefName, doc->variableFormatCollection()->format( "STRING" ), doc->getVariableCollection() ); insertVariable( var ); } void KWTextFrameSetEdit::insertComment(const QString &_comment) { KWDocument * doc = frameSet()->kWordDocument(); KoVariable * var = new KoNoteVariable( textFrameSet()->textDocument(), _comment, doc->variableFormatCollection()->format( "STRING" ), doc->getVariableCollection() ); insertVariable( var, 0,false/*don't delete selected text*/ ); } void KWTextFrameSetEdit::insertCustomVariable( const QString &name) { KWDocument * doc = frameSet()->kWordDocument(); KoVariable * var = new KoCustomVariable( textFrameSet()->textDocument(), name, doc->variableFormatCollection()->format( "STRING" ), doc->getVariableCollection()); insertVariable( var ); } void KWTextFrameSetEdit::insertFootNote( NoteType noteType, KWFootNoteVariable::Numbering numType, const QString &manualString ) { KWFootNoteFrameSet *fs = textFrameSet()->insertFootNote( noteType, numType, manualString ); KWFootNoteVariable * var = fs->footNoteVariable(); // Place the frame on the correct page, but the exact coordinates // will be determined by recalcFrames (KWFrameLayout) int pageNum = m_currentFrame->pageNum(); fs->createInitialFrame( pageNum ); insertVariable( var ); // Re-number footnote variables textFrameSet()->renumberFootNotes(); // Layout the footnote frame textFrameSet()->kWordDocument()->recalcFrames( pageNum, -1 ); // we know that for sure nothing changed before this page. KWCanvas* canvas = m_canvas; // And now edit the footnote frameset - all WPs do that it seems. m_canvas->editFrameSet( fs ); // --- from here, we are deleted! --- // (This is why we must use canvas and not m_canvas) // Ensure cursor is visible KWTextFrameSetEdit *textedit=dynamic_cast(canvas->currentFrameSetEdit()->currentTextEdit()); if ( textedit ) textedit->ensureCursorVisible(); } void KWTextFrameSetEdit::insertVariable( int type, int subtype ) { kdDebug() << "KWTextFrameSetEdit::insertVariable " << type << endl; KWDocument * doc = frameSet()->kWordDocument(); KoVariable * var = 0L; bool refreshCustomMenu = false; if ( type == VT_CUSTOM ) { KoCustomVarDialog dia( m_canvas ); if ( dia.exec() == QDialog::Accepted ) { KoCustomVariable *v = new KoCustomVariable( textFrameSet()->textDocument(), dia.name(), doc->variableFormatCollection()->format( "STRING" ),doc->getVariableCollection() ); v->setValue( dia.value() ); var = v; refreshCustomMenu = true; } } else if ( type == VT_MAILMERGE ) { KWMailMergeVariableInsertDia dia( m_canvas, doc->getMailMergeDataBase() ); if ( dia.exec() == QDialog::Accepted ) { var = new KWMailMergeVariable( textFrameSet()->textDocument(), dia.getName(), doc->variableFormatCollection()->format( "STRING" ),doc->getVariableCollection(),doc ); } } else var = doc->getVariableCollection()->createVariable( type, subtype, doc->variableFormatCollection(), 0L, textFrameSet()->textDocument(), doc, 0); if ( var) insertVariable( var, 0L /*means currentFormat()*/, true, refreshCustomMenu); } void KWTextFrameSetEdit::insertVariable( KoVariable *var, KoTextFormat *format /*=0*/, bool removeSelectedText, bool refreshCustomMenu ) { if ( var ) { CustomItemsMap customItemsMap; customItemsMap.insert( 0, var ); if (!format) format = currentFormat(); kdDebug() << "KWTextFrameSetEdit::insertVariable inserting into paragraph" << endl; #ifdef DEBUG_FORMATS kdDebug() << "KWTextFrameSetEdit::insertVariable format=" << format << endl; #endif textObject()->insert( cursor(), format, KoTextObject::customItemChar(), false, removeSelectedText, i18n("Insert Variable"), customItemsMap ); frameSet()->kWordDocument()->slotRepaintChanged( frameSet() ); if ( var->type()==VT_CUSTOM && refreshCustomMenu) frameSet()->kWordDocument()->refreshMenuCustomVariable(); } } void KWTextFrameSetEdit::insertWPPage() { KWTextFrameSet* textfs = textFrameSet(); textfs->clearUndoRedoInfo(); KoTextObject* textobj = textObject(); KWDocument * doc = frameSet()->kWordDocument(); int pages = doc->numPages(); int columns = doc->numColumns(); // There could be N columns. In that case we may need to add up to N framebreaks. int inserted = 0; KMacroCommand* macroCmd = new KMacroCommand( i18n("Insert Page") ); do { macroCmd->addCommand( textfs->insertFrameBreakCommand( cursor() ) ); textobj->setLastFormattedParag( cursor()->parag() ); textobj->formatMore( 2 ); } while ( pages == doc->numPages() && ++inserted <= columns ); if ( pages == doc->numPages() ) kdWarning(32002) << k_funcinfo << " didn't manage to insert a new page! inserted=" << inserted << " columns=" << columns << " pages=" << pages << endl; doc->addCommand( macroCmd ); textfs->slotRepaintChanged(); textobj->emitEnsureCursorVisible(); textobj->emitUpdateUI( true ); textobj->emitShowCursor(); } // Update the GUI toolbar button etc. to reflect the current cursor position. void KWTextFrameSetEdit::updateUI( bool updateFormat, bool force ) { // Update UI - only for those items which have changed KoTextView::updateUI( updateFormat, force ); // Paragraph settings KWTextParag * parag = static_cast(cursor()->parag()); if ( m_paragLayout.alignment != parag->resolveAlignment() || force ) { m_paragLayout.alignment = parag->resolveAlignment(); m_canvas->gui()->getView()->showAlign( m_paragLayout.alignment ); } // Counter if ( !m_paragLayout.counter ) m_paragLayout.counter = new KoParagCounter; // we can afford to always have one here KoParagCounter::Style cstyle = m_paragLayout.counter->style(); if ( parag->counter() ) *m_paragLayout.counter = *parag->counter(); else { m_paragLayout.counter->setNumbering( KoParagCounter::NUM_NONE ); m_paragLayout.counter->setStyle( KoParagCounter::STYLE_NONE ); } if ( m_paragLayout.counter->style() != cstyle || force ) m_canvas->gui()->getView()->showCounter( * m_paragLayout.counter ); if(m_paragLayout.leftBorder!=parag->leftBorder() || m_paragLayout.rightBorder!=parag->rightBorder() || m_paragLayout.topBorder!=parag->topBorder() || m_paragLayout.bottomBorder!=parag->bottomBorder() || force ) { m_paragLayout.leftBorder = parag->leftBorder(); m_paragLayout.rightBorder = parag->rightBorder(); m_paragLayout.topBorder = parag->topBorder(); m_paragLayout.bottomBorder = parag->bottomBorder(); m_canvas->gui()->getView()->showParagBorders( m_paragLayout.leftBorder, m_paragLayout.rightBorder, m_paragLayout.topBorder, m_paragLayout.bottomBorder ); } if ( !parag->style() ) kdWarning() << "Paragraph " << parag->paragId() << " has no style" << endl; else if ( m_paragLayout.style != parag->style() || force ) { m_paragLayout.style = parag->style(); m_canvas->gui()->getView()->showStyle( m_paragLayout.style->name() ); } if( m_paragLayout.margins[QStyleSheetItem::MarginLeft] != parag->margin(QStyleSheetItem::MarginLeft) || m_paragLayout.margins[QStyleSheetItem::MarginFirstLine] != parag->margin(QStyleSheetItem::MarginFirstLine) || m_paragLayout.margins[QStyleSheetItem::MarginRight] != parag->margin(QStyleSheetItem::MarginRight) || parag->string()->isRightToLeft() != m_rtl || force ) { m_paragLayout.margins[QStyleSheetItem::MarginFirstLine] = parag->margin(QStyleSheetItem::MarginFirstLine); m_paragLayout.margins[QStyleSheetItem::MarginLeft] = parag->margin(QStyleSheetItem::MarginLeft); m_paragLayout.margins[QStyleSheetItem::MarginRight] = parag->margin(QStyleSheetItem::MarginRight); if ( m_rtl != parag->string()->isRightToLeft() && parag->counter() ) { parag->counter()->invalidate(); parag->setChanged( true ); // repaint } m_rtl = parag->string()->isRightToLeft(); m_canvas->gui()->getView()->showRulerIndent( m_paragLayout.margins[QStyleSheetItem::MarginLeft], m_paragLayout.margins[QStyleSheetItem::MarginFirstLine], m_paragLayout.margins[QStyleSheetItem::MarginRight], m_rtl ); } if( m_paragLayout.tabList() != parag->tabList() || force) { m_paragLayout.setTabList( parag->tabList() ); KoRuler * hr = m_canvas->gui()->getHorzRuler(); if ( hr ) hr->setTabList( parag->tabList() ); } // There are more paragraph settings, but those that are not directly // visible in the UI don't need to be handled here. // For instance parag and line spacing stuff, borders etc. } void KWTextFrameSetEdit::showFormat( KoTextFormat *format ) { m_canvas->gui()->getView()->showFormat( *format ); } void KWTextFrameSetEdit::showPopup( KWFrame * /*frame*/, KWView *view, const QPoint &point ) { QString word = wordUnderCursor( *cursor() ); // Remove previous stuff view->unplugActionList( "datatools" ); view->unplugActionList( "variable_action" ); view->unplugActionList( "spell_result_action" ); view->unplugActionList( "datatools_link" ); // Those lists are stored in the KWView. Grab a ref to them. QPtrList &actionList = view->dataToolActionList(); QPtrList &variableList = view->variableActionList(); actionList.clear(); variableList.clear(); bool singleWord= false; KWDocument * doc = frameSet()->kWordDocument(); actionList = dataToolActionList(doc->instance(), word, singleWord); KoVariable* var = variable(); doc->getVariableCollection()->setVariableSelected(var); if ( var ) { variableList = doc->getVariableCollection()->popupActionList(); } if( variableList.count()>0) { view->plugActionList( "variable_action", variableList ); QPopupMenu * popup = view->popupMenu("variable_popup"); Q_ASSERT(popup); if (popup) popup->popup( point ); // using exec() here breaks the spellcheck tool (event loop pb) } else { kdDebug() << "showPopup: plugging actionlist with " << actionList.count() << " actions" << endl; KoLinkVariable* linkVar = dynamic_cast( var ); QPopupMenu * popup; if ( !linkVar ) { view->plugActionList( "datatools", actionList ); KoNoteVariable * noteVar = dynamic_cast( var ); KoCustomVariable * customVar = dynamic_cast( var ); KWFootNoteVariable * footNoteVar = dynamic_cast( var ); if( noteVar ) popup = view->popupMenu("comment_popup"); else if( customVar ) popup = view->popupMenu("custom_var_popup"); else if ( footNoteVar ) { view->changeFootNoteMenuItem( footNoteVar->noteType() == FootNote ); popup = view->popupMenu("footnote_popup"); } else { if ( singleWord ) { QPtrList actionCheckSpellList = view->listOfResultOfCheckWord( word ); if ( !actionCheckSpellList.isEmpty() ) { view->plugActionList( "spell_result_action", actionCheckSpellList ); popup = view->popupMenu("text_popup_spell_with_result"); } else popup = view->popupMenu("text_popup_spell"); } else popup = view->popupMenu("text_popup"); } } else { view->plugActionList( "datatools_link", actionList ); popup = view->popupMenu("text_popup_link"); } Q_ASSERT(popup); if (popup) popup->popup( point ); // using exec() here breaks the spellcheck tool (event loop pb) } } QPoint KWTextFrameSet::cursorPos( KoTextCursor *cursor, KWCanvas* canvas, KWFrame* currentFrame ) { KWViewMode *viewMode = canvas->viewMode(); KoTextParag* parag = cursor->parag(); const QPoint topLeft = parag->rect().topLeft(); // in QRT coords int lineY; parag->lineHeightOfChar( cursor->index(), 0, &lineY ); // iPoint is the topright corner of the current character QPoint iPoint( topLeft.x() + cursor->x() + parag->at( cursor->index() )->width, topLeft.y() + lineY ); KoPoint dPoint; QPoint vPoint; KoPoint hintDPoint = currentFrame ? currentFrame->innerRect().topLeft() : KoPoint(); if ( internalToDocumentWithHint( iPoint, dPoint, hintDPoint ) ) { vPoint = viewMode->normalToView( m_doc->zoomPoint( dPoint ) ); // from doc to view contents vPoint.rx() -= canvas->contentsX(); vPoint.ry() -= canvas->contentsY(); } // else ... ? return vPoint; } ////// bool KWFootNoteFrameSet::isFootNote() const { if ( !m_footNoteVar ) { kdWarning() << k_funcinfo << " called too early? No footnote var." << endl; return false; } return ( m_footNoteVar->noteType() == FootNote ); } bool KWFootNoteFrameSet::isEndNote() const { if ( !m_footNoteVar ) { kdWarning() << k_funcinfo << " called too early? No footnote var." << endl; return false; } return ( m_footNoteVar->noteType() == EndNote ); } void KWFootNoteFrameSet::createInitialFrame( int pageNum ) { KWFrame *frame = new KWFrame(this, 0, pageNum * m_doc->ptPaperHeight() + 1, 20, 20 ); frame->setFrameBehavior(KWFrame::AutoExtendFrame); frame->setNewFrameBehavior(KWFrame::NoFollowup); addFrame( frame ); } void KWFootNoteFrameSet::setFootNoteVariable( KWFootNoteVariable* var ) { m_footNoteVar = var; } void KWFootNoteFrameSet::setCounterText( const QString& text ) { KoTextParag* parag = textDocument()->firstParag(); Q_ASSERT( parag ); if ( parag ) { KoParagCounter counter; counter.setNumbering( KoParagCounter::NUM_FOOTNOTE ); counter.setPrefix( text ); counter.setSuffix( QString::null ); parag->setCounter( counter ); } } KWordFrameSetIface* KWFootNoteFrameSet::dcopObject() { if ( !m_dcop ) m_dcop = new KWFootNoteFrameSetIface( this ); return m_dcop; } #include "kwtextframeset.moc" diff --git a/kword/kwview.cc b/kword/kwview.cc index d2c8af2528..055785e67c 100644 --- a/kword/kwview.cc +++ b/kword/kwview.cc @@ -1,7875 +1,7875 @@ /* This file is part of the KDE project Copyright (C) 1998, 1999 Reginald Stadlbauer Copyright (C) 2001 David Faure 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 */ #undef Unsorted #include "kwview.h" #include "KWordViewIface.h" #include "configfootnotedia.h" #include "defs.h" #include "deldia.h" #include "docstruct.h" #include "footnotedia.h" #include "insdia.h" #include "kwanchor.h" #include "kwbookmark.h" #include "kwcanvas.h" #include "kwcommand.h" #include "kwconfig.h" #include "kwcreatebookmarkdia.h" #include "kwdoc.h" #include "kwdrag.h" #include "kweditpersonnalexpressiondia.h" #include "kwformulaframe.h" #include "kwframe.h" #include "kwframestyle.h" #include "kwframestylemanager.h" #include "kwimportstyledia.h" #include "kwinserthorizontallinedia.h" #include "kwinsertpagedia.h" #include "kwinsertpicdia.h" #include "kwpartframeset.h" #include "kwstylemanager.h" #include "kwtableframeset.h" #include "kwtablestyle.h" #include "kwtablestylemanager.h" #include "kwtextdocument.h" #include "kwvariable.h" #include "kwviewmode.h" #include "mailmerge.h" #include "mailmerge_actions.h" #include "resizetabledia.h" #include "searchdia.h" #include "sortdia.h" #include "splitcellsdia.h" #include "tabledia.h" #include "paragvisitors.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_LIBKSPELL2 #include #include #include "kospell.h" using namespace KSpell2; #endif KWView::KWView( KWViewMode* viewMode, QWidget *_parent, const char *_name, KWDocument* _doc ) : KoView( _doc, _parent, _name ) { m_doc = _doc; m_gui = 0; dcop = 0; dcopObject(); // build it fsInline=0L; m_spell.kospell = 0; #ifdef HAVE_LIBKSPELL2 m_spell.dlg = 0; m_broker = Broker::openBroker( KSharedConfig::openConfig( "kwordrc" ) ); #endif m_spell.macroCmdSpellCheck=0L; m_spell.textIterator = 0L; m_border.left.color = white; m_border.left.setStyle (KoBorder::SOLID); m_border.left.setPenWidth( 0); m_border.right = m_border.left; m_border.top = m_border.left; m_border.bottom = m_border.left; m_border.common.color = black; m_border.common.setStyle(KoBorder::SOLID); m_border.common.setPenWidth( 1); m_currentPage = 0; m_specialCharDlg=0L; m_searchEntry = 0L; m_replaceEntry = 0L; m_findReplace = 0L; m_fontDlg = 0L; m_paragDlg = 0L; m_actionList.setAutoDelete( true ); m_variableActionList.setAutoDelete( true ); // Default values. m_zoomViewModeNormal = m_doc->zoom(); m_zoomViewModePreview = 33; m_viewFrameBorders = m_doc->viewFrameBorders(); KoView::setZoom( m_doc->zoomedResolutionY() /* KoView only supports one zoom */ ); // initial value //m_viewTableGrid = true; setInstance( KWFactory::global() ); if ( !m_doc->isReadWrite() ) setXMLFile( "kword_readonly.rc" ); else setXMLFile( "kword.rc" ); QObject::connect( this, SIGNAL( embeddImage( const QString & ) ), this, SLOT( slotEmbedImage( const QString & ) ) ); setKeyCompression( TRUE ); setAcceptDrops( TRUE ); setupActions(); m_gui = new KWGUI( viewMode, this, this ); m_gui->setGeometry( 0, 0, width(), height() ); m_gui->show(); KStatusBar * sb = statusBar(); m_sbPageLabel = 0L; if ( sb ) // No statusbar in e.g. konqueror { m_sbPageLabel = new KStatusBarLabel( QString::null, 0, sb ); addStatusBarItem( m_sbPageLabel, 0 ); } m_sbFramesLabel = 0L; // Only added when frames are selected connect( m_doc, SIGNAL( pageNumChanged() ), this, SLOT( pageNumChanged()) ); connect( m_doc, SIGNAL( pageLayoutChanged( const KoPageLayout& ) ), this, SLOT( slotPageLayoutChanged( const KoPageLayout& )) ); connect( m_doc, SIGNAL( docStructureChanged(int) ), this, SLOT( docStructChanged(int)) ); connect( m_doc, SIGNAL( sig_refreshMenuCustomVariable()), this, SLOT( refreshCustomMenu())); connect( m_doc, SIGNAL(sig_frameSelectedChanged()), this, SLOT( frameSelectedChanged())); connect( QApplication::clipboard(), SIGNAL( dataChanged() ), this, SLOT( clipboardDataChanged() ) ); connect( m_gui->canvasWidget(), SIGNAL(currentFrameSetEditChanged()), this, SLOT(slotFrameSetEditChanged()) ); connect( m_gui->canvasWidget(), SIGNAL( currentMouseModeChanged(int) ), this, SLOT( showMouseMode(int) ) ); // Cut and copy are directly connected to the selectionChanged signal if ( m_doc->isReadWrite() ) { connect( m_gui->canvasWidget(), SIGNAL(selectionChanged(bool)), this, SLOT(slotChangeCutState(bool )) ); connect (m_gui->canvasWidget(), SIGNAL(selectionChanged(bool)), this, SLOT(slotChangeCaseState(bool ))); } else { actionEditCut->setEnabled( false ); actionChangeCase->setEnabled( false ); } connect( m_gui->canvasWidget(), SIGNAL(selectionChanged(bool)), actionEditCopy, SLOT(setEnabled(bool)) ); //connect (m_gui->canvasWidget(), SIGNAL(selectionChanged(bool)), // actionCreateStyleFromSelection, SLOT(setEnabled(bool))); connect (m_gui->canvasWidget(), SIGNAL(selectionChanged(bool)), actionConvertToTextBox, SLOT(setEnabled(bool))); connect (m_gui->canvasWidget(), SIGNAL(selectionChanged(bool)), actionAddPersonalExpression, SLOT(setEnabled(bool ))); connect (m_gui->canvasWidget(), SIGNAL(selectionChanged(bool)), actionSortText, SLOT(setEnabled(bool ))); connect( m_gui->canvasWidget(), SIGNAL(frameSelectedChanged()), this, SLOT(frameSelectedChanged())); connect( m_gui->canvasWidget(), SIGNAL(docStructChanged(int)), this, SLOT(docStructChanged(int))); connect( m_gui->canvasWidget(), SIGNAL(updateRuler()), this, SLOT(slotUpdateRuler())); if ( shell() ) { connect( shell(), SIGNAL( documentSaved()), m_doc,SLOT(slotDocumentInfoModifed() ) ); changeNbOfRecentFiles( m_doc->maxRecentFiles() ); } m_gui->canvasWidget()->updateCurrentFormat(); setFocusProxy( m_gui->canvasWidget() ); //when kword is embedded into konqueror apply a zoom=100 //in konqueror we can't change zoom -- ### TODO ? if(!m_doc->isReadWrite()) { setZoom( 100, true ); slotUpdateRuler(); initGui(); } // Determine initial scroll position // We do this delayed, so that the GUI has been fully constructed // (and e.g. the statusbar can repaint). QTimer::singleShot( 0, this, SLOT( slotSetInitialPosition() ) ); } KWView::~KWView() { delete m_tableActionList.first(); // the first one is the separator. clearSpellChecker(); delete m_searchEntry; m_searchEntry = 0L; delete m_replaceEntry; m_replaceEntry = 0L; if ( m_specialCharDlg ) m_specialCharDlg->closeDialog(); // will call slotSpecialCharDlgClosed // Abort any find/replace delete m_findReplace; deselectAllFrames(); // don't let resizehandles hang around // Delete gui while we still exist ( it needs documentDeleted() ) delete m_gui; delete m_sbPageLabel; delete fsInline; delete dcop; delete m_fontDlg; delete m_paragDlg; } DCOPObject* KWView::dcopObject() { if ( !dcop ) dcop = new KWordViewIface( this ); return dcop; } void KWView::slotChangeCutState(bool b) { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit && edit->textFrameSet()->protectContent()) actionEditCut->setEnabled( false ); else actionEditCut->setEnabled( b ); } void KWView::slotChangeCaseState(bool b) { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit && edit->textFrameSet()->protectContent()) actionChangeCase->setEnabled( false ); else actionChangeCase->setEnabled( b ); } void KWView::slotSetInitialPosition() { KWTextFrameSetEdit* textedit = dynamic_cast(m_gui->canvasWidget()->currentFrameSetEdit()); if ( textedit ) textedit->ensureCursorVisible(); else m_gui->canvasWidget()->setContentsPos( 0, 0 ); } void KWView::changeNbOfRecentFiles(int _nb) { if ( shell() ) // 0 when embedded into konq ! shell()->setMaxRecentItems( _nb ); } void KWView::initGui() { clipboardDataChanged(); if ( m_gui ) m_gui->showGUI(); showMouseMode( KWCanvas::MM_EDIT ); initGUIButton(); actionFormatDecreaseIndent->setEnabled(false); //setNoteType(m_doc->getNoteType(), false); actionFormatColor->setCurrentColor( Qt::black ); //refresh zoom combobox changeZoomMenu( m_doc->zoom() ); showZoom( m_doc->zoom() ); // This is probably to emit currentMouseModeChanged and set the cursor m_gui->canvasWidget()->setMouseMode( m_gui->canvasWidget()->mouseMode() ); - showFormulaToolbar( FALSE ); // not called, to avoid creating the formula-document if not necessary + //showFormulaToolbar( FALSE ); // not called, to avoid creating the formula-document if not necessary if(shell()) shell()->showToolbar( "formula_toolbar", false ); // Prevention against applyMainWindowSettings hiding the statusbar KStatusBar * sb = statusBar(); if ( sb ) sb->show(); updatePageInfo(); slotFrameSetEditChanged(); frameSelectedChanged(); renameButtonTOC(m_doc->isTOC()); //at the beginning actionBackgroundColor should be active actionBackgroundColor->setEnabled(true); updateBgSpellCheckingState(); updateDirectCursorButton(); actionCreateFrameStyle->setEnabled(false); } void KWView::updateBgSpellCheckingState() { actionAllowBgSpellCheck->setChecked( m_doc->backgroundSpellCheckEnabled() ); } void KWView::initGUIButton() { actionViewFrameBorders->setChecked( viewFrameBorders() ); actionViewFormattingChars->setChecked( m_doc->viewFormattingChars() ); actionShowDocStruct->setChecked(m_doc->showdocStruct()); actionShowRuler->setChecked(m_doc->showRuler()); updateHeaderFooterButton(); actionAllowAutoFormat->setChecked( m_doc->allowAutoFormat() ); QString mode=m_gui->canvasWidget()->viewMode()->type(); if(mode=="ModePreview") actionViewPreviewMode->setChecked(true); else if(mode=="ModeText") actionViewTextMode->setChecked(true); else if(mode=="ModeNormal") actionViewPageMode->setChecked(true); else actionViewPageMode->setChecked(true); switchModeView(); } void KWView::setupActions() { // The actions here are grouped by menu, because this helps noticing // accelerator clashes. // -------------- File menu actionExtraCreateTemplate = new KAction( i18n( "&Create Template From Document..." ), 0, this, SLOT( extraCreateTemplate() ), actionCollection(), "extra_template" ); actionExtraCreateTemplate->setToolTip( i18n( "Save this document and use it later as a template" ) ); actionExtraCreateTemplate->setWhatsThis( i18n( "You can save this document as a template.

You can use this new template as a starting point for another document." ) ); actionFileStatistics = new KAction( i18n( "Statistics" ), 0, this, SLOT( fileStatistics() ), actionCollection(), "file_statistics" ); actionFileStatistics->setToolTip( i18n( "Sentence, word and letter counts for this document" ) ); actionFileStatistics->setWhatsThis( i18n( "Information on the number of letters, words, syllables and sentences for this document.

Evaluates readability using the Flesch reading score." ) ); // -------------- Edit actions actionEditCut = KStdAction::cut( this, SLOT( editCut() ), actionCollection(), "edit_cut" ); actionEditCopy = KStdAction::copy( this, SLOT( editCopy() ), actionCollection(), "edit_copy" ); actionEditPaste = KStdAction::paste( this, SLOT( editPaste() ), actionCollection(), "edit_paste" ); actionEditFind = KStdAction::find( this, SLOT( editFind() ), actionCollection(), "edit_find" ); actionEditFindNext = KStdAction::findNext( this, SLOT( editFindNext() ), actionCollection(), "edit_findnext" ); actionEditFindPrevious = KStdAction::findPrev( this, SLOT( editFindPrevious() ), actionCollection(), "edit_findprevious" ); actionEditReplace = KStdAction::replace( this, SLOT( editReplace() ), actionCollection(), "edit_replace" ); actionEditSelectAll = KStdAction::selectAll( this, SLOT( editSelectAll() ), actionCollection(), "edit_selectall" ); new KAction( i18n( "Select All Frames" ), 0, this, SLOT( editSelectAllFrames() ), actionCollection(), "edit_selectallframes" ); actionSpellCheck = KStdAction::spelling( this, SLOT( slotSpellCheck() ), actionCollection(), "extra_spellcheck" ); actionDeletePage = new KAction( i18n( "Delete Page" ), "delslide", 0, this, SLOT( deletePage() ), actionCollection(), "delete_page" ); kdDebug() << m_doc->numPages() << " " << (m_doc->processingType() == KWDocument::DTP) << endl; (void) new KAction( i18n( "Configure Mai&l Merge..." ), "configure",0, this, SLOT( editMailMergeDataBase() ), actionCollection(), "edit_sldatabase" ); (void) new KWMailMergeLabelAction::KWMailMergeLabelAction( i18n("Drag Mail Merge Variable"), 0, this, SLOT(editMailMergeDataBase()), actionCollection(), "mailmerge_draglabel" ); // (void) new KWMailMergeComboAction::KWMailMergeComboAction(i18n("Insert Mailmerge Var"),0,this,SLOT(JWJWJW()),actionCollection(),"mailmerge_varchooser"); // -------------- Frame menu actionEditDelFrame = new KAction( i18n( "&Delete Frame" ), 0, this, SLOT( editDeleteFrame() ), actionCollection(), "edit_delframe" ); actionEditDelFrame->setToolTip( i18n( "Delete the currently selected frame(s)." ) ); actionEditDelFrame->setWhatsThis( i18n( "Delete the currently selected frame(s)." ) ); actionCreateLinkedFrame = new KAction( i18n( "Create Linked Copy" ), 0, this, SLOT( createLinkedFrame() ), actionCollection(), "create_linked_frame" ); actionCreateLinkedFrame->setToolTip( i18n( "Create a copy of the current frame, always showing the same contents" ) ); actionCreateLinkedFrame->setWhatsThis( i18n("Create a copy of the current frame, that remains linked to it. This means they always show the same contents: modifying the contents in such a frame will update all its linked copies.") ); actionRaiseFrame = new KAction( i18n( "Ra&ise Frame" ), "raise", CTRL +SHIFT+ Key_R, this, SLOT( raiseFrame() ), actionCollection(), "raiseframe" ); actionRaiseFrame->setToolTip( i18n( "Raise the currently selected frame so that it appears above all the other frames" ) ); actionRaiseFrame->setWhatsThis( i18n( "Raise the currently selected frame so that it appears above all the other frames. This is only useful if frames overlap each other. If multiple frames are selected they are all raised in turn." ) ); actionLowerFrame = new KAction( i18n( "&Lower Frame" ), "lower", CTRL +SHIFT+ Key_L, this, SLOT( lowerFrame() ), actionCollection(), "lowerframe" ); actionLowerFrame->setToolTip( i18n( "Lower the currently selected frame so that it disappears under any frame that overlaps it" ) ); actionLowerFrame->setWhatsThis( i18n( "Lower the currently selected frame so that it disappears under any frame that overlaps it. If multiple frames are selected they are all lowered in turn." ) ); actionBringToFront= new KAction( i18n( "Bring to Front" ), "bring_forward", 0, this, SLOT( bringToFront() ), actionCollection(), "bring_tofront_frame" ); actionSendBackward= new KAction( i18n( "Send to Back" ), "send_backward", 0, this, SLOT( sendToBack() ), actionCollection(), "send_toback_frame" ); // -------------- View menu actionViewTextMode = new KToggleAction( i18n( "Text Mode" ), 0, this, SLOT( viewTextMode() ), actionCollection(), "view_textmode" ); actionViewTextMode->setToolTip( i18n( "Only show the text of the document." ) ); actionViewTextMode->setWhatsThis( i18n( "Do not show any pictures, formatting or layout. KWord will display only the text for editing." ) ); actionViewTextMode->setExclusiveGroup( "viewmodes" ); actionViewPageMode = new KToggleAction( i18n( "&Page Mode" ), 0, this, SLOT( viewPageMode() ), actionCollection(), "view_pagemode" ); actionViewPageMode->setWhatsThis( i18n( "Switch to page mode.

Page mode is designed to make editing your text easy.

This function is most frequently used to return to text editing after switching to preview mode." ) ); actionViewPageMode->setToolTip( i18n( "Switch to page editing mode." ) ); actionViewPageMode->setExclusiveGroup( "viewmodes" ); actionViewPageMode->setChecked( true ); actionViewPreviewMode = new KToggleAction( i18n( "Pre&view Mode" ), 0, this, SLOT( viewPreviewMode() ), actionCollection(), "view_previewmode" ); actionViewPreviewMode->setWhatsThis( i18n( "Zoom out from your document to get a look at several pages of your document.

The number of pages per line can be customized." ) ); actionViewPreviewMode->setToolTip( i18n( "Zoom out to a multiple page view." ) ); actionViewPreviewMode->setExclusiveGroup( "viewmodes" ); actionViewFormattingChars = new KToggleAction( i18n( "&Formatting Characters" ), 0, this, SLOT( slotViewFormattingChars() ), actionCollection(), "view_formattingchars" ); actionViewFormattingChars->setToolTip( i18n( "Toggle the display of non-printing characters." ) ); actionViewFormattingChars->setWhatsThis( i18n( "Toggle the display of non-printing characters.

When this is enabled, KWord shows you tabs, spaces, carriage returns and other non-printing characters." ) ); actionViewFrameBorders = new KToggleAction( i18n( "Frame &Borders" ), 0, this, SLOT( slotViewFrameBorders() ), actionCollection(), "view_frameborders" ); actionViewFrameBorders->setToolTip( i18n( "Turns the border display on and off." ) ); actionViewFrameBorders->setWhatsThis( i18n( "Turns the border display on and off.

The borders are never printed. This option is useful to see how the document will appear on the printed page." ) ); actionViewHeader = new KToggleAction( i18n( "Show &Header" ), 0, this, SLOT( viewHeader() ), actionCollection(), "format_header" ); #if KDE_IS_VERSION(3,2,90) actionViewHeader->setCheckedState(i18n("Hide &Header")); #endif actionViewHeader->setToolTip( i18n( "Shows and hides header display." ) ); actionViewHeader->setWhatsThis( i18n( "Selecting this option toggles the display of headers in KWord.

Headers are special frames at the top of each page which can contain page numbers or other information." ) ); actionViewFooter = new KToggleAction( i18n( "Show Foo&ter" ), 0, this, SLOT( viewFooter() ), actionCollection(), "format_footer" ); #if KDE_IS_VERSION(3,2,90) actionViewFooter->setCheckedState(i18n("Hide Foo&ter")); #endif actionViewFooter->setToolTip( i18n( "Shows and hides footer display." ) ); actionViewFooter->setWhatsThis( i18n( "Selecting this option toggles the display of footers in KWord.

Footers are special frames at the bottom of each page which can contain page numbers or other information." ) ); actionViewZoom = new KSelectAction( i18n( "Zoom" ), "viewmag", 0, actionCollection(), "view_zoom" ); connect( actionViewZoom, SIGNAL( activated( const QString & ) ), this, SLOT( viewZoom( const QString & ) ) ); actionViewZoom->setEditable(true); changeZoomMenu( ); // -------------- Insert menu actionInsertSpecialChar = new KAction( i18n( "Sp&ecial Character..." ), "char", ALT + SHIFT + Key_C, this, SLOT( insertSpecialChar() ), actionCollection(), "insert_specialchar" ); actionInsertSpecialChar->setToolTip( i18n( "Insert one or more symbols or letters not found on the keyboard." ) ); actionInsertSpecialChar->setWhatsThis( i18n( "Insert one or more symbols or letters not found on the keyboard." ) ); actionInsertFrameBreak = new KAction( QString::null, CTRL + Key_Return, this, SLOT( insertFrameBreak() ), actionCollection(), "insert_framebreak" ); if ( m_doc->processingType() == KWDocument::WP ) { actionInsertFrameBreak->setText( i18n( "Page Break" ) ); actionInsertFrameBreak->setToolTip( i18n( "Force the remainder of the text into the next page." ) ); actionInsertFrameBreak->setWhatsThis( i18n( "This inserts a non-printing character at the current cursor position. All text after this point will be moved into the next page." ) ); } else { actionInsertFrameBreak->setText( i18n( "&Hard Frame Break" ) ); actionInsertFrameBreak->setToolTip( i18n( "Force the remainder of the text into the next frame." ) ); actionInsertFrameBreak->setWhatsThis( i18n( "This inserts a non-printing character at the current cursor position. All text after this point will be moved into the next frame in the frameset." ) ); } /*actionInsertPage =*/ new KAction( m_doc->processingType() == KWDocument::WP ? i18n( "Page" ) : i18n( "Page..." ), "page", 0, this, SLOT( insertPage() ), actionCollection(), "insert_page" ); actionInsertLink = new KAction( i18n( "Link..." ), 0, this, SLOT( insertLink() ), actionCollection(), "insert_link" ); actionInsertLink->setToolTip( i18n( "Insert a Web address, email address or hyperlink to a file." ) ); actionInsertLink->setWhatsThis( i18n( "Insert a Web address, email address or hyperlink to a file." ) ); actionInsertComment = new KAction( i18n( "Comment..." ), 0, this, SLOT( insertComment() ), actionCollection(), "insert_comment" ); actionInsertComment->setToolTip( i18n( "Insert a comment about the selected text." ) ); actionInsertComment->setWhatsThis( i18n( "Insert a comment about the selected text. These comments are not designed to appear on the final page." ) ); actionEditComment = new KAction( i18n("Edit Comment..."), 0, this,SLOT(editComment()), actionCollection(), "edit_comment"); actionEditComment->setToolTip( i18n( "Change the content of a comment." ) ); actionEditComment->setWhatsThis( i18n( "Change the content of a comment." ) ); actionRemoveComment = new KAction( i18n("Remove Comment"), 0, this,SLOT(removeComment()), actionCollection(), "remove_comment"); actionRemoveComment->setToolTip( i18n( "Remove the selected document comment." ) ); actionRemoveComment->setWhatsThis( i18n( "Remove the selected document comment." ) ); actionCopyTextOfComment = new KAction( i18n("Copy Text of Comment..."), 0, this,SLOT(copyTextOfComment()), actionCollection(), "copy_text_comment"); actionInsertFootEndNote = new KAction( i18n( "&Footnote/Endnote..." ), 0, this, SLOT( insertFootNote() ), actionCollection(), "insert_footendnote" ); actionInsertFootEndNote->setToolTip( i18n( "Insert a footnote referencing the selected text." ) ); actionInsertFootEndNote->setWhatsThis( i18n( "Insert a footnote referencing the selected text." ) ); actionInsertContents = new KAction( i18n( "Table of &Contents" ), 0, this, SLOT( insertContents() ), actionCollection(), "insert_contents" ); actionInsertContents->setToolTip( i18n( "Insert table of contents at the current cursor position." ) ); actionInsertContents->setWhatsThis( i18n( "Insert table of contents at the current cursor position." ) ); m_variableDefMap.clear(); actionInsertVariable = new KActionMenu( i18n( "&Variable" ), actionCollection(), "insert_variable" ); // The last argument is only needed if a submenu is to be created addVariableActions( VT_FIELD, KoFieldVariable::actionTexts(), actionInsertVariable, i18n("Document &Information") ); addVariableActions( VT_DATE, KoDateVariable::actionTexts(), actionInsertVariable, i18n("&Date") ); addVariableActions( VT_TIME, KoTimeVariable::actionTexts(), actionInsertVariable, i18n("&Time") ); addVariableActions( VT_PGNUM, KoPageVariable::actionTexts(), actionInsertVariable, i18n("&Page") ); addVariableActions( VT_STATISTIC, KWStatisticVariable::actionTexts(), actionInsertVariable, i18n("&Statistic") ); actionInsertCustom = new KActionMenu( i18n( "&Custom" ), actionCollection(), "insert_custom" ); actionInsertVariable->insert(actionInsertCustom); //addVariableActions( VT_CUSTOM, KWCustomVariable::actionTexts(), actionInsertVariable, QString::null ); addVariableActions( VT_MAILMERGE, KoMailMergeVariable::actionTexts(), actionInsertVariable, QString::null ); actionInsertVariable->popupMenu()->insertSeparator(); actionRefreshAllVariable = new KAction( i18n( "&Refresh All Variables" ), 0, this, SLOT( refreshAllVariable() ), actionCollection(), "refresh_all_variable" ); actionRefreshAllVariable->setToolTip( i18n( "Update all variables to current values." ) ); actionRefreshAllVariable->setWhatsThis( i18n( "Update all variables in the document to current values.

This will update page numbers, dates or any other variables that need updating." ) ); actionInsertVariable->insert(actionRefreshAllVariable); actionInsertExpression = new KActionMenu( i18n( "&Expression" ), actionCollection(), "insert_expression" ); loadexpressionActions( actionInsertExpression); actionToolsCreateText = new KToggleAction( i18n( "Te&xt Frame" ), "frame_text", Key_F10 /*same as kpr*/, this, SLOT( toolsCreateText() ), actionCollection(), "tools_createtext" ); actionToolsCreateText->setToolTip( i18n( "Create a new text frame." ) ); actionToolsCreateText->setWhatsThis( i18n( "Create a new text frame." ) ); actionToolsCreateText->setExclusiveGroup( "tools" ); actionInsertFormula = new KAction( i18n( "For&mula" ), "frame_formula", Key_F4, this, SLOT( insertFormula() ), actionCollection(), "tools_formula" ); actionInsertFormula->setToolTip( i18n( "Insert a formula into a new frame." ) ); actionInsertFormula->setWhatsThis( i18n( "Insert a formula into a new frame." ) ); actionInsertTable = new KAction( i18n( "&Table..." ), "inline_table", Key_F5, this, SLOT( insertTable() ), actionCollection(), "insert_table" ); actionInsertTable->setToolTip( i18n( "Create a table." ) ); actionInsertTable->setWhatsThis( i18n( "Create a table.

The table can either exist in a frame of its own or inline." ) ); actionToolsCreatePix = new KToggleAction( i18n( "P&icture..." ), "frame_image", // or inline_image ? SHIFT + Key_F5 /*same as kpr*/, this, SLOT( insertPicture() ), actionCollection(), "insert_picture" ); actionToolsCreatePix->setToolTip( i18n( "Create a new frame for a picture." ) ); actionToolsCreatePix->setWhatsThis( i18n( "Create a new frame for a picture or diagram." ) ); actionToolsCreatePix->setExclusiveGroup( "tools" ); actionToolsCreatePart = new KoPartSelectAction( i18n( "&Object Frame" ), "frame_query", this, SLOT( toolsPart() ), actionCollection(), "tools_part" ); actionToolsCreatePart->setToolTip( i18n( "Insert an object into a new frame." ) ); actionToolsCreatePart->setWhatsThis( i18n( "Insert an object into a new frame." ) ); actionInsertFile = new KAction( i18n( "Fi&le..." ), 0, this, SLOT( insertFile() ), actionCollection(), "insert_file" ); // ------------------------- Format menu actionFormatFont = new KAction( i18n( "&Font..." ), ALT + CTRL + Key_F, this, SLOT( formatFont() ), actionCollection(), "format_font" ); actionFormatFont->setToolTip( i18n( "Change character size, font, boldface, italics etc." ) ); actionFormatFont->setWhatsThis( i18n( "Change the attributes of the currently selected characters." ) ); actionFormatParag = new KAction( i18n( "&Paragraph..." ), ALT + CTRL + Key_P, this, SLOT( formatParagraph() ), actionCollection(), "format_paragraph" ); actionFormatParag->setToolTip( i18n( "Change paragraph margins, text flow, borders, bullets, numbering etc." ) ); actionFormatParag->setWhatsThis( i18n( "Change paragraph margins, text flow, borders, bullets, numbering etc.

Select text in multiple paragraphs to change the formatting of all selected paragraphs.

If no text is selected, the paragraph where the cursor is located will be changed." ) ); actionFormatFrameSet = new KAction( i18n( "F&rame/Frameset Properties..." ), 0, this, SLOT( formatFrameSet() ), actionCollection(), "format_frameset" ); actionFormatFrameSet->setToolTip( i18n( "Alter frameset properties." ) ); actionFormatFrameSet->setWhatsThis( i18n( "Alter frameset properties.

Currently you can change the frame background." ) ); actionFormatPage = new KAction( i18n( "Page &Layout..." ), 0, this, SLOT( formatPage() ), actionCollection(), "format_page" ); actionFormatPage->setToolTip( i18n( "Change properties of entire page." ) ); actionFormatPage->setWhatsThis( i18n( "Change properties of the entire page.

Currently you can change paper size, paper orientation, header and footer sizes, and column settings." ) ); actionFormatFrameStylist = new KAction( i18n( "&Frame Style Manager" ), 0 /*shortcut?*/, this, SLOT( extraFrameStylist() ), actionCollection(), "frame_stylist" ); actionFormatFrameStylist->setToolTip( i18n( "Change attributes of framestyles." ) ); actionFormatFrameStylist->setWhatsThis( i18n( "Change background and borders of framestyles.

Multiple framestyles can be changed using the dialog box." ) ); actionFormatStylist = new KAction( i18n( "&Style Manager" ), ALT + CTRL + Key_S, this, SLOT( extraStylist() ), actionCollection(), "format_stylist" ); actionFormatStylist->setToolTip( i18n( "Change attributes of styles." ) ); actionFormatStylist->setWhatsThis( i18n( "Change font and paragraph attributes of styles.

Multiple styles can be changed using the dialog box." ) ); actionFormatFontSize = new KFontSizeAction( i18n( "Font Size" ), 0, actionCollection(), "format_fontsize" ); connect( actionFormatFontSize, SIGNAL( fontSizeChanged( int ) ), this, SLOT( textSizeSelected( int ) ) ); actionFontSizeIncrease = new KAction( i18n("Increase Font Size"), "fontsizeup", CTRL + Key_Greater, this, SLOT( increaseFontSize() ), actionCollection(), "increase_fontsize" ); actionFontSizeDecrease = new KAction( i18n("Decrease Font Size"), "fontsizedown", CTRL + Key_Less, this, SLOT( decreaseFontSize() ), actionCollection(), "decrease_fontsize" ); #ifdef KFONTACTION_HAS_CRITERIA_ARG actionFormatFontFamily = new KFontAction( KFontChooser::SmoothScalableFonts, i18n( "Font Family" ), 0, actionCollection(), "format_fontfamily" ); #else actionFormatFontFamily = new KFontAction( i18n( "Font Family" ), 0, actionCollection(), "format_fontfamily" ); #endif connect( actionFormatFontFamily, SIGNAL( activated( const QString & ) ), this, SLOT( textFontSelected( const QString & ) ) ); actionFormatStyleMenu = new KActionMenu( i18n( "St&yle" ), 0, actionCollection(), "format_stylemenu" ); actionFormatStyle = new KSelectAction( i18n( "St&yle" ), 0, actionCollection(), "format_style" ); // In fact, binding a key to this action will simply re-apply the current style. Why not. //actionFormatStyle->setShortcutConfigurable( false ); connect( actionFormatStyle, SIGNAL( activated( int ) ), this, SLOT( textStyleSelected( int ) ) ); updateStyleList(); actionFormatDefault=new KAction( i18n( "Default Format" ), 0, this, SLOT( textDefaultFormat() ), actionCollection(), "text_default" ); actionFormatDefault->setToolTip( i18n( "Change font and paragraph attributes to their default values." ) ); actionFormatDefault->setWhatsThis( i18n( "Change font and paragraph attributes to their default values." ) ); // ----------------------- More format actions, for the toolbar only actionFormatBold = new KToggleAction( i18n( "&Bold" ), "text_bold", CTRL + Key_B, this, SLOT( textBold() ), actionCollection(), "format_bold" ); actionFormatItalic = new KToggleAction( i18n( "&Italic" ), "text_italic", CTRL + Key_I, this, SLOT( textItalic() ), actionCollection(), "format_italic" ); actionFormatUnderline = new KToggleAction( i18n( "&Underline" ), "text_under", CTRL + Key_U, this, SLOT( textUnderline() ), actionCollection(), "format_underline" ); actionFormatStrikeOut = new KToggleAction( i18n( "&Strike Out" ), "text_strike", 0 , this, SLOT( textStrikeOut() ), actionCollection(), "format_strike" ); actionFormatAlignLeft = new KToggleAction( i18n( "Align &Left" ), "text_left", CTRL + Key_L, this, SLOT( textAlignLeft() ), actionCollection(), "format_alignleft" ); actionFormatAlignLeft->setExclusiveGroup( "align" ); actionFormatAlignLeft->setChecked( TRUE ); actionFormatAlignCenter = new KToggleAction( i18n( "Align &Center" ), "text_center", CTRL + ALT + Key_C, this, SLOT( textAlignCenter() ), actionCollection(), "format_aligncenter" ); actionFormatAlignCenter->setExclusiveGroup( "align" ); actionFormatAlignRight = new KToggleAction( i18n( "Align &Right" ), "text_right", CTRL + ALT + Key_R, this, SLOT( textAlignRight() ), actionCollection(), "format_alignright" ); actionFormatAlignRight->setExclusiveGroup( "align" ); actionFormatAlignBlock = new KToggleAction( i18n( "Align &Block" ), "text_block", CTRL + Key_J, this, SLOT( textAlignBlock() ), actionCollection(), "format_alignblock" ); actionFormatAlignBlock->setExclusiveGroup( "align" ); actionFormatSuper = new KToggleAction( i18n( "Superscript" ), "super", 0, this, SLOT( textSuperScript() ), actionCollection(), "format_super" ); actionFormatSuper->setExclusiveGroup( "valign" ); actionFormatSub = new KToggleAction( i18n( "Subscript" ), "sub", 0, this, SLOT( textSubScript() ), actionCollection(), "format_sub" ); actionFormatSub->setExclusiveGroup( "valign" ); actionFormatIncreaseIndent= new KAction( i18n( "Increase Indent" ), QApplication::reverseLayout() ? "format_decreaseindent" : "format_increaseindent", KShortcut("SHIFT+tab"), this, SLOT( textIncreaseIndent() ), actionCollection(), "format_increaseindent" ); actionFormatDecreaseIndent= new KAction( i18n( "Decrease Indent" ), QApplication::reverseLayout() ? "format_increaseindent" :"format_decreaseindent", 0, this, SLOT( textDecreaseIndent() ), actionCollection(), "format_decreaseindent" ); actionFormatColor = new TKSelectColorAction( i18n( "Text Color..." ), TKSelectColorAction::TextColor, this, SLOT( textColor() ), actionCollection(), "format_color", true ); actionFormatColor->setDefaultColor(QColor()); //actionFormatList = new KToggleAction( i18n( "List" ), "enumList", 0, // this, SLOT( textList() ), // actionCollection(), "format_list" ); //actionFormatList->setExclusiveGroup( "style" ); actionFormatNumber = new KActionMenu( i18n( "Number" ), "enumList", actionCollection(), "format_number" ); actionFormatNumber->setDelayed( false ); actionFormatBullet = new KActionMenu( i18n( "Bullet" ), "unsortedList", actionCollection(), "format_bullet" ); actionFormatBullet->setDelayed( false ); QPtrList stylesList; KoCounterStyleWidget::makeCounterRepresenterList( stylesList ); QPtrListIterator styleIt( stylesList ); for ( ; styleIt.current() ; ++styleIt ) { // Dynamically create toggle-actions for each list style. // This approach allows to edit toolbars and extract separate actions from this menu KToggleAction* act = new KToggleAction( styleIt.current()->name(), /*TODO icon,*/ 0, this, SLOT( slotCounterStyleSelected() ), actionCollection(), QString("counterstyle_%1").arg( styleIt.current()->style() ).latin1() ); act->setExclusiveGroup( "counterstyle" ); // Add to the right menu: both for "none", bullet for bullets, numbers otherwise if ( styleIt.current()->style() == KoParagCounter::STYLE_NONE ) { actionFormatBullet->insert( act ); actionFormatNumber->insert( act ); } else if ( styleIt.current()->isBullet() ) actionFormatBullet->insert( act ); else actionFormatNumber->insert( act ); } // ---------------------------- frame toolbar actions actionFrameStyleMenu = new KActionMenu( i18n( "Fra&mestyle" ), 0, actionCollection(), "frame_stylemenu" ); actionFrameStyle = new KSelectAction( i18n( "Framest&yle" ), 0, actionCollection(), "frame_style" ); connect( actionFrameStyle, SIGNAL( activated( int ) ), this, SLOT( frameStyleSelected( int ) ) ); updateFrameStyleList(); actionBorderOutline = new KToggleAction( i18n( "Border Outline" ), "borderoutline", 0, this, SLOT( borderOutline() ), actionCollection(), "border_outline" ); actionBorderLeft = new KToggleAction( i18n( "Border Left" ), "borderleft", 0, this, SLOT( borderLeft() ), actionCollection(), "border_left" ); actionBorderRight = new KToggleAction( i18n( "Border Right" ), "borderright", 0, this, SLOT( borderRight() ), actionCollection(), "border_right" ); actionBorderTop = new KToggleAction( i18n( "Border Top" ), "bordertop", 0, this, SLOT( borderTop() ), actionCollection(), "border_top" ); actionBorderBottom = new KToggleAction( i18n( "Border Bottom" ), "borderbottom", 0, this, SLOT( borderBottom() ), actionCollection(), "border_bottom" ); actionBorderStyle = new KSelectAction( i18n( "Border Style" ), 0, actionCollection(), "border_style" ); connect( actionBorderStyle, SIGNAL( activated( const QString & ) ), this, SLOT( borderStyle( const QString & ) ) ); QStringList lst; lst << KoBorder::getStyle( KoBorder::SOLID ); lst << KoBorder::getStyle( KoBorder::DASH ); lst << KoBorder::getStyle( KoBorder::DOT ); lst << KoBorder::getStyle( KoBorder::DASH_DOT ); lst << KoBorder::getStyle( KoBorder::DASH_DOT_DOT ); lst << KoBorder::getStyle( KoBorder::DOUBLE_LINE ); actionBorderStyle->setItems( lst ); actionBorderWidth = new KSelectAction( i18n( "Border Width" ), 0, actionCollection(), "border_width" ); connect( actionBorderWidth, SIGNAL( activated( const QString & ) ), this, SLOT( borderWidth( const QString & ) ) ); lst.clear(); for ( unsigned int i = 1; i < 10; i++ ) lst << QString::number( i ); actionBorderWidth->setItems( lst ); actionBorderColor = new TKSelectColorAction( i18n("Border Color"), TKSelectColorAction::LineColor, actionCollection(), "border_color", true ); actionBorderColor->setDefaultColor(QColor()); connect(actionBorderColor,SIGNAL(activated()),SLOT(borderColor())); actionBackgroundColor = new TKSelectColorAction( i18n( "Text Background Color..." ), TKSelectColorAction::FillColor, actionCollection(),"border_backgroundcolor", true); actionBackgroundColor->setToolTip( i18n( "Change background color for currently selected text." ) ); actionBackgroundColor->setWhatsThis( i18n( "Change background color for currently selected text." ) ); connect(actionBackgroundColor,SIGNAL(activated()),SLOT(backgroundColor() )); actionBackgroundColor->setDefaultColor(QColor()); // ---------------------- Table menu actionTablePropertiesMenu = new KAction( i18n( "&Properties..." ), 0, this, SLOT( tableProperties() ), actionCollection(), "table_propertiesmenu" ); actionTablePropertiesMenu->setToolTip( i18n( "Adjust properties of the current table." ) ); actionTablePropertiesMenu->setWhatsThis( i18n( "Adjust properties of the current table." ) ); /* TODO: disabled for the moment because I first want a nice icon :-) (09-06-2002) actionTableProperties = new KAction( i18n( "&Properties..." ), 0, this, SLOT( tableProperties() ), actionCollection(), "table_properties" ); actionTableProperties->setToolTip( i18n( "Adjust properties of the current table." ) ); actionTableProperties->setWhatsThis( i18n( "Adjust properties of the current table." ) ); */ actionTableInsertRow = new KAction( i18n( "&Insert Row..." ), "insert_table_row", 0, this, SLOT( tableInsertRow() ), actionCollection(), "table_insrow" ); actionTableInsertRow->setToolTip( i18n( "Insert one or more rows at cursor location." ) ); actionTableInsertRow->setWhatsThis( i18n( "Insert one or more rows at current cursor location." ) ); actionTableInsertCol = new KAction( i18n( "I&nsert Column..." ), "insert_table_col", 0, this, SLOT( tableInsertCol() ), actionCollection(), "table_inscol" ); actionTableInsertCol->setToolTip( i18n( "Insert one or more columns into the current table." ) ); actionTableInsertCol->setWhatsThis( i18n( "Insert one or more columns into the current table." ) ); actionTableDelRow = new KAction( i18n( "&Delete Selected Rows..." ), "delete_table_row", 0, this, SLOT( tableDeleteRow() ), actionCollection(), "table_delrow" ); actionTableDelRow->setToolTip( i18n( "Delete selected rows from the current table." ) ); actionTableDelRow->setWhatsThis( i18n( "Delete selected rows from the current table." ) ); actionTableDelCol = new KAction( i18n( "D&elete Selected Columns..." ), "delete_table_col", 0, this, SLOT( tableDeleteCol() ), actionCollection(), "table_delcol" ); actionTableDelCol->setToolTip( i18n( "Delete selected columns from the current table." ) ); actionTableDelCol->setWhatsThis( i18n( "Delete selected columns from the current table." ) ); actionTableResizeCol = new KAction( i18n( "Resize Column..." ), 0, this, SLOT( tableResizeCol() ), actionCollection(), "table_resizecol" ); actionTableResizeCol->setToolTip( i18n( "Change the width of the currently selected column." ) ); actionTableResizeCol->setWhatsThis( i18n( "Change the width of the currently selected column." ) ); actionTableJoinCells = new KAction( i18n( "&Join Cells" ), 0, this, SLOT( tableJoinCells() ), actionCollection(), "table_joincells" ); actionTableJoinCells->setToolTip( i18n( "Join two or more cells into one large cell." ) ); actionTableJoinCells->setWhatsThis( i18n( "Join two or more cells into one large cell.

This is a good way to create titles and labels within a table." ) ); actionTableSplitCells= new KAction( i18n( "&Split Cells..." ), 0, this, SLOT( tableSplitCells() ), actionCollection(), "table_splitcells" ); actionTableSplitCells->setToolTip( i18n( "Split one cell into two or more cells." ) ); actionTableSplitCells->setWhatsThis( i18n( "Split one cell into two or more cells.

Cells can be split horizontally, vertically or both directions at once." ) ); actionTableProtectCells= new KToggleAction( i18n( "Protect Cells" ), 0, this, SLOT( tableProtectCells() ), actionCollection(), "table_protectcells" ); actionTableProtectCells->setToolTip( i18n( "Prevent changes to content of selected cells." ) ); actionTableProtectCells->setWhatsThis( i18n( "Toggles cell protection on and off.

When cell protection is on, the user can not alter the content or formatting of the text within the cell." ) ); actionTableUngroup = new KAction( i18n( "&Ungroup Table" ), 0, this, SLOT( tableUngroupTable() ), actionCollection(), "table_ungroup" ); actionTableUngroup->setToolTip( i18n( "Break a table into individual frames." ) ); actionTableUngroup->setWhatsThis( i18n( "Break a table into individual frames

Each frame can be moved independently around the page." ) ); actionTableDelete = new KAction( i18n( "Delete &Table" ), 0, this, SLOT( tableDelete() ), actionCollection(), "table_delete" ); actionTableDelete->setToolTip( i18n( "Delete the entire table." ) ); actionTableDelete->setWhatsThis( i18n( "Deletes all cells and the content within the cells of the currently selected table." ) ); actionTableStylist = new KAction( i18n( "T&able Style Manager..." ), 0, this, SLOT( tableStylist() ), actionCollection(), "table_stylist" ); actionTableStylist->setToolTip( i18n( "Change attributes of tablestyles." ) ); actionTableStylist->setWhatsThis( i18n( "Change textstyle and framestyle of the tablestyles.

Multiple tablestyles can be changed using the dialog box." ) ); actionTableStyleMenu = new KActionMenu( i18n( "Table&style" ), 0, actionCollection(), "table_stylemenu" ); actionTableStyle = new KSelectAction( i18n( "Table&style" ), 0, actionCollection(), "table_style" ); connect( actionTableStyle, SIGNAL( activated( int ) ), this, SLOT( tableStyleSelected( int ) ) ); updateTableStyleList(); actionConvertTableToText = new KAction( i18n( "Convert Table to Text" ), 0, this, SLOT( convertTableToText() ), actionCollection(), "convert_table_to_text" ); actionSortText= new KAction( i18n( "Sort Text..." ), 0, this, SLOT( sortText() ), actionCollection(), "sort_text" ); actionAddPersonalExpression= new KAction( i18n( "Add Expression" ), 0, this, SLOT( addPersonalExpression() ), actionCollection(), "add_personal_expression" ); // ---------------------- Tools menu actionAllowAutoFormat = new KToggleAction( i18n( "Enable Autocorrection" ), 0, this, SLOT( slotAllowAutoFormat() ), actionCollection(), "enable_autocorrection" ); #if KDE_IS_VERSION(3,2,90) actionAllowAutoFormat->setCheckedState(i18n("Disable Autocorrection")); #endif actionAllowAutoFormat->setToolTip( i18n( "Toggle autocorrection on and off." ) ); actionAllowAutoFormat->setWhatsThis( i18n( "Toggle autocorrection on and off." ) ); actionAutoFormat = new KAction( i18n( "Configure &Autocorrection..." ), 0, this, SLOT( extraAutoFormat() ), actionCollection(), "configure_autocorrection" ); actionAutoFormat->setToolTip( i18n( "Change autocorrection options." ) ); actionAutoFormat->setWhatsThis( i18n( "Change autocorrection options including:

  • exceptions to autocorrection

  • add/remove autocorrection replacement text

  • and basic autocorrection options

    ." ) ); actionEditCustomVarsEdit = new KAction( i18n( "Custom &Variables..." ), 0, this, SLOT( editCustomVars() ), // TODO: new dialog w add etc. actionCollection(), "custom_vars" ); actionEditPersonnalExpr=new KAction( i18n( "Edit &Personal Expressions..." ), 0, this, SLOT( editPersonalExpr() ), actionCollection(), "personal_expr" ); actionEditPersonnalExpr->setToolTip( i18n( "Add or change one or more personal expressions." ) ); actionEditPersonnalExpr->setWhatsThis( i18n( "Add or change one or more personal expressions.

    Personal expressions are a way to quickly insert commonly used phrases or text into your document." ) ); actionChangeCase=new KAction( i18n( "Change Case..." ), 0, this, SLOT( changeCaseOfText() ), actionCollection(), "change_case" ); actionChangeCase->setToolTip( i18n( "Alter the capitalization of selected text." ) ); actionChangeCase->setWhatsThis( i18n( "Alter the capitalization of selected text to one of five pre-defined patterns.

    You can also switch all letters from upper case to lower case and from lower case to upper case in one move." ) ); //------------------------ Settings menu actionConfigure = KStdAction::preferences(this, SLOT(configure()), actionCollection(), "configure" ); //------------------------ Menu frameSet actionChangePicture=new KAction( i18n( "Change Picture..." ),"frame_image",0, this, SLOT( changePicture() ), actionCollection(), "change_picture" ); actionChangePicture->setToolTip( i18n( "Change the picture in the currently selected frame." ) ); actionChangePicture->setWhatsThis( i18n( "You can specify a different picture in the current frame.

    KWord automatically resizes the new picture to fit within the old frame." ) ); actionConfigureHeaderFooter=new KAction( i18n( "Configure Header/Footer..." ), 0, this, SLOT( configureHeaderFooter() ), actionCollection(), "configure_headerfooter" ); actionConfigureHeaderFooter->setToolTip( i18n( "Configure the currently selected header or footer." ) ); actionConfigureHeaderFooter->setWhatsThis( i18n( "Configure the currently selected header or footer." ) ); actionInlineFrame = new KToggleAction( i18n( "Inline Frame" ), 0, this, SLOT( inlineFrame() ), actionCollection(), "inline_frame" ); actionInlineFrame->setToolTip( i18n( "Convert current frame to an inline frame." ) ); actionInlineFrame->setWhatsThis( i18n( "Convert the current frame to an inline frame.

    Place the inline frame within the text at the point nearest to the frames current position." ) ); actionOpenLink = new KAction( i18n( "Open Link" ), 0, this, SLOT( openLink() ), actionCollection(), "open_link" ); actionOpenLink->setToolTip( i18n( "Open the link with the appropriate application." ) ); actionOpenLink->setWhatsThis( i18n( "Open the link with the appropriate application.

    Web addresses are opened in a browser.
    Email addresses begin a new message addressed to the link.
    File links are opened by the appropriate viewer or editor." ) ); actionChangeLink=new KAction( i18n("Change Link..."), 0, this,SLOT(changeLink()), actionCollection(), "change_link"); actionChangeLink->setToolTip( i18n( "Change the content of the currently selected link." ) ); actionChangeLink->setWhatsThis( i18n( "Change the details of the currently selected link." ) ); actionCopyLink = new KAction( i18n( "Copy Link" ), 0, this, SLOT( copyLink() ), actionCollection(), "copy_link" ); actionAddLinkToBookmak = new KAction( i18n( "Add to Bookmark" ), 0, this, SLOT( addToBookmark() ), actionCollection(), "add_to_bookmark" ); actionRemoveLink = new KAction( i18n( "Remove Link" ), 0, this, SLOT( removeLink() ), actionCollection(), "remove_link" ); actionShowDocStruct = new KToggleAction( i18n( "Show Doc Structure" ), 0, this, SLOT( showDocStructure() ), actionCollection(), "show_docstruct" ); #if KDE_IS_VERSION(3,2,90) actionShowDocStruct->setCheckedState(i18n("Hide Doc Structure")); #endif actionShowDocStruct->setToolTip( i18n( "Open document structure sidebar." ) ); actionShowDocStruct->setWhatsThis( i18n( "Open document structure sidebar.

    This sidebar helps you organize your document and quickly find pictures, tables etc." ) ); actionShowRuler = new KToggleAction( i18n( "Show Rulers" ), 0, this, SLOT( showRuler() ), actionCollection(), "show_ruler" ); #if KDE_IS_VERSION(3,2,90) actionShowRuler->setCheckedState(i18n("Hide Rulers")); #endif actionShowRuler->setToolTip( i18n( "Shows or hides rulers." ) ); actionShowRuler->setWhatsThis( i18n("The rulers are the white measuring spaces top and left of the " "document. The rulers show the position and width of pages and of frames and can " "be used to position tabulators among others.

    Uncheck this to disable " "the rulers from being displayed." ) ); actionConfigureCompletion = new KAction( i18n( "Configure C&ompletion..." ), 0, this, SLOT( configureCompletion() ), actionCollection(), "configure_completion" ); actionConfigureCompletion->setToolTip( i18n( "Change the words and options for autocompletion." ) ); actionConfigureCompletion->setWhatsThis( i18n( "Add words or change the options for autocompletion." ) ); // ------------------- Actions with a key binding and no GUI item new KAction( i18n( "Insert Non-Breaking Space" ), CTRL+Key_Space, this, SLOT( slotNonbreakingSpace() ), actionCollection(), "nonbreaking_space" ); new KAction( i18n( "Insert Non-Breaking Hyphen" ), CTRL+SHIFT+Key_Minus, this, SLOT( slotNonbreakingHyphen() ), actionCollection(), "nonbreaking_hyphen" ); new KAction( i18n( "Insert Soft Hyphen" ), CTRL+Key_Minus, this, SLOT( slotSoftHyphen() ), actionCollection(), "soft_hyphen" ); new KAction( i18n( "Line Break" ), SHIFT+Key_Return, this, SLOT( slotLineBreak() ), actionCollection(), "line_break" ); new KAction( i18n( "Completion" ), KStdAccel::shortcut(KStdAccel::TextCompletion), this, SLOT( slotCompletion() ), actionCollection(), "completion" ); new KAction( i18n( "Increase Numbering Level" ), ALT+Key_Right, this, SLOT( slotIncreaseNumberingLevel() ), actionCollection(), "increase_numbering_level" ); new KAction( i18n( "Decrease Numbering Level" ), ALT+Key_Left, this, SLOT( slotDecreaseNumberingLevel() ), actionCollection(), "decrease_numbering_level" ); // -------- actionEditCustomVars = new KAction( i18n( "Edit Variable..." ), 0, this, SLOT( editCustomVariable() ), actionCollection(), "edit_customvars" ); actionApplyAutoFormat= new KAction( i18n( "Apply Autocorrection" ), 0, this, SLOT( applyAutoFormat() ), actionCollection(), "apply_autoformat" ); actionApplyAutoFormat->setToolTip( i18n( "Manually force KWord to scan the entire document and apply autocorrection." ) ); actionApplyAutoFormat->setWhatsThis( i18n( "Manually force KWord to scan the entire document and apply autocorrection." ) ); actionCreateStyleFromSelection = new KAction( i18n( "Create Style From Selection..." ), 0, this, SLOT( createStyleFromSelection()), actionCollection(), "create_style" ); actionCreateStyleFromSelection->setToolTip( i18n( "Create a new style based on the currently selected text." ) ); actionCreateStyleFromSelection->setWhatsThis( i18n( "Create a new style based on the currently selected text." ) ); // ## "on the current paragraph, taking the formatting from where the cursor is. Selecting text isn't even needed." actionConfigureFootEndNote = new KAction( i18n( "&Footnote..." ), 0, this, SLOT( configureFootEndNote()), actionCollection(), "format_footendnote" ); actionConfigureFootEndNote->setToolTip( i18n( "Change the look of footnotes." ) ); actionConfigureFootEndNote->setWhatsThis( i18n( "Change the look of footnotes." ) ); actionEditFootEndNote= new KAction( i18n("Edit Footnote"), 0, this, SLOT( editFootEndNote()), actionCollection(), "edit_footendnote" ); actionEditFootEndNote->setToolTip( i18n( "Change the content of the currently selected footnote." ) ); actionEditFootEndNote->setWhatsThis( i18n( "Change the content of the currently selected footnote." ) ); actionChangeFootNoteType = new KAction( i18n("Change Footnote/Endnote Parameter"), 0, this, SLOT( changeFootNoteType() ), actionCollection(), "change_footendtype"); actionSavePicture= new KAction( i18n("Save Picture..."), 0, this, SLOT( savePicture() ), actionCollection(), "save_picture"); actionSavePicture->setToolTip( i18n( "Save the picture in a separate file." ) ); actionSavePicture->setWhatsThis( i18n( "Save the picture in the currently selected frame in a separate file, outside the KWord document." ) ); actionAllowBgSpellCheck = new KToggleAction( i18n( "Autospellcheck" ), 0, this, SLOT( autoSpellCheck() ), actionCollection(), "tool_auto_spellcheck" ); actionGoToFootEndNote = new KAction( QString::null /*set dynamically*/, 0, this, SLOT( goToFootEndNote() ), actionCollection(), "goto_footendnote" ); actionEditFrameSet = new KAction( i18n( "Edit Text Frameset" ), 0, this, SLOT( editFrameSet() ), actionCollection(), "edit_frameset" ); actionDeleteFrameSet = new KAction( i18n( "Delete Frameset" ), 0, this, SLOT( deleteFrameSet() ), actionCollection(), "delete_frameset" ); actionEditFrameSetProperties = new KAction( i18n( "Edit Frameset Properties" ), 0, this, SLOT( editFrameSetProperties() ), actionCollection(), "edit_frameset_properties" ); actionSelectedFrameSet = new KAction( i18n( "Select Frameset" ), 0, this, SLOT( selectFrameSet() ), actionCollection(), "select_frameset" ); actionAddBookmark= new KAction( i18n( "&Bookmark..." ), 0, this, SLOT( addBookmark() ), actionCollection(), "add_bookmark" ); actionSelectBookmark= new KAction( i18n( "Select &Bookmark..." ), 0, this, SLOT( selectBookmark() ), actionCollection(), "select_bookmark" ); actionImportStyle= new KAction( i18n( "Import Styles..." ), 0, this, SLOT( importStyle() ), actionCollection(), "import_style" ); actionCreateFrameStyle = new KAction( i18n( "&Create Framestyle From Frame..." ), 0, this, SLOT( createFrameStyle()), actionCollection(), "create_framestyle" ); actionCreateFrameStyle->setToolTip( i18n( "Create a new style based on the currently selected frame." ) ); actionCreateFrameStyle->setWhatsThis( i18n( "Create a new framestyle based on the currently selected frame." ) ); #if 0 // re-enable after fixing actionInsertDirectCursor = new KToggleAction( i18n( "Type Anywhere Cursor" ), 0, this, SLOT( insertDirectCursor() ), actionCollection(), "direct_cursor" ); #endif actionConvertToTextBox = new KAction( i18n( "Convert to Text Box" ), 0, this, SLOT( convertToTextBox() ), actionCollection(), "convert_to_text_box" ); actionSpellIgnoreAll = new KAction( i18n( "Ignore All" ), 0, this, SLOT( slotAddIgnoreAllWord() ), actionCollection(), "ignore_all" ); #if 0 // KWORD_HORIZONTAL_LINE actionInsertHorizontalLine = new KAction( i18n( "Horizontal Line..." ), 0, this, SLOT( insertHorizontalLine() ), actionCollection(), "insert_horizontal_line" ); actionChangeHorizontalLine=new KAction( i18n( "Change Horizontal Line..." ),0, this, SLOT( changeHorizontalLine() ), actionCollection(), "change_horizontal_line" ); #endif actionAddWordToPersonalDictionary=new KAction( i18n( "Add Word to Dictionary" ),0, this, SLOT( addWordToDictionary() ), actionCollection(), "add_word_to_dictionary" ); actionEmbeddedStoreInternal=new KToggleAction( i18n( "Store Document Internally" ),0, this, SLOT( embeddedStoreInternal() ), actionCollection(), "embedded_store_internal" ); // For RMB inside a cell, see KWTableFrameSetEdit::showPopup // This isn't a dynamic list; it's only plugged/unplugged depending on the context. // If you change the contents of that list, check ~KWView. m_tableActionList.append( new KActionSeparator(actionCollection()) ); m_tableActionList.append( actionTableInsertRow ); m_tableActionList.append( actionTableDelRow ); m_tableActionList.append( actionTableInsertCol ); m_tableActionList.append( actionTableDelCol ); } void KWView::refreshMenuExpression() { loadexpressionActions( actionInsertExpression); } void KWView::loadexpressionActions( KActionMenu * parentMenu) { KActionPtrList lst = actionCollection()->actions("expression-action"); QValueList actions = lst; QValueList::ConstIterator it = lst.begin(); QValueList::ConstIterator end = lst.end(); // Delete all actions but keep their shortcuts in mind QMap personalShortCut; for (; it != end; ++it ) { if ( !(*it)->shortcut().isNull() ) { personalShortCut.insert( (*it)->text(), (*it)->shortcut() ); } delete *it; } parentMenu->popupMenu()->clear(); QStringList path = m_doc->personalExpressionPath(); QStringList files; for ( QStringList::Iterator it = path.begin(); it != path.end(); ++it ) { QDir dir( *it ); if ( dir.exists() ) { QStringList tmp = dir.entryList("*.xml"); for ( QStringList::Iterator it2 = tmp.begin(); it2 != tmp.end(); ++it2 ) files.append( QString( (*it) + (*it2))); } } //QStringList files = KWFactory::global()->dirs()->findAllResources( "expression", "*.xml", TRUE ); int i = 0; int nbFile = 0; for( QStringList::Iterator it = files.begin(); it != files.end(); ++it,nbFile++ ) createExpressionActions( parentMenu,*it, i,(nbFile<(int)files.count()-1), personalShortCut ); } void KWView::createExpressionActions( KActionMenu * parentMenu,const QString& filename,int &i, bool insertSepar, const QMap& personalShortCut ) { QFile file( filename ); if ( !file.exists() || !file.open( IO_ReadOnly ) ) return; QDomDocument doc; doc.setContent( &file ); file.close(); bool expressionExist =false; QDomNode n = doc.documentElement().firstChild(); for( ; !n.isNull(); n = n.nextSibling() ) { if ( n.isElement() ) { QDomElement e = n.toElement(); if ( e.tagName() == "Type" ) { expressionExist =true; QString group = i18n( e.namedItem( "TypeName" ).toElement().text().utf8() ); KActionMenu * subMenu = new KActionMenu( group, actionCollection() ); parentMenu->insert( subMenu ); QDomNode n2 = e.firstChild(); for( ; !n2.isNull(); n2 = n2.nextSibling() ) { if ( n2.isElement() ) { QDomElement e2 = n2.toElement(); if ( e2.tagName() == "Expression" ) { QString text = i18n( e2.namedItem( "Text" ).toElement().text().utf8() ); KAction * act = new KAction( text, 0, this, SLOT( insertExpression() ), actionCollection(), QString("expression-action_%1").arg(i).latin1() ); if ( personalShortCut.contains(text) ) act->setShortcut( personalShortCut[text] ); i++; act->setGroup("expression-action"); subMenu->insert( act ); } } } } } } if(expressionExist && insertSepar) parentMenu->popupMenu()->insertSeparator(); } void KWView::insertExpression() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KAction * act = (KAction *)(sender()); edit->insertExpression(act->text()); } } void KWView::addVariableActions( int type, const QStringList & texts, KActionMenu * parentMenu, const QString & menuText ) { // Single items go directly into parentMenu. // For multiple items we create a submenu. if ( texts.count() > 1 && !menuText.isEmpty() ) { KActionMenu * subMenu = new KActionMenu( menuText, actionCollection() ); parentMenu->insert( subMenu ); parentMenu = subMenu; } QStringList::ConstIterator it = texts.begin(); for ( int i = 0; it != texts.end() ; ++it, ++i ) { if ( !(*it).isEmpty() ) // in case of removed subtypes or placeholders { VariableDef v; v.type = type; v.subtype = i; QCString actionName; actionName.sprintf( "var-action-%d-%d", type, i ); KAction * act = new KAction( (*it), 0, this, SLOT( insertVariable() ), actionCollection(), actionName ); // Mainly for KEditToolbar act->setToolTip( i18n( "Insert variable \"%1\" into the text" ).arg( *it ) ); m_variableDefMap.insert( act, v ); parentMenu->insert( act ); } } } void KWView::refreshCustomMenu() { KActionPtrList lst2 = actionCollection()->actions("custom-variable-action"); QValueList actions = lst2; QValueList::ConstIterator it2 = lst2.begin(); QValueList::ConstIterator end = lst2.end(); QMap shortCut; for (; it2 != end; ++it2 ) { if ( !(*it2)->shortcut().toString().isEmpty()) { shortCut.insert((*it2)->text(), KShortcut( (*it2)->shortcut())); } delete *it2; } delete actionInsertCustom; actionInsertCustom = new KActionMenu( i18n( "&Custom" ), actionCollection(), "insert_custom" ); actionInsertVariable->insert(actionInsertCustom, 0); actionInsertCustom->popupMenu()->clear(); QPtrListIterator it( m_doc->getVariableCollection()->getVariables() ); KAction * act=0; QStringList lst; QString varName; int i = 0; for ( ; it.current() ; ++it ) { KoVariable *var = it.current(); if ( var->type() == VT_CUSTOM ) { varName=( (KoCustomVariable*) var )->name(); if ( !lst.contains( varName) ) { lst.append( varName ); QCString name = QString("custom-action_%1").arg(i).latin1(); if ( shortCut.contains( varName )) { act = new KAction( varName, (shortCut)[varName], this, SLOT( insertCustomVariable() ),actionCollection(), name ); } else act = new KAction( varName, 0, this, SLOT( insertCustomVariable() ), actionCollection(), name ); act->setGroup( "custom-variable-action" ); actionInsertCustom->insert( act ); i++; } } } bool state=!lst.isEmpty(); if(state) actionInsertCustom->popupMenu()->insertSeparator(); act = new KAction( i18n("New..."), 0, this, SLOT( insertNewCustomVariable() ), actionCollection(),QString("custom-action_%1").arg(i).latin1()); act->setGroup( "custom-variable-action" ); actionEditCustomVarsEdit->setEnabled( state ); actionInsertCustom->insert( act ); } void KWView::insertCustomVariable() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KAction * act = (KAction *)(sender()); edit->insertCustomVariable(act->text()); } } void KWView::insertNewCustomVariable() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->insertVariable( VT_CUSTOM, 0 ); } void KWView::showFormulaToolbar( bool show ) { m_doc->getFormulaDocument()->setEnabled( show ); if(shell()) shell()->showToolbar( "formula_toolbar", show ); } void KWView::updatePageInfo() { if ( m_sbPageLabel ) { KWFrameSetEdit * edit = m_gui->canvasWidget()->currentFrameSetEdit(); if ( edit && edit->currentFrame() ) { m_currentPage = edit->currentFrame()->pageNum(); } else { KWFrame* f = m_doc->getFirstSelectedFrame(); if ( f ) m_currentPage = f->pageNum(); } /*kdDebug() << (void*)this << " KWView::updatePageInfo " << " edit: " << edit << " " << ( edit?edit->frameSet()->getName():QString::null) << " currentFrame: " << (edit?edit->currentFrame():0L) << " m_currentPage=" << m_currentPage << " m_sbPageLabel=" << m_sbPageLabel << endl;*/ // To avoid bugs, apply max page number in case a page was removed. m_currentPage = QMIN( m_currentPage, m_doc->numPages()-1 ); QString oldText = m_sbPageLabel->text(); QString newText; newText= (m_gui->canvasWidget()->viewMode()->type()!="ModeText")? QString(" ")+i18n("Page %1/%2").arg(m_currentPage+1).arg(m_doc->numPages())+' ' : QString::null; if ( newText != oldText ) { m_sbPageLabel->setText( newText ); // Need to repaint immediately. Otherwise when deleting 100 pages // at once, there's no feedback. m_sbPageLabel->repaint(); } } slotUpdateRuler(); } void KWView::pageNumChanged() { docStructChanged(TextFrames); updatePageInfo(); int pages = m_doc->numPages(); kdDebug() << pages << " " << (m_doc->processingType() == KWDocument::DTP) << endl; refreshDeletePageAction(); } void KWView::updateFrameStatusBarItem() { KStatusBar * sb = statusBar(); int nbFrame=m_doc->getSelectedFrames().count(); if ( m_doc->showStatusBar() && sb && nbFrame > 0 ) { if ( !m_sbFramesLabel ) { m_sbFramesLabel = sb ? new KStatusBarLabel( QString::null, 0, sb ) : 0; addStatusBarItem( m_sbFramesLabel ); } if ( nbFrame == 1 ) { KoUnit::Unit unit = m_doc->getUnit(); QString unitName = m_doc->getUnitName(); KWFrame * frame = m_doc->getFirstSelectedFrame(); m_sbFramesLabel->setText( i18n( "Statusbar info", "%1. Frame: %2, %3 - %4, %5 (width: %6, height: %7) (%8)" ) .arg( frame->frameSet()->getName() ) .arg( KoUnit::toUserStringValue( frame->left(), unit ) ) .arg( KoUnit::toUserStringValue((frame->top() - (frame->pageNum() * m_doc->ptPaperHeight())), unit ) ) .arg( KoUnit::toUserStringValue( frame->right(), unit ) ) .arg( KoUnit::toUserStringValue( frame->bottom(), unit ) ) .arg( KoUnit::toUserStringValue( frame->width(), unit ) ) .arg( KoUnit::toUserStringValue( frame->height(), unit ) ) .arg( unitName ) ); } else m_sbFramesLabel->setText( i18n( "%1 frames selected" ).arg( nbFrame ) ); } else if ( sb && m_sbFramesLabel ) { removeStatusBarItem( m_sbFramesLabel ); delete m_sbFramesLabel; m_sbFramesLabel = 0L; } } void KWView::clipboardDataChanged() { if ( !m_gui || !m_doc->isReadWrite() ) { actionEditPaste->setEnabled(false); return; } KWFrameSetEdit * edit = m_gui->canvasWidget()->currentFrameSetEdit(); // Is there plain text in the clipboard ? if ( edit && !QApplication::clipboard()->text().isEmpty() ) { actionEditPaste->setEnabled(true); return; } QMimeSource *data = QApplication::clipboard()->data(); bool providesImage, providesKWordText, providesKWord, providesFormula; checkClipboard( data, providesImage, providesKWordText, providesKWord, providesFormula ); if ( providesImage || providesKWord || providesFormula ) actionEditPaste->setEnabled( true ); else { // KWord text requires a framesetedit actionEditPaste->setEnabled( edit && providesKWordText ); } } // TODO use a bitfield (defined with an enum) instead of all those bools? // Just to avoid errors when mixing the order up... void KWView::checkClipboard( QMimeSource *data, bool &providesImage, bool &providesKWordText, bool &providesKWord, bool &providesFormula ) { // QImageDrag::canDecode( data ) is very very slow in Qt 2 (n*m roundtrips) // Workaround.... QValueList formats; const char* fmt; for (int i=0; (fmt = data->format(i)); i++) formats.append( QCString( fmt ) ); providesImage = false; QStrList fileFormats = QImageIO::inputFormats(); for ( fileFormats.first() ; fileFormats.current() && !providesImage ; fileFormats.next() ) { QCString format = fileFormats.current(); QCString type = "image/" + format.lower(); providesImage = ( formats.findIndex( type ) != -1 ); } providesFormula = formats.findIndex( KFormula::MimeSource::selectionMimeType() ) != -1; // providesKWordText is true for kword text and for plain text, we send both to KWTextFrameSetEdit::paste providesKWordText = formats.findIndex( KWTextDrag::selectionMimeType() ) != -1 || formats.findIndex( "text/plain" ) != -1; providesKWord = formats.findIndex( KoStoreDrag::mimeType("application/x-kword") ) != -1; //kdDebug() << "KWView::checkClipboard providesFormula=" << providesFormula << " providesKWordText=" << providesKWordText << " providesImage=" << providesImage << " providesKWord=" << providesKWord << endl; } /*=========================== file print =======================*/ void KWView::setupPrinter( KPrinter &prt ) { //recalc time and date variable before to print //it's necessary otherwise we print a document //with a bad date and time //TODO call once this function m_doc->recalcVariables( VT_TIME ); m_doc->recalcVariables( VT_DATE ); m_doc->recalcVariables( VT_STATISTIC ); prt.setPageSelection( KPrinter::ApplicationSide ); prt.setCurrentPage( currentPage() + 1 ); prt.setMinMax( 1, m_doc->numPages() ); KoPageLayout pgLayout = m_doc->pageLayout(); prt.setPageSize( static_cast( KoPageFormat::printerPageSize( pgLayout.format ) ) ); if ( pgLayout.orientation == PG_LANDSCAPE || pgLayout.format == PG_SCREEN ) prt.setOrientation( KPrinter::Landscape ); else prt.setOrientation( KPrinter::Portrait ); } void KWView::print( KPrinter &prt ) { bool displayFieldCode = m_doc->getVariableCollection()->variableSetting()->displayFieldCode(); if ( displayFieldCode ) { m_doc->getVariableCollection()->variableSetting()->setDisplayFieldCode(false); m_doc->recalcVariables( VT_ALL ); } // Don't repaint behind the print dialog until we're done zooming/unzooming the doc m_gui->canvasWidget()->setUpdatesEnabled(false); m_gui->canvasWidget()->viewport()->setCursor( waitCursor ); prt.setFullPage( true ); // ### HACK: disable zooming-when-printing if embedded parts are used. // No koffice app supports zooming in paintContent currently. // Disable in ALL cases now bool doZoom = false; /*QPtrListIterator fit = m_doc->framesetsIterator(); for ( ; fit.current() && doZoom ; ++fit ) if ( fit.current()->type() == FT_PART ) doZoom = false;*/ int oldZoom = m_doc->zoom(); // We don't get valid metrics from the printer - and we want a better resolution // anyway (it's the PS driver that takes care of the printer resolution). QPaintDeviceMetrics metrics( &prt ); //int dpiX = metrics.logicalDpiX(); //int dpiY = metrics.logicalDpiY(); int dpiX = doZoom ? 300 : KoGlobal::dpiX(); int dpiY = doZoom ? 300 : KoGlobal::dpiY(); ///////// Changing the dpiX/dpiY is very wrong nowadays. This has no effect on the font size ///////// that we give Qt, anymore, so it leads to minuscule fonts in the printout => doZoom==false. m_doc->setZoomAndResolution( 100, dpiX, dpiY ); m_doc->newZoomAndResolution( false, true /* for printing*/ ); //kdDebug() << "KWView::print metrics: " << metrics.logicalDpiX() << "," << metrics.logicalDpiY() << endl; //kdDebug() << "x11AppDPI: " << KoGlobal::dpiX() << "," << KoGlobal::dpiY() << endl; bool serialLetter = FALSE; QPtrList vars = m_doc->getVariableCollection()->getVariables(); KoVariable *v = 0; for ( v = vars.first(); v; v = vars.next() ) { if ( v->type() == VT_MAILMERGE ) { serialLetter = TRUE; break; } } if ( !m_doc->getMailMergeDataBase() ) serialLetter=FALSE; else { m_doc->getMailMergeDataBase()->refresh(false); if (m_doc->getMailMergeDataBase()->getNumRecords() == 0 ) serialLetter = FALSE; } //float left_margin = 0.0; //float top_margin = 0.0; KoPageLayout pgLayout; KoColumns cl; KoKWHeaderFooter hf; m_doc->getPageLayout( pgLayout, cl, hf ); KoPageLayout oldPGLayout = pgLayout; if ( pgLayout.format == PG_SCREEN ) { //left_margin = 25.8; //top_margin = 15.0; pgLayout.ptLeft += 25.8; // Not sure why we need this.... pgLayout.ptRight += 15.0; m_doc->setPageLayout( pgLayout, cl, hf, false ); } QPainter painter; painter.begin( &prt ); kdDebug(32001) << "KWView::print scaling by " << (double)metrics.logicalDpiX() / (double)dpiX << "," << (double)metrics.logicalDpiY() / (double)dpiY << endl; painter.scale( (double)metrics.logicalDpiX() / (double)dpiX, (double)metrics.logicalDpiY() / (double)dpiY ); bool canceled = false; // Breaks wysiwyg, obviously - trying without //#define KW_PASS_PAINTER_TO_QRT #ifdef KW_PASS_PAINTER_TO_QRT int paragraphs = 0; fit.toFirst(); for ( ; fit.current() ; ++fit ) if ( fit.current()->isVisible() ) paragraphs += fit.current()->paragraphs(); kdDebug() << "KWView::print total paragraphs: " << paragraphs << endl; // This can take a lot of time (reformatting everything), so a progress dialog is needed QProgressDialog progress( i18n( "Printing..." ), i18n( "Cancel" ), paragraphs, this ); progress.setProgress( 0 ); int processedParags = 0; fit.toFirst(); for ( ; fit.current() ; ++fit ) if ( fit.current()->isVisible() ) { kapp->processEvents(); if ( progress.wasCancelled() ) { canceled = true; break; } kdDebug() << "KWView::print preparePrinting " << fit.current()->getName() << endl; fit.current()->preparePrinting( &painter, &progress, processedParags ); } #endif if ( !canceled ) { if ( !serialLetter ) m_gui->canvasWidget()->print( &painter, &prt ); else { for ( int i = 0; i < m_doc->getMailMergeDataBase()->getNumRecords(); ++i ) { m_doc->setMailMergeRecord( i ); m_doc->getVariableCollection()->recalcVariables(VT_MAILMERGE); m_gui->canvasWidget()->print( &painter, &prt ); if ( i < m_doc->getMailMergeDataBase()->getNumRecords() - 1 ) prt.newPage(); } m_doc->setMailMergeRecord( -1 ); } } if ( pgLayout.format == PG_SCREEN ) m_doc->setPageLayout( oldPGLayout, cl, hf, false ); #ifdef KW_PASS_PAINTER_TO_QRT fit.toFirst(); for ( ; fit.current() ; ++fit ) if ( fit.current()->isVisible() ) fit.current()->preparePrinting( 0L, 0L, processedParags ); #endif m_doc->setZoomAndResolution( oldZoom, KoGlobal::dpiX(), KoGlobal::dpiY() ); m_doc->newZoomAndResolution( false, false ); kdDebug() << "KWView::print zoom&res reset" << endl; m_gui->canvasWidget()->setUpdatesEnabled(true); m_gui->canvasWidget()->viewport()->setCursor( ibeamCursor ); m_doc->repaintAllViews(); if ( displayFieldCode ) { m_doc->getVariableCollection()->variableSetting()->setDisplayFieldCode(true); m_doc->recalcVariables( VT_ALL ); } else m_doc->getVariableCollection()->recalcVariables(VT_MAILMERGE); painter.end(); // this is what triggers the printing m_doc->getVariableCollection()->variableSetting()->setLastPrintingDate(QDateTime::currentDateTime()); m_doc->recalcVariables( VT_DATE ); } void KWView::showFormat( const KoTextFormat ¤tFormat ) { // update the gui with the current format. //kdDebug() << "KWView::setFormat font family=" << currentFormat.font().family() << endl; actionFormatFontFamily->setFont( currentFormat.font().family() ); actionFormatFontSize->setFontSize( currentFormat.pointSize() ); actionFormatBold->setChecked( currentFormat.font().bold()); actionFormatItalic->setChecked( currentFormat.font().italic() ); actionFormatUnderline->setChecked( currentFormat.underline()); actionFormatStrikeOut->setChecked( currentFormat.strikeOut()); QColor col=currentFormat.textBackgroundColor(); //actionBackgroundColor->setEnabled(true); actionBackgroundColor->setCurrentColor( col.isValid() ? col : QApplication::palette().color( QPalette::Active, QColorGroup::Base )); if ( m_doc->getSelectedFrames().count() > 0) actionBackgroundColor->setText(i18n("Frame Background Color...")); else actionBackgroundColor->setText(i18n("Text Background Color...")); switch(currentFormat.vAlign()) { case KoTextFormat::AlignSuperScript: { actionFormatSub->setChecked( false ); actionFormatSuper->setChecked( true ); break; } case KoTextFormat::AlignSubScript: { actionFormatSub->setChecked( true ); actionFormatSuper->setChecked( false ); break; } case KoTextFormat::AlignNormal: default: { actionFormatSub->setChecked( false ); actionFormatSuper->setChecked( false ); break; } } } void KWView::showRulerIndent( double _leftMargin, double _firstLine, double _rightMargin, bool rtl ) { KoRuler * hRuler = m_gui ? m_gui->getHorzRuler() : 0; if ( hRuler ) { hRuler->setFirstIndent( KoUnit::toUserValue( _firstLine, m_doc->getUnit() ) ); hRuler->setLeftIndent( KoUnit::toUserValue( _leftMargin, m_doc->getUnit() ) ); hRuler->setRightIndent( KoUnit::toUserValue( _rightMargin, m_doc->getUnit() ) ); hRuler->setDirection( rtl ); actionFormatDecreaseIndent->setEnabled( _leftMargin>0); } } void KWView::showAlign( int align ) { switch ( align ) { case Qt::AlignAuto: // In left-to-right mode it's align left. TODO: alignright if text->isRightToLeft() kdWarning() << k_funcinfo << "shouldn't be called with AlignAuto" << endl; // fallthrough case Qt::AlignLeft: actionFormatAlignLeft->setChecked( TRUE ); break; case Qt::AlignHCenter: actionFormatAlignCenter->setChecked( TRUE ); break; case Qt::AlignRight: actionFormatAlignRight->setChecked( TRUE ); break; case Qt::AlignJustify: actionFormatAlignBlock->setChecked( TRUE ); break; } } void KWView::showCounter( KoParagCounter &c ) { QString styleStr("counterstyle_"); styleStr += QString::number( c.style() ); //kdDebug() << "KWView::showCounter styleStr=" << styleStr << endl; KToggleAction* act = static_cast( actionCollection()->action( styleStr.latin1() ) ); Q_ASSERT( act ); if ( act ) act->setChecked( true ); } void KWView::showFrameBorders( const KoBorder& _left, const KoBorder& _right, const KoBorder& _top, const KoBorder& _bottom ) { showParagBorders( _left, _right, _top, _bottom ); } void KWView::showParagBorders( const KoBorder& left, const KoBorder& right, const KoBorder& top, const KoBorder& bottom ) { if ( m_border.left != left || m_border.right != right || m_border.top != top || m_border.bottom != bottom ) { m_border.left = left; m_border.right = right; m_border.top = top; m_border.bottom = bottom; actionBorderLeft->setChecked( left.penWidth() > 0 ); actionBorderRight->setChecked( right.penWidth() > 0 ); actionBorderTop->setChecked( top.penWidth() > 0 ); actionBorderBottom->setChecked( bottom.penWidth() > 0 ); actionBorderOutline->setChecked( actionBorderLeft->isChecked() && actionBorderRight->isChecked() && actionBorderTop->isChecked() && actionBorderBottom->isChecked()); if ( left.penWidth() > 0 ) { m_border.common = left; borderShowValues(); } if ( right.penWidth() > 0 ) { m_border.common = right; borderShowValues(); } if ( top.penWidth() > 0 ) { m_border.common = top; borderShowValues(); } if ( bottom.penWidth() > 0 ) { m_border.common = bottom; borderShowValues(); } } } void KWView::updateReadWrite( bool readwrite ) { // First disable or enable everything QValueList actions = actionCollection()->actions(); // Also grab actions from the document actions += m_doc->actionCollection()->actions(); QValueList::ConstIterator aIt = actions.begin(); QValueList::ConstIterator aEnd = actions.end(); for (; aIt != aEnd; ++aIt ) (*aIt)->setEnabled( readwrite ); if ( !readwrite ) { // Readonly -> re-enable a few harmless actions actionFileStatistics->setEnabled( true ); actionExtraCreateTemplate->setEnabled( true ); actionViewPageMode->setEnabled( true ); actionViewPreviewMode->setEnabled( true ); actionViewTextMode->setEnabled( true ); actionShowRuler->setEnabled( true ); actionEditFind->setEnabled( true ); actionViewFormattingChars->setEnabled( true ); actionViewFrameBorders->setEnabled( true ); // that's not readonly, in fact, it modifies the doc //actionViewHeader->setEnabled( true ); //actionViewFooter->setEnabled( true ); actionViewZoom->setEnabled( true ); actionInsertComment->setEnabled( true ); actionAllowAutoFormat->setEnabled( true ); actionShowDocStruct->setEnabled( true ); actionConfigureCompletion->setEnabled( true ); actionFormatBullet->setEnabled(true); actionFormatNumber->setEnabled( true); actionSelectBookmark->setEnabled( true ); KAction* act = actionCollection()->action("edit_sldatabase"); if (act) act->setEnabled( true ); // In fact the new view could be readwrite, so this is too dangerous // (e.g. during spellchecking or during search-n-replace) //act = actionCollection()->action("view_newview"); //if (act) // act->setEnabled( true ); } else { frameSelectedChanged(); slotFrameSetEditChanged(); refreshCustomMenu(); refreshDeletePageAction(); // Correctly enable or disable undo/redo actions again m_doc->commandHistory()->updateActions(); } } void KWView::refreshDeletePageAction() { actionDeletePage->setEnabled( m_doc->numPages() > 1 && m_doc->processingType() == KWDocument::DTP ); } void KWView::showMouseMode( int _mouseMode ) { switch ( _mouseMode ) { case KWCanvas::MM_EDIT: case KWCanvas::MM_CREATE_TABLE: case KWCanvas::MM_CREATE_FORMULA: case KWCanvas::MM_CREATE_PART: // No tool to activate for this mode -> deselect all the others actionToolsCreateText->setChecked( false ); actionToolsCreatePix->setChecked( false ); //actionToolsCreatePart->setChecked( false ); break; case KWCanvas::MM_CREATE_TEXT: actionToolsCreateText->setChecked( true ); break; case KWCanvas::MM_CREATE_PIX: actionToolsCreatePix->setChecked( true ); break; //case KWCanvas::MM_CREATE_PART: //actionToolsCreatePart->setChecked( true ); break; } actionTableJoinCells->setEnabled( FALSE ); actionTableSplitCells->setEnabled( FALSE ); actionTableProtectCells->setEnabled( false ); actionFormatFrameSet->setEnabled(FALSE); actionTablePropertiesMenu->setEnabled( false ); actionConvertTableToText->setEnabled( false ); } void KWView::showStyle( const QString & styleName ) { QPtrListIterator styleIt( m_doc->styleCollection()->styleList() ); for ( int pos = 0 ; styleIt.current(); ++styleIt, ++pos ) { if ( styleIt.current()->name() == styleName ) { // Select style in combo actionFormatStyle->setCurrentItem( pos ); // Check the appropriate action among the actionFormatStyleMenu actions KToggleAction* act = dynamic_cast(actionCollection()->action( /*QString("style_%1").arg(pos).latin1()*/ styleIt.current()->shortCutName().latin1())); if ( act ) act->setChecked( true ); return; } } } void KWView::updateStyleList() { QString currentStyle = actionFormatStyle->currentText(); // Generate list of styles QStringList lst; QPtrListIterator styleIt( m_doc->styleCollection()->styleList() ); int pos = -1; for ( int i = 0; styleIt.current(); ++styleIt, ++i ) { QString name = styleIt.current()->displayName(); lst << name; if ( pos == -1 && name == currentStyle ) pos = i; } // Fill the combo - using a KSelectAction actionFormatStyle->setItems( lst ); if ( pos > -1 ) actionFormatStyle->setCurrentItem( pos ); // Fill the menu - using a KActionMenu, so that it's possible to bind keys // to individual actions QStringList lstWithAccels; // Generate unique accelerators for the menu items KAccelGen::generate( lst, lstWithAccels ); QMap shortCut; KActionPtrList lst2 = actionCollection()->actions("styleList"); QValueList actions = lst2; QValueList::ConstIterator it = lst2.begin(); QValueList::ConstIterator end = lst2.end(); for (; it != end; ++it ) { if ( !(*it)->shortcut().toString().isEmpty()) { KoParagStyle* tmp = m_doc->styleCollection()->findStyleShortCut( (*it)->name() ); if ( tmp ) shortCut.insert( tmp->shortCutName(), KShortcut( (*it)->shortcut())); } actionFormatStyleMenu->remove( *it ); delete *it; } uint i = 0; for ( QStringList::Iterator it = lstWithAccels.begin(); it != lstWithAccels.end(); ++it, ++i ) { KToggleAction* act = 0L; // The list lst was created (unsorted) from the style collection, so we have still the same order. KoParagStyle *tmp = m_doc->styleCollection()->styleAt( i ); if ( tmp ) { QCString name = tmp->shortCutName().latin1(); if ( shortCut.contains(name)) { act = new KToggleAction( (*it), (shortCut)[name], this, SLOT( slotStyleSelected() ), actionCollection(), name ); } else act = new KToggleAction( (*it), 0, this, SLOT( slotStyleSelected() ), actionCollection(),name ); act->setGroup( "styleList" ); act->setExclusiveGroup( "styleListAction" ); actionFormatStyleMenu->insert( act ); } else kdWarning() << "No style found for " << *it << endl; } } void KWView::updateFrameStyleList() { QString currentStyle = actionFrameStyle->currentText(); // Generate list of styles QStringList lst; QPtrListIterator styleIt( m_doc->frameStyleCollection()->frameStyleList() ); int pos = -1; for ( int i = 0; styleIt.current(); ++styleIt, ++i ) { QString name = styleIt.current()->displayName(); lst << name; if ( pos == -1 && name == currentStyle ) pos = i; } // Fill the combo - using a KSelectAction actionFrameStyle->setItems( lst ); if ( pos > -1 ) actionFrameStyle->setCurrentItem( pos ); // Fill the menu - using a KActionMenu, so that it's possible to bind keys // to individual actions QStringList lstWithAccels; // Generate unique accelerators for the menu items KAccelGen::generate( lst, lstWithAccels ); QMap shortCut; KActionPtrList lst2 = actionCollection()->actions("frameStyleList"); QValueList actions = lst2; QValueList::ConstIterator it = lst2.begin(); QValueList::ConstIterator end = lst2.end(); for (; it != end; ++it ) { if ( !(*it)->shortcut().toString().isEmpty()) { KWFrameStyle* tmp = m_doc->frameStyleCollection()->findStyleShortCut( (*it)->name() ); if ( tmp ) shortCut.insert( tmp->shortCutName(), KShortcut( (*it)->shortcut())); } actionFrameStyleMenu->remove(*it ); delete *it; } uint i = 0; for ( QStringList::Iterator it = lstWithAccels.begin(); it != lstWithAccels.end(); ++it, ++i ) { KToggleAction* act =0L; // The list lst was created (unsorted) from the frame style collection, so we have still the same order. KWFrameStyle *tmp = m_doc->frameStyleCollection()->frameStyleAt( i ); if ( tmp ) { QCString name = tmp->shortCutName().latin1(); if ( shortCut.contains(name)) { act = new KToggleAction( (*it), (shortCut)[name], this, SLOT( slotFrameStyleSelected() ), actionCollection(), name ); } else act = new KToggleAction( (*it), 0, this, SLOT( slotFrameStyleSelected() ), actionCollection(), name ); act->setGroup( "frameStyleList" ); act->setExclusiveGroup( "frameStyleList" ); actionFrameStyleMenu->insert( act ); } else kdWarning() << "No frame style found for " << *it << endl; } } void KWView::updateTableStyleList() { QString currentStyle = actionTableStyle->currentText(); // Generate list of styles QStringList lst; QPtrListIterator styleIt( m_doc->tableStyleCollection()->tableStyleList() ); int pos = -1; for ( int i = 0; styleIt.current(); ++styleIt, ++i ) { QString name = styleIt.current()->displayName(); lst << name; if ( pos == -1 && name == currentStyle ) pos = i; } // Fill the combo - using a KSelectAction actionTableStyle->setItems( lst ); if ( pos > -1 ) actionTableStyle->setCurrentItem( pos ); // Fill the menu - using a KActionMenu, so that it's possible to bind keys // to individual actions QStringList lstWithAccels; // Generate unique accelerators for the menu items KAccelGen::generate( lst, lstWithAccels ); QMap shortCut; KActionPtrList lst2 = actionCollection()->actions("tableStyleList"); QValueList actions = lst2; QValueList::ConstIterator it = lst2.begin(); QValueList::ConstIterator end = lst2.end(); for (; it != end; ++it ) { if ( !(*it)->shortcut().toString().isEmpty()) { KWTableStyle* tmp = m_doc->tableStyleCollection()->findStyleShortCut( (*it)->name() ); if ( tmp ) shortCut.insert( tmp->shortCutName(), KShortcut( (*it)->shortcut())); } actionTableStyleMenu->remove( *it ); delete *it; } uint i = 0; for ( QStringList::Iterator it = lstWithAccels.begin(); it != lstWithAccels.end(); ++it, ++i ) { KToggleAction* act =0L; // The list lst was created (unsorted) from the table style collection, so we have still the same order. KWTableStyle *tmp = m_doc->tableStyleCollection()->tableStyleAt( i ); if ( tmp) { QCString name = tmp->shortCutName().latin1(); if ( shortCut.contains(name)) { act = new KToggleAction( (*it), (shortCut)[name], this, SLOT( slotTableStyleSelected() ), actionCollection(), name ); } else act = new KToggleAction( (*it), 0, this, SLOT( slotTableStyleSelected() ), actionCollection(), name ); act->setExclusiveGroup( "tableStyleList" ); act->setGroup( "tableStyleList" ); actionTableStyleMenu->insert( act ); } else kdWarning() << "No table style found for " << *it << endl; } } void KWView::editCut() { KWFrameSetEdit * edit = m_gui->canvasWidget()->currentFrameSetEdit(); if ( edit ) edit->cut(); else { m_gui->canvasWidget()->cutSelectedFrames(); } } void KWView::editCopy() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->copy(); else { QDragObject *drag = m_doc->dragSelected( 0 ); QApplication::clipboard()->setData( drag ); } } void KWView::editPaste() { QMimeSource *data = QApplication::clipboard()->data(); bool providesImage, providesKWordText, providesKWord, providesFormula; checkClipboard( data, providesImage, providesKWordText, providesKWord, providesFormula ); Q_ASSERT( providesImage || providesKWordText || providesKWord || providesFormula ); // formula must be the first as a formula is also available as image if ( providesFormula ) { KWFrameSetEdit * edit = m_gui->canvasWidget()->currentFrameSetEdit(); if ( edit && edit->frameSet()->type() == FT_FORMULA ) { edit->paste(); } else { insertFormula( data ); } } else // pasting frames { deselectAllFrames(); if ( providesKWord || providesKWordText ) { // TODO merge those two [once everything works] KWFrameSetEdit * edit = m_gui->canvasWidget()->currentFrameSetEdit(); if ( edit ) edit->paste(); QCString returnedTypeMime; // Not editing a frameset? We can't paste plain text then... only entire frames. if ( KWTextDrag::provides( data, KoTextObject::acceptSelectionMimeType(), returnedTypeMime) ) { QByteArray arr = data->encodedData( returnedTypeMime ); if( !arr.isEmpty() ) { QBuffer buffer( arr ); KoStore * store = KoStore::createStore( &buffer, KoStore::Read ); QValueList frames = m_doc->insertOasisData( store, 0 ); delete store; QValueList::ConstIterator it = frames.begin(); for ( ; it != frames.end() ; ++it ) (*it)->setSelected( true ); // TODO undo/redo command for the frames created above } } } else { // providesImage, must be after providesKWord KoPoint docPoint( m_doc->ptLeftBorder(), m_doc->ptPageTop( m_currentPage ) + m_doc->ptTopBorder() ); m_gui->canvasWidget()->pasteImage( data, docPoint ); } } } void KWView::editSelectAll() { KWFrameSetEdit * edit = m_gui->canvasWidget()->currentFrameSetEdit(); if ( edit ) edit->selectAll(); } void KWView::editSelectAllFrames() { m_gui->canvasWidget()->selectAllFrames( true ); frameSelectedChanged(); } void KWView::editFind() { if (!m_searchEntry) m_searchEntry = new KoSearchContext(); KWTextFrameSetEdit * edit = currentTextEdit(); bool hasSelection = edit && edit->textFrameSet()->hasSelection(); bool hasCursor = edit != 0L; KoSearchDia dialog( m_gui->canvasWidget(), "find", m_searchEntry, hasSelection, hasCursor ); if ( dialog.exec() == QDialog::Accepted ) { delete m_findReplace; m_findReplace = new KWFindReplace( m_gui->canvasWidget(), &dialog, m_gui->canvasWidget()->kWordDocument()->visibleTextObjects(m_gui->canvasWidget()->viewMode()), edit); editFindNext(); } } void KWView::editReplace() { if (!m_searchEntry) m_searchEntry = new KoSearchContext(); if (!m_replaceEntry) m_replaceEntry = new KoSearchContext(); KWTextFrameSetEdit * edit = currentTextEdit(); bool hasSelection = edit && edit->textFrameSet()->hasSelection(); bool hasCursor = edit != 0L; KoReplaceDia dialog( m_gui->canvasWidget(), "replace", m_searchEntry, m_replaceEntry, hasSelection, hasCursor ); if ( dialog.exec() == QDialog::Accepted ) { delete m_findReplace; m_findReplace = new KWFindReplace( m_gui->canvasWidget(), &dialog, m_gui->canvasWidget()->kWordDocument()->visibleTextObjects(m_gui->canvasWidget()->viewMode()), edit); editFindNext(); } } void KWView::editFindNext() { if ( !m_findReplace ) // shouldn't be called before find or replace is activated { editFind(); return; } (void) m_findReplace->findNext(); } void KWView::editFindPrevious() { if ( !m_findReplace ) // shouldn't be called before find or replace is activated { editFind(); return; } (void) m_findReplace->findPrevious(); } void KWView::adjustZOrderOfSelectedFrames(moveFrameType moveType) { KMacroCommand* macroCmd = 0L; // For each selected frame... QPtrList frames = m_doc->getSelectedFrames(); if(frames.count()==0) return; int pageNum= frames.at(0)->pageNum(); for (QPtrListIterator fIt( frames ); fIt.current() ; ++fIt ) { // include all frames in case of table. KWFrameSet *table = fIt.current()->frameSet()->getGroupManager(); if(table) { for (QPtrListIterator cellIt(table->frameIterator() ); cellIt.current() ; ++cellIt ) { if(frames.contains(cellIt.current() ) ==0 && cellIt.current()->pageNum()==pageNum) frames.append(cellIt.current()); } } } int lowestZOrder=10000; QString actionName; for (QPtrListIterator fIt( frames ); fIt.current() ; ++fIt ) { KWFrame* frame = fIt.current(); int newZOrder=0; switch(moveType) { case RaiseFrame: newZOrder=raiseFrame(frames,frame); actionName=i18n("Raise Frame"); break; case LowerFrame: newZOrder=lowerFrame(frames,frame); actionName=i18n("Lower Frame"); break; case BringToFront: newZOrder=bringToFront(frames,frame); actionName=i18n("Bring to Front"); break; case SendToBack: newZOrder=sendToBack(frames,frame); actionName=i18n("Send to Back"); break; } if ( newZOrder != frame->zOrder() ) { // only if changed. lowestZOrder=QMIN(lowestZOrder, newZOrder); KWFrame* frameCopy = frame->getCopy(); frame->setZOrder( newZOrder ); KWFramePropertiesCommand* cmd = new KWFramePropertiesCommand( QString::null, frameCopy, frame); if(!macroCmd) macroCmd = new KMacroCommand( actionName ); macroCmd->addCommand(cmd); frameCopy = frame->getCopy(); frame->setZOrder( newZOrder ); cmd = new KWFramePropertiesCommand( QString::null, frameCopy, frame ); if(!macroCmd) macroCmd = new KMacroCommand( actionName ); macroCmd->addCommand(cmd); } } if ( macroCmd ) { m_doc->addCommand(macroCmd); // Calling updateFrames() on the selected frames' framesets isn't enough, // we also need other framesets to notice the new frames on top. m_doc->updateAllFrames(); m_doc->layout(); m_doc->repaintAllViews(); } if(lowestZOrder != 10000 && m_doc->processingType() == KWDocument::WP) { m_doc->lowerMainFrames( pageNum, lowestZOrder ); } } // Make room for refZOrder, by raising all z-orders above it by 1 void KWView::increaseAllZOrdersAbove(int refZOrder, int pageNum, const QPtrList frameSelection) { QPtrList framesInPage = m_doc->framesInPage( pageNum, false ); for ( QPtrListIterator frameIt( framesInPage ); frameIt.current(); ++frameIt ) { if(frameSelection.contains(frameIt.current()) > 0) continue; // ignore frames we selected. if(frameIt.current()->zOrder() >= refZOrder) { frameIt.current()->setZOrder( frameIt.current()->zOrder() + 1 ); } } } // Make room for refZOrder, by lowering all z-orders below it by 1 void KWView::decreaseAllZOrdersUnder(int refZOrder, int pageNum, const QPtrList frameSelection) { QPtrList framesInPage = m_doc->framesInPage( pageNum, false ); for ( QPtrListIterator frameIt( framesInPage ); frameIt.current(); ++frameIt ) { if(frameSelection.contains(frameIt.current()) > 0) continue; // ignore frames we selected. if(frameIt.current()->zOrder() <= refZOrder) { frameIt.current()->setZOrder( frameIt.current()->zOrder() - 1 ); } } } int KWView::raiseFrame(const QPtrList frameSelection, const KWFrame *frame) { int newZOrder = 10000; QValueList zorders; QPtrList framesInPage = m_doc->framesInPage( frame->pageNum(), false ); for ( QPtrListIterator frameIt( framesInPage ); frameIt.current(); ++frameIt ) { if(frameSelection.contains(frameIt.current()) > 0) continue; // ignore other frames we selected. if(! frameIt.current()->intersects(*frame)) continue; // only frames that I intersect with. int z = frameIt.current()->zOrder(); if(z > frame->zOrder()) { newZOrder=QMIN(newZOrder, z + 1); } zorders.append( z ); } if(newZOrder==10000) return frame->zOrder(); // Ensure that newZOrder is "free" if ( zorders.find( newZOrder ) != zorders.end() ) increaseAllZOrdersAbove( newZOrder, frame->pageNum(), frameSelection ); return newZOrder; } int KWView::lowerFrame(const QPtrList frameSelection, const KWFrame *frame) { int newZOrder = -10000; QValueList zorders; QPtrList framesInPage = m_doc->framesInPage( frame->pageNum(), false ); for ( QPtrListIterator frameIt( framesInPage ); frameIt.current(); ++frameIt ) { if(frameSelection.contains(frameIt.current()) > 0) continue; // ignore other frames we selected. if(frameIt.current()->frameSet()->isMainFrameset()) continue; // ignore main frameset. if(! frameIt.current()->intersects(*frame)) continue; // only frames that I intersect with. int z = frameIt.current()->zOrder(); if(z < frame->zOrder()) { newZOrder=QMAX(newZOrder, z -1); } zorders.append( z ); } if(newZOrder==-10000) return frame->zOrder(); // Ensure that newZOrder is "free" if ( zorders.find( newZOrder ) != zorders.end() ) decreaseAllZOrdersUnder( newZOrder, frame->pageNum(), frameSelection ); return newZOrder; } int KWView::bringToFront(const QPtrList frameSelection, const KWFrame *frame) { int newZOrder = frame->zOrder(); QPtrList framesInPage = m_doc->framesInPage( frame->pageNum(), false ); for ( QPtrListIterator frameIt( framesInPage ); frameIt.current(); ++frameIt ) { if(frameSelection.contains(frameIt.current()) > 0) continue; // ignore other frames we selected. if(! frameIt.current()->intersects(*frame)) continue; // only frames that I intersect with. newZOrder=QMAX(newZOrder, frameIt.current()->zOrder()+1); } return newZOrder; } int KWView::sendToBack(const QPtrList frameSelection, const KWFrame *frame) { int newZOrder = frame->zOrder(); QPtrList framesInPage = m_doc->framesInPage( frame->pageNum(), false ); for ( QPtrListIterator frameIt( framesInPage ); frameIt.current(); ++frameIt ) { if(frameSelection.contains(frameIt.current()) > 0) continue; // ignore other frames we selected. if(frameIt.current()->frameSet()->isMainFrameset()) continue; // ignore main frameset. if(! frameIt.current()->intersects(*frame)) continue; // only frames that I intersect with. newZOrder=QMIN(newZOrder, frameIt.current()->zOrder()-1); } return newZOrder; } void KWView::editDeleteFrame() { deleteFrame(); } void KWView::deleteFrame( bool _warning ) { if ( !m_doc->isReadWrite() ) return; QPtrList frames=m_doc->getSelectedFrames(); Q_ASSERT( frames.count() >= 1 ); if( frames.count() < 1) return; if(frames.count()==1) { KWFrame *theFrame = frames.at(0); KWFrameSet *fs = theFrame->frameSet(); Q_ASSERT( !fs->isAHeader() ); // the action is disabled for such cases Q_ASSERT( !fs->isAFooter() ); if ( fs->isMainFrameset() || fs->isAFooter() || fs->isAHeader() || fs->isFootEndNote()) return; // frame is part of a table? if ( fs->getGroupManager() ) { int result = KMessageBox::warningContinueCancel( this, i18n( "You are about to delete a table.\n" "Doing so will delete all the text in the table.\n" "Are you sure you want to do that?"), i18n("Delete Table"), i18n("&Delete"), "DeleteTableConfirmation", true ); if (result != KMessageBox::Continue) return; m_doc->deleteTable( fs->getGroupManager() ); m_gui->canvasWidget()->emitFrameSelectedChanged(); return; } if ( fs->getNumFrames() == 1 && fs->type() == FT_TEXT) { if ( m_doc->processingType() == KWDocument::WP && m_doc->frameSetNum( fs ) == 0 ) return; // if primairy FS, we can't delete it :) KWTextFrameSet * textfs = dynamic_cast(fs); if ( !textfs ) // assertion... return; KoTextDocument * textdoc = textfs->textDocument(); if ( textdoc->length() > 0 ) { int result = KMessageBox::warningContinueCancel( this, i18n( "You are about to delete the last Frame of the " "Frameset '%1'. " "The contents of this Frameset will not appear " "anymore!\n" "Are you sure you want to do that?").arg(fs->getName()), i18n("Delete Frame"), i18n("&Delete")); if (result != KMessageBox::Continue) return; m_doc->deleteFrame( theFrame ); m_gui->canvasWidget()->emitFrameSelectedChanged(); return; } } if(_warning) { int result = KMessageBox::warningContinueCancel( this, i18n("Do you want to delete this frame?"), i18n("Delete Frame"), i18n("&Delete"), "DeleteLastFrameConfirmation", true ); if (result != KMessageBox::Continue) return; } m_doc->deleteFrame( theFrame ); m_gui->canvasWidget()->emitFrameSelectedChanged(); } else { //several frame if(_warning) { int result = KMessageBox::warningContinueCancel( this, i18n("Do you want to delete this frame?"), i18n("Delete Frame"), i18n("&Delete"), "DeleteLastFrameConfirmation", true ); if (result != KMessageBox::Continue) return; } m_doc->deleteSelectedFrames(); m_gui->canvasWidget()->emitFrameSelectedChanged(); } } void KWView::createLinkedFrame() { QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() != 1) return; // action is disabled in such a case KWFrame* frame = selectedFrames.getFirst(); KWFrame* newFrame = new KWFrame(0L, frame->x()+20, frame->y()+20, frame->width(), frame->height() ); newFrame->setZOrder( m_doc->maxZOrder( newFrame->pageNum(m_doc) ) + 1 ); // make sure it's on top newFrame->setCopy(true); newFrame->setNewFrameBehavior( KWFrame::Copy ); frame->frameSet()->addFrame( newFrame ); frame->setSelected(false); newFrame->setSelected(true); KWCreateFrameCommand *cmd = new KWCreateFrameCommand( i18n("Create Linked Copy"), newFrame ); m_doc->addCommand( cmd ); m_doc->frameChanged( newFrame ); } void KWView::editCustomVariable() { KWTextFrameSetEdit * edit = currentTextEdit(); if (edit) { KoCustomVariable *var = static_cast(edit->variable()); if (var) { QString oldvalue = var->value(); KoCustomVarDialog dia( this, var ); if ( dia.exec() ) { m_doc->recalcVariables( VT_CUSTOM ); if( var->value() != oldvalue ) { KWChangeCustomVariableValue *cmd=new KWChangeCustomVariableValue(i18n( "Change Custom Variable" ),m_doc, oldvalue, var->value(), var ); m_doc->addCommand(cmd); } } } } } void KWView::editCustomVars() { KoCustomVariablesDia dia( this, m_doc->getVariableCollection()->getVariables() ); QStringList listOldCustomValue; QPtrListIterator oldIt( m_doc->getVariableCollection()->getVariables() ); for ( ; oldIt.current() ; ++oldIt ) { if(oldIt.current()->type()==VT_CUSTOM) listOldCustomValue.append(((KoCustomVariable*)oldIt.current())->value()); } if(dia.exec()) { m_doc->recalcVariables( VT_CUSTOM ); //temporaly hack, for the moment we can't undo/redo change custom variables QPtrListIterator it( m_doc->getVariableCollection()->getVariables() ); KMacroCommand * macroCommand = 0L; int i=0; for ( ; it.current() ; ++it ) { if(it.current()->type() == VT_CUSTOM ) { if(((KoCustomVariable*)it.current())->value()!=*(listOldCustomValue.at(i))) { if(!macroCommand) macroCommand = new KMacroCommand( i18n( "Change Custom Variable" ) ); KWChangeCustomVariableValue *cmd=new KWChangeCustomVariableValue(i18n( "Change Custom Variable" ),m_doc,*(listOldCustomValue.at(i)), ((KoCustomVariable*)it.current())->value() ,((KoCustomVariable*)it.current())); macroCommand->addCommand(cmd); } i++; } } if(macroCommand) m_doc->addCommand(macroCommand); } } void KWView::editMailMergeDataBase() { m_doc->getMailMergeDataBase()->showConfigDialog(this); #if 0 KWMailMergeEditor *dia = new KWMailMergeEditor( this, m_doc->getMailMergeDataBase() ); dia->exec(); // Don't know if we really need this so it's commented out (SL) // m_gui->canvasWidget()->repaintAll( FALSE ); delete dia; #endif } void KWView::viewTextMode() { if ( actionViewTextMode->isChecked() ) { KWTextFrameSet* fs = KWViewModeText::determineTextFrameSet( m_doc ); if ( fs ) { // TODO: disable the action when there is no text frameset available if ( dynamic_cast(m_gui->canvasWidget()->viewMode()) ) m_zoomViewModePreview = m_doc->zoom(); showZoom( m_zoomViewModeNormal ); // share the same zoom setZoom( m_zoomViewModeNormal, false ); m_doc->switchViewMode( new KWViewModeText( m_doc, fs ) ); } else initGUIButton(); // ensure we show the current viewmode } else actionViewTextMode->setChecked( true ); // always one has to be checked ! } void KWView::viewPageMode() { if ( actionViewPageMode->isChecked() ) { if ( dynamic_cast(m_gui->canvasWidget()->viewMode()) ) m_zoomViewModePreview = m_doc->zoom(); showZoom( m_zoomViewModeNormal ); setZoom( m_zoomViewModeNormal, false ); m_doc->switchViewMode( new KWViewModeNormal( m_doc, viewFrameBorders() ) ); } else actionViewPageMode->setChecked( true ); // always one has to be checked ! } void KWView::viewPreviewMode() { if ( actionViewPreviewMode->isChecked() ) { m_zoomViewModeNormal = m_doc->zoom(); showZoom( m_zoomViewModePreview ); setZoom( m_zoomViewModePreview, false ); m_doc->switchViewMode( new KWViewModePreview( m_doc, viewFrameBorders(), m_doc->nbPagePerRow() ) ); } else actionViewPreviewMode->setChecked( true ); // always one has to be checked ! } void KWView::changeZoomMenu( int zoom ) { QString mode; if ( m_gui && m_gui->canvasWidget() && m_gui->canvasWidget()->viewMode()) mode = m_gui->canvasWidget()->viewMode()->type(); QStringList lst; lst << i18n( "Zoom to Width" ); if ( mode!="ModeText" ) { lst << i18n( "Zoom to Whole Page" ); } if(zoom>0) { QValueList list; bool ok; const QStringList itemsList ( actionViewZoom->items() ); QRegExp regexp("(\\d+)"); // "Captured" non-empty sequence of digits for (QStringList::ConstIterator it = itemsList.begin() ; it != itemsList.end() ; ++it) { regexp.search(*it); const int val=regexp.cap(1).toInt(&ok); //zoom : limit inferior=10 if(ok && val>9 && list.contains(val)==0) list.append( val ); } //necessary at the beginning when we read config //this value is not in combo list if(list.contains(zoom)==0) list.append( zoom ); qHeapSort( list ); for (QValueList::Iterator it = list.begin() ; it != list.end() ; ++it) lst.append( i18n("%1%").arg(*it) ); } else { lst << i18n("%1%").arg("33"); lst << i18n("%1%").arg("50"); lst << i18n("%1%").arg("75"); lst << i18n("%1%").arg("100"); lst << i18n("%1%").arg("125"); lst << i18n("%1%").arg("150"); lst << i18n("%1%").arg("200"); lst << i18n("%1%").arg("250"); lst << i18n("%1%").arg("350"); lst << i18n("%1%").arg("400"); lst << i18n("%1%").arg("450"); lst << i18n("%1%").arg("500"); } actionViewZoom->setItems( lst ); } void KWView::showZoom( int zoom ) { QStringList list = actionViewZoom->items(); QString zoomStr( i18n("%1%").arg( zoom ) ); actionViewZoom->setCurrentItem( list.findIndex(zoomStr) ); } void KWView::slotViewFormattingChars() { m_doc->setViewFormattingChars(actionViewFormattingChars->isChecked()); m_doc->layout(); // Due to the different formatting when this option is activated m_doc->repaintAllViews(); } void KWView::slotViewFrameBorders() { setViewFrameBorders(actionViewFrameBorders->isChecked()); m_gui->canvasWidget()->repaintAll(); } void KWView::viewHeader() { bool state = actionViewHeader->isChecked(); m_doc->setHeaderVisible( state ); KWHideShowHeader *cmd=new KWHideShowHeader( state ? i18n("Show Header"):i18n("Hide Header"), m_doc, state); m_doc->addCommand(cmd); updateHeader(); } void KWView::updateHeader() { KWTextFrameSetEdit * edit = currentTextEdit(); bool state = actionViewHeader->isChecked(); if(!state ) { KWFrameSet *frameSet=0L; if(edit) { frameSet=edit->frameSet(); if (frameSet->isAHeader()) m_doc->terminateEditing( frameSet ); else { KWTableFrameSet *table = frameSet->frame(0)->frameSet()->getGroupManager(); if (table) { if (table->isFloating() && table->anchorFrameset()->isAHeader()) m_doc->terminateEditing( table ); } } } else { KWFormulaFrameSetEdit * editFormula = dynamic_cast(m_gui->canvasWidget()->currentFrameSetEdit()); if(editFormula) { frameSet= editFormula->frameSet(); if(frameSet->type()==FT_FORMULA && frameSet->isFloating()) m_doc->terminateEditing( frameSet ); } } } m_doc->updateResizeHandles( ); } void KWView::viewFooter() { bool state=actionViewFooter->isChecked(); m_doc->setFooterVisible( state ); KWHideShowFooter *cmd=new KWHideShowFooter( state ? i18n("Show Footer"):i18n("Hide Footer"), m_doc, state); m_doc->addCommand(cmd); updateFooter(); } void KWView::updateFooter() { bool state=actionViewFooter->isChecked(); KWTextFrameSetEdit * edit = currentTextEdit(); if(!state ) { KWFrameSet *frameSet=0L; if(edit) { frameSet=edit->frameSet(); if (frameSet->isAFooter()) m_doc->terminateEditing( frameSet ); else { KWTableFrameSet *table = frameSet->frame(0)->frameSet()->getGroupManager(); if (table) { if (table->isFloating() && table->anchorFrameset()->isAFooter()) m_doc->terminateEditing( table ); } } } else { KWFormulaFrameSetEdit * editFormula = dynamic_cast(m_gui->canvasWidget()->currentFrameSetEdit()); if(editFormula) { frameSet= editFormula->frameSet(); if(frameSet->type()==FT_FORMULA && frameSet->isFloating()) m_doc->terminateEditing( frameSet ); } } } m_doc->updateResizeHandles( ); } void KWView::viewZoom( const QString &s ) { bool ok=false; KWCanvas * canvas = m_gui->canvasWidget(); int zoom = 0; if ( s == i18n("Zoom to Width") ) { zoom = qRound( static_cast(canvas->visibleWidth() * 100 ) / (m_doc->resolutionX() * m_doc->ptPaperWidth() ) ); ok = true; } else if ( s == i18n("Zoom to Whole Page") ) { double height = m_doc->resolutionY() * m_doc->ptPaperHeight(); double width = m_doc->resolutionX() * m_doc->ptPaperWidth(); zoom = QMIN( qRound( static_cast(canvas->visibleHeight() * 100 ) / height ), qRound( static_cast(canvas->visibleWidth() * 100 ) / width ) ); ok = true; } else { QRegExp regexp("(\\d+)"); // "Captured" non-empty sequence of digits regexp.search(s); zoom=regexp.cap(1).toInt(&ok); } if( !ok || zoom<10 ) //zoom should be valid and >10 zoom = m_doc->zoom(); //refresh menu changeZoomMenu( zoom ); //refresh menu item showZoom(zoom); //apply zoom if zoom!=m_doc->zoom() if( zoom != m_doc->zoom() ) { setZoom( zoom, true ); m_doc->updateResizeHandles(); KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->ensureCursorVisible(); } m_gui->canvasWidget()->setFocus(); } void KWView::setZoom( int zoom, bool updateViews ) { m_doc->setZoomAndResolution( zoom, KoGlobal::dpiX(), KoGlobal::dpiY()); m_doc->newZoomAndResolution( updateViews, false ); m_doc->updateZoomRuler(); // Also set the zoom in KoView (for embedded views) //kdDebug() << "KWView::showZoom setting koview zoom to " << m_doc->zoomedResolutionY() << endl; KoView::setZoom( m_doc->zoomedResolutionY() /* KoView only supports one zoom */ ); } void KWView::insertPicture() { if ( actionToolsCreatePix->isChecked() ) { KWInsertPicDia dia( this,m_gui->canvasWidget()->pictureInline(),m_gui->canvasWidget()->pictureKeepRatio(),m_doc ); if ( dia.exec() == QDialog::Accepted && !dia.picture().isNull() ) { insertPicture( dia.picture(), dia.makeInline(), dia.keepRatio() ); m_gui->canvasWidget()->setPictureInline( dia.makeInline()); m_gui->canvasWidget()->setPictureKeepRatio( dia.keepRatio() ); } else m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); } else { // clicked on the already active tool -> abort m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); } } void KWView::slotEmbedImage( const QString &filename ) { KoPicture picture; KoPictureKey key; key.setKeyFromFile( filename ); picture.setKey( key ); picture.loadFromFile( filename ); insertPicture( picture, false, true ); } void KWView::insertPicture( const KoPicture& picture, const bool makeInline, const bool _keepRatio ) { if ( makeInline ) { const double widthLimit = m_doc->unzoomItX( m_doc->paperWidth() - m_doc->leftBorder() - m_doc->rightBorder() - m_doc->zoomItX( 10 ) ); const double heightLimit = m_doc->unzoomItY( m_doc->paperHeight() - m_doc->topBorder() - m_doc->bottomBorder() - m_doc->zoomItY( 10 ) ); fsInline = 0L; KWPictureFrameSet *frameset = new KWPictureFrameSet( m_doc, QString::null ); frameset->insertPicture( picture ); QSize pixmapSize ( frameset->picture().getOriginalSize() ); // This ensures 1-1 at 100% on screen, but allows zooming and printing with correct DPI values // ### TODO/FIXME: is the qRound really necessary? double width = m_doc->unzoomItX( qRound( (double)pixmapSize.width() * m_doc->zoomedResolutionX() / POINT_TO_INCH( KoGlobal::dpiX() ) ) ); double height = m_doc->unzoomItY( qRound( (double)pixmapSize.height() * m_doc->zoomedResolutionY() / POINT_TO_INCH( KoGlobal::dpiY() ) ) ); frameset->setKeepAspectRatio( _keepRatio); if ( _keepRatio && ((width > widthLimit) || (height > heightLimit)) ) { // size too big => adjust the size and keep ratio const double ratioX = width / widthLimit; const double ratioY = height / heightLimit; const double ratioPicture = width / height; if ( ratioPicture == 0 ) // unlikely { width = widthLimit; height = heightLimit; } else if ( ratioX > ratioY ) // restrict width and calculate height { width = widthLimit; height = widthLimit/ratioPicture; } else // restrict height and calculate width { width = heightLimit*ratioPicture; height = heightLimit; } } else { // Apply reasonable limits width = kMin( width, widthLimit ); height = kMin( height, heightLimit ); } fsInline = frameset; KWFrame *frame = new KWFrame ( fsInline, 0, 0, width, height ); fsInline->addFrame( frame, false ); m_gui->canvasWidget()->inlinePictureStarted(); showMouseMode( KWCanvas::MM_EDIT ); displayFrameInlineInfo(); #if 0 edit->insertFloatingFrameSet( fs, i18n("Insert Picture Inline") ); fs->finalize(); // done last since it triggers a redraw showMouseMode( KWCanvas::MM_EDIT ); m_doc->refreshDocStructure(Pictures); #endif } else { m_gui->canvasWidget()->insertPicture( picture , picture.getOriginalSize(), _keepRatio ); } } bool KWView::insertInlinePicture() { KWTextFrameSetEdit * edit = currentTextEdit(); if(edit) { if ( edit->textFrameSet()->textObject()->protectContent() ) return false; m_doc->addFrameSet( fsInline, false ); // done first since the frame number is stored in the undo/redo #if 0 KWFrame *frame = new KWFrame( fsInline, 0, 0, m_doc->unzoomItX( width ), m_doc->unzoomItY( height ) ); fsInline->addFrame( frame, false ); #endif edit->insertFloatingFrameSet( fsInline, i18n("Insert Picture Inline") ); fsInline->finalize(); // done last since it triggers a redraw showMouseMode( KWCanvas::MM_EDIT ); m_doc->refreshDocStructure(Pictures); fsInline=0L; updateFrameStatusBarItem(); } else { delete fsInline; fsInline=0L; updateFrameStatusBarItem(); } return true; } void KWView::displayFrameInlineInfo() { KMessageBox::information(this, i18n("Set cursor where you want to insert inline frame."), i18n("Insert Inline Frame"), "SetCursorInsertInlineFrame",true); KStatusBar * sb = statusBar(); if (sb ) { if ( !m_sbFramesLabel ) { m_sbFramesLabel = sb ? new KStatusBarLabel( QString::null, 0, sb ) : 0; addStatusBarItem( m_sbFramesLabel ); } if(m_sbFramesLabel) m_sbFramesLabel->setText( i18n("Set cursor where you want to insert inline frame.") ); } } void KWView::insertSpecialChar() { KWTextFrameSetEdit *edit=currentTextEdit(); if ( !edit ) return; QString f = edit->textFontFamily(); QChar c=' '; if (m_specialCharDlg==0) { m_specialCharDlg = new KoCharSelectDia( this, "insert special char", f, c, false ); connect( m_specialCharDlg, SIGNAL(insertChar(QChar,const QString &)), this, SLOT(slotSpecialChar(QChar,const QString &))); connect( m_specialCharDlg, SIGNAL( finished() ), this, SLOT( slotSpecialCharDlgClosed() ) ); } m_specialCharDlg->show(); } void KWView::slotSpecialCharDlgClosed() { if ( m_specialCharDlg ) { disconnect( m_specialCharDlg, SIGNAL(insertChar(QChar,const QString &)), this, SLOT(slotSpecialChar(QChar,const QString &))); disconnect( m_specialCharDlg, SIGNAL( finished() ), this, SLOT( slotSpecialCharDlgClosed() ) ); m_specialCharDlg->deleteLater(); m_specialCharDlg = 0L; } } void KWView::slotSpecialChar(QChar c, const QString &_font) { KWTextFrameSetEdit *edit=currentTextEdit(); if ( !edit ) return; edit->insertSpecialChar(c, _font); } void KWView::insertFrameBreak() { KWTextFrameSetEdit *edit=currentTextEdit(); if ( !edit ) return; edit->insertFrameBreak(); } void KWView::insertPage() { if ( m_doc->processingType() == KWDocument::WP ) { m_gui->canvasWidget()->editFrameSet( m_doc->frameSet(0) ); KWTextFrameSetEdit *edit = currentTextEdit(); Q_ASSERT(edit); if ( edit ) edit->insertWPPage(); } else { KWInsertPageDia dlg( this, "insertpage"); if ( dlg.exec()) { // If 'before', subtract 1 to the page number KCommand* cmd = new KWInsertRemovePageCommand( m_doc, KWInsertRemovePageCommand::Insert, dlg.getInsertPagePos()==KW_INSERTPAGEAFTER ? m_currentPage : (m_currentPage -1)); cmd->execute(); m_doc->addCommand( cmd ); } } } void KWView::deletePage() { if ( m_doc->processingType() == KWDocument::WP ) { // TODO we have to remove text so that the page can be removed // (e.g. everything between two (auto or manual) frame breaks) // Note: This must also be done in DTP mode, in some cases. } else { KCommand* cmd = new KWInsertRemovePageCommand( m_doc, KWInsertRemovePageCommand::Remove, m_currentPage ); cmd->execute(); m_doc->addCommand( cmd ); } } void KWView::insertLink() { KWTextFrameSetEdit *edit=currentTextEdit(); if ( !edit ) return; QString link; QString ref; if ( edit->textFrameSet()->hasSelection() ) { QString selectedText = edit->textFrameSet()->textObject()->selectedText(); if ( selectedText.startsWith( "mailto:/" ) || selectedText.startsWith( "ftp:/" ) || selectedText.startsWith( "http:/" ) ) { link=selectedText; ref = selectedText; } else { //Just add text as link name and not url link = selectedText; } } if(KoInsertLinkDia::createLinkDia(link, ref, m_doc->listOfBookmarkName(0), this)) { if(!link.isEmpty() && !ref.isEmpty()) edit->insertLink(link, ref); } } void KWView::insertComment() { KWTextFrameSetEdit *edit=currentTextEdit(); if ( !edit ) return; QString authorName; KoDocumentInfo * info = m_doc->documentInfo(); KoDocumentInfoAuthor * authorPage = static_cast(info->page( "author" )); if ( !authorPage ) kdWarning() << "Author information not found in documentInfo !" << endl; else authorName = authorPage->fullName(); KoCommentDia *commentDia = new KoCommentDia( this, QString::null,authorName ); if( commentDia->exec() ) { edit->insertComment(commentDia->commentText()); } delete commentDia; } void KWView::insertVariable() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KAction * act = (KAction *)(sender()); VariableDefMap::Iterator it = m_variableDefMap.find( act ); if ( it == m_variableDefMap.end() ) kdWarning() << "Action not found in m_variableDefMap." << endl; else { if ( (*it).type == VT_FIELD ) edit->insertVariable( (*it).type, KoFieldVariable::fieldSubType( (*it).subtype ) ); else edit->insertVariable( (*it).type, (*it).subtype ); } } } void KWView::insertFootNote() { KWTextFrameSetEdit * edit = currentTextEdit(); //Q_ASSERT( edit ); // the action should be disabled if we're not editing a textframeset... if ( edit ) // test for dcop call ! { if ( edit->frameSet() != m_doc->frameSet(0) ) { KMessageBox::sorry( this, i18n( "You can only insert footnotes or " "endnotes into the first frameset."), i18n("Insert Footnote")); } else { KWFootNoteDia dia( m_gui->canvasWidget()->footNoteType(), m_gui->canvasWidget()->numberingFootNoteType(), QString::null, this, m_doc, 0 ); if ( dia.exec() ) { edit->insertFootNote( dia.noteType(), dia.numberingType(), dia.manualString() ); m_gui->canvasWidget()->setFootNoteType( dia.noteType() ); m_gui->canvasWidget()->setNumberingFootNoteType( dia.numberingType() ); } } } } void KWView::renameButtonTOC(bool b) { KActionCollection * coll = actionCollection(); QString name= b ? i18n("Update Table of &Contents"):i18n("Table of &Contents"); coll->action("insert_contents")->setText(name); } void KWView::insertContents() { KWTextFrameSetEdit *edit = currentTextEdit(); if (edit) edit->insertTOC(); } void KWView::formatFont() { KoTextFormatInterface* textIface = applicableTextInterfaces().first(); if ( !textIface || !textIface->currentFormat() ) return; delete m_fontDlg; m_fontDlg = new KoFontDia( *textIface->currentFormat() #ifdef HAVE_LIBKSPELL2 , m_broker #endif , this, "" ); connect( m_fontDlg, SIGNAL( applyFont() ), this, SLOT( slotApplyFont() ) ); m_fontDlg->exec(); delete m_fontDlg; m_fontDlg=0L; //m_gui->canvasWidget()->setFocus(); } void KWView::slotApplyFont() { int flags = m_fontDlg->changedFlags(); if ( flags ) { KMacroCommand *globalCmd = new KMacroCommand(i18n("Change Font")); QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); for ( ; it.current() ; ++it ) { KoTextFormat newFormat = m_fontDlg->newFormat(); KCommand *cmd = it.current()->setFormatCommand( &newFormat, flags, true); if (cmd) globalCmd->addCommand(cmd); } m_doc->addCommand(globalCmd); m_gui->canvasWidget()->setFocus(); // the combo keeps focus... } } void KWView::formatParagraph() { showParagraphDialog(); } void KWView::showParagraphDialog( int initialPage, double initialTabPos ) { KWTextFrameSetEdit *edit = currentTextEdit(); if (edit) { delete m_paragDlg; m_paragDlg = new KoParagDia( this, "", KoParagDia::PD_SPACING | KoParagDia::PD_ALIGN | KoParagDia::PD_BORDERS | KoParagDia::PD_NUMBERING | KoParagDia::PD_TABS, m_doc->getUnit(),edit->textFrameSet()->frame(0)->width() ,(!edit->frameSet()->isHeaderOrFooter() && !edit->frameSet()->getGroupManager()), edit->frameSet()->isFootEndNote()); m_paragDlg->setCaption( i18n( "Paragraph Settings" ) ); // Initialize the dialog from the current paragraph's settings m_paragDlg->setParagLayout( edit->cursor()->parag()->paragLayout() ); // Set initial page and initial tabpos if necessary if ( initialPage != -1 ) { m_paragDlg->setCurrentPage( initialPage ); if ( initialPage == KoParagDia::PD_TABS ) m_paragDlg->tabulatorsWidget()->setCurrentTab( initialTabPos ); } connect( m_paragDlg, SIGNAL( applyParagStyle() ), this, SLOT( slotApplyParag())); m_paragDlg->exec(); delete m_paragDlg; m_paragDlg=0L; } } void KWView::slotApplyParag() { KWTextFrameSetEdit *edit = currentTextEdit(); if( !edit) return; KMacroCommand * macroCommand = 0L; KCommand *cmd=0L; if(m_paragDlg->isLeftMarginChanged()) { cmd=edit->setMarginCommand( QStyleSheetItem::MarginLeft, m_paragDlg->leftIndent() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } m_gui->getHorzRuler()->setLeftIndent( KoUnit::toUserValue( m_paragDlg->leftIndent(), m_doc->getUnit() ) ); } if(m_paragDlg->isRightMarginChanged()) { cmd=edit->setMarginCommand( QStyleSheetItem::MarginRight, m_paragDlg->rightIndent() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } m_gui->getHorzRuler()->setRightIndent( KoUnit::toUserValue( m_paragDlg->rightIndent(), m_doc->getUnit() ) ); } if(m_paragDlg->isSpaceBeforeChanged()) { cmd=edit->setMarginCommand( QStyleSheetItem::MarginTop, m_paragDlg->spaceBeforeParag() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if(m_paragDlg->isSpaceAfterChanged()) { cmd=edit->setMarginCommand( QStyleSheetItem::MarginBottom, m_paragDlg->spaceAfterParag() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if(m_paragDlg->isFirstLineChanged()) { cmd=edit->setMarginCommand( QStyleSheetItem::MarginFirstLine, m_paragDlg->firstLineIndent()); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } m_gui->getHorzRuler()->setFirstIndent( KoUnit::toUserValue( m_paragDlg->firstLineIndent(), m_doc->getUnit() ) ); } if(m_paragDlg->isAlignChanged()) { cmd=edit->setAlignCommand( m_paragDlg->align() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if(m_paragDlg->isCounterChanged()) { cmd=edit->setCounterCommand( m_paragDlg->counter() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if(m_paragDlg->listTabulatorChanged()) { cmd=edit->setTabListCommand( m_paragDlg->tabListTabulator() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if(m_paragDlg->isLineSpacingChanged()) { cmd=edit->setLineSpacingCommand( m_paragDlg->lineSpacing(),m_paragDlg->lineSpacingType() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if(m_paragDlg->isBorderChanged()) { cmd=edit->setBordersCommand( m_paragDlg->leftBorder(), m_paragDlg->rightBorder(), m_paragDlg->topBorder(), m_paragDlg->bottomBorder() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if ( m_paragDlg->isPageBreakingChanged() ) { cmd=edit->setPageBreakingCommand( m_paragDlg->pageBreaking() ); if(cmd) { if ( !macroCommand ) macroCommand = new KMacroCommand( i18n( "Paragraph Settings" ) ); macroCommand->addCommand(cmd); } } if(macroCommand) m_doc->addCommand(macroCommand); // Set "oldLayout" in KoParagDia from the current paragraph's settings // Otherwise "isBlahChanged" will return wrong things when doing A -> B -> A m_paragDlg->setParagLayout( edit->cursor()->parag()->paragLayout() ); } // This handles Tabulators _only_ void KWView::slotHRulerDoubleClicked( double ptpos ) { showParagraphDialog( KoParagDia::PD_TABS, ptpos ); } // This handles either: // - Indents // - Page Layout // // This does _not_ handle Tabulators! void KWView::slotHRulerDoubleClicked() { QString mode = m_gui->canvasWidget()->viewMode()->type(); bool state = (mode!="ModeText"); if ( !state ) return; KoRuler *ruler = m_gui->getHorzRuler (); if ( (ruler->flags() & KoRuler::F_INDENTS) && currentTextEdit() ) { if ( ruler->doubleClickedIndent () ) { formatParagraph(); return; } } formatPage(); } void KWView::formatPage() { if( !m_doc->isReadWrite()) return; QString mode = m_gui->canvasWidget()->viewMode()->type(); bool state = (mode!="ModeText"); if ( !state ) return; KoPageLayout pgLayout; KoColumns cl; KoKWHeaderFooter kwhf; m_doc->getPageLayout( pgLayout, cl, kwhf ); KWPageLayoutStruct oldLayout( pgLayout, cl, kwhf ); KoHeadFoot hf; int flags = FORMAT_AND_BORDERS | DISABLE_UNIT; if ( m_doc->processingType() == KWDocument::WP ) flags |= KW_HEADER_AND_FOOTER | COLUMNS; else flags |= DISABLE_BORDERS; KoUnit::Unit unit = m_doc->getUnit(); KoUnit::Unit oldUnit = unit; if ( KoPageLayoutDia::pageLayout( pgLayout, hf, cl, kwhf, flags, unit, this ) ) { if( !(oldLayout._pgLayout==pgLayout) || oldLayout._cl != cl || oldLayout._hf != kwhf ) { KWPageLayoutStruct newLayout( pgLayout, cl, kwhf ); KWTextFrameSetEdit *edit = currentTextEdit(); if (edit) edit->textFrameSet()->clearUndoRedoInfo(); KCommand *cmd =new KWPageLayoutCommand( i18n("Change Layout"), m_doc, oldLayout, newLayout ); m_doc->addCommand(cmd); m_doc->setPageLayout( pgLayout, cl, kwhf ); } if ( unit != oldUnit ) m_doc->setUnit( unit ); // ##### needs undo/redo support } } void KWView::formatFrameSet() { if ( m_doc->getFirstSelectedFrame() ) { m_gui->canvasWidget()->editFrameProperties(); } else // Should never happen, the action is disabled KMessageBox::sorry( this, i18n("You must select a frame first."), i18n("Format Frameset")); } void KWView::slotSpellCheck() { #ifdef HAVE_LIBKSPELL2 if (m_spell.kospell) return; // Already in progress //m_doc->setReadWrite(false); // prevent editing text - not anymore m_spell.macroCmdSpellCheck = 0L; m_spell.replaceAll.clear(); QValueList objects; KWTextFrameSetEdit * edit = currentTextEdit(); if (!edit) return; int options = 0; if ( edit && edit->textFrameSet()->hasSelection() ) { objects.append(edit->textFrameSet()->textObject()); options = KFindDialog::SelectedText; } else { objects = m_gui->canvasWidget()->kWordDocument()->visibleTextObjects(m_gui->canvasWidget()->viewMode()); } m_spell.textIterator = new KoTextIterator( objects, edit, options ); kdDebug()<<"Created iterator with "<< objects.count() <getAutoFormat()->readConfig(); KoAutoFormatDia dia( this, 0, m_doc->getAutoFormat() ); dia.exec(); m_doc->startBackgroundSpellCheck(); // will do so if enabled } void KWView::extraFrameStylist() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->hideCursor(); KWFrameStyleManager * frameStyleManager = new KWFrameStyleManager( this, m_doc, m_doc->frameStyleCollection()->frameStyleList() ); frameStyleManager->exec(); delete frameStyleManager; if ( edit ) edit->showCursor(); } void KWView::createFrameStyle() { KWFrame* frame = 0L; QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count()== 1) frame = selectedFrames.first(); if (frame) { QStringList list; QPtrListIterator styleIt( m_doc->frameStyleCollection()->frameStyleList() ); for ( ; styleIt.current(); ++styleIt ) { list.append( styleIt.current()->name() ); } KoCreateStyleDia *dia = new KoCreateStyleDia( list , this, 0 ); if ( dia->exec() ) { KWFrameStyle *style= new KWFrameStyle( dia->nameOfNewStyle(), frame ); m_doc->frameStyleCollection()->addFrameStyleTemplate( style ); m_doc->updateAllFrameStyleLists(); } delete dia; } } void KWView::extraStylist() { KWTextFrameSetEdit * edit = currentTextEdit(); QString activeStyleName = QString::null; if ( edit ) { edit->hideCursor(); if (edit->cursor() && edit->cursor()->parag() && edit->cursor()->parag()->style()) activeStyleName = edit->cursor()->parag()->style()->displayName(); } KWStyleManager * styleManager = new KWStyleManager( this, m_doc->getUnit(),m_doc, m_doc->styleCollection()->styleList(), activeStyleName ); styleManager->exec(); delete styleManager; if ( edit ) edit->showCursor(); } void KWView::extraCreateTemplate() { int width = 60; int height = 60; QPixmap pix = m_doc->generatePreview(QSize(width, height)); KTempFile tempFile( QString::null, ".kwt" ); tempFile.setAutoDelete(true); m_doc->saveNativeFormat( tempFile.name() ); KoTemplateCreateDia::createTemplate( "kword_template", KWFactory::global(), tempFile.name(), pix, this ); KWFactory::global()->dirs()->addResourceType("kword_template", KStandardDirs::kde_default( "data" ) + "kword/templates/"); } void KWView::toolsCreateText() { if ( actionToolsCreateText->isChecked() ) m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_CREATE_TEXT ); else { // clicked on the already active tool -> abort m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); } } void KWView::insertTable() { KWCanvas * canvas = m_gui->canvasWidget(); canvas->setMouseMode( KWCanvas::MM_EDIT ); KWTableDia *tableDia = new KWTableDia( this, 0, KWTableDia::NEW, canvas, m_doc, canvas->tableRows(), canvas->tableCols(), canvas->tableWidthMode(), canvas->tableHeightMode(), canvas->tableIsFloating(), canvas->tableTemplateName(), canvas->tableFormat()); tableDia->setCaption( i18n( "Insert Table" ) ); if ( tableDia->exec() == QDialog::Rejected ) canvas->setMouseMode( KWCanvas::MM_EDIT ); delete tableDia; } void KWView::insertFormula( QMimeSource* source ) { KWTextFrameSetEdit *edit = currentTextEdit(); if (edit) { KWFormulaFrameSet *frameset = new KWFormulaFrameSet( m_doc, QString::null ); m_doc->addFrameSet( frameset, false ); // done first since the frame number is stored in the undo/redo if ( source ) { QByteArray data = source->encodedData( KFormula::MimeSource::selectionMimeType() ); QDomDocument formula; formula.setContent( data ); QDomElement formulaElem = formula.namedItem("KFORMULA").toElement(); frameset->paste( formulaElem ); } KWFrame *frame = new KWFrame(frameset, 0, 0, 10, 10 ); frame->setZOrder( m_doc->maxZOrder( frame->pageNum(m_doc) ) + 1 ); // make sure it's on top frameset->addFrame( frame, false ); edit->insertFloatingFrameSet( frameset, i18n("Insert Formula") ); frameset->finalize(); // done last since it triggers a redraw m_doc->refreshDocStructure(FT_FORMULA); m_gui->canvasWidget()->editFrameSet( frameset ); frameset->setChanged(); m_gui->canvasWidget()->repaintChanged( frameset, true ); } } void KWView::toolsPart() { m_gui->canvasWidget()->insertPart( actionToolsCreatePart->documentEntry() ); } int KWView::tableSelectCell(const QString &tableName, uint row, uint col) { if(!m_doc || !m_gui) return -1; KWFrameSet *fs = m_doc->frameSetByName(tableName); if(!fs) return -1; KWTableFrameSet *table = dynamic_cast(fs); if(!table) return -1; if (row >= table->getRows() || col >= table->getCols()) return -1; KWTableFrameSet::Cell *cell = table->getCell(row, col); KWCanvas *canvas = m_gui->canvasWidget(); if(!canvas) return -1; canvas->tableSelectCell(table, cell); return 0; } int KWView::tableDeleteRow(const QValueList& rows, KWTableFrameSet *table ) { if(!table) table = m_gui->canvasWidget()->getCurrentTable(); if (!m_doc || !table) return -1; if(rows.count() >= table->getRows()) { m_doc->deleteTable(table); return 0; } KMacroCommand *macro = new KMacroCommand(i18n("Remove Rows")); for (int i = rows.count() - 1; i >= 0 ; i--) { KWRemoveRowCommand *cmd = new KWRemoveRowCommand( i18n("Remove Row"), table, rows[i] ); macro->addCommand(cmd); } macro->execute(); m_doc->addCommand(macro); return 0; } int KWView::tableDeleteCol(const QValueList& cols, KWTableFrameSet *table) { if(!table) table = m_gui->canvasWidget()->getCurrentTable(); if (!m_doc || !table) return -1; if(cols.count() >= table->getCols()) { m_doc->deleteTable(table); return 0; } KMacroCommand *macro = new KMacroCommand(i18n("Remove Columns")); for (int i = cols.count() - 1; i >= 0; i--) { KWRemoveColumnCommand *cmd = new KWRemoveColumnCommand( i18n("Remove Column"), table, cols[i] ); macro->addCommand(cmd); } macro->execute(); m_doc->addCommand(macro); return 0; } void KWView::tableProperties() { KWCanvas * canvas = m_gui->canvasWidget(); KWTableFrameSet *table = canvas->getCurrentTable(); if (table) { canvas->setMouseMode( KWCanvas::MM_EDIT ); KWTableDia *tableDia = new KWTableDia( this, 0, KWTableDia::EDIT, canvas, m_doc, table->getRows(), table->getCols(), canvas->tableWidthMode(), canvas->tableHeightMode(), canvas->tableIsFloating(), canvas->tableTemplateName(), canvas->tableFormat()); tableDia->setCaption( i18n( "Adjust Table" ) ); if ( tableDia->exec() == QDialog::Rejected ) canvas->setMouseMode( KWCanvas::MM_EDIT ); delete tableDia; } } void KWView::tableInsertRow() { m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; KWInsertDia dia( this, "insert_row_dialog", table, m_doc, KWInsertDia::ROW, m_gui->canvasWidget() ); dia.setCaption( i18n( "Insert Row" ) ); dia.exec(); } void KWView::tableInsertRow(uint row, KWTableFrameSet *table) { if(!table) table = m_gui->canvasWidget()->getCurrentTable(); if (!m_doc || !table) return; if(row > table->getRows()) return; KWInsertRowCommand *cmd = new KWInsertRowCommand( i18n("Insert Row"), table, row); cmd->execute(); m_doc->addCommand(cmd); } void KWView::tableInsertCol() { m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; /* // value = 62 because a insert column = 60 +2 (border )see kwtableframeset.cc if ( table->boundingRect().right() + 62 > static_cast( m_doc->ptPaperWidth() ) ) { KMessageBox::sorry( this, i18n( "There is not enough space at the right of the table " "to insert a new column." ), i18n( "Insert Column" ) ); } else { KWInsertDia dia( this, "", table, m_doc, KWInsertDia::COL, m_gui->canvasWidget() ); dia.setCaption( i18n( "Insert Column" ) ); dia.exec(); } */ KWInsertDia dia( this, "insert_column_dialog", table, m_doc, KWInsertDia::COL, m_gui->canvasWidget() ); dia.setCaption( i18n( "Insert Column" ) ); dia.exec(); } void KWView::tableInsertCol(uint col, KWTableFrameSet *table ) { if(!table) table = m_gui->canvasWidget()->getCurrentTable(); if (!m_doc || !table) return; if(col > table->getCols()) return; // we pass as last parameter the maximum offset that the table can use. // this offset is the max right offset of the containing frame in the case // of an inline (floating) table, the size of the page for other tables. double maxRightOffset; if (table->isFloating()) // inline table: max offset of containing frame maxRightOffset = table->anchorFrameset()->frame(0)->right(); else // non inline table: max offset of the page maxRightOffset = m_doc->ptPaperWidth() - m_doc->ptRightBorder(); KWInsertColumnCommand *cmd = new KWInsertColumnCommand( i18n("Insert Column"), table, col, maxRightOffset); cmd->execute(); m_doc->addCommand(cmd); } void KWView::tableDeleteRow() { m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; if ( table->getRows() == 1 ) { int result; result = KMessageBox::warningContinueCancel(this, i18n("The table has only one row. " "Deleting this row will delete the table.\n" "Do you want to delete the table?"), i18n("Delete Row"), i18n("&Delete")); if (result == KMessageBox::Continue) { m_doc->deleteTable( table ); m_gui->canvasWidget()->emitFrameSelectedChanged(); } } else { KWDeleteDia dia( this, "", table, m_doc, KWDeleteDia::ROW, m_gui->canvasWidget() ); dia.setCaption( i18n( "Delete Row" ) ); dia.exec(); } } void KWView::tableDeleteCol() { m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; if ( table->getCols() == 1 ) { int result; result = KMessageBox::warningContinueCancel(this, i18n("The table has only one column. " "Deleting this column will delete the table.\n" "Do you want to delete the table?"), i18n("Delete Column"), i18n("&Delete")); if (result == KMessageBox::Continue) { m_doc->deleteTable( table ); m_gui->canvasWidget()->emitFrameSelectedChanged(); } } else { KWDeleteDia dia( this, "", table, m_doc, KWDeleteDia::COL, m_gui->canvasWidget() ); dia.setCaption( i18n( "Delete Column" ) ); dia.exec(); } } void KWView::tableResizeCol() { KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; KWResizeTableDia dia( this, "", table, m_doc, KWResizeTableDia::COL, m_gui->canvasWidget() ); dia.setCaption( i18n( "Resize Column" ) ); dia.exec(); } void KWView::tableJoinCells() { //m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT_FRAME ); KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; KCommand * cmd=table->joinCells(); if ( !cmd ) { KMessageBox::sorry( this, i18n( "You have to select some cells which are next to each other " "and are not already joined." ), i18n( "Join Cells" ) ); return; } m_doc->addCommand(cmd); m_doc->layout(); //KoRect r = m_doc->zoomRect( table->boundingRect() ); //m_gui->canvasWidget()->repaintScreen( r, TRUE ); m_gui->canvasWidget()->repaintAll(); m_gui->canvasWidget()->emitFrameSelectedChanged(); } void KWView::tableSplitCells() { KWSplitCellDia *splitDia=new KWSplitCellDia( this,"split cell",m_gui->canvasWidget()->splitCellRows(),m_gui->canvasWidget()->splitCellCols() ); if(splitDia->exec()) { unsigned int nbCols=splitDia->cols(); unsigned int nbRows=splitDia->rows(); m_gui->canvasWidget()->setSplitCellRows(nbRows); m_gui->canvasWidget()->setSplitCellCols(nbCols); tableSplitCells(nbCols, nbRows); } delete splitDia; } void KWView::tableSplitCells(int cols, int rows) { //m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT_FRAME ); QPtrList selectedFrames = m_doc->getSelectedFrames(); KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); if ( !table && selectedFrames.count() > 0) { table=selectedFrames.at(0)->frameSet()->getGroupManager(); } if(selectedFrames.count() >1 || table == 0) { KMessageBox::sorry( this, i18n( "You have to put the cursor into a table " "before splitting cells." ), i18n( "Split Cells" ) ); return; } //int rows=1, cols=2; KCommand *cmd=table->splitCell(rows,cols); if ( !cmd ) { KMessageBox::sorry( this, i18n("There is not enough space to split the cell into that many parts, make it bigger first"), i18n("Split Cells") ); return; } m_doc->addCommand(cmd); //KoRect r = m_doc->zoomRect( table->boundingRect() ); //m_gui->canvasWidget()->repaintScreen( r, TRUE ); m_doc->updateAllFrames(); m_doc->layout(); m_gui->canvasWidget()->repaintAll(); m_doc->frameSelectedChanged(); } void KWView::tableUngroupTable() { m_gui->canvasWidget()->setMouseMode( KWCanvas::MM_EDIT ); KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; // Use a macro command because we may have to make the table non-floating first KMacroCommand * macroCmd = new KMacroCommand( i18n( "Ungroup Table" ) ); if ( table->isFloating() ) { KWFrameSetInlineCommand *cmd = new KWFrameSetInlineCommand( QString::null, table, false ); macroCmd->addCommand(cmd); } KWUngroupTableCommand *cmd = new KWUngroupTableCommand( QString::null, table ); macroCmd->addCommand( cmd ); m_doc->addCommand( macroCmd ); macroCmd->execute(); // do it all } void KWView::tableDelete() { KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; m_doc->deleteTable( table ); m_gui->canvasWidget()->emitFrameSelectedChanged(); } void KWView::tableStylist() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->hideCursor(); KWTableStyleManager * tableStyleManager = new KWTableStyleManager( this, m_doc, m_doc->tableStyleCollection()->tableStyleList() ); tableStyleManager->exec(); delete tableStyleManager; if ( edit ) edit->showCursor(); } void KWView::tableProtectCells() { KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); Q_ASSERT(table); if (!table) return; KCommand *cmd = table->setProtectContentCommand( actionTableProtectCells->isChecked() ); if ( cmd ) m_doc->addCommand( cmd ); } // Called when selecting a style in the Format / Style menu void KWView::slotStyleSelected() { QString actionName = QString::fromLatin1(sender()->name()); if ( actionName.startsWith( "shortcut_style_" ) )//see lib/kotext/kostyle.cc { kdDebug() << "KWView::slotStyleSelected " << actionName << endl; textStyleSelected( m_doc->styleCollection()->findStyleShortCut( actionName) ); } } void KWView::textStyleSelected( KoParagStyle *_sty ) { if ( !_sty ) return; if ( m_gui->canvasWidget()->currentFrameSetEdit() ) { KWTextFrameSetEdit * edit = dynamic_cast(m_gui->canvasWidget()->currentFrameSetEdit()->currentTextEdit()); if ( edit ) edit->applyStyle( _sty ); } else { // it might be that a frame (or several frames) are selected QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() <= 0) return; // nope, no frames are selected. // yes, indeed frames are selected. QPtrListIterator it( selectedFrames ); KMacroCommand *globalCmd = 0L; for ( ; it.current() ; ++it ) { KWFrame *curFrame = it.current(); KWFrameSet *curFrameSet = curFrame->frameSet(); if (curFrameSet->type() == FT_TEXT) { KoTextObject *textObject = ((KWTextFrameSet*)curFrameSet)->textObject(); textObject->textDocument()->selectAll( KoTextDocument::Temp ); KCommand *cmd = textObject->applyStyleCommand( 0L, _sty , KoTextDocument::Temp, KoParagLayout::All, KoTextFormat::Format, true, true ); textObject->textDocument()->removeSelection( KoTextDocument::Temp ); if (cmd) { if ( !globalCmd ) globalCmd = new KMacroCommand( selectedFrames.count() == 1 ? i18n("Apply Style to Frame") : i18n("Apply Style to Frames")); globalCmd->addCommand( cmd ); } } } if ( globalCmd ) m_doc->addCommand( globalCmd ); } m_gui->canvasWidget()->setFocus(); // the combo keeps focus...*/ } // Called by the above, and when selecting a style in the style combobox void KWView::textStyleSelected( int index ) { textStyleSelected( m_doc->styleCollection()->styleAt( index ) ); } // Slot is called when selecting a framestyle in the Frames / Framestyle menu void KWView::slotFrameStyleSelected() { QString actionName = QString::fromLatin1(sender()->name()); if ( actionName.startsWith( "shortcut_framestyle_" ) )//see kwframestyle.cc { //kdDebug() << "KWView::slotFrameStyleSelected " << styleStr << endl; frameStyleSelected( m_doc->frameStyleCollection()->findStyleShortCut( actionName) ); } } void KWView::frameStyleSelected( int index ) { frameStyleSelected( m_doc->frameStyleCollection()->frameStyleAt( index ) ); } // Called by the above, and when selecting a style in the framestyle combobox void KWView::frameStyleSelected( KWFrameStyle *_sty ) { if ( !_sty ) return; if ( m_gui->canvasWidget()->currentFrameSetEdit() ) { KWFrame * single = m_gui->canvasWidget()->currentFrameSetEdit()->currentFrame(); if ( single ) { KCommand *cmd = new KWFrameStyleCommand( i18n("Apply Framestyle to Frame"), single, _sty ); if (cmd) { m_doc->addCommand( cmd ); cmd->execute(); } } } else { // it might be that a frame (or several frames) are selected QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() <= 0) return; // nope, no frames are selected. // yes, indeed frames are selected. QPtrListIterator it( selectedFrames ); KMacroCommand *globalCmd = new KMacroCommand( selectedFrames.count() == 1 ? i18n("Apply Framestyle to Frame") : i18n("Apply Framestyle to Frames")); for ( ; it.current() ; ++it ) { KWFrame *curFrame = it.current(); KCommand *cmd = new KWFrameStyleCommand( i18n("Apply Framestyle"), curFrame, _sty ); if (cmd) globalCmd->addCommand( cmd ); } m_doc->addCommand( globalCmd ); globalCmd->execute(); } m_gui->canvasWidget()->repaintAll(); m_gui->canvasWidget()->setFocus(); // the combo keeps focus...*/ // Adjust GUI QPtrListIterator styleIt( m_doc->frameStyleCollection()->frameStyleList() ); for ( int pos = 0 ; styleIt.current(); ++styleIt, ++pos ) { if ( styleIt.current()->name() == _sty->name() ) { actionFrameStyle->setCurrentItem( pos ); KToggleAction* act = dynamic_cast(actionCollection()->action( styleIt.current()->shortCutName().latin1() )); if ( act ) act->setChecked( true ); return; } } } // Called when selecting a tablestyle in the Table / Tablestyle menu void KWView::slotTableStyleSelected() { QString actionName = QString::fromLatin1(sender()->name()); if ( actionName.startsWith( "shortcut_tablestyle_" ) ) { tableStyleSelected( m_doc->tableStyleCollection()->findStyleShortCut( actionName) ); } } void KWView::tableStyleSelected( int index ) { tableStyleSelected( m_doc->tableStyleCollection()->tableStyleAt( index ) ); } // Called by the above, and when selecting a style in the framestyle combobox void KWView::tableStyleSelected( KWTableStyle *_sty ) { if ( !_sty ) return; if ( m_gui->canvasWidget()->currentFrameSetEdit() ) { KWFrame * single = m_gui->canvasWidget()->currentFrameSetEdit()->currentFrame(); if ( (single) && ( single->frameSet()->type() == FT_TEXT ) ) { KCommand *cmd = new KWTableStyleCommand( i18n("Apply Tablestyle to Frame"), single, _sty ); if (cmd) { m_doc->addCommand( cmd ); cmd->execute(); } } } else { QPtrList selectedFrames = m_doc->getSelectedFrames(); if (selectedFrames.count() <= 0) return; // nope, no frames are selected. QPtrListIterator it( selectedFrames ); KMacroCommand *globalCmd = new KMacroCommand( selectedFrames.count() == 1 ? i18n("Apply Tablestyle to Frame") : i18n("Apply Tablestyle to Frames")); for ( ; ( ( it.current() ) && ( it.current()->frameSet()->type() == FT_TEXT ) ); ++it ) { KWFrame *curFrame = it.current(); KCommand *cmd = new KWTableStyleCommand( i18n("Apply Tablestyle to Frame"), curFrame, _sty ); if (cmd) globalCmd->addCommand( cmd ); } m_doc->addCommand( globalCmd ); globalCmd->execute(); } m_gui->canvasWidget()->repaintAll(); m_gui->canvasWidget()->setFocus(); // the combo keeps focus...*/ // Adjust GUI QPtrListIterator styleIt( m_doc->tableStyleCollection()->tableStyleList() ); for ( int pos = 0 ; styleIt.current(); ++styleIt, ++pos ) { if ( styleIt.current()->name() == _sty->name() ) { actionTableStyle->setCurrentItem( pos ); KToggleAction* act = dynamic_cast(actionCollection()->action( styleIt.current()->shortCutName().latin1() )); if ( act ) act->setChecked( true ); return; } } } void KWView::increaseFontSize() { KWTextFrameSetEdit * edit = currentTextEdit(); KoTextFormat *format = edit->currentFormat(); if ( edit ) textSizeSelected( edit->textFrameSet()->textObject()->docFontSize( format ) + 1 ); } void KWView::decreaseFontSize() { KWTextFrameSetEdit * edit = currentTextEdit(); KoTextFormat *format = edit->currentFormat(); if ( edit ) textSizeSelected( edit->textFrameSet()->textObject()->docFontSize( format ) - 1 ); } void KWView::textSizeSelected( int size ) { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand *globalCmd = new KMacroCommand(i18n("Change Text Size")); for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setPointSizeCommand( size ); if (cmd) globalCmd->addCommand(cmd); } m_doc->addCommand(globalCmd); m_gui->canvasWidget()->setFocus(); // the combo keeps focus... } void KWView::textFontSelected( const QString & font ) { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setFamilyCommand( font ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Change Text Font") ); macroCmd->addCommand( cmd ); } } if ( macroCmd ) m_doc->addCommand( macroCmd ); m_gui->canvasWidget()->setFocus(); // the combo keeps focus... } QPtrList KWView::applicableTextInterfaces() const { QPtrList lst; if (currentTextEdit()) { if ( !currentTextEdit()->textObject()->protectContent()) { // simply return the current textEdit lst.append( currentTextEdit() ); kdDebug() << "text frame name: " << currentTextEdit()->textFrameSet()->name() << endl; KWCollectFramesetsVisitor visitor; currentTextEdit()->textDocument()->visitSelection( KoTextDocument::Standard, &visitor ); //find all framesets in the selection const QValueList& frameset = visitor.frameSets(); for ( QValueList::ConstIterator it = frameset.begin(); it != frameset.end(); ++it ) { if ( (*it)->type() == FT_TABLE ) { KWTableFrameSet* kwtableframeset = static_cast( *it ); //kdDebug() << "table found: " << kwtableframeset->getNumFrames() << endl; int const rows = kwtableframeset->getRows(); int const cols = kwtableframeset->getCols(); //finding all cells and add them to the interface list for (int r=0; rgetCell(r,c); if (cell) { kdDebug() << "adding (" << r << "," << c << ")" << endl; lst.append(cell); } } } } } } } else { // it might be that a frame (or several frames) are selected // in that case, list the text framesets behind them QPtrList selectedFrames = m_doc->getSelectedFrames(); QPtrListIterator it( selectedFrames ); for ( ; it.current() ; ++it ) { if ( it.current()->frameSet()->type() == FT_TEXT ) { KWTextFrameSet* fs = static_cast( it.current()->frameSet() ); if ( !lst.contains( fs )&& !fs->protectContent() ) lst.append( fs ); } } } return lst; } void KWView::textBold() { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setBoldCommand( actionFormatBold->isChecked() ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Make Text Bold") ); macroCmd->addCommand(cmd); } } if(macroCmd) m_doc->addCommand(macroCmd); } void KWView::textItalic() { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setItalicCommand( actionFormatItalic->isChecked() ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Make Text Italic") ); macroCmd->addCommand( cmd ); } } if( macroCmd) m_doc->addCommand( macroCmd ); } void KWView::textUnderline() { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setUnderlineCommand( actionFormatUnderline->isChecked() ); if ( cmd ) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Underline Text") ); macroCmd->addCommand( cmd ); } } if(macroCmd) m_doc->addCommand( macroCmd ); } void KWView::textStrikeOut() { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setStrikeOutCommand( actionFormatStrikeOut->isChecked() ); if ( cmd ) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Strike Out Text") ); macroCmd->addCommand( cmd ); } } if( macroCmd) m_doc->addCommand( macroCmd ); } void KWView::textColor() { /* QColor color = edit->textColor(); if ( KColorDialog::getColor( color ) ) { actionFormatColor->setColor( color ); edit->setTextColor( color ); } */ QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setTextColorCommand( actionFormatColor->color() ); if ( cmd ) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Set Text Color") ); macroCmd->addCommand( cmd ); } } if( macroCmd) m_doc->addCommand( macroCmd ); } void KWView::textAlignLeft() { if ( actionFormatAlignLeft->isChecked() ) { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setAlignCommand( Qt::AlignLeft ); if (cmd) { if ( !macroCmd) macroCmd = new KMacroCommand( i18n("Left-Align Text") ); macroCmd->addCommand( cmd ); } } if( macroCmd ) m_doc->addCommand( macroCmd ); } else actionFormatAlignLeft->setChecked( true ); } void KWView::textAlignCenter() { if ( actionFormatAlignCenter->isChecked() ) { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setAlignCommand( Qt::AlignHCenter ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Center Text") ); macroCmd->addCommand( cmd ); } } if( macroCmd ) m_doc->addCommand( macroCmd ); } else actionFormatAlignCenter->setChecked( true ); } void KWView::textAlignRight() { if ( actionFormatAlignRight->isChecked() ) { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setAlignCommand( Qt::AlignRight ); if ( cmd ) { if (!macroCmd ) macroCmd = new KMacroCommand( i18n("Right-Align Text") ); macroCmd->addCommand( cmd ); } } if( macroCmd) m_doc->addCommand( macroCmd ); } else actionFormatAlignRight->setChecked( true ); } void KWView::textAlignBlock() { if ( actionFormatAlignBlock->isChecked() ) { QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setAlignCommand( Qt::AlignJustify ); if ( cmd ) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Justify Text") ); macroCmd->addCommand( cmd ); } } if( macroCmd) m_doc->addCommand( macroCmd ); } else actionFormatAlignBlock->setChecked( true ); } void KWView::slotCounterStyleSelected() { QString actionName = QString::fromLatin1(sender()->name()); if ( actionName.startsWith( "counterstyle_" ) ) { QString styleStr = actionName.mid(13); //kdDebug() << "KWView::slotCounterStyleSelected styleStr=" << styleStr << endl; KoParagCounter::Style style = (KoParagCounter::Style)(styleStr.toInt()); KoParagCounter c; if ( style == KoParagCounter::STYLE_NONE ) c.setNumbering( KoParagCounter::NUM_NONE ); else { c.setNumbering( KoParagCounter::NUM_LIST ); c.setStyle( style ); if ( c.isBullet() ) c.setSuffix( QString::null ); // else the suffix remains the default, '.' // TODO save this setting, to use the last one selected in the dialog? // (same for custom bullet char etc.) // 68927: restart numbering, by default, if last parag wasn't numbered // (and if we're not applying this to a selection) if ( currentTextEdit() && !currentTextEdit()->textFrameSet()->hasSelection() ) { KoTextParag* parag = currentTextEdit()->cursor()->parag(); if ( parag->prev() && !parag->prev()->counter() ) c.setRestartCounter(true); } } QPtrList lst = applicableTextInterfaces(); QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setCounterCommand( c ); if ( cmd ) { if ( !macroCmd ) macroCmd=new KMacroCommand( i18n("Change List Type") ); macroCmd->addCommand( cmd ); } } if( macroCmd) m_doc->addCommand( macroCmd ); } } void KWView::textSuperScript() { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setTextSuperScriptCommand(actionFormatSuper->isChecked()); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Make Text Superscript") ); macroCmd->addCommand(cmd); } } if( macroCmd) m_doc->addCommand(macroCmd); } void KWView::textSubScript() { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setTextSubScriptCommand(actionFormatSub->isChecked()); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Make Text Subscript") ); macroCmd->addCommand(cmd); } } if( macroCmd ) m_doc->addCommand(macroCmd); } void KWView::changeCaseOfText() { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KoChangeCaseDia *caseDia=new KoChangeCaseDia( this,"change case" ); if(caseDia->exec()) { KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setChangeCaseOfTextCommand(caseDia->getTypeOfCase()); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Change Case of Text") ); macroCmd->addCommand(cmd); } } if( macroCmd ) m_doc->addCommand(macroCmd); } delete caseDia; } void KWView::editPersonalExpr() { KWEditPersonnalExpression *personalDia=new KWEditPersonnalExpression( this ); if(personalDia->exec()) m_doc->refreshMenuExpression(); delete personalDia; } void KWView::textIncreaseIndent() { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); double leftMargin=0.0; if(!lst.isEmpty()) leftMargin=lst.first()->currentParagLayoutFormat()->margins[QStyleSheetItem::MarginLeft]; double indent = m_doc->indentValue(); double newVal = leftMargin + indent; KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setMarginCommand( QStyleSheetItem::MarginLeft, newVal ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Increase Paragraph Depth") ); macroCmd->addCommand(cmd); } } if( macroCmd) m_doc->addCommand(macroCmd); if(!lst.isEmpty()) { const KoParagLayout *layout=lst.first()->currentParagLayoutFormat(); showRulerIndent( layout->margins[QStyleSheetItem::MarginLeft], layout->margins[QStyleSheetItem::MarginFirstLine], layout->margins[QStyleSheetItem::MarginRight], lst.first()->rtl()); } #if 0 KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { double leftMargin = edit->currentLeftMargin(); double indent = m_doc->indentValue(); double newVal = leftMargin + indent; // Test commented out. This breaks with the DTP case... The user can put // a frame anywhere, even closer to the edges than left/right border allows (DF). //if( newVal <= (m_doc->ptPaperWidth()-m_doc->ptRightBorder()-m_doc->ptLeftBorder())) { KCommand *cmd=edit->setMarginCommand( QStyleSheetItem::MarginLeft, newVal ); if(cmd) m_doc->addCommand(cmd); } } #endif } void KWView::textDecreaseIndent() { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); double leftMargin=0.0; if(!lst.isEmpty()) leftMargin=lst.first()->currentParagLayoutFormat()->margins[QStyleSheetItem::MarginLeft]; double indent = m_doc->indentValue(); double newVal = leftMargin - indent; KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setMarginCommand( QStyleSheetItem::MarginLeft, QMAX( newVal, 0 ) ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Decrease Paragraph Depth") ); macroCmd->addCommand(cmd); } } if( macroCmd) m_doc->addCommand(macroCmd); if(!lst.isEmpty()) { const KoParagLayout *layout=lst.first()->currentParagLayoutFormat(); showRulerIndent( layout->margins[QStyleSheetItem::MarginLeft], layout->margins[QStyleSheetItem::MarginFirstLine], layout->margins[QStyleSheetItem::MarginRight], lst.first()->rtl()); } #if 0 KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { double leftMargin = edit->currentLeftMargin(); if ( leftMargin > 0 ) { double indent = m_doc->indentValue(); double newVal = leftMargin - indent; KCommand *cmd=edit->setMarginCommand( QStyleSheetItem::MarginLeft, QMAX( newVal, 0 ) ); if(cmd) m_doc->addCommand(cmd); } } #endif } void KWView::textDefaultFormat() { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setDefaultFormatCommand(); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Default Format") ); macroCmd->addCommand(cmd); } } if( macroCmd) m_doc->addCommand(macroCmd); } void KWView::borderOutline() { bool b = actionBorderOutline->isChecked(); actionBorderLeft->setChecked(b); actionBorderRight->setChecked(b); actionBorderTop->setChecked(b); actionBorderBottom->setChecked(b); borderSet(); } void KWView::borderLeft() { actionBorderOutline->setChecked( actionBorderLeft->isChecked() && actionBorderRight->isChecked() && actionBorderTop->isChecked() && actionBorderBottom->isChecked()); borderSet(); } void KWView::borderRight() { actionBorderOutline->setChecked( actionBorderLeft->isChecked() && actionBorderRight->isChecked() && actionBorderTop->isChecked() && actionBorderBottom->isChecked()); borderSet(); } void KWView::borderTop() { actionBorderOutline->setChecked( actionBorderLeft->isChecked() && actionBorderRight->isChecked() && actionBorderTop->isChecked() && actionBorderBottom->isChecked()); borderSet(); } void KWView::borderBottom() { actionBorderOutline->setChecked( actionBorderLeft->isChecked() && actionBorderRight->isChecked() && actionBorderTop->isChecked() && actionBorderBottom->isChecked()); borderSet(); } void KWView::borderColor() { m_border.common.color = actionBorderColor->color(); m_border.left.color = m_border.common.color; m_border.right.color = m_border.common.color; m_border.top.color = m_border.common.color; m_border.bottom.color = m_border.common.color; borderSet(); } void KWView::borderWidth( const QString &width ) { m_border.common.setPenWidth( width.toInt()); m_border.left.setPenWidth(m_border.common.penWidth()); m_border.right.setPenWidth(m_border.common.penWidth()); m_border.top.setPenWidth(m_border.common.penWidth()); m_border.bottom.setPenWidth(m_border.common.penWidth()); borderSet(); m_gui->canvasWidget()->setFocus(); } void KWView::borderStyle( const QString &style ) { m_border.common.setStyle(KoBorder::getStyle( style )); m_border.left.setStyle( m_border.common.getStyle()); m_border.right.setStyle( m_border.common.getStyle()); m_border.top.setStyle( m_border.common.getStyle()); m_border.bottom.setStyle( m_border.common.getStyle()); borderSet(); m_gui->canvasWidget()->setFocus(); } void KWView::backgroundColor() { QColor backColor = actionBackgroundColor->color(); // ### TODO port to applicableTextInterfaces ? KWTextFrameSetEdit *edit = currentTextEdit(); if ( m_gui) { if(edit) { KCommand *cmd=edit->setTextBackgroundColorCommand(backColor); if( cmd) m_doc->addCommand( cmd ); } else m_gui->canvasWidget()->setFrameBackgroundColor( backColor ); } } void KWView::borderSet() { // The effect of this action depends on if we are in Edit Text or Edit Frame mode. m_border.left = m_border.common; m_border.right = m_border.common; m_border.top = m_border.common; m_border.bottom = m_border.common; if ( !actionBorderLeft->isChecked() ) { m_border.left.setPenWidth( 0); } if ( !actionBorderRight->isChecked() ) { m_border.right.setPenWidth( 0); } if ( !actionBorderTop->isChecked() ) { m_border.top.setPenWidth(0); } if ( !actionBorderBottom->isChecked() ) { m_border.bottom.setPenWidth(0); } KWTextFrameSetEdit *edit = currentTextEdit(); if ( edit ) { KCommand *cmd=edit->setBordersCommand( m_border.left, m_border.right, m_border.top, m_border.bottom ); if(cmd) m_doc->addCommand(cmd); } else { KMacroCommand *macro = 0L; KCommand*cmd=m_gui->canvasWidget()->setLeftFrameBorder( m_border.common, actionBorderLeft->isChecked() ); if ( cmd ) { if ( !macro ) macro = new KMacroCommand( i18n("Change Border")); macro->addCommand( cmd); } cmd = m_gui->canvasWidget()->setRightFrameBorder( m_border.common, actionBorderRight->isChecked() ); if ( cmd ) { if ( !macro ) macro = new KMacroCommand( i18n("Change Border")); macro->addCommand( cmd); } cmd = m_gui->canvasWidget()->setTopFrameBorder( m_border.common, actionBorderTop->isChecked() ); if ( cmd ) { if ( !macro ) macro = new KMacroCommand( i18n("Change Border")); macro->addCommand( cmd); } cmd = m_gui->canvasWidget()->setBottomFrameBorder( m_border.common, actionBorderBottom->isChecked() ); if ( cmd ) { if ( !macro ) macro = new KMacroCommand( i18n("Change Border")); macro->addCommand( cmd); } if ( macro ) m_doc->addCommand( macro ); } } void KWView::resizeEvent( QResizeEvent *e ) { QWidget::resizeEvent( e ); if ( m_gui ) m_gui->resize( width(), height() ); } void KWView::guiActivateEvent( KParts::GUIActivateEvent *ev ) { if ( ev->activated() ) { initGui(); if (m_doc->isEmbedded() ) setZoom( m_doc->zoom(), true ); } KoView::guiActivateEvent( ev ); } void KWView::borderShowValues() { actionBorderWidth->setCurrentItem( (int)m_border.common.penWidth() - 1 ); actionBorderStyle->setCurrentItem( (int)m_border.common.getStyle() ); } void KWView::tabListChanged( const KoTabulatorList & tabList ) { if(!m_doc->isReadWrite()) return; QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setTabListCommand( tabList ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand(i18n("Change Tabulator") ); macroCmd->addCommand(cmd); } } if(macroCmd) m_doc->addCommand(macroCmd); } void KWView::newPageLayout( const KoPageLayout &_layout ) { QString mode = m_gui->canvasWidget()->viewMode()->type(); bool state = (mode!="ModeText"); if ( !state ) return; KoPageLayout pgLayout; KoColumns cl; KoKWHeaderFooter hf; m_doc->getPageLayout( pgLayout, cl, hf ); if(_layout==pgLayout) return; KWPageLayoutStruct oldLayout( pgLayout, cl, hf ); m_doc->setPageLayout( _layout, cl, hf ); KWPageLayoutStruct newLayout( _layout, cl, hf ); KWTextFrameSetEdit *edit = currentTextEdit(); if (edit) edit->textFrameSet()->clearUndoRedoInfo(); KCommand *cmd = new KWPageLayoutCommand( i18n("Change Layout"), m_doc, oldLayout, newLayout ); m_doc->addCommand(cmd); } void KWView::slotPageLayoutChanged( const KoPageLayout& layout ) { // This is connected to a signal of KWDocument, so that when the // above method, or any other way of changing the page layout happens, // the rulers are updated in all views. m_gui->canvasWidget()->viewMode()->setPageLayout( m_gui->getHorzRuler(), m_gui->getVertRuler(), layout ); m_gui->canvasWidget()->repaintAll( true ); } void KWView::newFirstIndent( double _firstIndent ) { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setMarginCommand( QStyleSheetItem::MarginFirstLine, _firstIndent ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand(i18n("Change First Line Indent")); macroCmd->addCommand(cmd); } } if(macroCmd) m_doc->addCommand(macroCmd); } void KWView::newLeftIndent( double _leftIndent ) { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setMarginCommand( QStyleSheetItem::MarginLeft, _leftIndent ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand(i18n("Change Indent") ); macroCmd->addCommand(cmd); } } if(macroCmd) m_doc->addCommand(macroCmd); } void KWView::newRightIndent( double _rightIndent) { QPtrList lst = applicableTextInterfaces(); if ( lst.isEmpty() ) return; QPtrListIterator it( lst ); KMacroCommand* macroCmd = 0L; for ( ; it.current() ; ++it ) { KCommand *cmd = it.current()->setMarginCommand( QStyleSheetItem::MarginRight, _rightIndent ); if (cmd) { if ( !macroCmd ) macroCmd = new KMacroCommand(i18n("Change Indent") ); macroCmd->addCommand(cmd); } } if(macroCmd) m_doc->addCommand(macroCmd); } QPopupMenu * KWView::popupMenu( const QString& name ) { Q_ASSERT(factory()); if ( factory() ) return ((QPopupMenu*)factory()->container( name, this )); return 0L; } void KWView::openPopupMenuInsideFrame( KWFrame* frame, const QPoint & _point ) { KWFrameSetEdit *fse = m_gui->canvasWidget()->currentFrameSetEdit(); kdDebug() << (void*) fse << " in KWView::openPopupMenuInsideFrame" << endl; unplugActionList( "tableactions" ); // will be plugged again by KWTableFrameSetEdit if (fse) fse->showPopup( frame, this, _point ); else frame->frameSet()->showPopup( frame, this, _point ); } void KWView::openPopupMenuChangeAction( const QPoint & _point ) { if(!koDocument()->isReadWrite() || !factory()) return; QPopupMenu* popup = static_cast(factory()->container("action_popup",this)); if ( popup ) popup->popup(_point); } void KWView::openPopupMenuEditFrame( const QPoint & _point ) { if(!koDocument()->isReadWrite() || !factory()) return; KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); if(!table) { QPtrList actionList; int nbFrame=m_doc->getSelectedFrames().count(); KActionSeparator *separator=new KActionSeparator(); KActionSeparator *separator2=new KActionSeparator(); if(nbFrame ==1) { KWFrame *frame=m_doc->getFirstSelectedFrame(); KWFrameSet *frameSet=frame->frameSet(); // ## TODO design: move this to KWFrameSet and derived classes (virtual method) if( frameSet->type()==FT_PICTURE ) { actionList.append(separator); if ( !frameSet->protectContent() ) actionList.append(actionChangePicture); actionList.append(actionSavePicture); } #if 0 // KWORD_HORIZONTAL_LINE else if ( frameSet->type() == FT_HORZLINE ) { actionList.append(separator); actionList.append(actionChangeHorizontalLine); actionList.append(actionSavePicture); } #endif else if ( frameSet->type() == FT_PART ) { KWPartFrameSet *part = static_cast(frameSet); actionEmbeddedStoreInternal->setChecked(part->getChild()->document()->storeInternal()); actionEmbeddedStoreInternal->setEnabled(part->getChild()->document()->hasExternURL()); actionList.append(separator); actionList.append(actionEmbeddedStoreInternal); } else if(frameSet->isHeaderOrFooter()) { actionList.append(separator); actionList.append(actionConfigureHeaderFooter); } else if (frameSet->isFootEndNote()) { actionList.append(separator); actionGoToFootEndNote->setText( frameSet->isFootNote() ? i18n( "Go to Footnote" ) : i18n( "Go to Endnote" ) ); actionList.append(actionGoToFootEndNote); } bool state = !frameSet->isHeaderOrFooter() && !frameSet->isFootEndNote(); state = state && (m_doc->processingType() == KWDocument::WP &&frameSet!=m_doc->frameSet( 0 )); if(state) { actionList.append(separator2); KWFrameSet * parentFs = frameSet->getGroupManager() ? frameSet->getGroupManager() : frameSet; actionInlineFrame->setChecked(parentFs->isFloating()); actionList.append(actionInlineFrame); } } plugActionList( "frameset_type_action", actionList ); ((QPopupMenu*)factory()->container("frame_popup",this))->exec(_point); unplugActionList( "frameset_type_action" ); delete separator; delete separator2; } else ((QPopupMenu*)factory()->container("frame_popup_table",this))->popup(_point); } void KWView::startKSpell() { #ifdef HAVE_LIBKSPELL2 if ( !m_spell.kospell ) m_spell.kospell = new KoSpell( m_broker, this ); // Spell-check the next paragraph Q_ASSERT( m_spell.textIterator ); m_spell.kospell->check( m_spell.textIterator, true ); delete m_spell.dlg; m_spell.dlg = new KSpell2::Dialog( m_spell.kospell, this ); m_spell.dlg->activeAutoCorrect( true ); QObject::connect( m_spell.dlg, SIGNAL(misspelling(const QString&, int)), this, SLOT(spellCheckerMisspelling(const QString&, int)) ); QObject::connect( m_spell.dlg, SIGNAL(replace(const QString&, int, const QString&)), this, SLOT(spellCheckerCorrected(const QString&, int, const QString&)) ); QObject::connect( m_spell.dlg, SIGNAL(done(const QString&) ), this, SLOT(spellCheckerDone(const QString&)) ); QObject::connect( m_spell.dlg, SIGNAL( stop() ), this, SLOT( spellCheckerFinished( ) ) ); QObject::connect( m_spell.dlg, SIGNAL(cancel() ), this, SLOT( spellCheckerCancel() ) ); QObject::connect( m_spell.dlg, SIGNAL(autoCorrect(const QString &, const QString & ) ), this, SLOT( spellAddAutoCorrect (const QString &, const QString &) ) ); m_spell.dlg->show(); #endif //clearSpellChecker(); } void KWView::spellCheckerMisspelling( const QString &old, int pos ) { #ifdef HAVE_LIBKSPELL2 //kdDebug(32001) << "KWView::spellCheckerMisspelling old=" << old << " pos=" << pos << endl; KoTextObject* textobj = m_spell.kospell->currentTextObject(); KoTextParag* parag = m_spell.kospell->currentParag(); Q_ASSERT( textobj ); Q_ASSERT( parag ); if ( !textobj || !parag ) return; KWTextDocument *textdoc=static_cast( textobj->textDocument() ); Q_ASSERT( textdoc ); if ( !textdoc ) return; pos += m_spell.kospell->currentStartIndex(); kdDebug(32001) << "KWView::spellCheckerMisspelling parag=" << parag->paragId() << " pos=" << pos << " length=" << old.length() << endl; textdoc->textFrameSet()->highlightPortion( parag, pos, old.length(), m_gui->canvasWidget() ); #endif } void KWView::spellCheckerCorrected( const QString &old, int pos , const QString &corr ) { #ifdef HAVE_LIBKSPELL2 //kdDebug(32001) << "KWView::spellCheckerCorrected old=" << old << " corr=" << corr << " pos=" << pos << endl; KoTextObject* textobj = m_spell.kospell->currentTextObject(); KoTextParag* parag = m_spell.kospell->currentParag(); Q_ASSERT( textobj ); Q_ASSERT( parag ); if ( !textobj || !parag ) return; KWTextDocument *textdoc=static_cast( textobj->textDocument() ); Q_ASSERT( textdoc ); if ( !textdoc ) return; pos += m_spell.kospell->currentStartIndex(); textdoc->textFrameSet()->highlightPortion( parag, pos, old.length(), m_gui->canvasWidget() ); KoTextCursor cursor( textdoc ); cursor.setParag( parag ); cursor.setIndex( pos ); if(!m_spell.macroCmdSpellCheck) m_spell.macroCmdSpellCheck=new KMacroCommand(i18n("Correct Misspelled Word")); m_spell.macroCmdSpellCheck->addCommand(textobj->replaceSelectionCommand( &cursor, corr, KoTextObject::HighlightSelection, QString::null )); #endif } void KWView::spellCheckerDone( const QString & ) { #ifdef HAVE_LIBKSPELL2 //kdDebug(32001) << "KWView::spellCheckerDone" << endl; KWTextDocument *textdoc=static_cast( m_spell.kospell->textDocument() ); Q_ASSERT( textdoc ); if ( textdoc ) textdoc->textFrameSet()->removeHighlight(); clearSpellChecker(); #endif } void KWView::clearSpellChecker(bool cancelSpellCheck) { #ifdef HAVE_LIBKSPELL2 kdDebug(32001) << "KWView::clearSpellChecker" << endl; delete m_spell.textIterator; m_spell.textIterator = 0L; if ( m_spell.macroCmdSpellCheck ) { if ( !cancelSpellCheck ) m_doc->addCommand(m_spell.macroCmdSpellCheck); else { //reverte all changes m_spell.macroCmdSpellCheck->unexecute(); delete m_spell.macroCmdSpellCheck; } } m_spell.macroCmdSpellCheck=0L; m_spell.replaceAll.clear(); //m_doc->setReadWrite(true); #endif } void KWView::spellCheckerCancel() { #ifdef HAVE_LIBKSPELL2 kdDebug()<<"void KWView::spellCheckerCancel() \n"; spellCheckerRemoveHighlight(); //we add command :( => don't add command and reverte changes clearSpellChecker(true); #endif } void KWView::spellCheckerRemoveHighlight() { #ifdef HAVE_LIBKSPELL2 KoTextObject* textobj = m_spell.kospell->currentTextObject(); if ( textobj ) { KWTextDocument *textdoc=static_cast( textobj->textDocument() ); if ( textdoc ) textdoc->textFrameSet()->removeHighlight(); } KWTextFrameSetEdit * edit = currentTextEdit(); if (edit) edit->drawCursor( TRUE ); #endif } void KWView::spellCheckerFinished() { #ifdef HAVE_LIBKSPELL2 kdDebug(32001) << "KWView::spellCheckerFinished (death)" << endl; spellCheckerRemoveHighlight(); clearSpellChecker(); #endif } void KWView::spellAddAutoCorrect (const QString & originalword, const QString & newword) { m_doc->getAutoFormat()->addAutoFormatEntry( originalword, newword ); } void KWView::configure() { KWConfig configDia( this ); configDia.exec(); } KWTextFrameSetEdit *KWView::currentTextEdit() const { if (!m_gui) return 0L; KWFrameSetEdit * edit = m_gui->canvasWidget()->currentFrameSetEdit(); if ( edit ) return dynamic_cast(edit->currentTextEdit()); return 0L; } void KWView::slotFrameSetEditChanged() { KWTextFrameSetEdit * edit = currentTextEdit(); bool rw = koDocument()->isReadWrite(); bool hasSelection = false; if ( edit ) { hasSelection = edit->textFrameSet()->hasSelection(); if ( edit->textFrameSet()->textObject()->protectContent()) rw = false; } else { KWFrameSetEdit * e = m_gui->canvasWidget()->currentFrameSetEdit(); if ( e && e->frameSet()->type() == FT_FORMULA ) { hasSelection = true; } } actionEditCut->setEnabled( hasSelection && rw ); actionEditCopy->setEnabled( hasSelection ); actionEditReplace->setEnabled( /*edit &&*/ rw ); clipboardDataChanged(); // for paste bool state = (edit != 0L) && rw; actionEditSelectAll->setEnabled(state); actionInsertComment->setEnabled( state ); actionFormatDefault->setEnabled( rw); actionFormatFont->setEnabled( rw ); actionFormatFontSize->setEnabled( rw ); actionFormatFontFamily->setEnabled( rw ); actionAddBookmark->setEnabled(state); actionBackgroundColor->setEnabled( rw ); actionFormatStyleMenu->setEnabled( rw ); actionFormatBold->setEnabled( rw ); actionFormatItalic->setEnabled( rw ); actionFormatUnderline->setEnabled( rw ); actionFormatStrikeOut->setEnabled( rw ); actionFormatColor->setEnabled( rw ); actionFormatAlignLeft->setEnabled( rw ); actionFormatAlignCenter->setEnabled( rw ); actionFormatAlignRight->setEnabled( rw ); actionFormatAlignBlock->setEnabled( rw ); actionBorderLeft->setEnabled( rw ); actionBorderRight->setEnabled( rw ); actionBorderTop->setEnabled( rw ); actionBorderBottom->setEnabled( rw ); actionBorderOutline->setEnabled( rw ); actionBorderColor->setEnabled( rw ); actionBorderWidth->setEnabled( rw ); actionBorderStyle->setEnabled( rw ); //actionFormatIncreaseIndent->setEnabled(state); actionInsertLink->setEnabled(state); #if 0 // KWORD_HORIZONTAL_LINE actionInsertHorizontalLine->setEnabled( state); #endif actionCreateStyleFromSelection->setEnabled( state /*&& hasSelection*/); actionConvertToTextBox->setEnabled( state && hasSelection); actionAddPersonalExpression->setEnabled( state && hasSelection); actionSortText->setEnabled( state && hasSelection); bool goodleftMargin=false; if(state) goodleftMargin=(edit->currentLeftMargin()>0); actionFormatDecreaseIndent->setEnabled(goodleftMargin /*&& state*/); bool isFootNoteSelected = ((rw && edit && !edit->textFrameSet()->isFootEndNote())||(!edit&& rw)); actionFormatBullet->setEnabled(isFootNoteSelected); actionFormatNumber->setEnabled(isFootNoteSelected); actionFormatStyle->setEnabled(isFootNoteSelected); actionFormatSuper->setEnabled(rw); actionFormatSub->setEnabled(rw); actionFormatParag->setEnabled(state); actionInsertSpecialChar->setEnabled(state); actionSpellCheck->setEnabled(state); actionChangeCase->setEnabled( (rw && !edit)|| (state && hasSelection) ); if ( edit && edit->textFrameSet()->protectContent()) { actionChangeCase->setEnabled( false ); actionEditCut->setEnabled( false ); } else actionChangeCase->setEnabled( true ); updateTableActions( -1 ); actionInsertFormula->setEnabled(state && (m_gui->canvasWidget()->viewMode()->type()!="ModeText")); actionInsertVariable->setEnabled(state); actionInsertExpression->setEnabled(state); changeFootEndNoteState(); //frameset different of header/footer state= state && edit && edit->frameSet() && !edit->frameSet()->isHeaderOrFooter() && !edit->frameSet()->getGroupManager() && !edit->frameSet()->isFootEndNote(); actionInsertContents->setEnabled(state); actionInsertFrameBreak->setEnabled( state ); updatePageInfo(); } void KWView::changeFootEndNoteState() { bool rw = koDocument()->isReadWrite(); KWTextFrameSetEdit * edit = currentTextEdit(); QString mode = m_gui->canvasWidget()->viewMode()->type(); bool isEditableFrameset = edit && edit->frameSet() && edit->frameSet()->isMainFrameset(); bool ok = rw && isEditableFrameset && (mode!="ModeText"); actionInsertFootEndNote->setEnabled( ok ); actionEditFootEndNote->setEnabled( ok ); } void KWView::changeFootNoteMenuItem( bool _footnote) { actionEditFootEndNote->setText( _footnote? i18n("Edit Footnote"): i18n("Edit Endnote")); actionChangeFootNoteType->setText( _footnote? i18n("Change Footnote Parameter"):i18n("Change Endnote Parameter")); } void KWView::slotUpdateRuler() { KWCanvas* canvas = m_gui->canvasWidget(); QRect r( canvas->viewMode()->rulerFrameRect( canvas ) ); if ( !r.isNull() ) { m_gui->getHorzRuler()->setFrameStartEnd( r.left(), r.right() ); m_gui->getVertRuler()->setFrameStartEnd( r.top(), r.bottom() ); } canvas->updateRulerOffsets(); } void KWView::frameSelectedChanged() { bool rw = koDocument()->isReadWrite(); QPtrList selectedFrames = m_doc->getSelectedFrames(); int nbFrame = selectedFrames.count(); actionFormatFrameSet->setEnabled( nbFrame>=1 ); if ( rw && nbFrame >= 1 ) { bool okForDelete = true; bool okForLowerRaise = false; bool okForChangeParagStyle = true; bool okForChangeInline = true; QPtrListIterator it( selectedFrames ); for ( ; it.current() && ( okForDelete || okForLowerRaise || okForChangeParagStyle || okForChangeInline) ; ++it ) { // Check we selected no footer nor header bool isFootNote = it.current()->frameSet()->isFootEndNote(); bool headerFooterFootNote = it.current()->frameSet()->isHeaderOrFooter() || isFootNote; bool isMainWPFrame = it.current()->frameSet()->isMainFrameset(); okForChangeParagStyle &= !isFootNote; okForDelete &= !headerFooterFootNote; okForDelete &= !isMainWPFrame; // Check we selected a frame we can lower raise. // The header, footer, main frameset, footnotes and inline frames can't be raised. // As soon as we find one who we can lower/raise open the option. okForLowerRaise |= !(isMainWPFrame || headerFooterFootNote || it.current()->frameSet()->isFloating()); okForChangeInline &= !(isMainWPFrame || headerFooterFootNote ); } actionEditDelFrame->setEnabled( okForDelete ); actionEditCut->setEnabled( okForDelete ); actionLowerFrame->setEnabled( okForLowerRaise ); actionRaiseFrame->setEnabled( okForLowerRaise ); actionSendBackward->setEnabled( okForLowerRaise ); actionBringToFront->setEnabled( okForLowerRaise ); actionFormatBullet->setEnabled( okForChangeParagStyle ); actionFormatNumber->setEnabled( okForChangeParagStyle ); actionFormatStyle->setEnabled( okForChangeParagStyle); actionInlineFrame->setEnabled( okForChangeInline); } else { // readonly document, or no frame selected -> disable actionEditDelFrame->setEnabled( false ); actionInlineFrame->setEnabled(false); actionEditCut->setEnabled( false ); actionLowerFrame->setEnabled( false ); actionRaiseFrame->setEnabled( false ); actionSendBackward->setEnabled( false ); actionBringToFront->setEnabled( false ); } bool frameDifferentOfPart=false; if(nbFrame >= 1) { QPtrListIterator it( selectedFrames ); for ( ; it.current(); ++it ) { if ( it.current()->frameSet()->type()!=FT_PART && it.current()->frameSet()->type()!= FT_PICTURE) { frameDifferentOfPart=true; break; } } } actionBackgroundColor->setEnabled( (nbFrame >= 1) && frameDifferentOfPart); actionBackgroundColor->setText(i18n("Frame Background Color...")); if ( frameDifferentOfPart ) { KWFrame *frame = m_doc->getFirstSelectedFrame(); if ( frame ) { QColor frameCol=frame->backgroundColor().color(); //actionBackgroundColor->setText(i18n("Frame Background Color...")); actionBackgroundColor->setCurrentColor( frameCol.isValid()? frame->backgroundColor().color() : QApplication::palette().color( QPalette::Active, QColorGroup::Base )); } } actionCreateFrameStyle->setEnabled( nbFrame==1 ); actionCreateLinkedFrame->setEnabled( nbFrame==1 ); actionEditCopy->setEnabled( nbFrame >= 1 ); updateTableActions( nbFrame ); m_doc->refreshFrameBorderButton(); updatePageInfo(); // takes care of slotUpdateRuler() updateFrameStatusBarItem(); QPtrList lst = applicableTextInterfaces(); if ( !lst.isEmpty() ) { QPtrListIterator it( lst ); KoTextFormat format=*(lst.first()->currentFormat()); showFormat( format ); const KoParagLayout * paragLayout=lst.first()->currentParagLayoutFormat(); KoParagCounter counter; if(paragLayout->counter) counter = *(paragLayout->counter); showCounter( counter ); int align = paragLayout->alignment; if ( align == Qt::AlignAuto ) align = Qt::AlignLeft; // ## seems hard to detect RTL here showAlign( align ); } } void KWView::updateTableActions( int nbFramesSelected ) { if ( nbFramesSelected == -1 ) // not calculated by caller { QPtrList selectedFrames = m_doc->getSelectedFrames(); nbFramesSelected = selectedFrames.count(); } KWTableFrameSet *table = m_gui->canvasWidget()->getCurrentTable(); actionTableJoinCells->setEnabled( table && (nbFramesSelected>1)); actionConvertTableToText->setEnabled( table && table->isFloating() ); bool oneCellSelected = (table && nbFramesSelected==1); actionTableSplitCells->setEnabled( oneCellSelected ); // TODO also allow to split current cell // cellEdited: true if the cursor is in a table cell bool cellEdited = table && ( m_gui->canvasWidget()->currentTableRow() > -1 ); // rowKnown: true if cellEdited or if entire row(s) selected bool rowKnown = table && ( cellEdited || table->isRowsSelected() ); actionTableInsertRow->setEnabled( rowKnown ); actionTableDelRow->setEnabled( rowKnown ); // colKnown: true if cellEdited or if entire col(s) selected bool colKnown = table && ( cellEdited || table->isColsSelected() ); actionTableInsertCol->setEnabled( colKnown ); actionTableDelCol->setEnabled( colKnown ); // TODO (after msg freeze) : update text of actionTableDelCol to // either "Delete Current Column" or "Delete Selected Columns". // Same with actionTableDelRow. actionTableResizeCol->setEnabled( table ); actionTableDelete->setEnabled( table ); actionTablePropertiesMenu->setEnabled( table ); bool cellsSelected = (table && nbFramesSelected>0); actionTableUngroup->setEnabled( cellsSelected ); actionTableProtectCells->setEnabled( cellsSelected ); if ( cellsSelected ) { unsigned int row = 0; unsigned int col = 0; table->getFirstSelected(row, col ); bool _protect = table->getCell( row, col )->protectContent(); actionTableProtectCells->setChecked(_protect); } } void KWView::docStructChanged(int _type) { KWDocStruct *m_pDocStruct=m_gui->getDocStruct(); if(m_pDocStruct) m_pDocStruct->getDocStructTree()->refreshTree(_type); m_doc->recalcVariables( VT_STATISTIC ); } void KWView::setViewFrameBorders(bool b) { m_viewFrameBorders = b; // Store setting in doc, for further views and for saving m_doc->setViewFrameBorders( b ); m_doc->viewMode()->setDrawFrameBorders( b ); } bool KWView::doubleClickActivation() const { return TRUE; } QWidget* KWView::canvas() { return m_gui->canvasWidget()->viewport(); } int KWView::canvasXOffset() const { return m_gui->canvasWidget()->contentsX(); } int KWView::canvasYOffset() const { return m_gui->canvasWidget()->contentsY(); } void KWView::canvasAddChild( KoViewChild * /*child*/ ) { // Not necessary anymore //m_gui->canvasWidget()->addChild( child->frame() ); } void KWView::changePicture() { KWFrame * frame = m_doc->getFirstSelectedFrame(); KWPictureFrameSet *frameset = static_cast(frame->frameSet()); if ( frameset->protectContent() ) return; KoPictureKey oldKey ( frameset->picture().getKey() ); QString oldFile ( oldKey.filename() ); KURL url; url.setPath( oldFile ); if (!QDir(url.directory()).exists()) oldFile = url.fileName(); KoPicture picture ( KWInsertPicDia::selectPictureDia( oldFile, this ) ); if ( !picture.isNull() ) { KWFrameChangePictureCommand *cmd= new KWFrameChangePictureCommand( i18n("Change Picture"), FrameIndex(frame), oldKey, picture.getKey() ) ; frameset->insertPicture( picture ); m_doc->frameChanged( frame ); m_doc->refreshDocStructure( FT_PICTURE ); m_doc->addCommand(cmd); } else kdDebug() << "KWView::changePicture cancelled" << endl; } void KWView::savePicture() { KWFrame * frame = m_doc->getFirstSelectedFrame(); if ( frame )//test for dcop call { KWPictureFrameSet *frameset = static_cast(frame->frameSet()); QString oldFile = frameset->picture().getKey().filename(); KURL url; url.setPath( oldFile ); if ( !QDir(url.directory()).exists() ) oldFile = url.fileName(); KoPicture picture( frameset->picture() ); QString mimetype = picture.getMimeType(); kdDebug() << "Picture has mime type: " << mimetype << endl; QStringList mimetypes; mimetypes << mimetype; KFileDialog fd( oldFile, QString::null, this, 0, TRUE ); fd.setMimeFilter( mimetypes ); fd.setCaption(i18n("Save Picture")); fd.setOperationMode(KFileDialog::Saving); if ( fd.exec() == QDialog::Accepted ) { url = fd.selectedURL(); if ( url.isValid() ) { if ( url.isLocalFile() ) { QFile file( url.path() ); if ( file.open( IO_ReadWrite ) ) { picture.save( &file ); file.close(); } else { KMessageBox::error(this, i18n("Error during saving. Could not open '%1' for writing").arg ( url.path() ), i18n("Save Picture")); } } else { KTempFile tempFile; tempFile.setAutoDelete( true ); if ( tempFile.status() == 0 ) { QFile file( tempFile.name() ); if ( file.open( IO_ReadWrite ) ) { picture.save( &file ); file.close(); if ( !KIO::NetAccess::upload( tempFile.name(), url, this ) ) { KMessageBox::sorry( this, i18n( "Unable to save the file to '%1'. %2.").arg( url.prettyURL() ).arg( KIO::NetAccess::lastErrorString() ), i18n("Save Failed") ); } } else KMessageBox::error(this, i18n("Error during saving. Could not open '%1' temporary file for writing").arg ( file.name() ), i18n("Save Picture")); } else KMessageBox::sorry( this, i18n( "Error during saving. Could not create temporary file: %1.").arg( strerror( tempFile.status() ) ), i18n("Save Picture") ); } } else KMessageBox::sorry( this, i18n("URL %1 is invalid.").arg( url.prettyURL() ), i18n("Save Picture") ); } } } void KWView::configureHeaderFooter() { KoPageLayout pgLayout; KoColumns cl; KoKWHeaderFooter kwhf; m_doc->getPageLayout( pgLayout, cl, kwhf ); KWPageLayoutStruct oldLayout( pgLayout, cl, kwhf ); KoHeadFoot hf; int flags = KW_HEADER_AND_FOOTER; KoUnit::Unit unit = m_doc->getUnit(); KoUnit::Unit oldUnit = unit; if ( KoPageLayoutDia::pageLayout( pgLayout, hf, cl, kwhf, flags, unit ) ) { if( oldLayout._hf != kwhf ) { KWPageLayoutStruct newLayout( pgLayout, cl, kwhf ); KCommand *cmd = new KWPageLayoutCommand( i18n("Change Layout"), m_doc, oldLayout, newLayout ); m_doc->addCommand(cmd); m_doc->setPageLayout( pgLayout, cl, kwhf ); } if ( unit != oldUnit ) m_doc->setUnit( unit ); // needs undo/redo support } } void KWView::inlineFrame() { KWFrame * frame = m_doc->getFirstSelectedFrame(); KWFrameSet * fs = frame->frameSet(); KWFrameSet * parentFs = fs->getGroupManager() ? fs->getGroupManager() : fs; if(actionInlineFrame->isChecked()) { KMacroCommand* macroCmd = new KMacroCommand( i18n("Make Frameset Inline") ); QValueList frameindexList; QValueList frameindexMove; KoPoint initialPos = frame->topLeft(); // turn non-floating frame into floating frame KWFrameSetInlineCommand *cmd = new KWFrameSetInlineCommand( i18n("Make Frameset Inline"), parentFs, true ); cmd->execute(); frameindexList.append( FrameIndex( frame ) ); frameindexMove.append( FrameMoveStruct( initialPos, frame->topLeft() ) ); KWFrameMoveCommand *cmdMoveFrame = new KWFrameMoveCommand( i18n("Move Frame"), frameindexList, frameindexMove ); macroCmd->addCommand(cmdMoveFrame); macroCmd->addCommand(cmd); m_doc->addCommand(macroCmd); } else { KWFrameSetInlineCommand *cmd = new KWFrameSetInlineCommand( i18n("Make Frameset Non-Inline"), parentFs, false ); m_doc->addCommand(cmd); cmd->execute(); } } void KWView::openLink() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->openLink(); } void KWView::changeLink() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KoLinkVariable * var=edit->linkVariable(); if(var) { QString oldhref= var->url(); QString oldLinkName=var->value(); QString link=oldLinkName; QString ref=oldhref; if(KoInsertLinkDia::createLinkDia(link, ref, m_doc->listOfBookmarkName(0), this)) { if(!link.isEmpty() && !ref.isEmpty()) { if( ref != oldhref || link!=oldLinkName) { KWChangeLinkVariable*cmd=new KWChangeLinkVariable( i18n("Change Link"), m_doc,oldhref, ref, oldLinkName,link, var); cmd->execute(); m_doc->addCommand(cmd); } } } } } } void KWView::copyLink() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->copyLink(); } void KWView::removeLink() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->removeLink(); } void KWView::addToBookmark() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KoLinkVariable * var=edit->linkVariable(); if(var) { edit->addBookmarks(var->url()); } } } void KWView::showDocStructure() { m_doc->setShowDocStruct(actionShowDocStruct->isChecked()); m_doc->reorganizeGUI(); } void KWView::showRuler() { m_doc->setShowRuler( actionShowRuler->isChecked()); m_doc->reorganizeGUI(); } void KWView::slotSoftHyphen() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->insertSoftHyphen(); } void KWView::slotNonbreakingSpace() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->insertNonbreakingSpace(); } void KWView::slotNonbreakingHyphen() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->insertNonbreakingHyphen(); } void KWView::slotLineBreak() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->insertLineBreak(); } void KWView::slotIncreaseNumberingLevel() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->increaseNumberingLevel( m_doc->styleCollection() ); } void KWView::slotDecreaseNumberingLevel() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->decreaseNumberingLevel( m_doc->styleCollection() ); } void KWView::refreshAllVariable() { m_doc->recalcVariables( VT_ALL ); } void KWView::slotAllowAutoFormat() { bool state = actionAllowAutoFormat->isChecked(); m_doc->setAllowAutoFormat( state ); } void KWView::slotCompletion() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) edit->completion(); } void KWView::updateHeaderFooterButton() { actionViewHeader->setChecked(m_doc->isHeaderVisible()); actionViewFooter->setChecked(m_doc->isFooterVisible()); } void KWView::editComment() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KoVariable * tmpVar=edit->variable(); KoNoteVariable * var = dynamic_cast(tmpVar); if(var) { QString authorName; KoDocumentInfo * info = m_doc->documentInfo(); KoDocumentInfoAuthor * authorPage = static_cast(info->page( "author" )); if ( !authorPage ) kdWarning() << "Author information not found in documentInfo !" << endl; else authorName = authorPage->fullName(); QString oldValue = var->note(); QString createDate = var->createdNote(); KoCommentDia *commentDia = new KoCommentDia( this, oldValue, authorName, createDate); if( commentDia->exec() ) { if ( oldValue != commentDia->commentText()) { KWChangeVariableNoteText *cmd = new KWChangeVariableNoteText( i18n("Change Note Text"), m_doc, oldValue,commentDia->commentText(), var); m_doc->addCommand( cmd ); cmd->execute(); } } delete commentDia; } } } void KWView::fileStatistics() { KWStatisticsDialog *statisticsDialog = new KWStatisticsDialog( this, m_doc ); if ( !statisticsDialog->wasCanceled() ) statisticsDialog->exec(); delete statisticsDialog; } void KWView::removeComment() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { edit->removeComment(); } } void KWView::copyTextOfComment() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { edit->copyTextOfComment(); } } void KWView::configureCompletion() { m_doc->getAutoFormat()->readConfig(); KoCompletionDia dia( this, 0, m_doc->getAutoFormat() ); dia.exec(); } void KWView::applyAutoFormat() { m_doc->getAutoFormat()->readConfig(); KMacroCommand *macro = 0L; QValueList list(m_doc->visibleTextObjects(m_gui->canvasWidget()->viewMode())); QValueList::Iterator fit = list.begin(); for ( ; fit != list.end() ; ++fit ) { KCommand *cmd = m_doc->getAutoFormat()->applyAutoFormat( *fit ); if ( cmd ) { if ( !macro ) macro = new KMacroCommand( i18n("Apply Autoformat")); macro->addCommand( cmd ); } } if ( macro ) m_doc->addCommand( macro ); } void KWView::createStyleFromSelection() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { QStringList list; QPtrListIterator styleIt( m_doc->styleCollection()->styleList() ); for ( ; styleIt.current(); ++styleIt ) { list.append( styleIt.current()->name() ); } KoCreateStyleDia *dia = new KoCreateStyleDia( QStringList(), this, 0 ); if ( dia->exec() ) { QString name = dia->nameOfNewStyle(); if ( list.contains( name ) ) // update existing style { // TODO confirmation message box KoParagStyle* style = m_doc->styleCollection()->findStyle( name ); Q_ASSERT( style ); if ( style ) edit->updateStyleFromSelection( style ); } else // create new style { KoParagStyle *style = edit->createStyleFromSelection( name ); m_doc->styleCollection()->addStyleTemplate( style ); m_doc->updateAllStyleLists(); } showStyle( name ); } delete dia; } } // Initially called by initGUIButton void KWView::switchModeView() { // Apply the same viewmode to all views (due to limitations in the text formatter) // So we get the viewmode to use from the document. m_gui->canvasWidget()->switchViewMode( m_doc->viewMode() ); slotUpdateRuler(); // Now update the actions appropriately QString mode = m_gui->canvasWidget()->viewMode()->type(); bool isTextMode = mode == "ModeText"; bool state = !isTextMode; actionToolsCreateText->setEnabled(state); actionToolsCreatePix->setEnabled(state); actionToolsCreatePart->setEnabled(state); actionInsertFormula->setEnabled(state); actionInsertTable->setEnabled(state); changeFootEndNoteState(); actionViewFooter->setEnabled( state && m_doc->processingType() == KWDocument::WP ); actionViewHeader->setEnabled( state && m_doc->processingType() == KWDocument::WP ); //actionViewTextMode->setEnabled(m_doc->processingType()==KWDocument::WP); actionShowDocStruct->setEnabled(state); actionFormatPage->setEnabled(state); actionInsertContents->setEnabled( state ); actionFrameStyle->setEnabled( state ); actionTableStyle->setEnabled ( state ); if ( m_gui->getHorzRuler()) { m_gui->getHorzRuler()->setPageLayoutMenuItemEnabled( state ); if ( !koDocument()->isReadWrite()) m_gui->getHorzRuler()->changeFlags( KoRuler::F_NORESIZE ); else { if ( state ) m_gui->getHorzRuler()->changeFlags( m_gui->getHorzRuler()->flags() & ~(KoRuler::F_NORESIZE) ); else m_gui->getHorzRuler()->changeFlags( m_gui->getHorzRuler()->flags() | KoRuler::F_NORESIZE ); } } if ( m_gui->getVertRuler() ) { m_gui->getVertRuler()->setPageLayoutMenuItemEnabled( state ); if ( !koDocument()->isReadWrite()) m_gui->getVertRuler()->changeFlags( KoRuler::F_NORESIZE ); else { if ( state ) m_gui->getVertRuler()->changeFlags( m_gui->getVertRuler()->flags() & ~(KoRuler::F_NORESIZE) ); else m_gui->getVertRuler()->changeFlags( m_gui->getVertRuler()->flags() | KoRuler::F_NORESIZE ); } } if ( isTextMode ) { if ( m_doc->showdocStruct() ) { m_doc->setShowDocStruct(false); m_doc->reorganizeGUI(); } } else { m_doc->setShowDocStruct(actionShowDocStruct->isChecked()); m_doc->reorganizeGUI(); } //recalc pgnum variable when we swith viewmode //because in text mode view we display field code and not value //normal because we don't have real page in this mode m_doc->recalcVariables( VT_PGNUM ); if ( isTextMode ) { // Make sure we edit the same frameset as the one shown in the textview ;-) m_gui->canvasWidget()->editFrameSet( static_cast(m_doc->viewMode())->textFrameSet() ); } //remove/add "zoom to page". Not necessary in text mode view. changeZoomMenu( m_doc->zoom() ); showZoom( m_doc->zoom() ); updatePageInfo(); m_doc->viewMode()->setPageLayout( m_gui->getHorzRuler(), m_gui->getVertRuler(), m_doc->pageLayout() ); } void KWView::configureFootEndNote() { KWConfigFootNoteDia *dia = new KWConfigFootNoteDia( this, "configfootnote", m_doc ); dia->exec(); delete dia; } void KWView::editFootEndNote() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KWFootNoteVariable * var = dynamic_cast( edit->variable() ); if ( var && var->frameSet() ) { m_gui->canvasWidget()->editFrameSet( var->frameSet() ); KWTextFrameSetEdit* textedit = currentTextEdit(); if ( textedit ) textedit->ensureCursorVisible(); } } } void KWView::changeFootNoteType() { KWTextFrameSetEdit * edit = currentTextEdit(); if ( edit ) { KoVariable * tmpVar=edit->variable(); KWFootNoteVariable * var = dynamic_cast(tmpVar); if(var && var->frameSet()) { KWFootNoteDia dia( var->noteType(), var->numberingType(), (var->numberingType()==KWFootNoteVariable::Auto) ? QString::null : var->manualString(), this, m_doc, 0 ); if ( dia.exec() ) { FootNoteParameter oldParam( var ); FootNoteParameter newParam(dia.noteType(), dia.numberingType(), dia.manualString() ); KWChangeFootNoteParametersCommand * cmd = new KWChangeFootNoteParametersCommand( i18n("Change Footnote Parameters"), var , oldParam, newParam, m_doc); cmd->execute(); m_doc->addCommand ( cmd ); } } } } void KWView::autoSpellCheck() { autoSpellCheck( actionAllowBgSpellCheck->isChecked() ); } void KWView::autoSpellCheck(bool b) { m_doc->changeBgSpellCheckingState( b ); } void KWView::goToFootEndNote() { KWFrame * frm = m_doc->getFirstSelectedFrame(); if ( frm ) { KWFootNoteFrameSet *footNoteFrameSet = dynamic_cast(frm->frameSet()); if ( footNoteFrameSet ) { KWFootNoteVariable* var=footNoteFrameSet->footNoteVariable(); KoTextParag *parag = var->paragraph(); int index = var->index(); KWTextDocument *textDoc = static_cast(var->textDocument()); KWTextFrameSet *frameSet =textDoc->textFrameSet(); m_gui->canvasWidget()->editTextFrameSet( frameSet, parag, index ); } } } void KWView::openDocStructurePopupMenu( const QPoint &_p, KWFrameSet *frameset) { if(!koDocument()->isReadWrite() ) return; QPtrList actionList; bool state = (frameset->type()==FT_TEXT || frameset->type()==FT_TABLE || frameset->type()==FT_FORMULA ); if ( state ) actionList.append(actionEditFrameSet); actionDeleteFrameSet->setEnabled( (!frameset->isMainFrameset() && !frameset->isFootEndNote() && !frameset->isHeaderOrFooter()) ); plugActionList( "edit_action", actionList ); QPopupMenu* popup = static_cast(factory()->container("docstruct_popup",this)); if ( popup ) popup->exec(_p); unplugActionList( "edit_action" ); } void KWView::selectFrameSet() { if ( m_gui->getDocStruct() ) { m_gui->getDocStruct()->selectFrameSet(); } } void KWView::editFrameSet() { if ( m_gui->getDocStruct() ) { m_gui->getDocStruct()->editFrameSet(); //return focus to canvas. m_gui->canvasWidget()->setFocus(); } } void KWView::editFrameSetProperties() { if ( m_gui->getDocStruct() ) { m_gui->getDocStruct()->editProperties(); } } void KWView::deleteFrameSet() { if ( m_gui->getDocStruct() ) { m_gui->getDocStruct()->deleteFrameSet(); } } void KWView::insertFile() { KFileDialog fd( QString::null, QString::null, this, 0, TRUE ); fd.setMimeFilter( "application/x-kword" ); fd.setCaption(i18n("Insert File")); KURL url; if ( fd.exec() != QDialog::Accepted ) return; url = fd.selectedURL(); if( url.isEmpty() ) { KMessageBox::sorry( this, i18n("File name is empty."), i18n("Insert File")); return; } insertFile( url ); } void KWView::insertFile(const KURL& _url) { KMacroCommand* macroCmd = 0L; bool hasFixedFramesets = false; KoStore* store=KoStore::createStore( this, _url, KoStore::Read ); // ###### All of this should be ported to use the pasting code instead. QString maindoc = "maindoc.xml"; if ( store ) { // We need to load the pictures before we treat framesets // because KWDocument::pasteFrames() calls processPictureRequests(). bool b = store->open(maindoc); if ( !b ) { KMessageBox::sorry( this, i18n("This file is not a KWord file!"), i18n("Insert File")); delete store; return; } QDomDocument doc; doc.setContent( store->device() ); QDomElement word = doc.documentElement(); m_doc->loadPictureMap( word ); store->close(); m_doc->loadImagesFromStore( store ); } if ( store ) { bool b = store->open(maindoc); if ( !b ) { KMessageBox::sorry( this, i18n("File name is not a KWord file!"), i18n("Insert File")); delete store; return; } QDomDocument doc; doc.setContent( store->device() ); QDomElement word = doc.documentElement(); QDomElement framesets = word.namedItem( "FRAMESETS" ).toElement(); if ( !framesets.isNull() ) { QDomElement framesetElem = framesets.firstChild().toElement(); // just in case while ( !framesetElem.isNull() && framesetElem.tagName() != "FRAMESET" ) framesetElem = framesetElem.nextSibling().toElement(); if ( !framesetElem.isNull() ) { KWTextFrameSet *textFrameSet = dynamic_cast( m_doc->frameSet(0) ); KoTextCursor insertionCursor( textFrameSet->textDocument() ); KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit && !edit->textFrameSet()->protectContent()) { textFrameSet = edit->textFrameSet(); insertionCursor = *edit->cursor(); } // Handle the main textframeset special - concatenate the text QDomDocument domDoc( "PARAGRAPHS" ); QDomElement paragsElem = domDoc.createElement( "PARAGRAPHS" ); domDoc.appendChild( paragsElem ); // Need an intermediate list otherwise nextSibling doesn't work after moving the node // to the other DOM tree ;) QValueList paragList; QValueList inlineFsNames; QDomElement fsElem; QDomNode n = framesetElem.firstChild().toElement(); while( !n.isNull() ) { QDomElement e = n.toElement(); // try to convert the node to an element. if ( !e.isNull() && e.tagName() == "PARAGRAPH" ) { paragList.append( e ); // Handle inline framesets QDomElement formatsElem = e.namedItem( "FORMATS" ).toElement(); if ( !formatsElem.isNull() ) { // Get references to inline framesets QDomElement formatElem = formatsElem.firstChild().toElement(); for ( ; !formatElem.isNull() ; formatElem = formatElem.nextSibling().toElement() ) { QDomElement anchorElem = formatElem.namedItem( "ANCHOR" ).toElement(); if ( !anchorElem.isNull() ) { QString type = anchorElem.attribute( "type" ); if ( type == "grpMgr" /* old syntax */ || type == "frameset" ) { QString iName = anchorElem.attribute( "instance" ); inlineFsNames.append( iName ); // inline framsets shall appear after the paragraph QString tableName; QDomElement table; fsElem = framesetElem.nextSibling().toElement(); for ( ; !fsElem.isNull() ; fsElem = fsElem.nextSibling().toElement() ) { if ( fsElem.tagName() == "FRAMESET" ) { QString name = fsElem.attribute( "name" ); QString grpMgr = fsElem.attribute( "grpMgr" ); if ( name == iName ) { paragList.append( fsElem ); //kdDebug()<::Iterator it = paragList.begin(); QValueList::Iterator end = paragList.end(); for ( ; it!= end ; ++it ) { //kdDebug()< fsInHeader; QValueList framesetsList; framesetElem = framesetElem.nextSibling().toElement(); for ( ; !framesetElem.isNull() ; framesetElem = framesetElem.nextSibling().toElement() ) { if ( framesetElem.tagName() == "FRAMESET" ) { FrameSetType frameSetType = static_cast( KWDocument::getAttribute( framesetElem, "frameType", FT_BASE ) ); KWFrameSet::Info info = static_cast( framesetElem.attribute("frameInfo").toInt() ); if ( frameSetType == FT_TEXT && (info == KWFrameSet::FI_FIRST_HEADER || info == KWFrameSet::FI_EVEN_HEADER || info == KWFrameSet::FI_ODD_HEADER || info == KWFrameSet::FI_FIRST_FOOTER || info == KWFrameSet::FI_EVEN_FOOTER || info == KWFrameSet::FI_ODD_FOOTER) ) fsInHeader += getInlineFramesets( framesetElem ); QString name = framesetElem.attribute( "name" ); QString grpMgr = framesetElem.attribute( "grpMgr" ); if ( !inlineFsNames.contains(name) && !inlineFsNames.contains(grpMgr) ) { // fixed frameset if ( !grpMgr.isEmpty() ) { // Table cell if ( grpMgr != tableName ) { // New table (first cell) tableName = grpMgr; table = domDocFrames.createElement("FRAMESET"); table.setAttribute("frameType", FT_TABLE); table.setAttribute("frameInfo", 0); table.setAttribute("protectSize", framesetElem.attribute("protectSize","0")); table.setAttribute("name", tableName); table.setAttribute("visible", framesetElem.attribute("visible","1")); framesetsList.append( table ); //kdDebug()<( KWDocument::getAttribute( framesetElem, "frameType", FT_BASE ) ); KWFrameSet::Info info = static_cast( framesetElem.attribute("frameInfo").toInt() ); QString name = framesetElem.attribute("name"); QString grpMgr = framesetElem.attribute( "grpMgr" ); // We skip headers, footers and framsets/tables inside theese if ( !fsInHeader.contains(name) && !fsInHeader.contains(grpMgr) && !( frameSetType == FT_TEXT && (info == KWFrameSet::FI_FIRST_HEADER || info == KWFrameSet::FI_EVEN_HEADER || info == KWFrameSet::FI_ODD_HEADER || info == KWFrameSet::FI_FIRST_FOOTER || info == KWFrameSet::FI_EVEN_FOOTER || info == KWFrameSet::FI_ODD_FOOTER) ) ) { hasFixedFramesets = true; topElem.appendChild( framesetElem ); } } // Embedded documents QDomDocument embeddedDoc( "SELECTION" ); QDomElement selElem = embeddedDoc.createElement( "SELECTION" ); embeddedDoc.appendChild( selElem ); QValueList embeddedList; QDomElement embeddedElem = word.namedItem( "EMBEDDED" ).toElement(); for ( ; !embeddedElem.isNull() ; embeddedElem = embeddedElem.nextSibling().toElement() ) { if ( embeddedElem.tagName() == "EMBEDDED" ) { embeddedList.append( embeddedElem ); } } it = embeddedList.begin(); end = embeddedList.end(); bool hasEmbedded = false; for ( ; it!= end ; ++it ) { selElem.appendChild( *it ); hasEmbedded = true; } store->close(); // Now we do the insertion if ( !macroCmd ) macroCmd = new KMacroCommand( i18n("Insert File") ); if ( hasFixedFramesets ) { // insert fixed framesets //kdDebug() << k_funcinfo << domDocFrames.toCString() << endl; m_doc->pasteFrames( topElem, macroCmd, false, false, false /* don't select frames */ ); } if ( hasEmbedded ) { //kdDebug()<insertEmbedded( store, selElem, macroCmd, 0 ); } // insert paragraphs and inline framesets (we always have at least one paragraph) KCommand *cmd = textFrameSet->pasteOasis( &insertionCursor, domDoc.toCString(), true ); if ( cmd ) { macroCmd->addCommand( cmd ); } m_doc->addCommand( macroCmd ); } } m_doc->loadImagesFromStore( store ); m_doc->completePasting(); } delete store; } QValueList KWView::getInlineFramesets( const QDomNode &framesetElem) { //kdDebug()< list; QDomNode n = framesetElem.firstChild().toElement(); for( ; !n.isNull(); n = n.nextSibling() ) { QDomElement e = n.toElement(); // try to convert the node to an element. if ( !e.isNull() && e.tagName() == "PARAGRAPH" ) { QDomElement formatsElem = e.namedItem( "FORMATS" ).toElement(); if ( !formatsElem.isNull() ) { // Get references to inline framesets QDomElement formatElem = formatsElem.firstChild().toElement(); for ( ; !formatElem.isNull() ; formatElem = formatElem.nextSibling().toElement() ) { QDomElement anchorElem = formatElem.namedItem( "ANCHOR" ).toElement(); if ( !anchorElem.isNull() ) { QString type = anchorElem.attribute( "type" ); if ( type == "grpMgr" /* old syntax */ || type == "frameset" ) { QString iName = anchorElem.attribute( "instance" ); list.append( iName ); //kdDebug()<listOfBookmarkName(0L), this, 0 ); if ( dia.exec() ) { QString bookName = dia.bookmarkName(); KoTextCursor start, end; if ( edit->textDocument()->hasSelection( KoTextDocument::Standard ) ) { start = edit->textDocument()->selectionStartCursor( KoTextDocument::Standard ); end = edit->textDocument()->selectionEndCursor( KoTextDocument::Standard ); } else { start = *edit->cursor(); end = start; } int startSel = start.index(); int endSel = end.index(); m_doc->insertBookMark(bookName, static_cast(start.parag()),static_cast(end.parag()), edit->textFrameSet(), startSel, endSel); } } } void KWView::selectBookmark() { KWSelectBookmarkDia dia( m_doc->listOfBookmarkName(m_gui->canvasWidget()->viewMode()), m_doc, this, 0 ); if ( dia.exec() ) { QString bookName = dia.bookmarkSelected(); KWBookMark * book = m_doc->bookMarkByName( bookName ); Q_ASSERT( book ); if ( book ) { Q_ASSERT( book->startParag() ); Q_ASSERT( book->endParag() ); if ( !book->startParag() || !book->endParag() ) return; m_gui->canvasWidget()->editTextFrameSet( book->frameSet(), book->startParag(), book->bookmarkStartIndex() ); KWTextFrameSetEdit * edit = currentTextEdit(); Q_ASSERT( edit ); if ( edit ) { edit->textDocument()->removeSelection( KoTextDocument::Standard ); edit->textDocument()->setSelectionStart( KoTextDocument::Standard, edit->cursor() ); edit->cursor()->setParag( book->endParag()); edit->cursor()->setIndex(book->bookmarkEndIndex() ); edit->textDocument()->setSelectionEnd( KoTextDocument::Standard, edit->cursor() ); book->startParag()->setChanged( true ); book->endParag()->setChanged( true ); m_doc->slotRepaintChanged( edit->frameSet() ); } } } } void KWView::importStyle() { KWImportStyleDia dia( m_doc, m_doc->styleCollection(), this ); if ( dia.exec() && !dia.importedStyles().isEmpty() ) { m_doc->styleCollection()->importStyles( dia.importedStyles() ); m_doc->setModified( true ); m_doc->updateAllStyleLists(); } } void KWView::testAndCloseAllFrameSetProtectedContent() { KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit && edit->textFrameSet()->protectContent()) { m_doc->terminateEditing( edit->frameSet()); } } void KWView::updateRulerInProtectContentMode() { KWTextFrameSetEdit* edit = currentTextEdit(); KoRuler * hRuler = m_gui ? m_gui->getHorzRuler() : 0; if ( edit && hRuler) { if ( !edit->textFrameSet()->protectContent() ) hRuler->changeFlags(KoRuler::F_INDENTS | KoRuler::F_TABS); else hRuler->changeFlags(0); hRuler->repaint(); } } void KWView::deselectAllFrames() { m_gui->canvasWidget()->selectAllFrames( false ); } void KWView::insertDirectCursor() { #if 0 insertDirectCursor( actionInsertDirectCursor->isChecked()); #endif } void KWView::insertDirectCursor(bool b) { m_doc->setInsertDirectCursor(b); } void KWView::updateDirectCursorButton() { #if 0 actionInsertDirectCursor->setChecked(m_doc->insertDirectCursor()); #endif } void KWView::convertTableToText() { KWCanvas * canvas = m_gui->canvasWidget(); KWTableFrameSet *table = canvas->getCurrentTable(); if (table && table->isFloating()) { table->convertTableToText(); KWAnchor * anchor = table->findAnchor( 0 ); if ( anchor ) { KWTextFrameSet *frameset= table->anchorFrameset(); KoTextParag *parag = anchor->paragraph(); int pos = anchor->index(); KMacroCommand *macro = new KMacroCommand(i18n("Convert Table to Text")); KCommand *cmd =table->anchorFrameset()->deleteAnchoredFrame( anchor ); if ( cmd ) macro->addCommand( cmd); m_gui->canvasWidget()->emitFrameSelectedChanged(); deleteFrame( false ); m_gui->canvasWidget()->editTextFrameSet( frameset, parag, pos ); QMimeSource *data = QApplication::clipboard()->data(); // Hmm, we could reuse the result of KWView::checkClipboard... if ( data->provides( KWTextDrag::selectionMimeType() ) ) { QByteArray arr = data->encodedData( KWTextDrag::selectionMimeType() ); if ( arr.size() ) { KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit && edit->textFrameSet()) { KCommand *cmd =edit->textFrameSet()->pasteOasis( edit->cursor(), QCString( arr , arr.count()), true ); if ( cmd ) macro->addCommand( cmd); m_doc->addCommand(cmd); } } } m_doc->addCommand(macro); QApplication::clipboard()->clear(); } } } void KWView::convertToTextBox() { KWTextFrameSetEdit* edit = currentTextEdit(); if( edit && !edit->textFrameSet()->protectContent() && edit->textFrameSet()->textObject()->hasSelection()) { edit->copy(); KMacroCommand *macro = 0L; KCommand *cmd = edit->textFrameSet()->textObject()->removeSelectedTextCommand( edit->textView()->cursor(), KoTextDocument::Standard ); if ( cmd ) { if ( ! macro ) macro = new KMacroCommand( i18n("Convert to Text Box")); macro->addCommand( cmd ); } cmd = m_gui->canvasWidget()->createTextBox(KoRect(30,30,30,30) ); if ( cmd ) { if ( ! macro ) macro = new KMacroCommand( i18n("Convert to Text Box")); macro->addCommand( cmd ); } edit = currentTextEdit(); if ( edit ) { QMimeSource *data = QApplication::clipboard()->data(); // Hmm, we could reuse the result of KWView::checkClipboard... if ( data->provides( KWTextDrag::selectionMimeType() ) ) { QByteArray arr = data->encodedData( KWTextDrag::selectionMimeType() ); if ( arr.size() ) { cmd =edit->textFrameSet()->pasteOasis( edit->textView()->cursor(), QCString( arr, arr.size()+1 ), true ); if ( cmd ) { if ( ! macro ) macro = new KMacroCommand( i18n("Convert to Text Box")); macro->addCommand( cmd ); } } } } if ( macro ) m_doc->addCommand(macro); } } void KWView::slotAddIgnoreAllWord() { KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit ) m_doc->addIgnoreWordAll( edit->currentWordOrSelection() ); } void KWView::sortText() { KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit && edit->textFrameSet()->hasSelection()) { KWSortDia * dlg = new KWSortDia( this, "sort dia" ); if ( dlg->exec()) { if ( edit->textFrameSet()->sortText(dlg->getSortType()) ) { QMimeSource *data = QApplication::clipboard()->data(); if ( data->provides( KWTextDrag::selectionMimeType() ) ) { QByteArray arr = data->encodedData( KWTextDrag::selectionMimeType() ); if ( arr.size() ) { KCommand *cmd =edit->textFrameSet()->pasteOasis( edit->cursor(), QCString( arr , arr.size()+1), true ); if ( cmd ) m_doc->addCommand(cmd); } } QApplication::clipboard()->clear(); } } delete dlg; } } void KWView::addPersonalExpression() { KWTextFrameSetEdit* edit = currentTextEdit(); if ( !(edit && edit->textFrameSet()->hasSelection())) return; QString newExpression = edit->textFrameSet()->textObject()->selectedText(); //load file !!! QString tmp=locateLocal("data","kword/expression/perso.xml"); QFile file( tmp ); if ( !file.open( IO_ReadOnly ) ) return; QDomDocument doc; doc.setContent( &file ); file.close(); QString group; QMaplstOfPersonalExp; QStringList list; QDomNode n = doc.documentElement().firstChild(); for( ; !n.isNull(); n = n.nextSibling() ) { if ( n.isElement() ) { QDomElement e = n.toElement(); if ( e.tagName() == "Type" ) { list.clear(); group = i18n( e.namedItem( "TypeName" ).toElement().text().utf8() ); QDomNode n2 = e.firstChild(); for( ; !n2.isNull(); n2 = n2.nextSibling() ) { if ( n2.isElement() ) { QDomElement e2 = n2.toElement(); if ( e2.tagName() == "Expression" ) { QString text = i18n( e2.namedItem( "Text" ).toElement().text().utf8() ); list< itPersonalExp = lstOfPersonalExp.find(i18n("Normal")); if ( itPersonalExp != lstOfPersonalExp.end()) { list = itPersonalExp.data(); list<refreshMenuExpression(); } #if 0 // KWORD_HORIZONTAL_LINE void KWView::insertHorizontalLine() { KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit && edit->textFrameSet() && !edit->textFrameSet()->textObject()->protectContent() ) { KWinsertHorizontalLineDia *dia = new KWinsertHorizontalLineDia( m_doc, this); if ( dia->exec() ) { KWHorzLineFrameSet *horizontalLine = new KWHorzLineFrameSet( m_doc, QString::null /*automatic name*/ ); KWFrame *frame = new KWFrame(horizontalLine, 50, 50, edit->textFrameSet()->frame(0)->width(), 10 ); horizontalLine->addFrame( frame ); frame->setZOrder( m_doc->maxZOrder( frame->pageNum(m_doc) ) + 1 ); // make sure it's on top m_doc->addFrameSet( horizontalLine, false ); horizontalLine->loadPicture( dia->horizontalLineName() ); edit->insertFloatingFrameSet( horizontalLine, i18n("Insert Horizontal Line") ); m_doc->updateAllFrames(); } delete dia; } } void KWView::changeHorizontalLine() { KWFrame * frame = m_doc->getFirstSelectedFrame(); KWHorzLineFrameSet *frameset = static_cast(frame->frameSet()); KoPictureKey oldKey ( frameset->picture().getKey() ); QString oldFile ( oldKey.filename() ); KWinsertHorizontalLineDia *dia = new KWinsertHorizontalLineDia( m_doc, this); if ( dia->exec() ) { QString file( dia->horizontalLineName() ); KoPictureKey key; key.setKeyFromFile( file ); KoPicture picture; picture.setKey( key ); picture.loadFromFile( file ); KWFrameChangePictureCommand *cmd= new KWFrameChangePictureCommand( i18n("Change HorizontalLine"), FrameIndex(frame), oldFile, file) ; frameset->insertPicture( picture ); m_doc->frameChanged( frame ); m_doc->addCommand(cmd); } delete dia; } #endif void KWView::addWordToDictionary() { KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit && m_doc->backgroundSpellCheckEnabled() ) { QString word = edit->wordUnderCursor( *edit->cursor() ); if ( !word.isEmpty()) { m_doc->addWordToDictionary( word); // Re-check everything to make this word normal again m_doc->reactivateBgSpellChecking(); } } } void KWView::embeddedStoreInternal() { kdDebug()<getFirstSelectedFrame(); KWPartFrameSet *part = static_cast(frame->frameSet()); part->storeInternal(); } void KWView::deleteFrameSet( KWFrameSet * frameset) { if ( frameset && frameset->frame(0)) { frameset->frame(0)->setSelected( true ); deleteFrame(); } } QPtrList KWView::listOfResultOfCheckWord( const QString &word ) { QPtrList listAction; #ifdef HAVE_LIBKSPELL2 //not perfect, improve API!!!! DefaultDictionary *dict = m_broker->defaultDictionary(); QStringList lst = dict->suggest( word ); if ( !lst.contains( word ) ) { QStringList::ConstIterator it = lst.begin(); for ( ; it != lst.end() ; ++it ) { if ( !(*it).isEmpty() ) // in case of removed subtypes or placeholders { KAction * act = new KAction( *it ); connect( act, SIGNAL(activated()), this, SLOT(slotCorrectWord()) ); listAction.append( act ); } } } #endif return listAction; } void KWView::slotCorrectWord() { KAction * act = (KAction *)(sender()); KWTextFrameSetEdit* edit = currentTextEdit(); if ( edit ) { edit->selectWordUnderCursor( *(edit->cursor()) ); m_doc->addCommand( edit->textObject()->replaceSelectionCommand( edit->cursor(), act->text(), KoTextDocument::Standard, i18n("Replace Word") )); } } void KWView::slotChildActivated( bool a ) { // Same hack as in KoView KoViewChild* ch = child( (KoView*)sender() ); if ( !ch ) return; KWChild* kwchild = static_cast( ch->documentChild() ); KWPartFrameSet* fs = kwchild->partFrameSet(); //kdDebug() << "KWView::slotChildActivated fs=" << fs << endl; Q_ASSERT( fs ); if ( fs ) { if ( a ) fs->startEditing(); else fs->endEditing(); } KoView::slotChildActivated( a ); } #ifdef HAVE_LIBKSPELL2 Broker *KWView::broker() const { return m_broker; } #endif /******************************************************************/ /* Class: KWLayoutWidget */ /******************************************************************/ KWLayoutWidget::KWLayoutWidget( QWidget *parent, KWGUI *g ) : QWidget( parent ) { gui = g; } void KWLayoutWidget::resizeEvent( QResizeEvent *e ) { QWidget::resizeEvent( e ); gui->reorganize(); } /******************************************************************/ /* Class: KWGUI */ /******************************************************************/ KWGUI::KWGUI( KWViewMode* viewMode, QWidget *parent, KWView *_view ) : QWidget( parent, "" ) { view = _view; r_horz = r_vert = 0; KWDocument * doc = view->kWordDocument(); panner = new QSplitter( Qt::Horizontal, this ); docStruct = new KWDocStruct( panner, doc, this ); docStruct->setMinimumWidth( 0 ); left = new KWLayoutWidget( panner, this ); left->show(); canvas = new KWCanvas( viewMode, left, doc, this ); QValueList l; l << 10; l << 90; panner->setSizes( l ); KoPageLayout layout = doc->pageLayout(); tabChooser = new KoTabChooser( left, KoTabChooser::TAB_ALL ); tabChooser->setReadWrite(doc->isReadWrite()); r_horz = new KoRuler( left, canvas->viewport(), Qt::Horizontal, layout, KoRuler::F_INDENTS | KoRuler::F_TABS, doc->getUnit(), tabChooser ); r_horz->setReadWrite(doc->isReadWrite()); r_vert = new KoRuler( left, canvas->viewport(), Qt::Vertical, layout, 0, doc->getUnit() ); connect( r_horz, SIGNAL( newPageLayout( const KoPageLayout & ) ), view, SLOT( newPageLayout( const KoPageLayout & ) ) ); r_vert->setReadWrite(doc->isReadWrite()); r_horz->setZoom( doc->zoomedResolutionX() ); r_vert->setZoom( doc->zoomedResolutionY() ); r_horz->setGridSize(doc->gridX()); connect( r_horz, SIGNAL( newLeftIndent( double ) ), view, SLOT( newLeftIndent( double ) ) ); connect( r_horz, SIGNAL( newFirstIndent( double ) ), view, SLOT( newFirstIndent( double ) ) ); connect( r_horz, SIGNAL( newRightIndent( double ) ), view, SLOT( newRightIndent( double ) ) ); connect( r_horz, SIGNAL( doubleClicked() ), view, SLOT( slotHRulerDoubleClicked() ) ); connect( r_horz, SIGNAL( doubleClicked(double) ), view, SLOT( slotHRulerDoubleClicked(double) ) ); connect( r_horz, SIGNAL( unitChanged( KoUnit::Unit ) ), this, SLOT( unitChanged( KoUnit::Unit ) ) ); connect( r_vert, SIGNAL( newPageLayout( const KoPageLayout & ) ), view, SLOT( newPageLayout( const KoPageLayout & ) ) ); connect( r_vert, SIGNAL( doubleClicked() ), view, SLOT( formatPage() ) ); connect( r_vert, SIGNAL( unitChanged( KoUnit::Unit ) ), this, SLOT( unitChanged( KoUnit::Unit ) ) ); r_horz->hide(); r_vert->hide(); canvas->show(); reorganize(); connect( r_horz, SIGNAL( tabListChanged( const KoTabulatorList & ) ), view, SLOT( tabListChanged( const KoTabulatorList & ) ) ); setKeyCompression( TRUE ); setAcceptDrops( TRUE ); setFocusPolicy( QWidget::NoFocus ); } void KWGUI::showGUI() { reorganize(); } void KWGUI::resizeEvent( QResizeEvent *e ) { QWidget::resizeEvent( e ); reorganize(); } void KWGUI::reorganize() { int space=20; if(view->kWordDocument()->showRuler()) { r_vert->show(); r_horz->show(); tabChooser->show(); tabChooser->setGeometry( 0, 0, 20, 20 ); } else { r_vert->hide(); r_horz->hide(); tabChooser->hide(); space=0; } if(view->kWordDocument()->showdocStruct()) { if(docStruct->isHidden()) { docStruct->show(); if(panner->sizes()[0] < 50) { QValueList l; l << 100; l << width()-100; panner->setSizes( l ); } } } else docStruct->hide(); if( view->statusBar()) { if(view->kWordDocument()->showStatusBar()) view->statusBar()->show(); else view->statusBar()->hide(); } if ( view->kWordDocument()->showScrollBar()) { canvas->setVScrollBarMode(QScrollView::Auto); canvas->setHScrollBarMode(QScrollView::Auto); } else { canvas->setVScrollBarMode(QScrollView::AlwaysOff); canvas->setHScrollBarMode(QScrollView::AlwaysOff); } panner->setGeometry( 0, 0, width(), height() ); canvas->setGeometry( space, space, left->width() - space, left->height() - space ); r_horz->setGeometry( space, 0, left->width() - space, space ); r_vert->setGeometry( 0, space, space, left->height() - space ); } void KWGUI::unitChanged( KoUnit::Unit u ) { view->kWordDocument()->setUnit( u ); } // Implementation of KWStatisticsDialog KWStatisticsDialog::KWStatisticsDialog( QWidget *_parent, KWDocument *_doc ) : KDialogBase(_parent, "statistics", true, i18n("Statistics"),KDialogBase::Ok, KDialogBase::Ok, false ) { QWidget *page = new QWidget( this ); setMainWidget(page); QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); QTabWidget *tab = new QTabWidget( page ); QFrame *pageAll = 0; QFrame *pageGeneral = 0; QFrame *pageSelected = 0; for (int i=0; i < 7; ++i) { resultLabelAll[i] = 0; resultLabelSelected[i] = 0; if ( i < 6 ) resultGeneralLabel[i]=0; } m_doc = _doc; m_parent = _parent; m_canceled = true; // add Tab "General" pageGeneral = new QFrame( this ); tab->addTab( pageGeneral, i18n( "General" ) ); addBoxGeneral( pageGeneral, resultGeneralLabel ); calcGeneral( resultGeneralLabel ); // add Tab "All" pageAll = new QFrame( this ); tab->addTab( pageAll, i18n( "Text" ) ); addBox( pageAll, resultLabelAll, true ); m_canceled = true; pageSelected = new QFrame( this ); tab->addTab( pageSelected, i18n( "Selected Text" ) ); // let's see if there's selected text bool b = docHasSelection(); tab->setTabEnabled(pageSelected, b); if ( b ) { addBox( pageSelected, resultLabelSelected, false); // assign results to 'selected' tab. if ( !calcStats( resultLabelSelected, true,true ) ) return; if ( !calcStats( resultLabelAll, false,false ) ) return; showPage( 2 ); } else { // assign results if ( !calcStats( resultLabelAll, false, false ) ) return; showPage( 1 ); } topLayout->addWidget( tab ); m_canceled = false; } void KWStatisticsDialog::slotRefreshValue(bool state) { m_canceled = true; // let's see if there's selected text bool b = docHasSelection(); if ( b ) { if ( !calcStats( resultLabelSelected, true, true ) ) return; if ( !calcStats( resultLabelAll, false, state ) ) return; } else { // assign results if ( !calcStats( resultLabelAll, false, state ) ) return; } m_canceled = false; } void KWStatisticsDialog::calcGeneral( QLabel **resultLabel ) { KLocale *locale = KGlobal::locale(); resultLabel[0]->setText( locale->formatNumber( m_doc->numPages(), 0) ); int table =0; int picture = 0; int part = 0; int nbFrameset = 0; int nbFormula = 0; QPtrListIterator framesetIt( m_doc->framesetsIterator() ); for ( framesetIt.toFirst(); framesetIt.current(); ++framesetIt ) { KWFrameSet *frameSet = framesetIt.current(); if ( frameSet && frameSet->isVisible()) { if ( frameSet->type() == FT_TABLE) table++; else if ( frameSet->type() == FT_PICTURE) picture++; else if ( frameSet->type() == FT_PART ) part++; else if ( frameSet->type() == FT_FORMULA ) nbFormula++; nbFrameset++; } } resultLabel[1]->setText( locale->formatNumber( nbFrameset, 0 ) ); resultLabel[2]->setText( locale->formatNumber( picture, 0 ) ); resultLabel[3]->setText( locale->formatNumber( table, 0 ) ); resultLabel[4]->setText( locale->formatNumber( part, 0 ) ); resultLabel[5]->setText( locale->formatNumber( nbFormula, 0 ) ); } bool KWStatisticsDialog::calcStats( QLabel **resultLabel, bool selection, bool useFootEndNote ) { ulong charsWithSpace = 0L; ulong charsWithoutSpace = 0L; ulong words = 0L; ulong sentences = 0L; ulong lines = 0L; ulong syllables = 0L; // safety check result labels for (int i=0; i < 7; ++i) { if ( !resultLabel[i] ) { kdDebug() << "Warning: KWStatisticsDiaolog::calcStats result table not initialized." << endl; return false; } } // count paragraphs for progress dialog: ulong paragraphs = 0L; QPtrListIterator framesetIt( m_doc->framesetsIterator() ); for ( framesetIt.toFirst(); framesetIt.current(); ++framesetIt ) { KWFrameSet *frameSet = framesetIt.current(); if ( (frameSet->frameSetInfo() == KWFrameSet::FI_FOOTNOTE || frameSet->frameSetInfo() == KWFrameSet::FI_BODY) && frameSet->isVisible() ) { if ( (useFootEndNote && frameSet->frameSetInfo() == KWFrameSet::FI_FOOTNOTE) || frameSet->frameSetInfo() == KWFrameSet::FI_BODY ) { if ( selection && false ) paragraphs += frameSet->paragraphsSelected(); else paragraphs += frameSet->paragraphs(); } } } QProgressDialog progress( i18n( "Counting..." ), i18n( "Cancel" ), paragraphs, this, "count", true ); progress.setMinimumDuration( 1000 ); progress.setProgress( 0 ); // do the actual counting for ( framesetIt.toFirst(); framesetIt.current(); ++framesetIt ) { KWFrameSet *frameSet = framesetIt.current(); // Exclude headers and footers if ( (frameSet->frameSetInfo() == KWFrameSet::FI_FOOTNOTE || frameSet->frameSetInfo() == KWFrameSet::FI_BODY) && frameSet->isVisible() ) { if ( (useFootEndNote && frameSet->frameSetInfo() == KWFrameSet::FI_FOOTNOTE) || frameSet->frameSetInfo() == KWFrameSet::FI_BODY ) { if( ! frameSet->statistics( &progress, charsWithSpace, charsWithoutSpace, words, sentences, syllables, lines, selection ) ) { // someone pressed "Cancel" return false; } } } } // assign results KLocale *locale = KGlobal::locale(); resultLabel[0]->setText( locale->formatNumber( charsWithSpace, 0) ); resultLabel[1]->setText( locale->formatNumber( charsWithoutSpace, 0 ) ); resultLabel[2]->setText( locale->formatNumber( syllables, 0 ) ); resultLabel[3]->setText( locale->formatNumber( words, 0 ) ); resultLabel[4]->setText( locale->formatNumber( sentences, 0 ) ); resultLabel[5]->setText( locale->formatNumber( lines, 0 ) ); // add flesch double f = calcFlesch( sentences, words, syllables ); QString flesch = locale->formatNumber( f , 1 ); if( words < 200 ) { // a kind of warning if too few words: flesch = i18n("approximately %1").arg( flesch ); } resultLabel[6]->setText( flesch ); return true; } double KWStatisticsDialog::calcFlesch( ulong sentences, ulong words, ulong syllables ) { // calculate Flesch reading ease score: float flesch_score = 0; if( words > 0 && sentences > 0 ) flesch_score = 206.835 - (1.015 * (words / sentences)) - (84.6 * syllables / words); return flesch_score; } void KWStatisticsDialog::addBoxGeneral( QFrame *page, QLabel **resultLabel ) { // Layout Managers QVBoxLayout *topLayout = new QVBoxLayout( page, 0, 7 ); QGroupBox *box = new QGroupBox( i18n( "Statistics" ), page ); QGridLayout *grid = new QGridLayout( box, 9, 3, KDialog::marginHint(), KDialog::spacingHint() ); grid->setRowStretch (9, 1); // margins int fHeight = box->fontMetrics().height(); grid->setMargin( fHeight ); grid->addColSpacing( 1, fHeight ); grid->addRowSpacing( 0, fHeight ); // insert labels QLabel *label1 = new QLabel( i18n( "Number of pages:" ), box ); grid->addWidget( label1, 1, 0, 1 ); resultLabel[0] = new QLabel( "", box ); grid->addWidget( resultLabel[0], 1, 2, 2 ); QLabel *label2 = new QLabel( i18n( "Number of frames:" ), box ); grid->addWidget( label2, 2, 0, 1 ); resultLabel[1] = new QLabel( "", box ); grid->addWidget( resultLabel[1], 2, 2, 2 ); QLabel *label3 = new QLabel( i18n( "Number of pictures:" ), box ); grid->addWidget( label3, 3, 0, 1 ); resultLabel[2] = new QLabel( "", box ); grid->addWidget( resultLabel[2], 3, 2, 2 ); QLabel *label4 = new QLabel( i18n( "Number of tables:" ), box ); grid->addWidget( label4, 4, 0, 1 ); resultLabel[3] = new QLabel( "", box ); grid->addWidget( resultLabel[3], 4, 2, 2 ); QLabel *label5 = new QLabel( i18n( "Number of embedded objects:" ), box ); grid->addWidget( label5, 5, 0, 1 ); resultLabel[4] = new QLabel( "", box ); grid->addWidget( resultLabel[4], 5, 2, 2 ); QLabel *label6 = new QLabel( i18n( "Number of formula frameset:" ), box ); grid->addWidget( label6, 6, 0, 1 ); resultLabel[5] = new QLabel( "", box ); grid->addWidget( resultLabel[5], 6, 2, 2 ); topLayout->addWidget( box ); } void KWStatisticsDialog::addBox( QFrame *page, QLabel **resultLabel, bool calcWithFootNoteCheckbox ) { // Layout Managers QVBoxLayout *topLayout = new QVBoxLayout( page, 0, 7 ); if ( calcWithFootNoteCheckbox ) { QWidget *w = new QWidget(page); topLayout->addWidget( w ); QVBoxLayout *noteLayout = new QVBoxLayout( w, KDialog::marginHint(), 0 ); QCheckBox *calcWithFootNote = new QCheckBox( i18n("&Include text from foot- and endnotes"), w); noteLayout->addWidget( calcWithFootNote ); connect( calcWithFootNote, SIGNAL(toggled ( bool )), this, SLOT( slotRefreshValue(bool))); } QGroupBox *box = new QGroupBox( i18n( "Statistics" ), page ); QGridLayout *grid = new QGridLayout( box, 9, 3, KDialog::marginHint(), KDialog::spacingHint() ); grid->setRowStretch (9, 1); // margins int fHeight = box->fontMetrics().height(); grid->setMargin( fHeight ); grid->addColSpacing( 1, fHeight ); grid->addRowSpacing( 0, fHeight ); //maximum size for result column (don't know how to do this better..) QString init = i18n("approximately %1").arg( "00000000" ); // insert labels QLabel *label1 = new QLabel( i18n( "Characters including spaces:" ), box ); grid->addWidget( label1, 1, 0, 1 ); resultLabel[0] = new QLabel( "", box ); grid->addWidget( resultLabel[0], 1, 2, 2 ); QLabel *label2 = new QLabel( i18n( "Characters without spaces:" ), box ); grid->addWidget( label2, 2, 0, 1 ); resultLabel[1] = new QLabel( "", box ); grid->addWidget( resultLabel[1], 2, 2, 2 ); QLabel *label3 = new QLabel( i18n( "Syllables:" ), box ); grid->addWidget( label3, 3, 0, 1 ); resultLabel[2] = new QLabel( "", box ); grid->addWidget( resultLabel[2], 3, 2, 2 ); QLabel *label4 = new QLabel( i18n( "Words:" ), box ); grid->addWidget( label4, 4, 0, 1 ); resultLabel[3] = new QLabel( "", box ); grid->addWidget( resultLabel[3], 4, 2, 2 ); QLabel *label5 = new QLabel( i18n( "Sentences:" ), box ); grid->addWidget( label5, 5, 0, 1 ); resultLabel[4] = new QLabel( "", box ); grid->addWidget( resultLabel[4], 5, 2, 2 ); QLabel *label6 = new QLabel( i18n( "Lines:" ), box ); grid->addWidget( label6, 6, 0, 1 ); resultLabel[5] = new QLabel( "", box ); grid->addWidget( resultLabel[5], 6, 2, 2 ); QLabel *label7 = new QLabel( i18n( "Flesch reading ease:" ), box ); grid->addWidget( label7, 7, 0, 1 ); resultLabel[6] = new QLabel( init, box ); grid->addWidget( resultLabel[6], 7, 2, 2 ); topLayout->addWidget( box ); } bool KWStatisticsDialog::docHasSelection()const { QPtrListIterator fsIt( m_doc->framesetsIterator() ); for ( ; fsIt.current(); ++fsIt ) { KWFrameSet *fs = fsIt.current(); if ( fs->paragraphsSelected() ) { return true; } } return false; } #include "kwview.moc"