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.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Fri Sep 24 18:22:27 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003