lib Library API Documentation

kotextview.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2001 David Faure <faure@kde.org>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017    Boston, MA 02111-1307, USA.
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; // For the alt+123 feature
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     //updateUI( true, true );
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 // Compare with QTextEdit::keyPressEvent
00153 void KoTextView::handleKeyPressEvent( QKeyEvent * e )
00154 {
00155     textObject()->typingStarted();
00156 
00157     /* bool selChanged = FALSE;
00158     for ( int i = 1; i < textDocument()->numSelections(); ++i )
00159         selChanged = textDocument()->removeSelection( i ) || selChanged;
00160 
00161     if ( selChanged ) {
00162         // m_cursor->parag()->document()->nextDoubleBuffered = TRUE; ######## we need that only if we have nested items/documents
00163         textFrameSet()->selectionChangedNotify();
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         // a bit hacky, but can't change this without introducing new enum values for move and keeping the
00188         // correct semantics and movement for BiDi and non BiDi text.
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: // Copy key on Sun keyboards
00256         emit copy();
00257         break;
00258     case Key_F18:  // Paste key on Sun keyboards
00259         emit paste();
00260         break;
00261     case Key_F20:  // Cut key on Sun keyboards
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             //kdDebug(32500) << "KoTextView::keyPressEvent ascii=" << e->ascii() << " text=" << e->text()[0].unicode() << " state=" << e->state() << endl;
00280             if ( e->text().length() &&
00281 //               !( e->state() & AltButton ) &&
00282                  ( !e->ascii() || e->ascii() >= 32 ) ||
00283                  ( e->text() == "\t" && !( e->state() & ControlButton ) ) ) {
00284                 clearUndoRedoInfo = FALSE;
00285                 if ( e->key() == Key_Tab ) {
00286                     // We don't have support for nested counters at the moment.
00287                     /*if ( m_cursor->index() == 0 && m_cursor->parag()->style() &&
00288                          m_cursor->parag()->style()->displayMode() == QStyleSheetItem::DisplayListItem ) {
00289                         m_cursor->parag()->incDepth();
00290                         emit hideCursor();
00291                         emit repaintChanged();
00292                         emit showCursor();
00293                         break;
00294                     }*/
00295                 }
00296                 // Port to setCounter if we really want that - and make configurable
00297                 /*if ( m_cursor->parag()->style() &&
00298                      m_cursor->parag()->style()->displayMode() == QStyleSheetItem::DisplayBlock &&
00299                      m_cursor->index() == 0 && ( e->text() == "-" || e->text() == "*" ) ) {
00300                     setParagType( QStyleSheetItem::DisplayListItem, QStyleSheetItem::ListDisc );
00301                     break;
00302                 }*/
00303                 QString text = e->text();
00304 
00305                 // Alt+123 feature
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                     // Bidi support: need to reverse mirrored chars (e.g. parenthesis)
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                         // Don't use 'p' past this point. If we replaced a selection, p could have been deleted (#48999)
00332                         doAutoFormat( m_cursor, m_cursor->parag(), m_cursor->index() - 1, text[ text.length() - 1 ] );
00333                     }
00334                 }
00335                 break;
00336             }
00337             // We should use KAccel instead, to make this configurable !
00338             // Well, those are all alternate keys, for keys already configurable (KDE-wide)
00339             // and a kaccel makes it hard to
00340             if ( e->state() & ControlButton ) {
00341                 switch ( e->key() ) {
00342                 case Key_F16: // Copy key on Sun keyboards
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 ) // e.g. not when pressing Ctrl/PgDown after the last parag
00420     {
00421         ensureCursorVisible();
00422         // updateUI( true ); // done by moveCursor
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     // The above is almost correct, but gotoWordRight also skips the spaces/punctuations
00506     // until the next word. So the 'word under cursor' contained e.g. that trailing space.
00507     // To be on the safe side, we skip spaces/punctuations on both sides:
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         // Copy the selection.
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     //else // it may be that the initial click was out of the frame
00566     //    textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
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     //kdDebug(32500) << "KoTextView::mousePressEvent redraw=" << redraw << endl;
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     // Double click + mouse still down + moving the mouse selects full words.
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 // it may be that the initial click was out of the frame
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         // Copy the selection.
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   //after a triple click it's not a double click but a simple click
00713   //but as triple click didn't exist it's necessary to do it.
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     // Copy the selection.
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& /* Currently unused */ )
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             //FIXME me bidi.
00794             //change parag alignment => right alignment
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     //kdDebug(32500) << "KoTextView::blinkCursor m_cursorVisible=" << m_cursorVisible
00831     //          << " blinkCursorVisible=" << blinkCursorVisible << endl;
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     // The rest is up to the app ;)
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 /*void KoTextView::setFormat( KoTextFormat * newFormat, int flags, bool zoomFont)
00859 {
00860     textObject()->setFormat( m_cursor, m_currentFormat, newFormat, flags, zoomFont );
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 /*force*/ )
00884 {
00885     // Update UI - only for those items which have changed
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     //kdDebug(32500) << "KoTextView::showCurrentFormat currentFormat=" << currentFormat() << " " << currentFormat()->key() << endl;
00923     KoTextFormat format = *currentFormat();
00924     //format.setPointSize( textObject()->docFontSize( currentFormat() ) ); // "unzoom" the font size
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             //laurent : don't try to search thesaurus when we have a customItemChar.
00995             if( text.find(KoTextObject::customItemChar())!=-1)
00996                 text = QString::null;
00997         }
00998     }
00999     else // No selection -> use word under cursor
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()) // Nothing to apply a tool to
01010         return QPtrList<KAction>();
01011 
01012     // Any tool that works on plain text is relevant
01013     QValueList<KDataToolInfo> tools;
01014     tools +=KDataToolInfo::query( "QString", "text/plain", instance );
01015 
01016     // Add tools that work on a single word if that is the case
01017     if ( m_singleWord )
01018     {
01019         _singleWord = true;
01020         tools += KDataToolInfo::query( "QString", "application/x-singleword", instance );
01021     }
01022     // Maybe one day we'll have tools that use libkotext (or qt3's qrt), to act on formatted text
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     // Preferred type is richtext
01057     QString mimetype = "application/x-qrichtext";
01058     QString datatype = "KoTextString";
01059     // If unsupported, try text/plain
01060     if ( !info.mimeTypes().contains( mimetype ) )
01061     {
01062         mimetype = "text/plain";
01063         datatype = "QString";
01064     }
01065     // If unsupported (and if we have a single word indeed), try application/x-singleword
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                 // Warning: ok for now, but wrong cursor if RMB doesn't place cursor anymore
01080                 selectWordUnderCursor( *m_cursor );
01081             }
01082             // replace selection with 'text'
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) /* see QRichText */,
01103                           false /* no newline */, true, i18n("Insert Soft Hyphen") );
01104 }
01105 
01106 void KoTextView::insertLineBreak()
01107 {
01108     textObject()->insert( cursor(), currentFormat(), QChar('\n'),
01109                           false /* no newline */, true, i18n("Insert Line Break") );
01110 }
01111 
01112 void KoTextView::insertNonbreakingSpace()
01113 {
01114     textObject()->insert( cursor(), currentFormat(), QChar(0xa0) /* see QRichText */,
01115                           false /* no newline */, 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 //void KoTextView::setParagLayoutFormat( KoParagLayout *newLayout,int flags,int marginIndex)
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         // Dropping into the selection itself ?
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/*(tmp ==textFrameSet())*/
01207                           && ( dropCursor.parag() == startSel.parag() )
01208                           && dropCursor.index() >= startSel.index()
01209                           && dropCursor.index() <= endSel.index();
01210         else
01211         {
01212             // Looking at first line first:
01213             inSelection = /*(tmp ==textFrameSet())*/dropInSameObj && dropCursor.parag() == startSel.parag() && dropCursor.index() >= startSel.index();
01214             if ( !inSelection )
01215             {
01216                 // Look at all other paragraphs except last one
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                 // Look at last paragraph
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         // Tricky. We don't want to do the placeCursor after removing the selection
01245         // (the user pointed at some text with the old selection in place).
01246         // However, something got deleted in our parag, dropCursor's index needs adjustment.
01247         if ( endSel.parag() == dropCursor.parag() )
01248         {
01249             // Does the selection starts before (other parag or same parag) ?
01250             if ( startSel.parag() != dropCursor.parag() || startSel.index() < dropCursor.index() )
01251             {
01252                 // If other -> endSel.parag() will get deleted. The final position is in startSel.parag(),
01253                 // where the selection started + how much after the end we are. Make a drawing :)
01254                 // If same -> simply move back by how many chars we've deleted. Funny thing is, it's the same formula.
01255                 int dropIndex = dropCursor.index();
01256                 dropCursor.setParag( startSel.parag() );
01257                 // If dropCursor - endSel < 0, selection ends after, we're dropping into selection (no-op)
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     // Select this new style - hmm only the parag layout, we don't want to erase any text-formatting
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     // delete bookManager;
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"
KDE Logo
This file is part of the documentation for lib Library Version 1.3.5.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Nov 17 13:19:26 2004 by doxygen 1.3.5 written by Dimitri van Heesch, © 1997-2003