summaryrefslogtreecommitdiffstats
path: root/lib/kotext/KoTextView.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /lib/kotext/KoTextView.cpp
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'lib/kotext/KoTextView.cpp')
-rw-r--r--lib/kotext/KoTextView.cpp1549
1 files changed, 1549 insertions, 0 deletions
diff --git a/lib/kotext/KoTextView.cpp b/lib/kotext/KoTextView.cpp
new file mode 100644
index 00000000..c5edcf61
--- /dev/null
+++ b/lib/kotext/KoTextView.cpp
@@ -0,0 +1,1549 @@
+/* This file is part of the KDE project
+ Copyright (C) 2001-2006 David Faure <faure@kde.org>
+
+ 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., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+*/
+
+#include "KoTextView.h"
+#include "KoTextParag.h"
+#include "KoParagCounter.h"
+#include "KoTextObject.h"
+#include "KoTextViewIface.h"
+#include "KoStyleCollection.h"
+#include "KoBgSpellCheck.h"
+#include "KoVariable.h"
+
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kstdaccel.h>
+#include <kdebug.h>
+#include <kinstance.h>
+#include <kdatatool.h>
+#include <krun.h>
+#include <kmessagebox.h>
+#include <kcommand.h>
+#include <kbookmarkmanager.h>
+#include <kbookmark.h>
+#include <kurldrag.h>
+
+#include <qapplication.h>
+#include <qtimer.h>
+#include <qclipboard.h>
+
+class KoTextView::KoTextViewPrivate
+{
+public:
+ KoTextViewPrivate()
+ {
+ m_currentUnicodeNumber = 0;
+ m_backSpeller = 0;
+ }
+
+ void appendDigit( int digit ) { m_currentUnicodeNumber = 10 * m_currentUnicodeNumber + digit; }
+ int currentUnicodeNumber() const { return m_currentUnicodeNumber; }
+ void clearCurrentUnicodeNumber() { m_currentUnicodeNumber = 0; }
+
+ KoBgSpellCheck* m_backSpeller;
+
+private:
+ int m_currentUnicodeNumber; // For the alt+123 feature
+};
+
+KoTextView::KoTextView( KoTextObject *textobj )
+{
+ d = new KoTextViewPrivate;
+ m_bReadWrite = true;
+ m_textobj = textobj;
+ dcop=0;
+ connect( m_textobj, SIGNAL( hideCursor() ), this, SLOT( hideCursor() ) );
+ connect( m_textobj, SIGNAL( showCursor() ), this, SLOT( showCursor() ) );
+ connect( m_textobj, SIGNAL( setCursor( KoTextCursor * ) ), this, SLOT( setCursor( KoTextCursor * ) ) );
+ connect( m_textobj, SIGNAL( updateUI(bool, bool) ), this, SLOT( updateUI(bool, bool) ) );
+ connect( m_textobj, SIGNAL( showCurrentFormat() ), this, SLOT( showCurrentFormat() ) );
+ connect( m_textobj, SIGNAL( ensureCursorVisible() ), this, SLOT( ensureCursorVisible() ) );
+
+ m_cursor = new KoTextCursor( m_textobj->textDocument() );
+
+ m_cursorVisible = false;
+
+ showCursor();
+ blinkTimer = new QTimer( this );
+ connect( blinkTimer, SIGNAL( timeout() ),
+ this, SLOT( blinkCursor() ) );
+ if ( QApplication::cursorFlashTime() > 0 )
+ blinkTimer->start( QApplication::cursorFlashTime() / 2 );
+
+ dragStartTimer = new QTimer( this );
+ connect( dragStartTimer, SIGNAL( timeout() ),
+ this, SLOT( startDrag() ) );
+
+ m_textobj->formatMore( 2 );
+
+ blinkCursorVisible = FALSE;
+ inDoubleClick = FALSE;
+ mightStartDrag = FALSE;
+ possibleTripleClick = FALSE;
+ afterTripleClick = FALSE;
+ m_currentFormat = 0;
+ m_variablePosition =-1;
+ m_overwriteMode = false;
+ //updateUI( true, true );
+}
+
+KoTextView::~KoTextView()
+{
+ delete m_cursor;
+ delete d;
+ delete dcop;
+ delete blinkTimer;
+ delete dragStartTimer;
+}
+
+KoTextViewIface* KoTextView::dcopObject()
+{
+ if ( !dcop )
+ dcop = new KoTextViewIface( this );
+
+ return dcop;
+}
+
+void KoTextView::terminate(bool removeselection)
+{
+ textObject()->clearUndoRedoInfo();
+ if ( removeselection && textDocument()->removeSelection( KoTextDocument::Standard ) )
+ textObject()->selectionChangedNotify();
+ hideCursor();
+}
+
+void KoTextView::deleteWordRight()
+{
+ if ( textObject()->hasSelection() ) {
+ textObject()->removeSelectedText( m_cursor );
+ return;
+ }
+ textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
+
+ do {
+ m_cursor->gotoRight();
+ } while ( !m_cursor->atParagEnd()
+ && !m_cursor->parag()->at( m_cursor->index() )->c.isSpace() );
+ textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
+ textObject()->removeSelectedText( m_cursor, KoTextDocument::Standard, i18n("Remove Word") );
+}
+
+void KoTextView::deleteWordLeft()
+{
+ if ( textObject()->hasSelection() ) {
+ textObject()->removeSelectedText( m_cursor );
+ return;
+ }
+ textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
+
+ do {
+ m_cursor->gotoLeft();
+ } while ( !m_cursor->atParagStart()
+ && !m_cursor->parag()->at( m_cursor->index()-1 )->c.isSpace() );
+ textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
+ textObject()->removeSelectedText( m_cursor, KoTextDocument::Standard, i18n("Remove Word") );
+}
+
+// Compare with QTextEdit::keyPressEvent
+void KoTextView::handleKeyPressEvent( QKeyEvent * e, QWidget *widget, const QPoint &pos)
+{
+ textObject()->typingStarted();
+
+ /* bool selChanged = FALSE;
+ for ( int i = 1; i < textDocument()->numSelections(); ++i )
+ selChanged = textDocument()->removeSelection( i ) || selChanged;
+
+ if ( selChanged ) {
+ // m_cursor->parag()->document()->nextDoubleBuffered = TRUE; ######## we need that only if we have nested items/documents
+ textFrameSet()->selectionChangedNotify();
+ }*/
+
+ bool clearUndoRedoInfo = TRUE;
+ if ( KShortcut( KKey( e ) ) == KStdAccel::deleteWordBack() )
+ {
+ if ( m_cursor->parag()->string()->isRightToLeft() )
+ deleteWordRight();
+ else
+ deleteWordLeft();
+ clearUndoRedoInfo = TRUE;
+ } else if ( KShortcut( KKey( e ) ) == KStdAccel::deleteWordForward() )
+ {
+ if ( m_cursor->parag()->string()->isRightToLeft() )
+ deleteWordLeft();
+ else
+ deleteWordRight();
+ clearUndoRedoInfo = TRUE;
+ }
+ else
+ switch ( e->key() ) {
+ case Key_Left:
+ case Key_Right: {
+ if (!doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
+ {
+ // a bit hacky, but can't change this without introducing new enum values for move and keeping the
+ // correct semantics and movement for BiDi and non BiDi text.
+ CursorAction a;
+ if ( m_cursor->parag()->string()->isRightToLeft() == (e->key() == Key_Right) )
+ a = e->state() & ControlButton ? MoveWordBackward : MoveBackward;
+ else
+ a = e->state() & ControlButton ? MoveWordForward : MoveForward;
+ moveCursor( a, e->state() & ShiftButton );
+ }
+ break;
+ }
+ case Key_Up:
+ moveCursor( e->state() & ControlButton ? MoveParagUp : MoveUp, e->state() & ShiftButton );
+ break;
+ case Key_Down:
+ moveCursor( e->state() & ControlButton ? MoveParagDown : MoveDown, e->state() & ShiftButton );
+ break;
+ case Key_Home:
+ moveCursor( e->state() & ControlButton ? MoveHome : MoveLineStart, e->state() & ShiftButton );
+ break;
+ case Key_End:
+ if (!doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
+ moveCursor( e->state() & ControlButton ? MoveEnd : MoveLineEnd, e->state() & ShiftButton );
+ break;
+ case Key_Prior:
+ moveCursor( e->state() & ControlButton ? MovePgUp : MoveViewportUp, e->state() & ShiftButton );
+ break;
+ case Key_Next:
+ moveCursor( e->state() & ControlButton ? MovePgDown : MoveViewportDown, e->state() & ShiftButton );
+ break;
+ case Key_Return: case Key_Enter:
+
+ if (!doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
+ if ( (e->state() & (ShiftButton|ControlButton)) == 0 )
+ {
+ if ( textObject()->hasSelection() )
+ textObject()->removeSelectedText( m_cursor );
+ clearUndoRedoInfo = FALSE;
+ textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionReturn );
+ Q_ASSERT( m_cursor->parag()->prev() );
+ if ( m_cursor->parag()->prev() )
+ doAutoFormat( m_cursor, m_cursor->parag()->prev(),
+ m_cursor->parag()->prev()->length() - 1, '\n' );
+ }
+ clearUndoRedoInfo = true;
+ break;
+ case Key_Delete:
+ if ( textObject()->hasSelection() ) {
+ textObject()->removeSelectedText( m_cursor );
+ break;
+ }
+
+ textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionDelete );
+
+ clearUndoRedoInfo = FALSE;
+ break;
+ case Key_Backtab:
+ if (e->state() & ShiftButton && m_cursor->parag() && m_cursor->atParagStart() && m_cursor->parag()->counter() && textDecreaseIndent())
+ break;
+ break;
+ case Key_Backspace:
+ if ( textObject()->hasSelection() ) {
+ textObject()->removeSelectedText( m_cursor );
+ break;
+ }
+ textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionBackspace );
+
+ clearUndoRedoInfo = FALSE;
+ break;
+ case Key_F16: // Copy key on Sun keyboards
+ emit copy();
+ break;
+ case Key_F18: // Paste key on Sun keyboards
+ emit paste();
+ break;
+ case Key_F20: // Cut key on Sun keyboards
+ emit cut();
+ break;
+ case Key_Direction_L: {
+ if ( m_cursor->parag() && m_cursor->parag()->direction() != QChar::DirL )
+ {
+ KCommand* cmd = textObject()->setParagDirectionCommand( m_cursor, QChar::DirL );
+ textObject()->emitNewCommand( cmd );
+ }
+ break;
+ }
+ case Key_Direction_R: {
+ if ( m_cursor->parag() && m_cursor->parag()->direction() != QChar::DirR )
+ {
+ KCommand* cmd = textObject()->setParagDirectionCommand( m_cursor, QChar::DirR );
+ textObject()->emitNewCommand( cmd );
+ }
+ break;
+ }
+ default: {
+ //kdDebug(32500) << "KoTextView::keyPressEvent ascii=" << e->ascii() << " text=" << e->text()[0].unicode() << " state=" << e->state() << endl;
+ if (e->key() == Qt::Key_Tab)
+ {
+ if (doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
+ break;
+ if ( m_cursor->parag() && m_cursor->atParagStart() && m_cursor->parag()->counter() )
+ {
+ textIncreaseIndent();
+ break;
+ }
+ }
+
+ if ( e->key() == Qt::Key_Space )
+ {
+ if (doToolTipCompletion(m_cursor, m_cursor->parag(), m_cursor->index() - 1, e->key()) )
+ break;
+ }
+ if ( e->text().length() &&
+ ( !e->ascii() || e->ascii() >= 32 ) ||
+ ( e->text() == "\t" && !( e->state() & ControlButton ) ) ) {
+ clearUndoRedoInfo = FALSE;
+ QString text = e->text();
+
+ if ( d->m_backSpeller ) {
+ d->m_backSpeller->setIntraWordEditing( m_cursor->parag(), m_cursor->index() );
+ }
+
+ // Alt+123 feature
+ if ( ( e->state() & AltButton ) && text[0].isDigit() )
+ {
+ while ( text[0].isDigit() ) {
+ d->appendDigit( text[0].digitValue() );
+ text.remove( 0, 1 );
+ }
+ }
+ if ( !text.isEmpty() )
+ {
+ // Bidi support: need to reverse mirrored chars (e.g. parenthesis)
+ KoTextParag *p = m_cursor->parag();
+ if ( p && p->string() && p->string()->isRightToLeft() ) {
+ QChar *c = (QChar *)text.unicode();
+ int l = text.length();
+ while( l-- ) {
+ if ( c->mirrored() )
+ *c = c->mirroredChar();
+ c++;
+ }
+ }
+
+ if( !doIgnoreDoubleSpace( p, m_cursor->index()-1, text[ text.length() - 1 ] ) )
+ {
+ // ###### BUG: with the event compression, typing "kde" and then " k", might not apply
+ // autocorrection like it does for "kde" followed by " " followed by "k". We need to insert
+ // one character at a time, or better, to tell doAutoFormat how many chars to consider...
+ insertText( text );
+ // Don't use 'p' past this point. If we replaced a selection, p could have been deleted (#48999)
+ doAutoFormat( m_cursor, m_cursor->parag(), m_cursor->index() - 1, text[ text.length() - 1 ] );
+ }
+ showToolTipBox(m_cursor->parag(), m_cursor->index()-1, widget,pos);
+ }
+ else
+ removeToolTipCompletion();
+
+ }
+ // We should use KAccel instead, to make this configurable !
+ // Well, those are all alternate keys, for keys already configurable (KDE-wide)
+ // and a kaccel makes it hard to
+ else
+ {
+ if ( e->state() & ControlButton ) {
+ switch ( e->key() )
+ {
+ case Key_F16: // Copy key on Sun keyboards
+ copy();
+ break;
+ case Key_A:
+ moveCursor( MoveLineStart, e->state() & ShiftButton );
+ break;
+ case Key_E:
+ moveCursor( MoveLineEnd, e->state() & ShiftButton );
+ break;
+ case Key_K:
+ textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionKill );
+ break;
+ case Key_Insert:
+ copy();
+ break;
+ case Key_Space:
+ insertNonbreakingSpace();
+ break;
+ default:
+ clearUndoRedoInfo = FALSE;
+ break;
+ }
+ }
+ else // e.g. just Key_Shift -> don't do anything (#129481)
+ {
+ clearUndoRedoInfo = FALSE;
+ }
+ }
+ break;
+ }
+ }
+
+ if ( clearUndoRedoInfo ) {
+ textObject()->clearUndoRedoInfo();
+ if ( d->m_backSpeller )
+ d->m_backSpeller->setIntraWordEditing( 0, 0 );
+ }
+
+ textObject()->typingDone();
+}
+
+void KoTextView::setOverwriteMode( bool overwriteMode )
+{
+ m_overwriteMode = overwriteMode;
+}
+
+void KoTextView::insertText( const QString &text )
+{
+ int insertFlags = KoTextObject::DefaultInsertFlags;
+ if ( m_overwriteMode )
+ insertFlags |= KoTextObject::OverwriteMode;
+ textObject()->insert( m_cursor, m_currentFormat, text, i18n("Insert Text"), KoTextDocument::Standard, insertFlags );
+}
+
+void KoTextView::newParagraph()
+{
+ textObject()->insert( m_cursor, m_currentFormat, "\n", i18n("Insert Text"), KoTextDocument::Standard, KoTextObject::CheckNewLine );
+}
+
+void KoTextView::handleKeyReleaseEvent( QKeyEvent * e )
+{
+ if ( e->key() == Key_Alt && d->currentUnicodeNumber() >= 32 )
+ {
+ QString text = QChar( d->currentUnicodeNumber() );
+ d->clearCurrentUnicodeNumber();
+ insertText( text );
+ doAutoFormat( m_cursor, m_cursor->parag(),
+ m_cursor->index() - 1, text[ text.length() - 1 ] );
+ }
+}
+
+void KoTextView::handleImStartEvent( QIMEvent * )
+{
+ // nothing to do
+}
+
+void KoTextView::handleImComposeEvent( QIMEvent * e )
+{
+ // remove old preedit
+ if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
+ textDocument()->removeSelection( KoTextDocument::Standard );
+ if ( textDocument()->hasSelection( KoTextDocument::InputMethodPreedit ) )
+ textDocument()->removeSelectedText( KoTextDocument::InputMethodPreedit, m_cursor );
+
+ // insert preedit
+ int preeditStartIdx = m_cursor->index();
+ textDocument()->setSelectionStart( KoTextDocument::InputMethodPreedit, m_cursor );
+ textObject()->insert( m_cursor, m_currentFormat, e->text(), i18n("Insert Text"),
+ KoTextDocument::Standard,
+ KoTextObject::DoNotRepaint/* DO NOT REPAINT CURSOR! */ );
+ textDocument()->setSelectionEnd( KoTextDocument::InputMethodPreedit, m_cursor );
+
+ // selection
+ int preeditSelStart = preeditStartIdx + e->cursorPos();
+ int preeditSelEnd = preeditSelStart + e->selectionLength();
+ m_cursor->setIndex( preeditSelStart );
+ textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
+ m_cursor->setIndex( preeditSelEnd );
+ textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
+
+ // set cursor pos
+ m_cursor->setIndex( preeditSelStart );
+
+ textObject()->emitUpdateUI( true );
+ textObject()->emitShowCursor();
+ textObject()->selectionChangedNotify();
+}
+
+void KoTextView::handleImEndEvent( QIMEvent * e )
+{
+ // remove old preedit
+ if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
+ textDocument()->removeSelection( KoTextDocument::Standard );
+ if ( textDocument()->hasSelection( KoTextDocument::InputMethodPreedit ) )
+ textDocument()->removeSelectedText( KoTextDocument::InputMethodPreedit, m_cursor );
+
+ insertText( e->text() );
+
+ textObject()->emitUpdateUI( true );
+ textObject()->emitShowCursor();
+ textObject()->selectionChangedNotify();
+}
+
+void KoTextView::completion()
+{
+ (void) doCompletion(m_cursor, m_cursor->parag(),
+ m_cursor->index() - 1);
+}
+
+void KoTextView::moveCursor( CursorAction action, bool select )
+{
+ hideCursor();
+ bool cursorMoved = false;
+ if ( select ) {
+ if ( !textDocument()->hasSelection( KoTextDocument::Standard ) )
+ textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
+ cursorMoved = moveCursor( action );
+ if ( textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor ) ) {
+ textObject()->selectionChangedNotify();
+ }
+ } else {
+ bool redraw = textDocument()->removeSelection( KoTextDocument::Standard );
+ cursorMoved = moveCursor( action );
+ if ( redraw ) {
+ textObject()->selectionChangedNotify();
+ }
+ }
+
+ if ( cursorMoved ) // e.g. not when pressing Ctrl/PgDown after the last parag
+ {
+ ensureCursorVisible();
+ // updateUI( true ); // done by moveCursor
+ }
+ showCursor();
+}
+
+bool KoTextView::moveCursor( CursorAction action )
+{
+ bool cursorMoved = true;
+ switch ( action ) {
+ case MoveBackward:
+ m_cursor->gotoPreviousLetter();
+ break;
+ case MoveWordBackward:
+ m_cursor->gotoPreviousWord();
+ break;
+ case MoveForward:
+ m_cursor->gotoNextLetter();
+ break;
+ case MoveWordForward:
+ m_cursor->gotoNextWord();
+ break;
+ case MoveUp:
+ m_cursor->gotoUp();
+ break;
+ case MoveDown:
+ m_cursor->gotoDown();
+ break;
+ case MoveViewportUp:
+ cursorMoved = pgUpKeyPressed();
+ break;
+ case MoveViewportDown:
+ cursorMoved = pgDownKeyPressed();
+ break;
+ case MovePgUp:
+ ctrlPgUpKeyPressed();
+ break;
+ case MovePgDown:
+ ctrlPgDownKeyPressed();
+ break;
+ case MoveLineStart:
+ m_cursor->gotoLineStart();
+ break;
+ case MoveHome:
+ m_cursor->gotoHome();
+ break;
+ case MoveLineEnd:
+ m_cursor->gotoLineEnd();
+ break;
+ case MoveEnd:
+ textObject()->ensureFormatted( textDocument()->lastParag() );
+ m_cursor->gotoEnd();
+ break;
+ case MoveParagUp: {
+ KoTextParag * parag = m_cursor->parag()->prev();
+ if ( m_cursor->index()==0 && parag )
+ {
+ m_cursor->setParag( parag );
+ m_cursor->setIndex( 0 );
+ }
+ else m_cursor->setIndex( 0 );
+ } break;
+ case MoveParagDown: {
+ KoTextParag * parag = m_cursor->parag()->next();
+ if ( parag )
+ {
+ m_cursor->setParag( parag );
+ m_cursor->setIndex( 0 );
+ }
+ } break;
+ }
+
+ updateUI( true );
+ return cursorMoved;
+}
+
+KoTextCursor KoTextView::selectWordUnderCursor( const KoTextCursor& cursor, int selectionId )
+{
+ KoTextCursor c1 = cursor;
+ KoTextCursor c2 = cursor;
+ if ( cursor.index() > 0 && !cursor.parag()->at( cursor.index()-1 )->c.isSpace() )
+ c1.gotoWordLeft();
+ if ( !cursor.parag()->at( cursor.index() )->c.isSpace() && !cursor.atParagEnd() )
+ c2.gotoWordRight();
+
+ // The above is almost correct, but gotoWordRight also skips the spaces/punctuations
+ // until the next word. So the 'word under cursor' contained e.g. that trailing space.
+ // To be on the safe side, we skip spaces/punctuations on both sides:
+ KoTextString *s = cursor.parag()->string();
+ bool beginFound = false;
+ for ( int i = c1.index(); i< c2.index(); i++)
+ {
+ const QChar ch = s->at(i).c;
+ // This list comes from KoTextCursor::gotoPreviousWord.
+ // Can't use QChar::isPunct since "'" and "-" are not word separators
+ const bool isWordDelimiter = ch.isSpace()
+ || ch.category() == QChar::Punctuation_Open // e.g. '('
+ || ch.category() == QChar::Punctuation_Close // e.g. ')'
+ || ch.category() == QChar::Punctuation_Other // see http://www.fileformat.info/info/unicode/category/Po/list.htm
+ ;
+
+ if( !beginFound && !isWordDelimiter )
+ {
+ c1.setIndex(i);
+ beginFound = true;
+ }
+ else if ( beginFound && isWordDelimiter )
+ {
+ c2.setIndex(i);
+ break;
+ }
+ }
+
+ textDocument()->setSelectionStart( selectionId, &c1 );
+ textDocument()->setSelectionEnd( selectionId, &c2 );
+ return c2;
+}
+
+KoTextCursor KoTextView::selectParagUnderCursor( const KoTextCursor& cursor, int selectionId, bool copyAndNotify )
+{
+ KoTextCursor c1 = cursor;
+ KoTextCursor c2 = cursor;
+ c1.setIndex(0);
+ c2.setIndex(c1.parag()->string()->length() - 1);
+ textDocument()->setSelectionStart( selectionId, &c1 );
+ textDocument()->setSelectionEnd( selectionId, &c2 );
+ if ( copyAndNotify )
+ {
+ textObject()->selectionChangedNotify();
+ // Copy the selection.
+ QApplication::clipboard()->setSelectionMode( true );
+ emit copy();
+ QApplication::clipboard()->setSelectionMode( false );
+ }
+ return c2;
+}
+
+void KoTextView::extendParagraphSelection( const QPoint& iPoint )
+{
+ hideCursor();
+ KoTextCursor oldCursor = *m_cursor;
+ placeCursor( iPoint );
+
+ bool redraw = FALSE;
+ if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
+ {
+ redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
+ if ( textDocument()->isSelectionSwapped( KoTextDocument::Standard ) )
+ m_cursor->setIndex( 0 );
+ else
+ m_cursor->setIndex( m_cursor->parag()->string()->length() - 1 );
+ textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
+ }
+ //else // it may be that the initial click was out of the frame
+ // textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
+
+ if ( redraw )
+ textObject()->selectionChangedNotify( false );
+
+ showCursor();
+}
+
+QString KoTextView::wordUnderCursor( const KoTextCursor& cursor )
+{
+ selectWordUnderCursor( cursor, KoTextDocument::Temp );
+ QString text = textObject()->selectedText( KoTextDocument::Temp );
+ bool hasCustomItems = textObject()->selectionHasCustomItems( KoTextDocument::Temp );
+ textDocument()->removeSelection( KoTextDocument::Temp );
+ if( !hasCustomItems )
+ return text;
+ return QString::null;
+}
+
+bool KoTextView::handleMousePressEvent( QMouseEvent *e, const QPoint &iPoint, bool canStartDrag, bool insertDirectCursor )
+{
+ bool addParag = false;
+ mightStartDrag = FALSE;
+ hideCursor();
+
+ if (possibleTripleClick)
+ {
+ handleMouseTripleClickEvent( e, iPoint );
+ return addParag;
+ }
+
+ KoTextCursor oldCursor = *m_cursor;
+ addParag = placeCursor( iPoint, insertDirectCursor&& isReadWrite() );
+ ensureCursorVisible();
+
+ if ( e->button() != LeftButton )
+ {
+ showCursor();
+ return addParag;
+ }
+
+ KoLinkVariable* lv = linkVariable();
+ if ( lv && openLink( lv ) )
+ {
+ return addParag;
+ }
+
+ KoTextDocument * textdoc = textDocument();
+ if ( canStartDrag && textdoc->inSelection( KoTextDocument::Standard, iPoint ) ) {
+ mightStartDrag = TRUE;
+ m_textobj->emitShowCursor();
+ dragStartTimer->start( QApplication::startDragTime(), TRUE );
+ dragStartPos = e->pos();
+ return addParag;
+ }
+
+ bool redraw = FALSE;
+ if ( textdoc->hasSelection( KoTextDocument::Standard ) ) {
+ if ( !( e->state() & ShiftButton ) ) {
+ redraw = textdoc->removeSelection( KoTextDocument::Standard );
+ textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
+ } else {
+ redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
+ }
+ } else {
+ if ( !( e->state() & ShiftButton ) ) {
+ textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
+ } else {
+ textdoc->setSelectionStart( KoTextDocument::Standard, &oldCursor );
+ redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
+ }
+ }
+
+ //kdDebug(32500) << "KoTextView::mousePressEvent redraw=" << redraw << endl;
+ if ( !redraw ) {
+ showCursor();
+ } else {
+ textObject()->selectionChangedNotify();
+ }
+ return addParag;
+}
+
+void KoTextView::handleMouseMoveEvent( QMouseEvent*, const QPoint& iPoint )
+{
+ hideCursor();
+ KoTextCursor oldCursor = *m_cursor;
+ placeCursor( iPoint );
+
+ // Double click + mouse still down + moving the mouse selects full words.
+ if ( inDoubleClick ) {
+ KoTextCursor cl = *m_cursor;
+ cl.gotoWordLeft();
+ KoTextCursor cr = *m_cursor;
+ cr.gotoWordRight();
+
+ int diff = QABS( oldCursor.parag()->at( oldCursor.index() )->x - iPoint.x() );
+ int ldiff = QABS( cl.parag()->at( cl.index() )->x - iPoint.x() );
+ int rdiff = QABS( cr.parag()->at( cr.index() )->x - iPoint.x() );
+
+ if ( m_cursor->parag()->lineStartOfChar( m_cursor->index() ) !=
+ oldCursor.parag()->lineStartOfChar( oldCursor.index() ) )
+ diff = 0xFFFFFF;
+
+ if ( rdiff < diff && rdiff < ldiff )
+ *m_cursor = cr;
+ else if ( ldiff < diff && ldiff < rdiff )
+ *m_cursor = cl;
+ else
+ *m_cursor = oldCursor;
+ }
+
+ bool redraw = FALSE;
+ if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
+ redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
+ else // it may be that the initial click was out of the frame
+ textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
+
+ if ( redraw )
+ textObject()->selectionChangedNotify( false );
+
+ showCursor();
+}
+
+void KoTextView::handleMouseReleaseEvent()
+{
+ if ( dragStartTimer->isActive() )
+ dragStartTimer->stop();
+ if ( mightStartDrag ) {
+ textObject()->selectAll( FALSE );
+ mightStartDrag = false;
+ }
+ else
+ {
+ if ( textDocument()->selectionStartCursor( KoTextDocument::Standard ) == textDocument()->selectionEndCursor( KoTextDocument::Standard ) )
+ {
+ textDocument()->removeSelection( KoTextDocument::Standard );
+ }
+
+ textObject()->selectionChangedNotify();
+
+ // Copy the selection.
+ QApplication::clipboard()->setSelectionMode( true );
+ emit copy();
+ QApplication::clipboard()->setSelectionMode( false );
+ }
+
+ inDoubleClick = FALSE;
+ m_textobj->emitShowCursor();
+}
+
+void KoTextView::handleMouseDoubleClickEvent( QMouseEvent*ev, const QPoint& i )
+{
+ //after a triple click it's not a double click but a simple click
+ //but as triple click didn't exist it's necessary to do it.
+ if(afterTripleClick)
+ {
+ handleMousePressEvent( ev, i );
+ return;
+ }
+
+ inDoubleClick = TRUE;
+ *m_cursor = selectWordUnderCursor( *m_cursor );
+ textObject()->selectionChangedNotify();
+ // Copy the selection.
+ QApplication::clipboard()->setSelectionMode( true );
+ emit copy();
+ QApplication::clipboard()->setSelectionMode( false );
+
+ possibleTripleClick=true;
+
+ QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
+}
+
+void KoTextView::tripleClickTimeout()
+{
+ possibleTripleClick=false;
+}
+
+void KoTextView::handleMouseTripleClickEvent( QMouseEvent*ev, const QPoint& /* Currently unused */ )
+{
+ if ( ev->button() != LeftButton)
+ {
+ showCursor();
+ return;
+ }
+ afterTripleClick= true;
+ inDoubleClick = FALSE;
+ *m_cursor = selectParagUnderCursor( *m_cursor );
+ QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(afterTripleClickTimeout()));
+}
+
+void KoTextView::afterTripleClickTimeout()
+{
+ afterTripleClick=false;
+}
+
+bool KoTextView::maybeStartDrag( QMouseEvent* e )
+{
+ if ( mightStartDrag ) {
+ dragStartTimer->stop();
+ if ( ( e->pos() - dragStartPos ).manhattanLength() > QApplication::startDragDistance() )
+ startDrag();
+ return true;
+ }
+ return false;
+}
+
+bool KoTextView::insertParagraph(const QPoint &pos)
+{
+ KoTextParag *last = textDocument()->lastParag();
+ KoTextFormat *f = 0;
+ KoParagStyle *style = last->style();
+ KoParagCounter *counter = last->counter();
+ int diff = (pos.y()- textDocument()->height());
+ f = last->at( last->length()-1 )->format();
+ int height =f->height();
+ int nbParag = (diff / height);
+ QFontMetrics fm = f->refFontMetrics();
+ for (int i = 0; i < nbParag ;i++)
+ {
+ KoTextParag *s=textDocument()->createParag( textDocument(), last );
+ s->setFormat( 0, 1, f, TRUE );
+ if ( style )
+ s->setStyle( style );
+ s->setCounter( counter );
+ last = s;
+ }
+ bool createParag = (nbParag > 0 );
+ if ( createParag )
+ {
+ if ( pos.x() + f->width(' ') >= textDocument()->width())
+ {
+ //FIXME me bidi.
+ //change parag alignment => right alignment
+ last->setAlignment( Qt::AlignRight );
+ }
+ else
+ {
+ int nbSpace = pos.x()/f->width(' ');
+ QString tmp;
+ for (int i = 0; i< nbSpace; i++)
+ {
+ tmp+=' ';
+ }
+ last->insert( 0, tmp );
+ }
+ }
+ return createParag;
+
+}
+
+bool KoTextView::placeCursor( const QPoint &pos, bool insertDirectCursor )
+{
+ bool addParag = false;
+ if ( insertDirectCursor && (pos.y()>textDocument()->height()) )
+ addParag = insertParagraph(pos);
+ KoTextParag *s = 0L;
+ if ( addParag )
+ s = textDocument()->lastParag();
+ else
+ s = textDocument()->firstParag();
+ m_cursor->place( pos, s, false, &m_variablePosition );
+ if ( m_variablePosition != -1 )
+ kdDebug() << k_funcinfo << " m_variablePosition set to " << m_variablePosition << endl;
+ updateUI( true );
+ return addParag;
+}
+
+void KoTextView::blinkCursor()
+{
+ //kdDebug(32500) << "KoTextView::blinkCursor m_cursorVisible=" << m_cursorVisible
+ // << " blinkCursorVisible=" << blinkCursorVisible << endl;
+ if ( !m_cursorVisible )
+ return;
+ bool cv = m_cursorVisible;
+ blinkCursorVisible = !blinkCursorVisible;
+ drawCursor( blinkCursorVisible );
+ m_cursorVisible = cv;
+}
+
+void KoTextView::drawCursor( bool visible )
+{
+ m_cursorVisible = visible;
+ // The rest is up to the app ;)
+}
+
+void KoTextView::focusInEvent()
+{
+ if ( QApplication::cursorFlashTime() > 0 )
+ blinkTimer->start( QApplication::cursorFlashTime() / 2 );
+ showCursor();
+}
+
+void KoTextView::focusOutEvent()
+{
+ blinkTimer->stop();
+ hideCursor();
+}
+
+/*void KoTextView::setFormat( KoTextFormat * newFormat, int flags, bool zoomFont)
+{
+ textObject()->setFormat( m_cursor, m_currentFormat, newFormat, flags, zoomFont );
+}*/
+
+KCommand* KoTextView::setFormatCommand( const KoTextFormat * newFormat, int flags, bool zoomFont)
+{
+ return textObject()->setFormatCommand( m_cursor, &m_currentFormat, newFormat, flags, zoomFont );
+}
+
+void KoTextView::dragStarted()
+{
+ mightStartDrag = FALSE;
+ inDoubleClick = FALSE;
+}
+
+void KoTextView::applyStyle( const KoParagStyle * style )
+{
+ if ( style )
+ {
+ textObject()->applyStyle( m_cursor, style );
+ showCurrentFormat();
+ }
+}
+
+void KoTextView::updateUI( bool updateFormat, bool /*force*/ )
+{
+ // Update UI - only for those items which have changed
+
+ if ( updateFormat )
+ {
+ int i = cursor()->index();
+ if ( i > 0 )
+ --i;
+#ifdef DEBUG_FORMATS
+ if ( currentFormat() )
+ kdDebug(32500) << "KoTextView::updateUI old currentFormat=" << currentFormat()
+ << " " << currentFormat()->key()
+ << " parag format=" << cursor()->parag()->at( i )->format()->key() << endl;
+ else
+ kdDebug(32500) << "KoTextView::updateUI old currentFormat=0" << endl;
+#endif
+ if ( !currentFormat() || currentFormat()->key() != cursor()->parag()->at( i )->format()->key() )
+ {
+ if ( currentFormat() )
+ currentFormat()->removeRef();
+#ifdef DEBUG_FORMATS
+ kdDebug(32500) << "Setting currentFormat from format " << cursor()->parag()->at( i )->format()
+ << " ( character " << i << " in paragraph " << cursor()->parag()->paragId() << " )" << endl;
+#endif
+ setCurrentFormat( textDocument()->formatCollection()->format( cursor()->parag()->at( i )->format() ) );
+ if ( currentFormat()->isMisspelled() ) {
+ KoTextFormat fNoMisspelled( *currentFormat() );
+ fNoMisspelled.setMisspelled( false );
+ currentFormat()->removeRef();
+ setCurrentFormat( textDocument()->formatCollection()->format( &fNoMisspelled ) );
+ }
+ showCurrentFormat();
+ }
+ }
+}
+
+void KoTextView::showCurrentFormat()
+{
+ //kdDebug(32500) << "KoTextView::showCurrentFormat currentFormat=" << currentFormat() << " " << currentFormat()->key() << endl;
+ KoTextFormat format = *currentFormat();
+ //format.setPointSize( textObject()->docFontSize( currentFormat() ) ); // "unzoom" the font size
+ showFormat( &format );
+}
+
+KCommand * KoTextView::setCounterCommand( const KoParagCounter & counter )
+{
+ return textObject()->setCounterCommand( m_cursor, counter );
+}
+KCommand * KoTextView::setAlignCommand( int align )
+{
+ return textObject()->setAlignCommand( m_cursor, align );
+}
+KCommand * KoTextView::setLineSpacingCommand( double spacing, KoParagLayout::SpacingType _type)
+{
+ return textObject()->setLineSpacingCommand( m_cursor, spacing, _type);
+}
+KCommand * KoTextView::setBordersCommand( const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& bottomBorder, const KoBorder& topBorder )
+{
+ return textObject()->setBordersCommand( m_cursor, leftBorder, rightBorder, bottomBorder, topBorder );
+}
+KCommand * KoTextView::setJoinBordersCommand( bool join )
+{
+ return textObject()->setJoinBordersCommand( m_cursor, join );
+}
+KCommand * KoTextView::setMarginCommand( QStyleSheetItem::Margin m, double margin )
+{
+ return textObject()->setMarginCommand( m_cursor, m, margin );
+}
+KCommand * KoTextView::setTabListCommand( const KoTabulatorList & tabList )
+{
+ return textObject()->setTabListCommand( m_cursor, tabList );
+}
+KCommand * KoTextView::setBackgroundColorCommand( const QColor & color )
+{
+ return textObject()->setBackgroundColorCommand( m_cursor, color );
+}
+
+KoTextDocument * KoTextView::textDocument() const
+{
+ return textObject()->textDocument();
+}
+
+KoVariable *KoTextView::variable()
+{
+ if ( m_variablePosition < 0 )
+ return 0;
+ // Can't use m_cursor here, it could be before or after the variable, depending on which half of it was clicked
+ return textObject()->variableAtPosition( m_cursor->parag(), m_variablePosition );
+}
+
+KoLinkVariable * KoTextView::linkVariable()
+{
+ return dynamic_cast<KoLinkVariable *>(variable());
+}
+
+QPtrList<KAction> KoTextView::dataToolActionList(KInstance * instance, const QString& word, bool & _singleWord )
+{
+ m_singleWord = false;
+ m_wordUnderCursor = QString::null;
+ QString text;
+ if ( textObject()->hasSelection() )
+ {
+ text = textObject()->selectedText();
+ if ( text.find(' ') == -1 && text.find('\t') == -1 && text.find(KoTextObject::customItemChar()) == -1 )
+ {
+ m_singleWord = true;
+ }
+ else
+ {
+ m_singleWord = false;
+ //laurent : don't try to search thesaurus when we have a customItemChar.
+ if( text.find(KoTextObject::customItemChar())!=-1)
+ text = QString::null;
+ }
+ }
+ else // No selection -> use word under cursor
+ {
+ if ( !word.isEmpty() )
+ {
+ m_singleWord = true;
+ m_wordUnderCursor = word;
+ text = word;
+ }
+ }
+
+ if ( text.isEmpty() || textObject()->protectContent()) // Nothing to apply a tool to
+ return QPtrList<KAction>();
+
+ // Any tool that works on plain text is relevant
+ QValueList<KDataToolInfo> tools;
+ tools +=KDataToolInfo::query( "QString", "text/plain", instance );
+
+ // Add tools that work on a single word if that is the case
+ if ( m_singleWord )
+ {
+ _singleWord = true;
+ tools += KDataToolInfo::query( "QString", "application/x-singleword", instance );
+ }
+ // Maybe one day we'll have tools that use libkotext (or qt3's qrt), to act on formatted text
+ tools += KDataToolInfo::query( "KoTextString", "application/x-qrichtext", instance );
+
+ return KDataToolAction::dataToolActionList( tools, this, SLOT( slotToolActivated( const KDataToolInfo &, const QString & ) ) );
+}
+
+QString KoTextView::currentWordOrSelection() const
+{
+ if ( textObject()->hasSelection() )
+ return textObject()->selectedText();
+ else
+ return m_wordUnderCursor;
+}
+
+void KoTextView::slotToolActivated( const KDataToolInfo & info, const QString & command )
+{
+ KDataTool* tool = info.createTool( );
+ if ( !tool )
+ {
+ kdWarning() << "Could not create Tool !" << endl;
+ return;
+ }
+
+ kdDebug(32500) << "KWTextFrameSetEdit::slotToolActivated command=" << command
+ << " dataType=" << info.dataType() << endl;
+
+ QString text;
+ if ( textObject()->hasSelection() )
+ text = textObject()->selectedText();
+ else
+ text = m_wordUnderCursor;
+
+ // Preferred type is richtext
+ QString mimetype = "application/x-qrichtext";
+ QString datatype = "KoTextString";
+ // If unsupported, try text/plain
+ if ( !info.mimeTypes().contains( mimetype ) )
+ {
+ mimetype = "text/plain";
+ datatype = "QString";
+ }
+ // If unsupported (and if we have a single word indeed), try application/x-singleword
+ if ( !info.mimeTypes().contains( mimetype ) && m_singleWord )
+ mimetype = "application/x-singleword";
+
+ kdDebug(32500) << "Running tool with datatype=" << datatype << " mimetype=" << mimetype << endl;
+
+ QString origText = text;
+ if ( tool->run( command, &text, datatype, mimetype) )
+ {
+ kdDebug(32500) << "Tool ran. Text is now " << text << endl;
+ if ( origText != text )
+ {
+ if ( !textObject()->hasSelection() )
+ {
+ // Warning: ok for now, but wrong cursor if RMB doesn't place cursor anymore
+ selectWordUnderCursor( *m_cursor );
+ }
+ // replace selection with 'text'
+ textObject()->emitNewCommand( textObject()->replaceSelectionCommand(
+ cursor(), text, i18n("Replace Word") ));
+ }
+ }
+ delete tool;
+}
+
+bool KoTextView::openLink( KoLinkVariable* variable )
+{
+ kdDebug() << k_funcinfo << variable->url() << endl;
+ KURL url( variable->url() );
+ if( url.isValid() )
+ {
+ (void) new KRun( url );
+ return true;
+ }
+ else
+ {
+ KMessageBox::sorry( 0, i18n("%1 is not a valid link.").arg( variable->url() ) );
+ return false;
+ }
+}
+
+
+void KoTextView::insertSoftHyphen()
+{
+ textObject()->insert( cursor(), currentFormat(), QChar(0xad) /* see QRichText */,
+ i18n("Insert Soft Hyphen") );
+}
+
+void KoTextView::insertLineBreak()
+{
+ textObject()->insert( cursor(), currentFormat(), QChar('\n'),
+ i18n("Insert Line Break") );
+}
+
+void KoTextView::insertNonbreakingSpace()
+{
+ textObject()->insert( cursor(), currentFormat(), QChar(0xa0) /* see QRichText */,
+ i18n("Insert Non-Breaking Space") );
+}
+
+void KoTextView::insertNonbreakingHyphen()
+{
+ textObject()->insert( cursor(), currentFormat(), QChar(0x2013),
+ i18n("Insert Non-Breaking Hyphen") );
+}
+
+void KoTextView::insertSpecialChar(QChar _c, const QString& font)
+{
+ KoTextFormat * newFormat = new KoTextFormat(*currentFormat());
+ newFormat->setFamily( font );
+ if ( textObject()->hasSelection() )
+ {
+ KoTextFormat * lastFormat = currentFormat();
+
+ KCommand *cmd = textObject()->setFormatCommand( cursor(), &lastFormat, newFormat, KoTextFormat::Family );
+
+ KMacroCommand* macroCmd = new KMacroCommand( i18n("Insert Special Char") );
+ macroCmd->addCommand( cmd );
+ macroCmd->addCommand( textObject()->replaceSelectionCommand(
+ cursor(), _c, QString::null) );
+ textObject()->emitNewCommand( macroCmd );
+ }
+ else
+ {
+ textObject()->insert( cursor(), newFormat, _c, i18n("Insert Special Char"));
+ delete newFormat;
+ }
+}
+
+const KoParagLayout * KoTextView::currentParagLayoutFormat() const
+{
+ KoTextParag * parag = m_cursor->parag();
+ return &(parag->paragLayout());
+}
+
+bool KoTextView::rtl() const
+{
+ return m_cursor->parag()->string()->isRightToLeft();
+}
+
+KCommand* KoTextView::setParagLayoutFormatCommand( KoParagLayout *newLayout, int flags, int marginIndex )
+{
+ return textObject()->setParagLayoutCommand( m_cursor, *newLayout, KoTextDocument::Standard,
+ flags, marginIndex, true /*createUndoRedo*/ );
+}
+
+// Heading1 -> Heading2 -> Heading3 -> normal -> 1 -> 1.1 -> 1.1.1
+void KoTextView::increaseNumberingLevel( const KoStyleCollection* styleCollection )
+{
+ // TODO: do this for each paragraph in the selection
+ KoParagStyle* style = 0;
+ int level = 0;
+ KoParagCounter* counter = m_cursor->parag()->counter();
+ if ( counter )
+ level = counter->depth() + 1;
+ if ( m_cursor->parag()->style()->isOutline() )
+ {
+ QValueVector<KoParagStyle *> outlineStyles = styleCollection->outlineStyles();
+ while ( level < 10 && !style ) {
+ style = outlineStyles[ level ];
+ ++level;
+ }
+ if ( !style ) // no lower-level heading exists, use standard style
+ style = styleCollection->defaultStyle();
+ }
+ else // non-outline, just a numbered list
+ {
+ // Try to find a style with this depth, to know if the user wants display-levels etc.
+ style = styleCollection->numberedStyleForLevel( level );
+ if ( !style ) { // not found. Make the change though.
+ KoParagCounter c;
+ if (counter) {
+ c = *counter;
+ c.setDepth( level );
+ c.setDisplayLevels( c.displayLevels() + 1 );
+ } else {
+ // Start a simple numbered list.
+ c.setNumbering(KoParagCounter::NUM_LIST);
+ c.setStyle(KoParagCounter::STYLE_NUM);
+ }
+ KCommand* command = textObject()->setCounterCommand( m_cursor, c );
+ textObject()->emitNewCommand( command );
+ }
+ }
+ if ( style ) // can't be 0
+ textObject()->applyStyle( m_cursor, style );
+}
+
+// 1.1.1 -> 1.1 -> 1 -> normal -> Heading3 -> Heading2 -> Heading1
+void KoTextView::decreaseNumberingLevel( const KoStyleCollection* styleCollection )
+{
+ // TODO: do this for each paragraph in the selection
+ KoParagCounter* counter = m_cursor->parag()->counter();
+ int level = 9;
+ if ( counter )
+ level = counter->depth() - 1;
+ KoParagStyle* style = 0;
+ if ( m_cursor->parag()->style()->isOutline() || !counter ) // heading or normal
+ {
+ if ( level == -1 ) // nothing higher than Heading1
+ return;
+ QValueVector<KoParagStyle *> outlineStyles = styleCollection->outlineStyles();
+ while ( level >= 0 && !style ) {
+ style = outlineStyles[ level ];
+ --level;
+ }
+ }
+ else // non-outline, numbered list
+ {
+ if ( level == -1 )
+ style = styleCollection->defaultStyle();
+ else
+ {
+ style = styleCollection->numberedStyleForLevel( level );
+ if ( !style ) { // not found. Make the change though.
+ KoParagCounter c( *counter );
+ c.setDepth( level );
+ if ( c.displayLevels() > 1 ) {
+ c.setDisplayLevels( c.displayLevels() - 1 );
+ }
+ KCommand* command = textObject()->setCounterCommand( m_cursor, c );
+ textObject()->emitNewCommand( command );
+ }
+ }
+ }
+ if ( style )
+ textObject()->applyStyle( m_cursor, style );
+}
+
+KCommand *KoTextView::setChangeCaseOfTextCommand(KoChangeCaseDia::TypeOfCase _type)
+{
+ QString text;
+ if ( textObject()->hasSelection() )
+ text = textObject()->selectedText();
+ if(!text.isEmpty())
+ return textObject()->changeCaseOfText(cursor(), _type);
+ else
+ return 0L;
+}
+
+KCommand *KoTextView::prepareDropMove( KoTextCursor dropCursor )
+{
+ Q_ASSERT( textDocument()->hasSelection( KoTextDocument::Standard ) );
+ // Dropping into the selection itself ?
+ KoTextCursor startSel = textDocument()->selectionStartCursor( KoTextDocument::Standard );
+ KoTextCursor endSel = textDocument()->selectionEndCursor( KoTextDocument::Standard );
+ bool inSelection = false;
+ if ( startSel.parag() == endSel.parag() )
+ inSelection = dropCursor.parag() == startSel.parag()
+ && dropCursor.index() >= startSel.index()
+ && dropCursor.index() <= endSel.index();
+ else
+ {
+ // Looking at first line first:
+ inSelection = dropCursor.parag() == startSel.parag() && dropCursor.index() >= startSel.index();
+ if ( !inSelection )
+ {
+ // Look at all other paragraphs except last one
+ KoTextParag *p = startSel.parag()->next();
+ while ( !inSelection && p && p != endSel.parag() )
+ {
+ inSelection = ( p == dropCursor.parag() );
+ p = p->next();
+ }
+ // Look at last paragraph
+ if ( !inSelection )
+ inSelection = dropCursor.parag() == endSel.parag() && dropCursor.index() <= endSel.index();
+ }
+ }
+ if ( inSelection || m_textobj->protectContent() )
+ {
+ textDocument()->removeSelection( KoTextDocument::Standard );
+ textObject()->selectionChangedNotify();
+ hideCursor();
+ *cursor() = dropCursor;
+ showCursor();
+ ensureCursorVisible();
+ return 0L;
+ }
+ if ( textObject()->protectContent() )
+ {
+ textDocument()->removeSelection( KoTextDocument::Standard );
+ textObject()->selectionChangedNotify();
+ }
+ // Tricky. We don't want to do the placeCursor after removing the selection
+ // (the user pointed at some text with the old selection in place).
+ // However, something got deleted in our parag, dropCursor's index needs adjustment.
+ if ( endSel.parag() == dropCursor.parag() )
+ {
+ // Does the selection starts before (other parag or same parag) ?
+ if ( startSel.parag() != dropCursor.parag() || startSel.index() < dropCursor.index() )
+ {
+ // If other -> endSel.parag() will get deleted. The final position is in startSel.parag(),
+ // where the selection started + how much after the end we are. Make a drawing :)
+ // If same -> simply move back by how many chars we've deleted. Funny thing is, it's the same formula.
+ int dropIndex = dropCursor.index();
+ dropCursor.setParag( startSel.parag() );
+ // If dropCursor - endSel < 0, selection ends after, we're dropping into selection (no-op)
+ dropCursor.setIndex( dropIndex - QMIN( endSel.index(), dropIndex ) + startSel.index() );
+ }
+ kdDebug(32500) << "dropCursor: parag=" << dropCursor.parag()->paragId() << " index=" << dropCursor.index() << endl;
+ }
+ KCommand* cmd = textObject()->removeSelectedTextCommand( cursor(), KoTextDocument::Standard );
+
+ hideCursor();
+ *cursor() = dropCursor;
+ showCursor();
+
+ return cmd;
+}
+
+
+void KoTextView::copyTextOfComment()
+{
+ KoNoteVariable *var = dynamic_cast<KoNoteVariable *>( variable() );
+ if( var )
+ {
+ KURL::List lst;
+ lst.append( var->note() );
+ QApplication::clipboard()->setSelectionMode(true);
+ QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
+ QApplication::clipboard()->setSelectionMode(false);
+ QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
+ }
+}
+
+void KoTextView::removeComment()
+{
+ KoNoteVariable *var = dynamic_cast<KoNoteVariable *>( variable() );
+ if( var )
+ {
+ m_cursor->setIndex( m_variablePosition );
+ textDocument()->setSelectionStart( KoTextDocument::Temp, m_cursor );
+ m_cursor->setIndex( m_variablePosition + 1 );
+ textDocument()->setSelectionEnd( KoTextDocument::Temp, m_cursor );
+ textObject()->removeSelectedText( m_cursor, KoTextDocument::Temp, i18n("Remove Comment") );
+ }
+}
+
+KoParagStyle * KoTextView::createStyleFromSelection(const QString & name)
+{
+ KoTextCursor cursor = *m_cursor;
+ if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
+ cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
+ KoParagStyle * style = new KoParagStyle (name);
+ KoParagLayout layout(cursor.parag()->paragLayout());
+ layout.style = style;
+ style->setFollowingStyle( style );
+ style->format() = *(cursor.parag()->at(cursor.index())->format());
+
+ style->paragLayout() = layout;
+ // Select this new style - hmm only the parag layout, we don't want to erase any text-formatting
+ cursor.parag()->setParagLayout( style->paragLayout() );
+ return style;
+}
+
+void KoTextView::updateStyleFromSelection( KoParagStyle* style )
+{
+ KoTextCursor cursor = *m_cursor;
+ if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
+ cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
+
+ style->paragLayout() = cursor.parag()->paragLayout();
+ style->paragLayout().style = style;
+ style->format() = *(cursor.parag()->at(cursor.index())->format());
+}
+
+void KoTextView::addBookmarks(const QString &url)
+{
+ QString filename = locateLocal( "data", QString::fromLatin1("konqueror/bookmarks.xml") );
+ KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,false );
+ KBookmarkGroup group = bookManager->root();
+ group.addBookmark( bookManager, url, KURL( url));
+ bookManager->save();
+ // delete bookManager;
+}
+
+void KoTextView::copyLink()
+{
+ KoLinkVariable * var=linkVariable();
+ if(var)
+ {
+ KURL::List lst;
+ lst.append( var->url() );
+ QApplication::clipboard()->setSelectionMode(true);
+ QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
+ QApplication::clipboard()->setSelectionMode(false);
+ QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
+ }
+}
+
+void KoTextView::removeLink()
+{
+ KoLinkVariable * var=linkVariable();
+ if(var)
+ {
+ KoTextCursor c1 = *m_cursor;
+ KoTextCursor c2 = *m_cursor;
+ c1.setIndex(var->index());
+ c2.setIndex(var->index()+1);
+ textDocument()->setSelectionStart( KoTextDocument::Temp, &c1 );
+ textDocument()->setSelectionEnd( KoTextDocument::Temp, &c2 );
+ KCommand *cmd=textObject()->replaceSelectionCommand( &c1, var->value(),
+ i18n("Remove Link"), KoTextDocument::Temp );
+ if ( cmd )
+ textObject()->emitNewCommand( cmd );
+ }
+}
+
+void KoTextView::setBackSpeller( KoBgSpellCheck* backSpeller )
+{
+ d->m_backSpeller = backSpeller;
+}
+
+#include "KoTextView.moc"
+class KoBgSpellCheck;