00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <qtimer.h>
00021 #include <qclipboard.h>
00022 #include "kotextview.h"
00023 #include "koparagcounter.h"
00024 #include "kotextobject.h"
00025 #include <klocale.h>
00026 #include <kstandarddirs.h>
00027 #include <kstdaccel.h>
00028 #include <kdebug.h>
00029 #include <kinstance.h>
00030 #include <kdatatool.h>
00031 #include <krun.h>
00032 #include <kmessagebox.h>
00033 #include <kovariable.h>
00034 #include <kcommand.h>
00035 #include "KoTextViewIface.h"
00036 #include <kostyle.h>
00037 #include <kbookmarkmanager.h>
00038 #include <kbookmark.h>
00039 #include <kurldrag.h>
00040
00041 class KoTextView::KoTextViewPrivate
00042 {
00043 public:
00044 KoTextViewPrivate()
00045 {
00046 m_currentUnicodeNumber = 0;
00047 }
00048
00049 void appendDigit( int digit ) { m_currentUnicodeNumber = 10 * m_currentUnicodeNumber + digit; }
00050 int currentUnicodeNumber() const { return m_currentUnicodeNumber; }
00051 void clearCurrentUnicodeNumber() { m_currentUnicodeNumber = 0; }
00052 private:
00053 int m_currentUnicodeNumber;
00054 };
00055
00056 KoTextView::KoTextView( KoTextObject *textobj )
00057 {
00058 d = new KoTextViewPrivate;
00059 m_bReadWrite = true;
00060 m_textobj = textobj;
00061 dcop=0;
00062 connect( m_textobj, SIGNAL( hideCursor() ), this, SLOT( hideCursor() ) );
00063 connect( m_textobj, SIGNAL( showCursor() ), this, SLOT( showCursor() ) );
00064 connect( m_textobj, SIGNAL( setCursor( KoTextCursor * ) ), this, SLOT( setCursor( KoTextCursor * ) ) );
00065 connect( m_textobj, SIGNAL( updateUI(bool, bool) ), this, SLOT( updateUI(bool, bool) ) );
00066 connect( m_textobj, SIGNAL( showCurrentFormat() ), this, SLOT( showCurrentFormat() ) );
00067 connect( m_textobj, SIGNAL( ensureCursorVisible() ), this, SLOT( ensureCursorVisible() ) );
00068
00069 m_cursor = new KoTextCursor( m_textobj->textDocument() );
00070
00071 m_cursorVisible = false;
00072
00073 showCursor();
00074 blinkTimer = new QTimer( this );
00075 connect( blinkTimer, SIGNAL( timeout() ),
00076 this, SLOT( blinkCursor() ) );
00077 blinkTimer->start( QApplication::cursorFlashTime() / 2 );
00078
00079 dragStartTimer = new QTimer( this );
00080 connect( dragStartTimer, SIGNAL( timeout() ),
00081 this, SLOT( startDrag() ) );
00082
00083 m_textobj->formatMore( 2 );
00084
00085 blinkCursorVisible = FALSE;
00086 inDoubleClick = FALSE;
00087 mightStartDrag = FALSE;
00088 possibleTripleClick = FALSE;
00089 afterTripleClick = FALSE;
00090 m_currentFormat = 0;
00091 variablePosition =-1;
00092
00093 }
00094
00095 KoTextView::~KoTextView()
00096 {
00097 delete m_cursor;
00098 delete d;
00099 delete dcop;
00100 delete blinkTimer;
00101 delete dragStartTimer;
00102 }
00103
00104 KoTextViewIface* KoTextView::dcopObject()
00105 {
00106 if ( !dcop )
00107 dcop = new KoTextViewIface( this );
00108
00109 return dcop;
00110 }
00111
00112 void KoTextView::terminate(bool removeselection)
00113 {
00114 textObject()->clearUndoRedoInfo();
00115 if ( removeselection && textDocument()->removeSelection( KoTextDocument::Standard ) )
00116 textObject()->selectionChangedNotify();
00117 hideCursor();
00118 }
00119
00120 void KoTextView::deleteWordRight()
00121 {
00122 if ( textObject()->hasSelection() ) {
00123 textObject()->removeSelectedText( m_cursor );
00124 return;
00125 }
00126 textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
00127
00128 do {
00129 m_cursor->gotoRight();
00130 } while ( !m_cursor->atParagEnd()
00131 && !m_cursor->parag()->at( m_cursor->index() )->c.isSpace() );
00132 textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
00133 textObject()->removeSelectedText( m_cursor, KoTextDocument::Standard, i18n("Remove Word") );
00134 }
00135
00136 void KoTextView::deleteWordLeft()
00137 {
00138 if ( textObject()->hasSelection() ) {
00139 textObject()->removeSelectedText( m_cursor );
00140 return;
00141 }
00142 textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
00143
00144 do {
00145 m_cursor->gotoLeft();
00146 } while ( !m_cursor->atParagStart()
00147 && !m_cursor->parag()->at( m_cursor->index()-1 )->c.isSpace() );
00148 textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
00149 textObject()->removeSelectedText( m_cursor, KoTextDocument::Standard, i18n("Remove Word") );
00150 }
00151
00152
00153 void KoTextView::handleKeyPressEvent( QKeyEvent * e )
00154 {
00155 textObject()->typingStarted();
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166 bool clearUndoRedoInfo = TRUE;
00167
00168 if ( KShortcut( KKey( e ) ) == KStdAccel::deleteWordBack() )
00169 {
00170 if ( m_cursor->parag()->string()->isRightToLeft() )
00171 deleteWordRight();
00172 else
00173 deleteWordLeft();
00174 clearUndoRedoInfo = TRUE;
00175 } else if ( KShortcut( KKey( e ) ) == KStdAccel::deleteWordForward() )
00176 {
00177 if ( m_cursor->parag()->string()->isRightToLeft() )
00178 deleteWordLeft();
00179 else
00180 deleteWordRight();
00181 clearUndoRedoInfo = TRUE;
00182 }
00183 else
00184 switch ( e->key() ) {
00185 case Key_Left:
00186 case Key_Right: {
00187
00188
00189 CursorAction a;
00190 if ( m_cursor->parag()->string()->isRightToLeft() == (e->key() == Key_Right) )
00191 a = e->state() & ControlButton ? MoveWordBackward : MoveBackward;
00192 else
00193 a = e->state() & ControlButton ? MoveWordForward : MoveForward;
00194 moveCursor( a, e->state() & ShiftButton );
00195 break;
00196 }
00197 case Key_Up:
00198 moveCursor( e->state() & ControlButton ? MoveParagUp : MoveUp, e->state() & ShiftButton );
00199 break;
00200 case Key_Down:
00201 moveCursor( e->state() & ControlButton ? MoveParagDown : MoveDown, e->state() & ShiftButton );
00202 break;
00203 case Key_Home:
00204 moveCursor( e->state() & ControlButton ? MoveHome : MoveLineStart, e->state() & ShiftButton );
00205 break;
00206 case Key_End:
00207 moveCursor( e->state() & ControlButton ? MoveEnd : MoveLineEnd, e->state() & ShiftButton );
00208 break;
00209 case Key_Prior:
00210 moveCursor( e->state() & ControlButton ? MovePgUp : MoveViewportUp, e->state() & ShiftButton );
00211 break;
00212 case Key_Next:
00213 moveCursor( e->state() & ControlButton ? MovePgDown : MoveViewportDown, e->state() & ShiftButton );
00214 break;
00215 case Key_Return: case Key_Enter:
00216 if ( (e->state() & (ShiftButton|ControlButton)) == 0 )
00217 {
00218 if ( textObject()->hasSelection() )
00219 textObject()->removeSelectedText( m_cursor );
00220 clearUndoRedoInfo = FALSE;
00221 textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionReturn );
00222 Q_ASSERT( m_cursor->parag()->prev() );
00223 if ( m_cursor->parag()->prev() )
00224 doAutoFormat( m_cursor, m_cursor->parag()->prev(),
00225 m_cursor->parag()->prev()->length() - 1, '\n' );
00226 }
00227 break;
00228 case Key_Delete:
00229 if ( textObject()->hasSelection() ) {
00230 textObject()->removeSelectedText( m_cursor );
00231 break;
00232 }
00233
00234 textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionDelete );
00235
00236 clearUndoRedoInfo = FALSE;
00237 break;
00238 case Key_Backspace:
00239 if ( textObject()->hasSelection() ) {
00240 textObject()->removeSelectedText( m_cursor );
00241 break;
00242 }
00243 if ( !m_cursor->parag()->prev() &&
00244 m_cursor->atParagStart() )
00245 {
00246 KoTextParag * parag = m_cursor->parag();
00247 if ( parag->counter() && parag->counter()->style() != KoParagCounter::STYLE_NONE)
00248 textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionBackspace );
00249 break;
00250 }
00251 textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionBackspace );
00252
00253 clearUndoRedoInfo = FALSE;
00254 break;
00255 case Key_F16:
00256 emit copy();
00257 break;
00258 case Key_F18:
00259 emit paste();
00260 break;
00261 case Key_F20:
00262 emit cut();
00263 break;
00264 case Key_Direction_L: {
00265 if ( !m_cursor->parag() || m_cursor->parag()->direction() == QChar::DirL )
00266 return;
00267 KCommand* cmd = textObject()->setParagDirectionCommand( m_cursor, QChar::DirL );
00268 textObject()->emitNewCommand( cmd );
00269 break;
00270 }
00271 case Key_Direction_R: {
00272 if ( !m_cursor->parag() || m_cursor->parag()->direction() == QChar::DirR )
00273 return;
00274 KCommand* cmd = textObject()->setParagDirectionCommand( m_cursor, QChar::DirR );
00275 textObject()->emitNewCommand( cmd );
00276 break;
00277 }
00278 default: {
00279
00280 if ( e->text().length() &&
00281
00282 ( !e->ascii() || e->ascii() >= 32 ) ||
00283 ( e->text() == "\t" && !( e->state() & ControlButton ) ) ) {
00284 clearUndoRedoInfo = FALSE;
00285 if ( e->key() == Key_Tab ) {
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 }
00296
00297
00298
00299
00300
00301
00302
00303 QString text = e->text();
00304
00305
00306 if ( ( e->state() & AltButton ) && text[0].isDigit() )
00307 {
00308 while ( text[0].isDigit() ) {
00309 d->appendDigit( text[0].digitValue() );
00310 text.remove( 0, 1 );
00311 }
00312 }
00313
00314 if ( !text.isEmpty() )
00315 {
00316
00317 KoTextParag *p = m_cursor->parag();
00318 if ( p && p->string() && p->string()->isRightToLeft() ) {
00319 QChar *c = (QChar *)text.unicode();
00320 int l = text.length();
00321 while( l-- ) {
00322 if ( c->mirrored() )
00323 *c = c->mirroredChar();
00324 c++;
00325 }
00326 }
00327
00328 if( !doIgnoreDoubleSpace( p, m_cursor->index()-1, text[ text.length() - 1 ] ) )
00329 {
00330 insertText( text );
00331
00332 doAutoFormat( m_cursor, m_cursor->parag(), m_cursor->index() - 1, text[ text.length() - 1 ] );
00333 }
00334 }
00335 break;
00336 }
00337
00338
00339
00340 if ( e->state() & ControlButton ) {
00341 switch ( e->key() ) {
00342 case Key_F16:
00343 copy();
00344 break;
00345 case Key_A:
00346 moveCursor( MoveLineStart, e->state() & ShiftButton );
00347 break;
00348 case Key_E:
00349 moveCursor( MoveLineEnd, e->state() & ShiftButton );
00350 break;
00351 case Key_K:
00352 textObject()->doKeyboardAction( m_cursor, m_currentFormat, KoTextObject::ActionKill );
00353 break;
00354 case Key_Insert:
00355 copy();
00356 break;
00357 case Key_Space:
00358 insertNonbreakingSpace();
00359 break;
00360 }
00361 break;
00362 }
00363 }
00364 }
00365
00366 if ( clearUndoRedoInfo ) {
00367 textObject()->clearUndoRedoInfo();
00368 }
00369 textObject()->typingDone();
00370 }
00371
00372 void KoTextView::insertText( const QString &text )
00373 {
00374 textObject()->insert( m_cursor, m_currentFormat, text, false, true, i18n("Insert Text") );
00375 }
00376
00377 void KoTextView::newParagraph()
00378 {
00379 textObject()->insert( m_cursor, m_currentFormat, "\n", true, true, i18n("Insert Text") );
00380 }
00381
00382 void KoTextView::handleKeyReleaseEvent( QKeyEvent * e )
00383 {
00384 if ( e->key() == Key_Alt && d->currentUnicodeNumber() >= 32 )
00385 {
00386 QString text = QChar( d->currentUnicodeNumber() );
00387 d->clearCurrentUnicodeNumber();
00388 insertText( text );
00389 doAutoFormat( m_cursor, m_cursor->parag(),
00390 m_cursor->index() - 1, text[ text.length() - 1 ] );
00391 }
00392 }
00393
00394 void KoTextView::completion()
00395 {
00396 doCompletion(m_cursor, m_cursor->parag(),
00397 m_cursor->index() - 1);
00398 }
00399
00400 void KoTextView::moveCursor( CursorAction action, bool select )
00401 {
00402 hideCursor();
00403 bool cursorMoved = false;
00404 if ( select ) {
00405 if ( !textDocument()->hasSelection( KoTextDocument::Standard ) )
00406 textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
00407 cursorMoved = moveCursor( action );
00408 if ( textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor ) ) {
00409 textObject()->selectionChangedNotify();
00410 }
00411 } else {
00412 bool redraw = textDocument()->removeSelection( KoTextDocument::Standard );
00413 cursorMoved = moveCursor( action );
00414 if ( redraw ) {
00415 textObject()->selectionChangedNotify();
00416 }
00417 }
00418
00419 if ( cursorMoved )
00420 {
00421 ensureCursorVisible();
00422
00423 }
00424 showCursor();
00425 }
00426
00427 bool KoTextView::moveCursor( CursorAction action )
00428 {
00429 bool cursorMoved = true;
00430 switch ( action ) {
00431 case MoveBackward:
00432 m_cursor->gotoPreviousLetter();
00433 break;
00434 case MoveWordBackward:
00435 m_cursor->gotoPreviousWord();
00436 break;
00437 case MoveForward:
00438 m_cursor->gotoNextLetter();
00439 break;
00440 case MoveWordForward:
00441 m_cursor->gotoNextWord();
00442 break;
00443 case MoveUp:
00444 m_cursor->gotoUp();
00445 break;
00446 case MoveDown:
00447 m_cursor->gotoDown();
00448 break;
00449 case MoveViewportUp:
00450 cursorMoved = pgUpKeyPressed();
00451 break;
00452 case MoveViewportDown:
00453 cursorMoved = pgDownKeyPressed();
00454 break;
00455 case MovePgUp:
00456 ctrlPgUpKeyPressed();
00457 break;
00458 case MovePgDown:
00459 ctrlPgDownKeyPressed();
00460 break;
00461 case MoveLineStart:
00462 m_cursor->gotoLineStart();
00463 break;
00464 case MoveHome:
00465 m_cursor->gotoHome();
00466 break;
00467 case MoveLineEnd:
00468 m_cursor->gotoLineEnd();
00469 break;
00470 case MoveEnd:
00471 textObject()->ensureFormatted( textDocument()->lastParag() );
00472 m_cursor->gotoEnd();
00473 break;
00474 case MoveParagUp: {
00475 KoTextParag * parag = m_cursor->parag()->prev();
00476 if ( parag )
00477 {
00478 m_cursor->setParag( parag );
00479 m_cursor->setIndex( 0 );
00480 }
00481 } break;
00482 case MoveParagDown: {
00483 KoTextParag * parag = m_cursor->parag()->next();
00484 if ( parag )
00485 {
00486 m_cursor->setParag( parag );
00487 m_cursor->setIndex( 0 );
00488 }
00489 } break;
00490 }
00491
00492 updateUI( true );
00493 return cursorMoved;
00494 }
00495
00496 KoTextCursor KoTextView::selectWordUnderCursor( const KoTextCursor& cursor, int selectionId )
00497 {
00498 KoTextCursor c1 = cursor;
00499 KoTextCursor c2 = cursor;
00500 if ( cursor.index() > 0 && !cursor.parag()->at( cursor.index()-1 )->c.isSpace() )
00501 c1.gotoWordLeft();
00502 if ( !cursor.parag()->at( cursor.index() )->c.isSpace() && !cursor.atParagEnd() )
00503 c2.gotoWordRight();
00504
00505
00506
00507
00508 KoTextString *s = cursor.parag()->string();
00509 bool beginFound=false;
00510 for ( int i = c1.index(); i< c2.index(); i++)
00511 {
00512 QChar ch = s->at(i).c;
00513 if( !beginFound && !ch.isSpace() && !ch.isPunct() )
00514 {
00515 c1.setIndex(i);
00516 beginFound=true;
00517 }
00518 else if ( beginFound && (ch.isSpace() || ch.isPunct()) )
00519 {
00520 c2.setIndex(i);
00521 break;
00522 }
00523 }
00524
00525 textDocument()->setSelectionStart( selectionId, &c1 );
00526 textDocument()->setSelectionEnd( selectionId, &c2 );
00527 return c2;
00528 }
00529
00530 KoTextCursor KoTextView::selectParagUnderCursor( const KoTextCursor& cursor, int selectionId, bool copyAndNotify )
00531 {
00532 KoTextCursor c1 = cursor;
00533 KoTextCursor c2 = cursor;
00534 c1.setIndex(0);
00535 c2.setIndex(c1.parag()->string()->length() - 1);
00536 textDocument()->setSelectionStart( selectionId, &c1 );
00537 textDocument()->setSelectionEnd( selectionId, &c2 );
00538 if ( copyAndNotify )
00539 {
00540 textObject()->selectionChangedNotify();
00541
00542 QApplication::clipboard()->setSelectionMode( true );
00543 emit copy();
00544 QApplication::clipboard()->setSelectionMode( false );
00545 }
00546 return c2;
00547 }
00548
00549 void KoTextView::extendParagraphSelection( const QPoint& iPoint )
00550 {
00551 hideCursor();
00552 KoTextCursor oldCursor = *m_cursor;
00553 placeCursor( iPoint );
00554
00555 bool redraw = FALSE;
00556 if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
00557 {
00558 redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
00559 if ( textDocument()->isSelectionSwapped( KoTextDocument::Standard ) )
00560 m_cursor->setIndex( 0 );
00561 else
00562 m_cursor->setIndex( m_cursor->parag()->string()->length() - 1 );
00563 textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
00564 }
00565
00566
00567
00568 if ( redraw )
00569 textObject()->selectionChangedNotify( false );
00570
00571 showCursor();
00572 }
00573
00574 QString KoTextView::wordUnderCursor( const KoTextCursor& cursor )
00575 {
00576 selectWordUnderCursor( cursor, KoTextDocument::Temp );
00577 QString text = textObject()->selectedText( KoTextDocument::Temp );
00578 bool hasCustomItems = textObject()->selectionHasCustomItems( KoTextDocument::Temp );
00579 textDocument()->removeSelection( KoTextDocument::Temp );
00580 if( !hasCustomItems )
00581 return text;
00582 return QString::null;
00583 }
00584
00585 bool KoTextView::handleMousePressEvent( QMouseEvent *e, const QPoint &iPoint, bool canStartDrag, bool insertDirectCursor )
00586 {
00587 bool addParag = false;
00588 mightStartDrag = FALSE;
00589 hideCursor();
00590
00591 if (possibleTripleClick)
00592 {
00593 handleMouseTripleClickEvent( e, iPoint );
00594 return addParag;
00595 }
00596
00597 KoTextCursor oldCursor = *m_cursor;
00598 addParag = placeCursor( iPoint, insertDirectCursor&& isReadWrite() );
00599 ensureCursorVisible();
00600
00601 if ( e->button() != LeftButton )
00602 {
00603 showCursor();
00604 return addParag;
00605 }
00606
00607 KoTextDocument * textdoc = textDocument();
00608 if ( canStartDrag && textdoc->inSelection( KoTextDocument::Standard, iPoint ) ) {
00609 mightStartDrag = TRUE;
00610 m_textobj->emitShowCursor();
00611 dragStartTimer->start( QApplication::startDragTime(), TRUE );
00612 dragStartPos = e->pos();
00613 return addParag;
00614 }
00615
00616 bool redraw = FALSE;
00617 if ( textdoc->hasSelection( KoTextDocument::Standard ) ) {
00618 if ( !( e->state() & ShiftButton ) ) {
00619 redraw = textdoc->removeSelection( KoTextDocument::Standard );
00620 textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
00621 } else {
00622 redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
00623 }
00624 } else {
00625 if ( !( e->state() & ShiftButton ) ) {
00626 textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
00627 } else {
00628 textdoc->setSelectionStart( KoTextDocument::Standard, &oldCursor );
00629 redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
00630 }
00631 }
00632
00633
00634 if ( !redraw ) {
00635 showCursor();
00636 } else {
00637 textObject()->selectionChangedNotify();
00638 }
00639 return addParag;
00640 }
00641
00642 void KoTextView::handleMouseMoveEvent( QMouseEvent*, const QPoint& iPoint )
00643 {
00644 hideCursor();
00645 KoTextCursor oldCursor = *m_cursor;
00646 placeCursor( iPoint );
00647
00648
00649 if ( inDoubleClick ) {
00650 KoTextCursor cl = *m_cursor;
00651 cl.gotoWordLeft();
00652 KoTextCursor cr = *m_cursor;
00653 cr.gotoWordRight();
00654
00655 int diff = QABS( oldCursor.parag()->at( oldCursor.index() )->x - iPoint.x() );
00656 int ldiff = QABS( cl.parag()->at( cl.index() )->x - iPoint.x() );
00657 int rdiff = QABS( cr.parag()->at( cr.index() )->x - iPoint.x() );
00658
00659 if ( m_cursor->parag()->lineStartOfChar( m_cursor->index() ) !=
00660 oldCursor.parag()->lineStartOfChar( oldCursor.index() ) )
00661 diff = 0xFFFFFF;
00662
00663 if ( rdiff < diff && rdiff < ldiff )
00664 *m_cursor = cr;
00665 else if ( ldiff < diff && ldiff < rdiff )
00666 *m_cursor = cl;
00667 else
00668 *m_cursor = oldCursor;
00669 }
00670
00671 bool redraw = FALSE;
00672 if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
00673 redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
00674 else
00675 textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
00676
00677 if ( redraw )
00678 textObject()->selectionChangedNotify( false );
00679
00680 showCursor();
00681 }
00682
00683 void KoTextView::handleMouseReleaseEvent()
00684 {
00685 if ( dragStartTimer->isActive() )
00686 dragStartTimer->stop();
00687 if ( mightStartDrag ) {
00688 textObject()->selectAll( FALSE );
00689 mightStartDrag = false;
00690 }
00691 else
00692 {
00693 if ( textDocument()->selectionStartCursor( KoTextDocument::Standard ) == textDocument()->selectionEndCursor( KoTextDocument::Standard ) )
00694 {
00695 textDocument()->removeSelection( KoTextDocument::Standard );
00696 }
00697
00698 textObject()->selectionChangedNotify();
00699
00700
00701 QApplication::clipboard()->setSelectionMode( true );
00702 emit copy();
00703 QApplication::clipboard()->setSelectionMode( false );
00704 }
00705
00706 inDoubleClick = FALSE;
00707 m_textobj->emitShowCursor();
00708 }
00709
00710 void KoTextView::handleMouseDoubleClickEvent( QMouseEvent*ev, const QPoint& i )
00711 {
00712
00713
00714 if(afterTripleClick)
00715 {
00716 handleMousePressEvent( ev, i );
00717 return;
00718 }
00719
00720 inDoubleClick = TRUE;
00721 *m_cursor = selectWordUnderCursor( *m_cursor );
00722 textObject()->selectionChangedNotify();
00723
00724 QApplication::clipboard()->setSelectionMode( true );
00725 emit copy();
00726 QApplication::clipboard()->setSelectionMode( false );
00727
00728 possibleTripleClick=true;
00729
00730 QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
00731 }
00732
00733 void KoTextView::tripleClickTimeout()
00734 {
00735 possibleTripleClick=false;
00736 }
00737
00738 void KoTextView::handleMouseTripleClickEvent( QMouseEvent*ev, const QPoint& )
00739 {
00740 if ( ev->button() != LeftButton)
00741 {
00742 showCursor();
00743 return;
00744 }
00745 afterTripleClick= true;
00746 inDoubleClick = FALSE;
00747 *m_cursor = selectParagUnderCursor( *m_cursor );
00748 QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(afterTripleClickTimeout()));
00749 }
00750
00751 void KoTextView::afterTripleClickTimeout()
00752 {
00753 afterTripleClick=false;
00754 }
00755
00756 bool KoTextView::maybeStartDrag( QMouseEvent* e )
00757 {
00758 if ( mightStartDrag ) {
00759 dragStartTimer->stop();
00760 if ( ( e->pos() - dragStartPos ).manhattanLength() > QApplication::startDragDistance() )
00761 startDrag();
00762 return true;
00763 }
00764 return false;
00765 }
00766
00767 bool KoTextView::insertParagraph(const QPoint &pos)
00768 {
00769 KoTextParag *last = textDocument()->lastParag();
00770 KoTextFormat *f = 0;
00771 KoStyle *style = last->style();
00772 KoParagCounter *counter = last->counter();
00773 int diff = (pos.y()- textDocument()->height());
00774 f = last->at( last->length()-1 )->format();
00775 int height =f->height();
00776 int nbParag = (diff / height);
00777 QFontMetrics fm = f->refFontMetrics();
00778 for (int i = 0; i < nbParag ;i++)
00779 {
00780 KoTextParag *s=textDocument()->createParag( textDocument(), last );
00781 if ( f )
00782 s->setFormat( 0, 1, f, TRUE );
00783 if ( style )
00784 s->setStyle( style );
00785 s->setCounter( counter );
00786 last = s;
00787 }
00788 bool createParag = (nbParag > 0 );
00789 if ( createParag )
00790 {
00791 if ( pos.x() + f->width(' ') >= textDocument()->width())
00792 {
00793
00794
00795 last->setAlignment( Qt::AlignRight );
00796 }
00797 else
00798 {
00799 int nbSpace = pos.x()/f->width(' ');
00800 QString tmp;
00801 for (int i = 0; i< nbSpace; i++)
00802 {
00803 tmp+=' ';
00804 }
00805 last->insert( 0, tmp );
00806 }
00807 }
00808 return createParag;
00809
00810 }
00811
00812 bool KoTextView::placeCursor( const QPoint &pos, bool insertDirectCursor )
00813 {
00814 bool addParag = false;
00815 m_cursor->restoreState();
00816 if ( insertDirectCursor && (pos.y()>textDocument()->height()) )
00817 addParag = insertParagraph(pos);
00818 KoTextParag *s = 0L;
00819 if ( addParag )
00820 s = textDocument()->lastParag();
00821 else
00822 s = textDocument()->firstParag();
00823 m_cursor->place( pos, s, false, &variablePosition );
00824 updateUI( true );
00825 return addParag;
00826 }
00827
00828 void KoTextView::blinkCursor()
00829 {
00830
00831
00832 if ( !m_cursorVisible )
00833 return;
00834 bool cv = m_cursorVisible;
00835 blinkCursorVisible = !blinkCursorVisible;
00836 drawCursor( blinkCursorVisible );
00837 m_cursorVisible = cv;
00838 }
00839
00840 void KoTextView::drawCursor( bool visible )
00841 {
00842 m_cursorVisible = visible;
00843
00844 }
00845
00846 void KoTextView::focusInEvent()
00847 {
00848 blinkTimer->start( QApplication::cursorFlashTime() / 2 );
00849 showCursor();
00850 }
00851
00852 void KoTextView::focusOutEvent()
00853 {
00854 blinkTimer->stop();
00855 hideCursor();
00856 }
00857
00858
00859
00860
00861
00862
00863 KCommand* KoTextView::setFormatCommand( const KoTextFormat * newFormat, int flags, bool zoomFont)
00864 {
00865 return textObject()->setFormatCommand( m_cursor, &m_currentFormat, newFormat, flags, zoomFont );
00866 }
00867
00868 void KoTextView::dragStarted()
00869 {
00870 mightStartDrag = FALSE;
00871 inDoubleClick = FALSE;
00872 }
00873
00874 void KoTextView::applyStyle( const KoStyle * style )
00875 {
00876 if ( style )
00877 {
00878 textObject()->applyStyle( m_cursor, style );
00879 showCurrentFormat();
00880 }
00881 }
00882
00883 void KoTextView::updateUI( bool updateFormat, bool )
00884 {
00885
00886
00887 if ( updateFormat )
00888 {
00889 int i = cursor()->index();
00890 if ( i > 0 )
00891 --i;
00892 #ifdef DEBUG_FORMATS
00893 if ( currentFormat() )
00894 kdDebug(32500) << "KoTextView::updateUI old currentFormat=" << currentFormat()
00895 << " " << currentFormat()->key()
00896 << " parag format=" << cursor()->parag()->at( i )->format()->key() << endl;
00897 else
00898 kdDebug(32500) << "KoTextView::updateUI old currentFormat=0" << endl;
00899 #endif
00900 if ( !currentFormat() || currentFormat()->key() != cursor()->parag()->at( i )->format()->key() )
00901 {
00902 if ( currentFormat() )
00903 currentFormat()->removeRef();
00904 #ifdef DEBUG_FORMATS
00905 kdDebug(32500) << "Setting currentFormat from format " << cursor()->parag()->at( i )->format()
00906 << " ( character " << i << " in paragraph " << cursor()->parag()->paragId() << " )" << endl;
00907 #endif
00908 setCurrentFormat( textDocument()->formatCollection()->format( cursor()->parag()->at( i )->format() ) );
00909 if ( currentFormat()->isMisspelled() ) {
00910 KoTextFormat fNoMisspelled( *currentFormat() );
00911 fNoMisspelled.setMisspelled( false );
00912 currentFormat()->removeRef();
00913 setCurrentFormat( textDocument()->formatCollection()->format( &fNoMisspelled ) );
00914 }
00915 showCurrentFormat();
00916 }
00917 }
00918 }
00919
00920 void KoTextView::showCurrentFormat()
00921 {
00922
00923 KoTextFormat format = *currentFormat();
00924
00925 showFormat( &format );
00926 }
00927
00928 KCommand * KoTextView::setCounterCommand( const KoParagCounter & counter )
00929 {
00930 return textObject()->setCounterCommand( m_cursor, counter );
00931 }
00932 KCommand * KoTextView::setAlignCommand( int align )
00933 {
00934 return textObject()->setAlignCommand( m_cursor, align );
00935 }
00936 KCommand * KoTextView::setLineSpacingCommand( double spacing, KoParagLayout::SpacingType _type)
00937 {
00938 return textObject()->setLineSpacingCommand( m_cursor, spacing, _type);
00939 }
00940 KCommand * KoTextView::setBordersCommand( const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& bottomBorder, const KoBorder& topBorder )
00941 {
00942 return textObject()->setBordersCommand( m_cursor, leftBorder, rightBorder, bottomBorder, topBorder );
00943 }
00944 KCommand * KoTextView::setMarginCommand( QStyleSheetItem::Margin m, double margin )
00945 {
00946 return textObject()->setMarginCommand( m_cursor, m, margin );
00947 }
00948 KCommand * KoTextView::setTabListCommand( const KoTabulatorList & tabList )
00949 {
00950 return textObject()->setTabListCommand( m_cursor, tabList );
00951 }
00952
00953 KoTextDocument * KoTextView::textDocument() const
00954 {
00955 return textObject()->textDocument();
00956 }
00957
00958 KoVariable *KoTextView::variable()
00959 {
00960 if ( variablePosition > -1 )
00961 {
00962 KoTextStringChar * ch = m_cursor->parag()->at( variablePosition );
00963 ch = m_cursor->parag()->at( variablePosition );
00964 if(ch->isCustom())
00965 return dynamic_cast<KoVariable *>(ch->customItem());
00966 }
00967 return 0L;
00968 }
00969
00970 KoLinkVariable * KoTextView::linkVariable()
00971 {
00972 return dynamic_cast<KoLinkVariable *>(variable());
00973 }
00974
00975 QPtrList<KAction> KoTextView::dataToolActionList(KInstance * instance, const QString& word, bool & _singleWord )
00976 {
00977 m_singleWord = false;
00978 m_wordUnderCursor = QString::null;
00979 m_refLink= QString::null;
00980 KoLinkVariable* linkVar = linkVariable();
00981 if(linkVar)
00982 m_refLink = linkVar->url();
00983 QString text;
00984 if ( textObject()->hasSelection() )
00985 {
00986 text = textObject()->selectedText();
00987 if ( text.find(' ') == -1 && text.find('\t') == -1 && text.find(KoTextObject::customItemChar()) == -1 )
00988 {
00989 m_singleWord = true;
00990 }
00991 else
00992 {
00993 m_singleWord = false;
00994
00995 if( text.find(KoTextObject::customItemChar())!=-1)
00996 text = QString::null;
00997 }
00998 }
00999 else
01000 {
01001 if ( !word.isEmpty() )
01002 {
01003 m_singleWord = true;
01004 m_wordUnderCursor = word;
01005 text = word;
01006 }
01007 }
01008
01009 if ( text.isEmpty() || textObject()->protectContent())
01010 return QPtrList<KAction>();
01011
01012
01013 QValueList<KDataToolInfo> tools;
01014 tools +=KDataToolInfo::query( "QString", "text/plain", instance );
01015
01016
01017 if ( m_singleWord )
01018 {
01019 _singleWord = true;
01020 tools += KDataToolInfo::query( "QString", "application/x-singleword", instance );
01021 }
01022
01023 tools += KDataToolInfo::query( "KoTextString", "application/x-qrichtext", instance );
01024
01025 return KDataToolAction::dataToolActionList( tools, this, SLOT( slotToolActivated( const KDataToolInfo &, const QString & ) ) );
01026 }
01027
01028 QString KoTextView::underCursorWord()
01029 {
01030 QString text;
01031 if ( textObject()->hasSelection() )
01032 text = textObject()->selectedText();
01033 else
01034 text = m_wordUnderCursor;
01035 return text;
01036 }
01037
01038 void KoTextView::slotToolActivated( const KDataToolInfo & info, const QString & command )
01039 {
01040 KDataTool* tool = info.createTool( );
01041 if ( !tool )
01042 {
01043 kdWarning() << "Could not create Tool !" << endl;
01044 return;
01045 }
01046
01047 kdDebug(32500) << "KWTextFrameSetEdit::slotToolActivated command=" << command
01048 << " dataType=" << info.dataType() << endl;
01049
01050 QString text;
01051 if ( textObject()->hasSelection() )
01052 text = textObject()->selectedText();
01053 else
01054 text = m_wordUnderCursor;
01055
01056
01057 QString mimetype = "application/x-qrichtext";
01058 QString datatype = "KoTextString";
01059
01060 if ( !info.mimeTypes().contains( mimetype ) )
01061 {
01062 mimetype = "text/plain";
01063 datatype = "QString";
01064 }
01065
01066 if ( !info.mimeTypes().contains( mimetype ) && m_singleWord )
01067 mimetype = "application/x-singleword";
01068
01069 kdDebug(32500) << "Running tool with datatype=" << datatype << " mimetype=" << mimetype << endl;
01070
01071 QString origText = text;
01072 if ( tool->run( command, &text, datatype, mimetype) )
01073 {
01074 kdDebug(32500) << "Tool ran. Text is now " << text << endl;
01075 if ( origText != text )
01076 {
01077 if ( !textObject()->hasSelection() )
01078 {
01079
01080 selectWordUnderCursor( *m_cursor );
01081 }
01082
01083 textObject()->emitNewCommand( textObject()->replaceSelectionCommand(
01084 cursor(), text, KoTextDocument::Standard, i18n("Replace Word") ));
01085 }
01086 }
01087 delete tool;
01088 }
01089
01090 void KoTextView::openLink()
01091 {
01092 KURL url( m_refLink );
01093 if( url.isValid() )
01094 (void) new KRun( url );
01095 else
01096 KMessageBox::sorry(0L,i18n("%1 is not a valid link.").arg(m_refLink));
01097 }
01098
01099
01100 void KoTextView::insertSoftHyphen()
01101 {
01102 textObject()->insert( cursor(), currentFormat(), QChar(0xad) ,
01103 false , true, i18n("Insert Soft Hyphen") );
01104 }
01105
01106 void KoTextView::insertLineBreak()
01107 {
01108 textObject()->insert( cursor(), currentFormat(), QChar('\n'),
01109 false , true, i18n("Insert Line Break") );
01110 }
01111
01112 void KoTextView::insertNonbreakingSpace()
01113 {
01114 textObject()->insert( cursor(), currentFormat(), QChar(0xa0) ,
01115 false , true, i18n("Insert Non-Breaking Space") );
01116 }
01117
01118 void KoTextView::insertSpecialChar(QChar _c, const QString& font)
01119 {
01120 KoTextFormat * newFormat = new KoTextFormat(*currentFormat());
01121 newFormat->setFamily( font );
01122 if ( textObject()->hasSelection() )
01123 {
01124 KoTextFormat * lastFormat = currentFormat();
01125
01126 KCommand *cmd = textObject()->setFormatCommand( cursor(), &lastFormat, newFormat, KoTextFormat::Family );
01127
01128 KMacroCommand* macroCmd = new KMacroCommand( i18n("Insert Special Char") );
01129 macroCmd->addCommand( cmd );
01130 macroCmd->addCommand( textObject()->replaceSelectionCommand(
01131 cursor(), _c, KoTextDocument::Standard, QString::null) );
01132 textObject()->emitNewCommand( macroCmd );
01133 }
01134 else
01135 {
01136 textObject()->insert( cursor(), newFormat, _c, false, true, i18n("Insert Special Char"));
01137 delete newFormat;
01138 }
01139 }
01140
01141 const KoParagLayout * KoTextView::currentParagLayoutFormat() const
01142 {
01143 KoTextParag * parag = m_cursor->parag();
01144 return &(parag->paragLayout());
01145 }
01146
01147 bool KoTextView::rtl() const
01148 {
01149 return m_cursor->parag()->string()->isRightToLeft();
01150 }
01151
01152
01153 KCommand* KoTextView::setParagLayoutFormatCommand( KoParagLayout *newLayout,int flags,int marginIndex)
01154 {
01155 #if 0
01156 KCommand *cmd =0L;
01157 KoParagCounter c;
01158 if(newLayout->counter)
01159 c=*newLayout->counter;
01160 switch(flags)
01161 {
01162 case KoParagLayout::Alignment:
01163 {
01164 cmd = textObject()->setAlignCommand( m_cursor, newLayout->alignment );
01165 break;
01166 }
01167 case KoParagLayout::Tabulator:
01168 cmd= textObject()->setTabListCommand( m_cursor, newLayout->tabList() );
01169 break;
01170 case KoParagLayout::Margins:
01171 cmd= textObject()->setMarginCommand(m_cursor,(QStyleSheetItem::Margin)marginIndex, newLayout->margins[marginIndex] );
01172 break;
01173 case KoParagLayout::BulletNumber:
01174 cmd= textObject()->setCounterCommand( m_cursor, c );
01175 break;
01176 default:
01177 break;
01178 }
01179 if (cmd)
01180 textObject()->emitNewCommand( cmd );
01181 #endif
01182 return textObject()->setParagLayoutFormatCommand( m_cursor, KoTextDocument::Standard, newLayout, flags, marginIndex );
01183 }
01184
01185 KCommand *KoTextView::setChangeCaseOfTextCommand(KoChangeCaseDia::TypeOfCase _type)
01186 {
01187 QString text;
01188 if ( textObject()->hasSelection() )
01189 text = textObject()->selectedText();
01190 if(!text.isEmpty())
01191 return textObject()->changeCaseOfText(cursor(), _type);
01192 else
01193 return 0L;
01194 }
01195
01196 KCommand *KoTextView::dropEvent( KoTextObject *tmp, KoTextCursor dropCursor, bool dropInSameObj)
01197 {
01198 KMacroCommand *macroCmd=new KMacroCommand(i18n("Paste Text"));
01199 if ( tmp->hasSelection() )
01200 {
01201
01202 KoTextCursor startSel = textDocument()->selectionStartCursor( KoTextDocument::Standard );
01203 KoTextCursor endSel = textDocument()->selectionEndCursor( KoTextDocument::Standard );
01204 bool inSelection = false;
01205 if ( startSel.parag() == endSel.parag() )
01206 inSelection = dropInSameObj
01207 && ( dropCursor.parag() == startSel.parag() )
01208 && dropCursor.index() >= startSel.index()
01209 && dropCursor.index() <= endSel.index();
01210 else
01211 {
01212
01213 inSelection = dropInSameObj && dropCursor.parag() == startSel.parag() && dropCursor.index() >= startSel.index();
01214 if ( !inSelection )
01215 {
01216
01217 KoTextParag *p = startSel.parag()->next();
01218 while ( !inSelection && p && p != endSel.parag() )
01219 {
01220 inSelection = ( p == dropCursor.parag() );
01221 p = p->next();
01222 }
01223
01224 if ( !inSelection )
01225 inSelection = dropCursor.parag() == endSel.parag() && dropCursor.index() <= endSel.index();
01226 }
01227 }
01228 if ( inSelection || m_textobj->protectContent() )
01229 {
01230 delete macroCmd;
01231 tmp->textDocument()->removeSelection( KoTextDocument::Standard );
01232 tmp->selectionChangedNotify();
01233 hideCursor();
01234 *cursor() = dropCursor;
01235 showCursor();
01236 ensureCursorVisible();
01237 return 0L;
01238 }
01239 if ( tmp->protectContent())
01240 {
01241 tmp->textDocument()->removeSelection( KoTextDocument::Standard );
01242 tmp->selectionChangedNotify();
01243 }
01244
01245
01246
01247 if ( endSel.parag() == dropCursor.parag() )
01248 {
01249
01250 if ( startSel.parag() != dropCursor.parag() || startSel.index() < dropCursor.index() )
01251 {
01252
01253
01254
01255 int dropIndex = dropCursor.index();
01256 dropCursor.setParag( startSel.parag() );
01257
01258 dropCursor.setIndex( dropIndex - QMIN( endSel.index(), dropIndex ) + startSel.index() );
01259 }
01260 kdDebug(32500) << "dropCursor: parag=" << dropCursor.parag()->paragId() << " index=" << dropCursor.index() << endl;
01261 }
01262 macroCmd->addCommand(tmp->removeSelectedTextCommand( cursor(), KoTextDocument::Standard ));
01263 }
01264 hideCursor();
01265 *cursor() = dropCursor;
01266 showCursor();
01267 kdDebug(32500) << "cursor set back to drop cursor: parag=" << cursor()->parag()->paragId() << " index=" << cursor()->index() << endl;
01268
01269 return macroCmd;
01270 }
01271
01272
01273 void KoTextView::copyTextOfComment()
01274 {
01275 KoTextStringChar * ch = m_cursor->parag()->at( variablePosition );
01276 if(ch->isCustom())
01277 {
01278 KoNoteVariable *var=dynamic_cast<KoNoteVariable *>(ch->customItem());
01279 if( var )
01280 {
01281 KURL::List lst;
01282 lst.append( var->note() );
01283 QApplication::clipboard()->setSelectionMode(true);
01284 QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01285 QApplication::clipboard()->setSelectionMode(false);
01286 QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01287 }
01288 }
01289 }
01290
01291 void KoTextView::removeComment()
01292 {
01293 KoTextStringChar * ch = m_cursor->parag()->at( variablePosition );
01294 if(ch->isCustom())
01295 {
01296 KoNoteVariable *var=dynamic_cast<KoNoteVariable *>(ch->customItem());
01297 if( var )
01298 {
01299 if( variablePosition == m_cursor->index() )
01300 m_cursor->setIndex( m_cursor->index() );
01301 else
01302 m_cursor->setIndex( m_cursor->index() -1 );
01303
01304 textDocument()->setSelectionStart( KoTextDocument::Temp, m_cursor );
01305
01306 if( variablePosition == m_cursor->index() )
01307 m_cursor->setIndex( m_cursor->index() +1);
01308 else
01309 m_cursor->setIndex( m_cursor->index() );
01310
01311 textDocument()->setSelectionEnd( KoTextDocument::Temp, m_cursor );
01312
01313 textObject()->removeSelectedText( m_cursor, KoTextDocument::Temp, i18n("Remove Comment") );
01314 }
01315 }
01316 }
01317
01318 KoStyle * KoTextView::createStyleFromSelection(const QString & name)
01319 {
01320 KoTextCursor cursor = *m_cursor;
01321 if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
01322 cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
01323 KoStyle * style = new KoStyle (name);
01324 KoParagLayout layout(cursor.parag()->paragLayout());
01325 layout.style = style;
01326 style->setFollowingStyle( style );
01327 style->format() = *(cursor.parag()->at(cursor.index())->format());
01328
01329 style->paragLayout() = layout;
01330
01331 cursor.parag()->setParagLayout( style->paragLayout() );
01332 return style;
01333 }
01334
01335 void KoTextView::updateStyleFromSelection( KoStyle* style )
01336 {
01337 KoTextCursor cursor = *m_cursor;
01338 if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
01339 cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
01340
01341 style->paragLayout() = cursor.parag()->paragLayout();
01342 style->paragLayout().style = style;
01343 style->format() = *(cursor.parag()->at(cursor.index())->format());
01344 }
01345
01346 void KoTextView::addBookmarks(const QString &url)
01347 {
01348 QString filename = locateLocal( "data", QString::fromLatin1("konqueror/bookmarks.xml") );
01349 KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,false );
01350 KBookmarkGroup group = bookManager->root();
01351 group.addBookmark( bookManager, url, KURL( url));
01352 bookManager->save();
01353
01354 }
01355
01356 void KoTextView::copyLink()
01357 {
01358 KoLinkVariable * var=linkVariable();
01359 if(var)
01360 {
01361 KURL::List lst;
01362 lst.append( var->url() );
01363 QApplication::clipboard()->setSelectionMode(true);
01364 QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01365 QApplication::clipboard()->setSelectionMode(false);
01366 QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01367 }
01368 }
01369
01370 void KoTextView::removeLink()
01371 {
01372 KoLinkVariable * var=linkVariable();
01373 if(var)
01374 {
01375 KoTextCursor c1 = *m_cursor;
01376 KoTextCursor c2 = *m_cursor;
01377 c1.setIndex(var->index());
01378 c2.setIndex(var->index()+1);
01379 textDocument()->setSelectionStart( KoTextDocument::Temp, &c1 );
01380 textDocument()->setSelectionEnd( KoTextDocument::Temp, &c2 );
01381 KCommand *cmd=textObject()->replaceSelectionCommand( &c1, var->value(),
01382 KoTextDocument::Temp, i18n("Remove Link") );
01383 if ( cmd )
01384 textObject()->emitNewCommand( cmd );
01385 }
01386 }
01387
01388
01389 #include "kotextview.moc"