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         const QChar ch = s->at(i).c;
00513         // This list comes from KoTextCursor::gotoPreviousWord.
00514         // Can't use QChar::isPunct since "'" and "-" are not word separators
00515         const bool isWordDelimiter = ch.isSpace() || ch == '.' ||
00516                                      ch == ',' || ch == ':' || ch == ';';
00517 
00518         if( !beginFound && !isWordDelimiter )
00519         {
00520             c1.setIndex(i);
00521             beginFound = true;
00522         }
00523         else if ( beginFound && isWordDelimiter )
00524         {
00525             c2.setIndex(i);
00526             break;
00527         }
00528     }
00529 
00530     textDocument()->setSelectionStart( selectionId, &c1 );
00531     textDocument()->setSelectionEnd( selectionId, &c2 );
00532     return c2;
00533 }
00534 
00535 KoTextCursor KoTextView::selectParagUnderCursor( const KoTextCursor& cursor, int selectionId, bool copyAndNotify )
00536 {
00537     KoTextCursor c1 = cursor;
00538     KoTextCursor c2 = cursor;
00539     c1.setIndex(0);
00540     c2.setIndex(c1.parag()->string()->length() - 1);
00541     textDocument()->setSelectionStart( selectionId, &c1 );
00542     textDocument()->setSelectionEnd( selectionId, &c2 );
00543     if ( copyAndNotify )
00544     {
00545         textObject()->selectionChangedNotify();
00546         // Copy the selection.
00547         QApplication::clipboard()->setSelectionMode( true );
00548         emit copy();
00549         QApplication::clipboard()->setSelectionMode( false );
00550     }
00551     return c2;
00552 }
00553 
00554 void KoTextView::extendParagraphSelection( const QPoint& iPoint )
00555 {
00556     hideCursor();
00557     KoTextCursor oldCursor = *m_cursor;
00558     placeCursor( iPoint );
00559 
00560     bool redraw = FALSE;
00561     if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
00562     {
00563         redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
00564         if ( textDocument()->isSelectionSwapped( KoTextDocument::Standard ) )
00565             m_cursor->setIndex( 0 );
00566         else
00567             m_cursor->setIndex( m_cursor->parag()->string()->length() - 1 );
00568         textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor );
00569     }
00570     //else // it may be that the initial click was out of the frame
00571     //    textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
00572 
00573     if ( redraw )
00574         textObject()->selectionChangedNotify( false );
00575 
00576     showCursor();
00577 }
00578 
00579 QString KoTextView::wordUnderCursor( const KoTextCursor& cursor )
00580 {
00581     selectWordUnderCursor( cursor, KoTextDocument::Temp );
00582     QString text = textObject()->selectedText( KoTextDocument::Temp );
00583     bool hasCustomItems = textObject()->selectionHasCustomItems( KoTextDocument::Temp );
00584     textDocument()->removeSelection( KoTextDocument::Temp );
00585     if( !hasCustomItems )
00586         return text;
00587     return QString::null;
00588 }
00589 
00590 bool KoTextView::handleMousePressEvent( QMouseEvent *e, const QPoint &iPoint, bool canStartDrag, bool insertDirectCursor )
00591 {
00592     bool addParag = false;
00593     mightStartDrag = FALSE;
00594     hideCursor();
00595 
00596     if (possibleTripleClick)
00597     {
00598         handleMouseTripleClickEvent( e, iPoint );
00599         return addParag;
00600     }
00601 
00602     KoTextCursor oldCursor = *m_cursor;
00603     addParag = placeCursor( iPoint, insertDirectCursor&& isReadWrite() );
00604     ensureCursorVisible();
00605 
00606     if ( e->button() != LeftButton )
00607     {
00608         showCursor();
00609         return addParag;
00610     }
00611 
00612     KoTextDocument * textdoc = textDocument();
00613     if ( canStartDrag && textdoc->inSelection( KoTextDocument::Standard, iPoint ) ) {
00614         mightStartDrag = TRUE;
00615         m_textobj->emitShowCursor();
00616         dragStartTimer->start( QApplication::startDragTime(), TRUE );
00617         dragStartPos = e->pos();
00618         return addParag;
00619     }
00620 
00621     bool redraw = FALSE;
00622     if ( textdoc->hasSelection( KoTextDocument::Standard ) ) {
00623         if ( !( e->state() & ShiftButton ) ) {
00624             redraw = textdoc->removeSelection( KoTextDocument::Standard );
00625             textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
00626         } else {
00627             redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
00628         }
00629     } else {
00630         if ( !( e->state() & ShiftButton ) ) {
00631             textdoc->setSelectionStart( KoTextDocument::Standard, m_cursor );
00632         } else {
00633             textdoc->setSelectionStart( KoTextDocument::Standard, &oldCursor );
00634             redraw = textdoc->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
00635         }
00636     }
00637 
00638     //kdDebug(32500) << "KoTextView::mousePressEvent redraw=" << redraw << endl;
00639     if ( !redraw ) {
00640         showCursor();
00641     } else {
00642         textObject()->selectionChangedNotify();
00643     }
00644     return addParag;
00645 }
00646 
00647 void KoTextView::handleMouseMoveEvent( QMouseEvent*, const QPoint& iPoint )
00648 {
00649     hideCursor();
00650     KoTextCursor oldCursor = *m_cursor;
00651     placeCursor( iPoint );
00652 
00653     // Double click + mouse still down + moving the mouse selects full words.
00654     if ( inDoubleClick ) {
00655         KoTextCursor cl = *m_cursor;
00656         cl.gotoWordLeft();
00657         KoTextCursor cr = *m_cursor;
00658         cr.gotoWordRight();
00659 
00660         int diff = QABS( oldCursor.parag()->at( oldCursor.index() )->x - iPoint.x() );
00661         int ldiff = QABS( cl.parag()->at( cl.index() )->x - iPoint.x() );
00662         int rdiff = QABS( cr.parag()->at( cr.index() )->x - iPoint.x() );
00663 
00664         if ( m_cursor->parag()->lineStartOfChar( m_cursor->index() ) !=
00665              oldCursor.parag()->lineStartOfChar( oldCursor.index() ) )
00666             diff = 0xFFFFFF;
00667 
00668         if ( rdiff < diff && rdiff < ldiff )
00669             *m_cursor = cr;
00670         else if ( ldiff < diff && ldiff < rdiff )
00671             *m_cursor = cl;
00672         else
00673             *m_cursor = oldCursor;
00674     }
00675 
00676     bool redraw = FALSE;
00677     if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
00678         redraw = textDocument()->setSelectionEnd( KoTextDocument::Standard, m_cursor ) || redraw;
00679     else // it may be that the initial click was out of the frame
00680         textDocument()->setSelectionStart( KoTextDocument::Standard, m_cursor );
00681 
00682     if ( redraw )
00683         textObject()->selectionChangedNotify( false );
00684 
00685     showCursor();
00686 }
00687 
00688 void KoTextView::handleMouseReleaseEvent()
00689 {
00690     if ( dragStartTimer->isActive() )
00691         dragStartTimer->stop();
00692     if ( mightStartDrag ) {
00693         textObject()->selectAll( FALSE );
00694         mightStartDrag = false;
00695     }
00696     else
00697     {
00698         if ( textDocument()->selectionStartCursor( KoTextDocument::Standard ) == textDocument()->selectionEndCursor( KoTextDocument::Standard ) )
00699         {
00700             textDocument()->removeSelection( KoTextDocument::Standard );
00701         }
00702 
00703         textObject()->selectionChangedNotify();
00704 
00705         // Copy the selection.
00706         QApplication::clipboard()->setSelectionMode( true );
00707         emit copy();
00708         QApplication::clipboard()->setSelectionMode( false );
00709     }
00710 
00711     inDoubleClick = FALSE;
00712     m_textobj->emitShowCursor();
00713 }
00714 
00715 void KoTextView::handleMouseDoubleClickEvent( QMouseEvent*ev, const QPoint& i )
00716 {
00717   //after a triple click it's not a double click but a simple click
00718   //but as triple click didn't exist it's necessary to do it.
00719     if(afterTripleClick)
00720     {
00721         handleMousePressEvent( ev, i );
00722         return;
00723     }
00724 
00725     inDoubleClick = TRUE;
00726     *m_cursor = selectWordUnderCursor( *m_cursor );
00727     textObject()->selectionChangedNotify();
00728     // Copy the selection.
00729     QApplication::clipboard()->setSelectionMode( true );
00730     emit copy();
00731     QApplication::clipboard()->setSelectionMode( false );
00732 
00733     possibleTripleClick=true;
00734 
00735     QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(tripleClickTimeout()));
00736 }
00737 
00738 void KoTextView::tripleClickTimeout()
00739 {
00740    possibleTripleClick=false;
00741 }
00742 
00743 void KoTextView::handleMouseTripleClickEvent( QMouseEvent*ev, const QPoint& /* Currently unused */ )
00744 {
00745     if ( ev->button() != LeftButton)
00746     {
00747         showCursor();
00748         return;
00749     }
00750     afterTripleClick= true;
00751     inDoubleClick = FALSE;
00752     *m_cursor = selectParagUnderCursor( *m_cursor );
00753     QTimer::singleShot(QApplication::doubleClickInterval(),this,SLOT(afterTripleClickTimeout()));
00754 }
00755 
00756 void KoTextView::afterTripleClickTimeout()
00757 {
00758     afterTripleClick=false;
00759 }
00760 
00761 bool KoTextView::maybeStartDrag( QMouseEvent* e )
00762 {
00763     if ( mightStartDrag ) {
00764         dragStartTimer->stop();
00765         if ( ( e->pos() - dragStartPos ).manhattanLength() > QApplication::startDragDistance() )
00766             startDrag();
00767         return true;
00768     }
00769     return false;
00770 }
00771 
00772 bool KoTextView::insertParagraph(const QPoint &pos)
00773 {
00774     KoTextParag *last = textDocument()->lastParag();
00775     KoTextFormat *f = 0;
00776     KoStyle *style = last->style();
00777     KoParagCounter *counter = last->counter();
00778     int diff = (pos.y()- textDocument()->height());
00779     f = last->at( last->length()-1 )->format();
00780     int height =f->height();
00781     int nbParag = (diff / height);
00782     QFontMetrics fm = f->refFontMetrics();
00783     for (int i = 0; i < nbParag ;i++)
00784     {
00785         KoTextParag *s=textDocument()->createParag( textDocument(), last );
00786         if ( f )
00787         s->setFormat( 0, 1, f, TRUE );
00788         if ( style )
00789             s->setStyle( style );
00790         s->setCounter( counter );
00791         last = s;
00792     }
00793     bool createParag = (nbParag > 0 );
00794     if ( createParag )
00795     {
00796         if ( pos.x() + f->width(' ') >= textDocument()->width())
00797         {
00798             //FIXME me bidi.
00799             //change parag alignment => right alignment
00800             last->setAlignment( Qt::AlignRight );
00801         }
00802         else
00803         {
00804             int nbSpace = pos.x()/f->width(' ');
00805             QString tmp;
00806             for (int i = 0; i< nbSpace; i++)
00807             {
00808                 tmp+=' ';
00809             }
00810             last->insert( 0, tmp );
00811         }
00812     }
00813     return createParag;
00814 
00815 }
00816 
00817 bool KoTextView::placeCursor( const QPoint &pos, bool insertDirectCursor )
00818 {
00819     bool addParag = false;
00820     m_cursor->restoreState();
00821     if ( insertDirectCursor && (pos.y()>textDocument()->height()) )
00822         addParag = insertParagraph(pos);
00823     KoTextParag *s = 0L;
00824     if ( addParag )
00825         s = textDocument()->lastParag();
00826     else
00827         s = textDocument()->firstParag();
00828     m_cursor->place( pos, s, false, &variablePosition );
00829     updateUI( true );
00830     return addParag;
00831 }
00832 
00833 void KoTextView::blinkCursor()
00834 {
00835     //kdDebug(32500) << "KoTextView::blinkCursor m_cursorVisible=" << m_cursorVisible
00836     //          << " blinkCursorVisible=" << blinkCursorVisible << endl;
00837     if ( !m_cursorVisible )
00838         return;
00839     bool cv = m_cursorVisible;
00840     blinkCursorVisible = !blinkCursorVisible;
00841     drawCursor( blinkCursorVisible );
00842     m_cursorVisible = cv;
00843 }
00844 
00845 void KoTextView::drawCursor( bool visible )
00846 {
00847     m_cursorVisible = visible;
00848     // The rest is up to the app ;)
00849 }
00850 
00851 void KoTextView::focusInEvent()
00852 {
00853     blinkTimer->start( QApplication::cursorFlashTime() / 2 );
00854     showCursor();
00855 }
00856 
00857 void KoTextView::focusOutEvent()
00858 {
00859     blinkTimer->stop();
00860     hideCursor();
00861 }
00862 
00863 /*void KoTextView::setFormat( KoTextFormat * newFormat, int flags, bool zoomFont)
00864 {
00865     textObject()->setFormat( m_cursor, m_currentFormat, newFormat, flags, zoomFont );
00866 }*/
00867 
00868 KCommand* KoTextView::setFormatCommand( const KoTextFormat * newFormat, int flags, bool zoomFont)
00869 {
00870     return textObject()->setFormatCommand( m_cursor, &m_currentFormat, newFormat, flags, zoomFont );
00871 }
00872 
00873 void KoTextView::dragStarted()
00874 {
00875     mightStartDrag = FALSE;
00876     inDoubleClick = FALSE;
00877 }
00878 
00879 void KoTextView::applyStyle( const KoStyle * style )
00880 {
00881     if ( style )
00882     {
00883         textObject()->applyStyle( m_cursor, style );
00884         showCurrentFormat();
00885     }
00886 }
00887 
00888 void KoTextView::updateUI( bool updateFormat, bool /*force*/ )
00889 {
00890     // Update UI - only for those items which have changed
00891 
00892     if ( updateFormat )
00893     {
00894         int i = cursor()->index();
00895         if ( i > 0 )
00896             --i;
00897 #ifdef DEBUG_FORMATS
00898         if ( currentFormat() )
00899             kdDebug(32500) << "KoTextView::updateUI old currentFormat=" << currentFormat()
00900                            << " " << currentFormat()->key()
00901                            << " parag format=" << cursor()->parag()->at( i )->format()->key() << endl;
00902         else
00903             kdDebug(32500) << "KoTextView::updateUI old currentFormat=0" << endl;
00904 #endif
00905         if ( !currentFormat() || currentFormat()->key() != cursor()->parag()->at( i )->format()->key() )
00906         {
00907             if ( currentFormat() )
00908                 currentFormat()->removeRef();
00909 #ifdef DEBUG_FORMATS
00910             kdDebug(32500) << "Setting currentFormat from format " << cursor()->parag()->at( i )->format()
00911                       << " ( character " << i << " in paragraph " << cursor()->parag()->paragId() << " )" << endl;
00912 #endif
00913             setCurrentFormat( textDocument()->formatCollection()->format( cursor()->parag()->at( i )->format() ) );
00914             if ( currentFormat()->isMisspelled() ) {
00915                 KoTextFormat fNoMisspelled( *currentFormat() );
00916                 fNoMisspelled.setMisspelled( false );
00917                 currentFormat()->removeRef();
00918                 setCurrentFormat( textDocument()->formatCollection()->format( &fNoMisspelled ) );
00919             }
00920             showCurrentFormat();
00921         }
00922     }
00923 }
00924 
00925 void KoTextView::showCurrentFormat()
00926 {
00927     //kdDebug(32500) << "KoTextView::showCurrentFormat currentFormat=" << currentFormat() << " " << currentFormat()->key() << endl;
00928     KoTextFormat format = *currentFormat();
00929     //format.setPointSize( textObject()->docFontSize( currentFormat() ) ); // "unzoom" the font size
00930     showFormat( &format );
00931 }
00932 
00933 KCommand * KoTextView::setCounterCommand( const KoParagCounter & counter )
00934 {
00935      return textObject()->setCounterCommand( m_cursor, counter );
00936 }
00937 KCommand * KoTextView::setAlignCommand( int align )
00938 {
00939      return textObject()->setAlignCommand( m_cursor, align );
00940 }
00941 KCommand * KoTextView::setLineSpacingCommand( double spacing, KoParagLayout::SpacingType _type)
00942 {
00943      return textObject()->setLineSpacingCommand( m_cursor, spacing, _type);
00944 }
00945 KCommand * KoTextView::setBordersCommand( const KoBorder& leftBorder, const KoBorder& rightBorder, const KoBorder& bottomBorder, const KoBorder& topBorder )
00946 {
00947     return textObject()->setBordersCommand( m_cursor, leftBorder, rightBorder, bottomBorder, topBorder );
00948 }
00949 KCommand * KoTextView::setMarginCommand( QStyleSheetItem::Margin m, double margin )
00950 {
00951     return textObject()->setMarginCommand( m_cursor, m, margin );
00952 }
00953 KCommand * KoTextView::setTabListCommand( const KoTabulatorList & tabList )
00954 {
00955     return textObject()->setTabListCommand( m_cursor, tabList );
00956 }
00957 
00958 KoTextDocument * KoTextView::textDocument() const
00959 {
00960     return textObject()->textDocument();
00961 }
00962 
00963 KoVariable *KoTextView::variable()
00964 {
00965     if ( variablePosition > -1 ) 
00966     {
00967         KoTextStringChar * ch = m_cursor->parag()->at( variablePosition );
00968         ch = m_cursor->parag()->at( variablePosition );
00969         if(ch->isCustom())
00970             return dynamic_cast<KoVariable *>(ch->customItem());
00971     }
00972     return 0L;
00973 }
00974 
00975 KoLinkVariable * KoTextView::linkVariable()
00976 {
00977     return dynamic_cast<KoLinkVariable *>(variable());
00978 }
00979 
00980 QPtrList<KAction> KoTextView::dataToolActionList(KInstance * instance, const QString& word, bool & _singleWord )
00981 {
00982     m_singleWord = false;
00983     m_wordUnderCursor = QString::null;
00984     m_refLink= QString::null;
00985     KoLinkVariable* linkVar = linkVariable();
00986     if(linkVar)
00987         m_refLink = linkVar->url();
00988     QString text;
00989     if ( textObject()->hasSelection() )
00990     {
00991         text = textObject()->selectedText();
00992         if ( text.find(' ') == -1 && text.find('\t') == -1 && text.find(KoTextObject::customItemChar()) == -1 )
00993         {
00994             m_singleWord = true;
00995         }
00996         else
00997          {
00998             m_singleWord = false;
00999             //laurent : don't try to search thesaurus when we have a customItemChar.
01000             if( text.find(KoTextObject::customItemChar())!=-1)
01001                 text = QString::null;
01002         }
01003     }
01004     else // No selection -> use word under cursor
01005     {
01006         if ( !word.isEmpty() )
01007         {
01008             m_singleWord = true;
01009             m_wordUnderCursor = word;
01010             text = word;
01011         }
01012     }
01013 
01014     if ( text.isEmpty() || textObject()->protectContent()) // Nothing to apply a tool to
01015         return QPtrList<KAction>();
01016 
01017     // Any tool that works on plain text is relevant
01018     QValueList<KDataToolInfo> tools;
01019     tools +=KDataToolInfo::query( "QString", "text/plain", instance );
01020 
01021     // Add tools that work on a single word if that is the case
01022     if ( m_singleWord )
01023     {
01024         _singleWord = true;
01025         tools += KDataToolInfo::query( "QString", "application/x-singleword", instance );
01026     }
01027     // Maybe one day we'll have tools that use libkotext (or qt3's qrt), to act on formatted text
01028     tools += KDataToolInfo::query( "KoTextString", "application/x-qrichtext", instance );
01029 
01030     return KDataToolAction::dataToolActionList( tools, this, SLOT( slotToolActivated( const KDataToolInfo &, const QString & ) ) );
01031 }
01032 
01033 QString KoTextView::underCursorWord()
01034 {
01035     QString text;
01036     if ( textObject()->hasSelection() )
01037         text = textObject()->selectedText();
01038     else
01039         text = m_wordUnderCursor;
01040     return text;
01041 }
01042 
01043 void KoTextView::slotToolActivated( const KDataToolInfo & info, const QString & command )
01044 {
01045     KDataTool* tool = info.createTool( );
01046     if ( !tool )
01047     {
01048         kdWarning() << "Could not create Tool !" << endl;
01049         return;
01050     }
01051 
01052     kdDebug(32500) << "KWTextFrameSetEdit::slotToolActivated command=" << command
01053               << " dataType=" << info.dataType() << endl;
01054 
01055     QString text;
01056     if ( textObject()->hasSelection() )
01057         text = textObject()->selectedText();
01058     else
01059         text = m_wordUnderCursor;
01060 
01061     // Preferred type is richtext
01062     QString mimetype = "application/x-qrichtext";
01063     QString datatype = "KoTextString";
01064     // If unsupported, try text/plain
01065     if ( !info.mimeTypes().contains( mimetype ) )
01066     {
01067         mimetype = "text/plain";
01068         datatype = "QString";
01069     }
01070     // If unsupported (and if we have a single word indeed), try application/x-singleword
01071     if ( !info.mimeTypes().contains( mimetype ) && m_singleWord )
01072         mimetype = "application/x-singleword";
01073 
01074     kdDebug(32500) << "Running tool with datatype=" << datatype << " mimetype=" << mimetype << endl;
01075 
01076     QString origText = text;
01077     if ( tool->run( command, &text, datatype, mimetype) )
01078     {
01079         kdDebug(32500) << "Tool ran. Text is now " << text << endl;
01080         if ( origText != text )
01081         {
01082             if ( !textObject()->hasSelection() )
01083             {
01084                 // Warning: ok for now, but wrong cursor if RMB doesn't place cursor anymore
01085                 selectWordUnderCursor( *m_cursor );
01086             }
01087             // replace selection with 'text'
01088             textObject()->emitNewCommand( textObject()->replaceSelectionCommand(
01089                 cursor(), text, KoTextDocument::Standard, i18n("Replace Word") ));
01090         }
01091     }
01092     delete tool;
01093 }
01094 
01095 void KoTextView::openLink()
01096 {
01097     KURL url( m_refLink );
01098     if( url.isValid() )
01099         (void) new KRun( url );
01100     else
01101         KMessageBox::sorry(0L,i18n("%1 is not a valid link.").arg(m_refLink));
01102 }
01103 
01104 
01105 void KoTextView::insertSoftHyphen()
01106 {
01107     textObject()->insert( cursor(), currentFormat(), QChar(0xad) /* see QRichText */,
01108                           false /* no newline */, true, i18n("Insert Soft Hyphen") );
01109 }
01110 
01111 void KoTextView::insertLineBreak()
01112 {
01113     textObject()->insert( cursor(), currentFormat(), QChar('\n'),
01114                           false /* no newline */, true, i18n("Insert Line Break") );
01115 }
01116 
01117 void KoTextView::insertNonbreakingSpace()
01118 {
01119     textObject()->insert( cursor(), currentFormat(), QChar(0xa0) /* see QRichText */,
01120                           false /* no newline */, true, i18n("Insert Non-Breaking Space") );
01121 }
01122 
01123 void KoTextView::insertSpecialChar(QChar _c, const QString& font)
01124 {
01125     KoTextFormat * newFormat = new KoTextFormat(*currentFormat());
01126     newFormat->setFamily( font );
01127     if ( textObject()->hasSelection() )
01128     {
01129         KoTextFormat * lastFormat = currentFormat();
01130 
01131         KCommand *cmd = textObject()->setFormatCommand( cursor(), &lastFormat, newFormat, KoTextFormat::Family );
01132 
01133         KMacroCommand* macroCmd = new KMacroCommand( i18n("Insert Special Char") );
01134         macroCmd->addCommand( cmd );
01135         macroCmd->addCommand( textObject()->replaceSelectionCommand(
01136                                   cursor(), _c, KoTextDocument::Standard, QString::null) );
01137         textObject()->emitNewCommand( macroCmd );
01138     }
01139     else
01140     {
01141         textObject()->insert( cursor(), newFormat, _c, false, true, i18n("Insert Special Char"));
01142         delete newFormat;
01143     }
01144 }
01145 
01146 const KoParagLayout * KoTextView::currentParagLayoutFormat() const
01147 {
01148     KoTextParag * parag = m_cursor->parag();
01149     return &(parag->paragLayout());
01150 }
01151 
01152 bool KoTextView::rtl() const
01153 {
01154     return m_cursor->parag()->string()->isRightToLeft();
01155 }
01156 
01157 //void KoTextView::setParagLayoutFormat( KoParagLayout *newLayout,int flags,int marginIndex)
01158 KCommand* KoTextView::setParagLayoutFormatCommand( KoParagLayout *newLayout,int flags,int marginIndex)
01159 {
01160 #if 0
01161     KCommand *cmd =0L;
01162     KoParagCounter c;
01163     if(newLayout->counter)
01164         c=*newLayout->counter;
01165     switch(flags)
01166     {
01167     case KoParagLayout::Alignment:
01168     {
01169         cmd = textObject()->setAlignCommand( m_cursor, newLayout->alignment );
01170         break;
01171     }
01172     case KoParagLayout::Tabulator:
01173         cmd= textObject()->setTabListCommand( m_cursor, newLayout->tabList() );
01174         break;
01175     case KoParagLayout::Margins:
01176         cmd= textObject()->setMarginCommand(m_cursor,(QStyleSheetItem::Margin)marginIndex, newLayout->margins[marginIndex] );
01177         break;
01178     case KoParagLayout::BulletNumber:
01179         cmd= textObject()->setCounterCommand( m_cursor, c  );
01180         break;
01181     default:
01182         break;
01183     }
01184     if (cmd)
01185        textObject()->emitNewCommand( cmd );
01186 #endif
01187     return textObject()->setParagLayoutFormatCommand( m_cursor, KoTextDocument::Standard, newLayout, flags, marginIndex );
01188 }
01189 
01190 KCommand *KoTextView::setChangeCaseOfTextCommand(KoChangeCaseDia::TypeOfCase _type)
01191 {
01192     QString text;
01193     if ( textObject()->hasSelection() )
01194         text = textObject()->selectedText();
01195     if(!text.isEmpty())
01196         return textObject()->changeCaseOfText(cursor(), _type);
01197     else
01198         return 0L;
01199 }
01200 
01201 KCommand *KoTextView::dropEvent( KoTextObject *tmp, KoTextCursor dropCursor, bool dropInSameObj)
01202 {
01203     KMacroCommand *macroCmd=new KMacroCommand(i18n("Paste Text"));
01204     if ( tmp->hasSelection() )
01205     {
01206         // Dropping into the selection itself ?
01207         KoTextCursor startSel = textDocument()->selectionStartCursor( KoTextDocument::Standard );
01208         KoTextCursor endSel = textDocument()->selectionEndCursor( KoTextDocument::Standard );
01209         bool inSelection = false;
01210         if ( startSel.parag() == endSel.parag() )
01211             inSelection = dropInSameObj/*(tmp ==textFrameSet())*/
01212                           && ( dropCursor.parag() == startSel.parag() )
01213                           && dropCursor.index() >= startSel.index()
01214                           && dropCursor.index() <= endSel.index();
01215         else
01216         {
01217             // Looking at first line first:
01218             inSelection = /*(tmp ==textFrameSet())*/dropInSameObj && dropCursor.parag() == startSel.parag() && dropCursor.index() >= startSel.index();
01219             if ( !inSelection )
01220             {
01221                 // Look at all other paragraphs except last one
01222                 KoTextParag *p = startSel.parag()->next();
01223                 while ( !inSelection && p && p != endSel.parag() )
01224                 {
01225                     inSelection = ( p == dropCursor.parag() );
01226                     p = p->next();
01227                 }
01228                 // Look at last paragraph
01229                 if ( !inSelection )
01230                     inSelection = dropCursor.parag() == endSel.parag() && dropCursor.index() <= endSel.index();
01231             }
01232         }
01233         if ( inSelection || m_textobj->protectContent() )
01234         {
01235             delete macroCmd;
01236             tmp->textDocument()->removeSelection( KoTextDocument::Standard );
01237             tmp->selectionChangedNotify();
01238             hideCursor();
01239             *cursor() = dropCursor;
01240             showCursor();
01241             ensureCursorVisible();
01242             return 0L;
01243         }
01244         if ( tmp->protectContent())
01245         {
01246             tmp->textDocument()->removeSelection( KoTextDocument::Standard );
01247             tmp->selectionChangedNotify();
01248         }
01249         // Tricky. We don't want to do the placeCursor after removing the selection
01250         // (the user pointed at some text with the old selection in place).
01251         // However, something got deleted in our parag, dropCursor's index needs adjustment.
01252         if ( endSel.parag() == dropCursor.parag() )
01253         {
01254             // Does the selection starts before (other parag or same parag) ?
01255             if ( startSel.parag() != dropCursor.parag() || startSel.index() < dropCursor.index() )
01256             {
01257                 // If other -> endSel.parag() will get deleted. The final position is in startSel.parag(),
01258                 // where the selection started + how much after the end we are. Make a drawing :)
01259                 // If same -> simply move back by how many chars we've deleted. Funny thing is, it's the same formula.
01260                 int dropIndex = dropCursor.index();
01261                 dropCursor.setParag( startSel.parag() );
01262                 // If dropCursor - endSel < 0, selection ends after, we're dropping into selection (no-op)
01263                 dropCursor.setIndex( dropIndex - QMIN( endSel.index(), dropIndex ) + startSel.index() );
01264             }
01265             kdDebug(32500) << "dropCursor: parag=" << dropCursor.parag()->paragId() << " index=" << dropCursor.index() << endl;
01266         }
01267         macroCmd->addCommand(tmp->removeSelectedTextCommand( cursor(), KoTextDocument::Standard ));
01268     }
01269     hideCursor();
01270     *cursor() = dropCursor;
01271     showCursor();
01272     kdDebug(32500) << "cursor set back to drop cursor: parag=" << cursor()->parag()->paragId() << " index=" << cursor()->index() << endl;
01273 
01274     return macroCmd;
01275 }
01276 
01277 
01278 void KoTextView::copyTextOfComment()
01279 {
01280     KoTextStringChar * ch = m_cursor->parag()->at( variablePosition );
01281     if(ch->isCustom())
01282     {
01283         KoNoteVariable *var=dynamic_cast<KoNoteVariable *>(ch->customItem());
01284         if( var )
01285         {
01286             KURL::List lst;
01287             lst.append( var->note() );
01288             QApplication::clipboard()->setSelectionMode(true);
01289             QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01290             QApplication::clipboard()->setSelectionMode(false);
01291             QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01292         }
01293     }
01294 }
01295 
01296 void KoTextView::removeComment()
01297 {
01298     KoTextStringChar * ch = m_cursor->parag()->at( variablePosition );
01299     if(ch->isCustom())
01300     {
01301         KoNoteVariable *var=dynamic_cast<KoNoteVariable *>(ch->customItem());
01302         if( var )
01303         {
01304             if( variablePosition == m_cursor->index() )
01305                 m_cursor->setIndex( m_cursor->index() );
01306             else
01307                 m_cursor->setIndex( m_cursor->index() -1 );
01308 
01309             textDocument()->setSelectionStart( KoTextDocument::Temp, m_cursor );
01310 
01311             if( variablePosition == m_cursor->index() )
01312                 m_cursor->setIndex( m_cursor->index() +1);
01313             else
01314                 m_cursor->setIndex( m_cursor->index()  );
01315 
01316             textDocument()->setSelectionEnd( KoTextDocument::Temp, m_cursor );
01317 
01318             textObject()->removeSelectedText( m_cursor,  KoTextDocument::Temp, i18n("Remove Comment") );
01319         }
01320     }
01321 }
01322 
01323 KoStyle * KoTextView::createStyleFromSelection(const QString & name)
01324 {
01325     KoTextCursor cursor = *m_cursor;
01326     if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
01327         cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
01328     KoStyle * style = new KoStyle (name);
01329     KoParagLayout layout(cursor.parag()->paragLayout());
01330     layout.style = style;
01331     style->setFollowingStyle( style );
01332     style->format() = *(cursor.parag()->at(cursor.index())->format());
01333 
01334     style->paragLayout() = layout;
01335     // Select this new style - hmm only the parag layout, we don't want to erase any text-formatting
01336     cursor.parag()->setParagLayout( style->paragLayout() );
01337     return style;
01338 }
01339 
01340 void KoTextView::updateStyleFromSelection( KoStyle* style )
01341 {
01342     KoTextCursor cursor = *m_cursor;
01343     if ( textDocument()->hasSelection( KoTextDocument::Standard ) )
01344         cursor = textDocument()->selectionStartCursor( KoTextDocument::Standard );
01345 
01346     style->paragLayout() = cursor.parag()->paragLayout();
01347     style->paragLayout().style = style;
01348     style->format() = *(cursor.parag()->at(cursor.index())->format());
01349 }
01350 
01351 void KoTextView::addBookmarks(const QString &url)
01352 {
01353     QString filename = locateLocal( "data", QString::fromLatin1("konqueror/bookmarks.xml") );
01354     KBookmarkManager *bookManager = KBookmarkManager::managerForFile( filename,false );
01355     KBookmarkGroup group = bookManager->root();
01356     group.addBookmark( bookManager, url, KURL( url));
01357     bookManager->save();
01358     // delete bookManager;
01359 }
01360 
01361 void KoTextView::copyLink()
01362 {
01363     KoLinkVariable * var=linkVariable();
01364     if(var)
01365     {
01366         KURL::List lst;
01367         lst.append( var->url() );
01368         QApplication::clipboard()->setSelectionMode(true);
01369         QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01370         QApplication::clipboard()->setSelectionMode(false);
01371         QApplication::clipboard()->setData( new KURLDrag(lst, 0, 0) );
01372     }
01373 }
01374 
01375 void KoTextView::removeLink()
01376 {
01377     KoLinkVariable * var=linkVariable();
01378     if(var)
01379     {
01380         KoTextCursor c1 = *m_cursor;
01381         KoTextCursor c2 = *m_cursor;
01382         c1.setIndex(var->index());
01383         c2.setIndex(var->index()+1);
01384         textDocument()->setSelectionStart( KoTextDocument::Temp, &c1 );
01385         textDocument()->setSelectionEnd( KoTextDocument::Temp, &c2 );
01386         KCommand *cmd=textObject()->replaceSelectionCommand( &c1, var->value(),
01387                                         KoTextDocument::Temp, i18n("Remove Link") );
01388         if ( cmd )
01389             textObject()->emitNewCommand( cmd );
01390     }
01391 }
01392 
01393 
01394 #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 Fri Mar 11 11:47:44 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003