00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "kateviewinternal.h"
00029 #include "kateviewinternal.moc"
00030
00031 #include "kateview.h"
00032 #include "katecodefolding.h"
00033 #include "kateviewhelpers.h"
00034 #include "katehighlight.h"
00035 #include "katesmartrange.h"
00036 #include "katerenderer.h"
00037 #include "kateconfig.h"
00038 #include "katelayoutcache.h"
00039 #include "katedynamicanimation.h"
00040 #include "katesmartmanager.h"
00041 #include "katecompletionwidget.h"
00042 #include "katenamespace.h"
00043
00044 #include <kcursor.h>
00045 #include <kdebug.h>
00046 #include <kapplication.h>
00047 #include <kglobalsettings.h>
00048
00049 #include <QtCore/QMimeData>
00050 #include <QtGui/QPainter>
00051 #include <QtGui/QLayout>
00052 #include <QtGui/QClipboard>
00053 #include <QtGui/QPixmap>
00054 #include <QtGui/QKeyEvent>
00055 #include <QtCore/QStack>
00056 #include <QtCore/QMutex>
00057 #include <QtCore/QThread>
00058
00059 static const bool debugPainting = false;
00060
00061 KateViewInternal::KateViewInternal(KateView *view, KateDocument *doc)
00062 : QWidget (view)
00063 , editSessionNumber (0)
00064 , editIsRunning (false)
00065 , m_view (view)
00066 , m_doc (doc)
00067 , m_cursor(doc)
00068 , m_mouse()
00069 , m_possibleTripleClick (false)
00070 , m_bm(doc->smartManager()->newSmartRange())
00071 , m_bmStart(doc->smartManager()->newSmartRange(KTextEditor::Range(), m_bm))
00072 , m_bmEnd(doc->smartManager()->newSmartRange(KTextEditor::Range(), m_bm))
00073 , m_bmHighlighted(false)
00074 , m_dummy (0)
00075
00076
00077 , m_startPos(doc, KTextEditor::SmartCursor::StayOnInsert)
00078
00079 , m_madeVisible(false)
00080 , m_shiftKeyPressed (false)
00081 , m_autoCenterLines (false)
00082 , m_selChangedByUser (false)
00083 , m_selectAnchor (-1, -1)
00084 , m_selectionMode( Default )
00085 , m_layoutCache(new KateLayoutCache(renderer(), this))
00086 , m_preserveMaxX(false)
00087 , m_currentMaxX(0)
00088 , m_usePlainLines(false)
00089 , m_updatingView(true)
00090 , m_cachedMaxStartPos(-1, -1)
00091 , m_dragScrollTimer(this)
00092 , m_scrollTimer (this)
00093 , m_cursorTimer (this)
00094 , m_textHintTimer (this)
00095 , m_textHintEnabled(false)
00096 , m_textHintMouseX(-1)
00097 , m_textHintMouseY(-1)
00098 , m_imPreedit(0L)
00099 , m_smartDirty(false)
00100 {
00101 m_watcherCount1 = 0;
00102 m_watcherCount3 = 0;
00103
00104 updateBracketMarkAttributes();
00105
00106 setMinimumSize (0,0);
00107 setAttribute(Qt::WA_OpaquePaintEvent);
00108 setAttribute(Qt::WA_InputMethodEnabled);
00109
00110
00111 m_cursor.setInsertBehavior (KTextEditor::SmartCursor::MoveOnInsert);
00112 m_cursor.setInternal();
00113
00114 m_startPos.setInternal();
00115
00116
00117 m_selectionCached = KTextEditor::Range::invalid();
00118
00119
00120
00121 m_lineScroll = new KateScrollBar(Qt::Vertical, this);
00122 m_lineScroll->show();
00123 m_lineScroll->setTracking (true);
00124 m_lineScroll->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Expanding );
00125
00126
00127 m_dummy = new QWidget(m_view);
00128 m_dummy->setFixedSize(m_lineScroll->width(), m_lineScroll->width());
00129 m_dummy->setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed );
00130
00131 if (m_view->dynWordWrap())
00132 m_dummy->hide();
00133 else
00134 m_dummy->show();
00135
00136 cache()->setWrap(m_view->dynWordWrap());
00137
00138
00139 connect(m_lineScroll, SIGNAL(actionTriggered(int)), SLOT(scrollAction(int)));
00140 connect(m_lineScroll, SIGNAL(sliderMoved(int)), SLOT(scrollLines(int)));
00141 connect(m_lineScroll, SIGNAL(sliderMMBMoved(int)), SLOT(scrollLines(int)));
00142
00143
00144
00145
00146
00147
00148
00149 m_columnScroll = new QScrollBar(Qt::Horizontal,m_view);
00150
00151 if (m_view->dynWordWrap())
00152 m_columnScroll->hide();
00153 else
00154 m_columnScroll->show();
00155
00156 m_columnScroll->setTracking(true);
00157 m_startX = 0;
00158
00159 connect(m_columnScroll, SIGNAL(valueChanged(int)), SLOT(scrollColumns(int)));
00160
00161
00162
00163
00164 m_leftBorder = new KateIconBorder( this, m_view );
00165 m_leftBorder->show ();
00166
00167 connect( m_leftBorder, SIGNAL(toggleRegionVisibility(unsigned int)),
00168 m_doc->foldingTree(), SLOT(toggleRegionVisibility(unsigned int)));
00169
00170 connect( doc->foldingTree(), SIGNAL(regionVisibilityChangedAt(unsigned int)),
00171 this, SLOT(slotRegionVisibilityChangedAt(unsigned int)));
00172 connect( doc, SIGNAL(codeFoldingUpdated()),
00173 this, SLOT(slotCodeFoldingChanged()) );
00174
00175 m_displayCursor.setPosition(0, 0);
00176 m_cursor.setInsertBehavior(KTextEditor::SmartCursor::MoveOnInsert);
00177 m_cursorX = 0;
00178
00179 setAcceptDrops( true );
00180
00181
00182 installEventFilter(this);
00183 m_view->viewBar()->installEventFilter(this);
00184
00185
00186 setAttribute(Qt::WA_InputMethodEnabled, true);
00187
00188
00189 m_mouseCursor = Qt::IBeamCursor;
00190 setCursor(m_mouseCursor);
00191
00192
00193 setMouseTracking(true);
00194
00195 m_dragInfo.state = diNone;
00196
00197
00198 connect( &m_dragScrollTimer, SIGNAL( timeout() ),
00199 this, SLOT( doDragScroll() ) );
00200
00201 connect( &m_scrollTimer, SIGNAL( timeout() ),
00202 this, SLOT( scrollTimeout() ) );
00203
00204 connect( &m_cursorTimer, SIGNAL( timeout() ),
00205 this, SLOT( cursorTimeout() ) );
00206
00207 connect( &m_textHintTimer, SIGNAL( timeout() ),
00208 this, SLOT( textHintTimeout() ) );
00209
00210
00211 connect( m_view, SIGNAL( selectionChanged(KTextEditor::View*) ),
00212 this, SLOT( viewSelectionChanged() ) );
00213
00214 connect(m_doc, SIGNAL(dynamicHighlightAdded(KateSmartRange*)), SLOT(dynamicHighlightAdded(KateSmartRange*)));
00215 connect(m_doc, SIGNAL(dynamicHighlightRemoved(KateSmartRange*)), SLOT(dynamicHighlightRemoved(KateSmartRange*)));
00216 connect(m_view, SIGNAL(dynamicHighlightAdded(KateSmartRange*)), SLOT(dynamicHighlightAdded(KateSmartRange*)));
00217 connect(m_view, SIGNAL(dynamicHighlightRemoved(KateSmartRange*)), SLOT(dynamicHighlightRemoved(KateSmartRange*)));
00218 connect(m_doc->smartManager(), SIGNAL(signalRangeDeleted(KateSmartRange*)), SLOT(rangeDeleted(KateSmartRange*)));
00219
00220
00221
00222
00223
00224 connect(this, SIGNAL(requestViewUpdate(bool)), this, SLOT(updateView(bool)), Qt::QueuedConnection);
00225 }
00226
00227 void KateViewInternal::removeWatcher(KTextEditor::SmartRange* range, KTextEditor::SmartRangeWatcher* watcher)
00228 {
00229 if (range->watchers().contains(this)) {
00230 --m_watcherCount1;
00231 range->removeWatcher(watcher);
00232
00233 }
00234
00235 foreach (KTextEditor::SmartRange* child, range->childRanges())
00236 removeWatcher(child, watcher);
00237 }
00238
00239 void KateViewInternal::addWatcher(KTextEditor::SmartRange* range, KTextEditor::SmartRangeWatcher* watcher)
00240 {
00241
00242
00243
00244
00245 if (!range->watchers().contains(watcher)) {
00246 range->addWatcher(watcher);
00247 ++m_watcherCount1;
00248 Q_ASSERT(range->watchers().contains(watcher));
00249
00250 }
00251
00252 foreach (KTextEditor::SmartRange* child, range->childRanges())
00253 addWatcher(child, watcher);
00254 }
00255
00256 KateViewInternal::~KateViewInternal ()
00257 {
00258
00259 disconnect(m_doc->smartManager(), SIGNAL(signalRangeDeleted(KateSmartRange*)), this, SLOT(rangeDeleted(KateSmartRange*)));
00260
00261 qDeleteAll(m_dynamicHighlights);
00262
00263 delete m_imPreedit;
00264
00265
00266 }
00267
00268 void KateViewInternal::prepareForDynWrapChange()
00269 {
00270
00271 m_wrapChangeViewLine = cache()->displayViewLine(m_displayCursor, true);
00272 }
00273
00274 void KateViewInternal::dynWrapChanged()
00275 {
00276 if (m_view->dynWordWrap())
00277 {
00278 m_columnScroll->hide();
00279 m_dummy->hide();
00280
00281 }
00282 else
00283 {
00284
00285 m_columnScroll->show();
00286 m_dummy->show();
00287 }
00288
00289 cache()->setWrap(m_view->dynWordWrap());
00290 updateView();
00291
00292 if (m_view->dynWordWrap())
00293 scrollColumns(0);
00294
00295
00296 if (m_wrapChangeViewLine != -1) {
00297 KTextEditor::Cursor newStart = viewLineOffset(m_displayCursor, -m_wrapChangeViewLine);
00298 makeVisible(newStart, newStart.column(), true);
00299
00300 } else {
00301 update();
00302 }
00303 }
00304
00305 KTextEditor::Cursor KateViewInternal::endPos() const
00306 {
00307
00308 if (!cache()->viewCacheLineCount())
00309 return KTextEditor::Cursor();
00310
00311 for (int i = qMin(linesDisplayed() - 1, cache()->viewCacheLineCount() - 1); i >= 0; i--) {
00312 const KateTextLayout& thisLine = cache()->viewLine(i);
00313
00314 if (thisLine.line() == -1) continue;
00315
00316 if (thisLine.virtualLine() >= m_doc->numVisLines()) {
00317
00318 return KTextEditor::Cursor(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1)));
00319 }
00320
00321 return KTextEditor::Cursor(thisLine.virtualLine(), thisLine.wrap() ? thisLine.endCol() - 1 : thisLine.endCol());
00322 }
00323
00324 Q_ASSERT(false);
00325 kDebug(13030) << "WARNING: could not find a lineRange at all";
00326 return KTextEditor::Cursor(-1, -1);
00327 }
00328
00329 int KateViewInternal::endLine() const
00330 {
00331 return endPos().line();
00332 }
00333
00334 KateTextLayout KateViewInternal::yToKateTextLayout(int y) const
00335 {
00336 if (y < 0 || y > size().height())
00337 return KateTextLayout::invalid();
00338
00339 int range = y / renderer()->fontHeight();
00340
00341
00342 if (range >= 0 && range <= cache()->viewCacheLineCount())
00343 return cache()->viewLine(range);
00344
00345 return KateTextLayout::invalid();
00346 }
00347
00348 int KateViewInternal::lineToY(int viewLine) const
00349 {
00350 return (viewLine-startLine()) * renderer()->fontHeight();
00351 }
00352
00353 void KateViewInternal::slotIncFontSizes()
00354 {
00355 renderer()->increaseFontSizes();
00356 }
00357
00358 void KateViewInternal::slotDecFontSizes()
00359 {
00360 renderer()->decreaseFontSizes();
00361 }
00362
00366 void KateViewInternal::scrollLines ( int line )
00367 {
00368 KTextEditor::Cursor newPos(line, 0);
00369 scrollPos(newPos);
00370 }
00371
00372
00373 void KateViewInternal::scrollViewLines(int offset)
00374 {
00375 KTextEditor::Cursor c = viewLineOffset(startPos(), offset);
00376 scrollPos(c);
00377
00378 bool blocked = m_lineScroll->blockSignals(true);
00379 m_lineScroll->setValue(startLine());
00380 m_lineScroll->blockSignals(blocked);
00381 }
00382
00383 void KateViewInternal::scrollAction( int action )
00384 {
00385 switch (action) {
00386 case QAbstractSlider::SliderSingleStepAdd:
00387 scrollNextLine();
00388 break;
00389
00390 case QAbstractSlider::SliderSingleStepSub:
00391 scrollPrevLine();
00392 break;
00393
00394 case QAbstractSlider::SliderPageStepAdd:
00395 scrollNextPage();
00396 break;
00397
00398 case QAbstractSlider::SliderPageStepSub:
00399 scrollPrevPage();
00400 break;
00401
00402 case QAbstractSlider::SliderToMinimum:
00403 top_home();
00404 break;
00405
00406 case QAbstractSlider::SliderToMaximum:
00407 bottom_end();
00408 break;
00409 }
00410 }
00411
00412 void KateViewInternal::scrollNextPage()
00413 {
00414 scrollViewLines(qMax( linesDisplayed() - 1, 0 ));
00415 }
00416
00417 void KateViewInternal::scrollPrevPage()
00418 {
00419 scrollViewLines(-qMax( linesDisplayed() - 1, 0 ));
00420 }
00421
00422 void KateViewInternal::scrollPrevLine()
00423 {
00424 scrollViewLines(-1);
00425 }
00426
00427 void KateViewInternal::scrollNextLine()
00428 {
00429 scrollViewLines(1);
00430 }
00431
00432 KTextEditor::Cursor KateViewInternal::maxStartPos(bool changed)
00433 {
00434 m_usePlainLines = true;
00435 cache()->setAcceptDirtyLayouts(true);
00436
00437 if (m_cachedMaxStartPos.line() == -1 || changed)
00438 {
00439 KTextEditor::Cursor end(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1)));
00440
00441 m_cachedMaxStartPos = viewLineOffset(end, -(linesDisplayed() - 1));
00442 }
00443
00444 m_usePlainLines = false;
00445 cache()->setAcceptDirtyLayouts(false);
00446
00447 return m_cachedMaxStartPos;
00448 }
00449
00450
00451 void KateViewInternal::scrollPos(KTextEditor::Cursor& c, bool force, bool calledExternally)
00452 {
00453 if (!force && ((!m_view->dynWordWrap() && c.line() == startLine()) || c == startPos()))
00454 return;
00455
00456 if (c.line() < 0)
00457 c.setLine(0);
00458
00459 KTextEditor::Cursor limit = maxStartPos();
00460 if (c > limit) {
00461 c = limit;
00462
00463
00464 if (!force && ((!m_view->dynWordWrap() && c.line() == startLine()) || c == startPos()))
00465 return;
00466 }
00467
00468 int viewLinesScrolled = 0;
00469
00470
00471
00472
00473 bool viewLinesScrolledUsable = !force
00474 && (c.line() >= startLine() - linesDisplayed() - 1)
00475 && (c.line() <= endLine() + linesDisplayed() + 1);
00476
00477 if (viewLinesScrolledUsable)
00478 viewLinesScrolled = cache()->displayViewLine(c);
00479
00480 m_startPos.setPosition(c);
00481
00482
00483 m_madeVisible = false;
00484
00485 if (viewLinesScrolledUsable)
00486 {
00487 int lines = linesDisplayed();
00488 if (m_doc->numVisLines() < lines) {
00489 KTextEditor::Cursor end(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1)));
00490 lines = qMin(linesDisplayed(), cache()->displayViewLine(end) + 1);
00491 }
00492
00493 Q_ASSERT(lines >= 0);
00494
00495 if (!calledExternally && qAbs(viewLinesScrolled) < lines)
00496 {
00497 updateView(false, viewLinesScrolled);
00498
00499 int scrollHeight = -(viewLinesScrolled * (int)renderer()->fontHeight());
00500
00501 scroll(0, scrollHeight);
00502 m_leftBorder->scroll(0, scrollHeight);
00503
00504 emit m_view->verticalScrollPositionChanged( m_view, c );
00505 return;
00506 }
00507 }
00508
00509 updateView();
00510 update();
00511 m_leftBorder->update();
00512 emit m_view->verticalScrollPositionChanged( m_view, c );
00513 }
00514
00515 void KateViewInternal::scrollColumns ( int x )
00516 {
00517 if (x == m_startX)
00518 return;
00519
00520 if (x < 0)
00521 x = 0;
00522
00523 int dx = m_startX - x;
00524 m_startX = x;
00525
00526 if (qAbs(dx) < width())
00527 scroll(dx, 0);
00528 else
00529 update();
00530
00531 emit m_view->horizontalScrollPositionChanged( m_view );
00532
00533 bool blocked = m_columnScroll->blockSignals(true);
00534 m_columnScroll->setValue(m_startX);
00535 m_columnScroll->blockSignals(blocked);
00536 }
00537
00538
00539 void KateViewInternal::updateView(bool changed, int viewLinesScrolled)
00540 {
00541 QMutexLocker lock(m_doc->smartMutex());
00542
00543 doUpdateView(changed, viewLinesScrolled);
00544
00545 if (changed)
00546 updateDirty();
00547 }
00548
00549 void KateViewInternal::doUpdateView(bool changed, int viewLinesScrolled)
00550 {
00551 m_updatingView = true;
00552
00553 bool blocked = m_lineScroll->blockSignals(true);
00554
00555 if (width() != cache()->viewWidth())
00556 cache()->setViewWidth(width());
00557
00558
00559
00560
00561
00562
00563 int newSize = (qMax (0, height()) / renderer()->fontHeight()) + 1;
00564 cache()->updateViewCache(startPos(), newSize, viewLinesScrolled);
00565
00566 KTextEditor::Cursor maxStart = maxStartPos(changed);
00567 int maxLineScrollRange = maxStart.line();
00568 if (m_view->dynWordWrap() && maxStart.column() != 0)
00569 maxLineScrollRange++;
00570 m_lineScroll->setRange(0, maxLineScrollRange);
00571
00572 m_lineScroll->setValue(startPos().line());
00573 m_lineScroll->setSingleStep(1);
00574 m_lineScroll->setPageStep(qMax (0, height()) / renderer()->fontHeight());
00575 m_lineScroll->blockSignals(blocked);
00576
00577 if (!m_view->dynWordWrap())
00578 {
00579 int max = maxLen(startLine()) - width();
00580 if (max < 0)
00581 max = 0;
00582
00583
00584 if (max == 0)
00585 {
00586 scrollColumns(0);
00587 }
00588
00589 blocked = m_columnScroll->blockSignals(true);
00590
00591
00592 m_columnScroll->setDisabled (max == 0);
00593
00594 m_columnScroll->setRange(0, max);
00595
00596 m_columnScroll->setValue(m_startX);
00597
00598
00599 m_columnScroll->setSingleStep(renderer()->config()->fontMetrics().width('a'));
00600 m_columnScroll->setPageStep(width());
00601
00602 m_columnScroll->blockSignals(blocked);
00603 }
00604
00605 if (m_smartDirty)
00606 m_smartDirty = false;
00607
00608 m_updatingView = false;
00609 }
00610
00615 void KateViewInternal::makeVisible (const KTextEditor::Cursor& c, int endCol, bool force, bool center, bool calledExternally)
00616 {
00617
00618
00619
00620
00621
00622 if ( force )
00623 {
00624 KTextEditor::Cursor scroll = c;
00625 scrollPos(scroll, force, calledExternally);
00626 }
00627 else if (center && (c < startPos() || c > endPos()))
00628 {
00629 KTextEditor::Cursor scroll = viewLineOffset(c, -int(linesDisplayed()) / 2);
00630 scrollPos(scroll, false, calledExternally);
00631 }
00632 else if ( c > viewLineOffset(endPos(), -m_minLinesVisible) )
00633 {
00634 KTextEditor::Cursor scroll = viewLineOffset(c, -(linesDisplayed() - m_minLinesVisible - 1));
00635 scrollPos(scroll, false, calledExternally);
00636 }
00637 else if ( c < viewLineOffset(startPos(), m_minLinesVisible) )
00638 {
00639 KTextEditor::Cursor scroll = viewLineOffset(c, -m_minLinesVisible);
00640 scrollPos(scroll, false, calledExternally);
00641 }
00642 else
00643 {
00644
00645 KTextEditor::Cursor max = maxStartPos();
00646 if (startPos() > max) {
00647 scrollPos(max, max.column(), calledExternally);
00648 }
00649 }
00650
00651 if (!m_view->dynWordWrap() && endCol != -1)
00652 {
00653 int sX = renderer()->cursorToX(cache()->textLayout(c), c);
00654
00655 int sXborder = sX-8;
00656 if (sXborder < 0)
00657 sXborder = 0;
00658
00659 if (sX < m_startX)
00660 scrollColumns (sXborder);
00661 else if (sX > m_startX + width())
00662 scrollColumns (sX - width() + 8);
00663 }
00664
00665 m_madeVisible = !force;
00666 }
00667
00668 void KateViewInternal::slotRegionVisibilityChangedAt(unsigned int)
00669 {
00670 kDebug(13030) << "slotRegionVisibilityChangedAt()";
00671 m_cachedMaxStartPos.setLine(-1);
00672 KTextEditor::Cursor max = maxStartPos();
00673 if (startPos() > max)
00674 scrollPos(max);
00675
00676 updateView();
00677 update();
00678 m_leftBorder->update();
00679 }
00680
00681 void KateViewInternal::slotCodeFoldingChanged()
00682 {
00683 m_leftBorder->update();
00684 }
00685
00686 void KateViewInternal::slotRegionBeginEndAddedRemoved(unsigned int)
00687 {
00688 kDebug(13030) << "slotRegionBeginEndAddedRemoved()";
00689
00690 m_leftBorder->update();
00691 }
00692
00693 void KateViewInternal::showEvent ( QShowEvent *e )
00694 {
00695 updateView ();
00696
00697 QWidget::showEvent (e);
00698 }
00699
00700 int KateViewInternal::linesDisplayed() const
00701 {
00702 int h = height();
00703 int fh = renderer()->fontHeight();
00704
00705
00706
00707 return qMax (1, (h - (h % fh)) / fh);
00708 }
00709
00710 KTextEditor::Cursor KateViewInternal::getCursor() const
00711 {
00712 QMutexLocker l(m_doc->smartMutex());
00713
00714 return m_cursor;
00715 }
00716
00717 QPoint KateViewInternal::cursorToCoordinate( const KTextEditor::Cursor & cursor, bool realCursor, bool includeBorder ) const
00718 {
00719 QMutexLocker l(m_doc->smartMutex());
00720
00721 int viewLine = cache()->displayViewLine(realCursor ? toVirtualCursor(cursor) : cursor, true);
00722
00723 if (viewLine < 0 || viewLine >= cache()->viewCacheLineCount())
00724 return QPoint(-1, -1);
00725
00726 int y = viewLine * renderer()->fontHeight();
00727
00728 KateTextLayout layout = cache()->viewLine(viewLine);
00729 int x = (int)layout.lineLayout().cursorToX(cursor.column());
00730 if (includeBorder) x += m_leftBorder->width();
00731
00732 return QPoint(x, y);
00733 }
00734
00735 QPoint KateViewInternal::cursorCoordinates(bool includeBorder) const
00736 {
00737 return cursorToCoordinate(m_displayCursor, false, includeBorder);
00738 }
00739
00740 void KateViewInternal::doReturn()
00741 {
00742 m_doc->newLine( view() );
00743 updateView();
00744 }
00745
00746 void KateViewInternal::doDelete()
00747 {
00748 m_doc->del( m_view, m_cursor );
00749 }
00750
00751 void KateViewInternal::doBackspace()
00752 {
00753 m_doc->backspace( m_view, m_cursor );
00754 }
00755
00756 void KateViewInternal::doTranspose()
00757 {
00758 m_doc->transpose( m_cursor );
00759 }
00760
00761 void KateViewInternal::doDeleteWordLeft()
00762 {
00763 wordLeft( true );
00764 KTextEditor::Range selection = m_view->selectionRange();
00765 m_view->removeSelectedText();
00766 tagRange(selection, true);
00767 updateDirty();
00768 }
00769
00770 void KateViewInternal::doDeleteWordRight()
00771 {
00772 wordRight( true );
00773 KTextEditor::Range selection = m_view->selectionRange();
00774 m_view->removeSelectedText();
00775 tagRange(selection, true);
00776 updateDirty();
00777 }
00778
00779 class CalculatingCursor : public KTextEditor::Cursor {
00780 public:
00781 CalculatingCursor(KateViewInternal* vi)
00782 : KTextEditor::Cursor()
00783 , m_vi(vi)
00784 {
00785 Q_ASSERT(valid());
00786 }
00787
00788 CalculatingCursor(KateViewInternal* vi, const KTextEditor::Cursor& c)
00789 : KTextEditor::Cursor(c)
00790 , m_vi(vi)
00791 {
00792 Q_ASSERT(valid());
00793 }
00794
00795
00796 CalculatingCursor(KateViewInternal* vi, int line, int col)
00797 : KTextEditor::Cursor(line, col)
00798 , m_vi(vi)
00799 {
00800 makeValid();
00801 }
00802
00803
00804 virtual CalculatingCursor& operator+=( int n ) = 0;
00805
00806 virtual CalculatingCursor& operator-=( int n ) = 0;
00807
00808 CalculatingCursor& operator++() { return operator+=( 1 ); }
00809
00810 CalculatingCursor& operator--() { return operator-=( 1 ); }
00811
00812 void makeValid() {
00813 setLine(qBound( 0, line(), int( m_vi->m_doc->lines() - 1 ) ) );
00814 if (m_vi->m_view->wrapCursor())
00815 m_column = qBound( 0, column(), m_vi->m_doc->lineLength( line() ) );
00816 else
00817 m_column = qMax( 0, column() );
00818 Q_ASSERT( valid() );
00819 }
00820
00821 void toEdge( KateViewInternal::Bias bias ) {
00822 if( bias == KateViewInternal::left ) m_column = 0;
00823 else if( bias == KateViewInternal::right ) m_column = m_vi->m_doc->lineLength( line() );
00824 }
00825
00826 bool atEdge() const { return atEdge( KateViewInternal::left ) || atEdge( KateViewInternal::right ); }
00827
00828 bool atEdge( KateViewInternal::Bias bias ) const {
00829 switch( bias ) {
00830 case KateViewInternal::left: return column() == 0;
00831 case KateViewInternal::none: return atEdge();
00832 case KateViewInternal::right: return column() == m_vi->m_doc->lineLength( line() );
00833 default: Q_ASSERT(false); return false;
00834 }
00835 }
00836
00837 protected:
00838 bool valid() const {
00839 return line() >= 0 &&
00840 line() < m_vi->m_doc->lines() &&
00841 column() >= 0 &&
00842 (!m_vi->m_view->wrapCursor() || column() <= m_vi->m_doc->lineLength( line() ));
00843 }
00844 KateViewInternal* m_vi;
00845 };
00846
00847 class BoundedCursor : public CalculatingCursor {
00848 public:
00849 BoundedCursor(KateViewInternal* vi)
00850 : CalculatingCursor( vi ) {}
00851 BoundedCursor(KateViewInternal* vi, const KTextEditor::Cursor& c )
00852 : CalculatingCursor( vi, c ) {}
00853 BoundedCursor(KateViewInternal* vi, int line, int col )
00854 : CalculatingCursor( vi, line, col ) {}
00855 virtual CalculatingCursor& operator+=( int n ) {
00856 KateLineLayoutPtr thisLine = m_vi->cache()->line(line());
00857 if (!thisLine->isValid()) {
00858 kWarning() << "Did not retrieve valid layout for line " << line();
00859 return *this;
00860 }
00861
00862 const bool blockSelectionMode = m_vi->view()->blockSelection();
00863 int maxColumn = -1;
00864 if (n >= 0) {
00865 for (int i = 0; i < n; i++) {
00866 if (m_column >= thisLine->length()) {
00867 if (!blockSelectionMode) {
00868 break;
00869
00870 } else if (m_vi->view()->dynWordWrap()) {
00871
00872 if (maxColumn == -1)
00873 maxColumn = thisLine->length() + ((m_vi->width() - thisLine->widthOfLastLine()) / m_vi->renderer()->spaceWidth()) - 1;
00874
00875 if (m_column >= maxColumn) {
00876 m_column = maxColumn;
00877 break;
00878 }
00879
00880 ++m_column;
00881
00882 } else {
00883 ++m_column;
00884 }
00885
00886 } else {
00887 m_column = thisLine->layout()->nextCursorPosition(m_column);
00888 }
00889 }
00890 } else {
00891 for (int i = 0; i > n; i--) {
00892 if (m_column >= thisLine->length())
00893 --m_column;
00894 else if (m_column == 0)
00895 break;
00896 else
00897 m_column = thisLine->layout()->previousCursorPosition(m_column);
00898 }
00899 }
00900
00901 Q_ASSERT( valid() );
00902 return *this;
00903 }
00904 virtual CalculatingCursor& operator-=( int n ) {
00905 return operator+=( -n );
00906 }
00907 };
00908
00909 class WrappingCursor : public CalculatingCursor {
00910 public:
00911 WrappingCursor(KateViewInternal* vi)
00912 : CalculatingCursor( vi) {}
00913 WrappingCursor(KateViewInternal* vi, const KTextEditor::Cursor& c )
00914 : CalculatingCursor( vi, c ) {}
00915 WrappingCursor(KateViewInternal* vi, int line, int col )
00916 : CalculatingCursor( vi, line, col ) {}
00917
00918 virtual CalculatingCursor& operator+=( int n ) {
00919 KateLineLayoutPtr thisLine = m_vi->cache()->line(line());
00920 if (!thisLine->isValid()) {
00921 kWarning() << "Did not retrieve a valid layout for line " << line();
00922 return *this;
00923 }
00924
00925 if (n >= 0) {
00926 for (int i = 0; i < n; i++) {
00927 if (m_column == thisLine->length()) {
00928
00929 if (line() >= m_vi->m_doc->lines() - 1)
00930
00931 break;
00932
00933
00934 m_column = 0;
00935 setLine(line() + 1);
00936
00937
00938 thisLine = m_vi->cache()->line(line());
00939 if (!thisLine->isValid()) {
00940 kWarning() << "Did not retrieve a valid layout for line " << line();
00941 return *this;
00942 }
00943
00944 continue;
00945 }
00946
00947 m_column = thisLine->layout()->nextCursorPosition(m_column);
00948 }
00949
00950 } else {
00951 for (int i = 0; i > n; i--) {
00952 if (m_column == 0) {
00953
00954 if (line() == 0)
00955 break;
00956
00957
00958 setLine(line() - 1);
00959
00960
00961 thisLine = m_vi->cache()->line(line());
00962 if (!thisLine->isValid()) {
00963 kWarning() << "Did not retrieve a valid layout for line " << line();
00964 return *this;
00965 }
00966
00967
00968 m_column = thisLine->length();
00969
00970 continue;
00971 }
00972
00973 m_column = thisLine->layout()->previousCursorPosition(m_column);
00974 }
00975 }
00976
00977 Q_ASSERT(valid());
00978 return *this;
00979 }
00980 virtual CalculatingCursor& operator-=( int n ) {
00981 return operator+=( -n );
00982 }
00983 };
00984
00985 void KateViewInternal::moveChar( KateViewInternal::Bias bias, bool sel )
00986 {
00987 KTextEditor::Cursor c;
00988 if ( m_view->wrapCursor() ) {
00989 c = WrappingCursor( this, m_cursor ) += bias;
00990 } else {
00991 c = BoundedCursor( this, m_cursor ) += bias;
00992 }
00993
00994 updateSelection( c, sel );
00995 updateCursor( c );
00996 }
00997
00998 void KateViewInternal::cursorLeft( bool sel )
00999 {
01000 if( m_view->isCompletionActive() && view()->completionWidget()->cursorLeft(sel) )
01001 return;
01002
01003 if ( ! m_view->wrapCursor() && m_cursor.column() == 0 )
01004 return;
01005
01006 moveChar( KateViewInternal::left, sel );
01007 }
01008
01009 void KateViewInternal::cursorRight( bool sel )
01010 {
01011 if( m_view->isCompletionActive() && view()->completionWidget()->cursorRight(sel) )
01012 return;
01013 moveChar( KateViewInternal::right, sel );
01014 }
01015
01016 void KateViewInternal::wordLeft ( bool sel )
01017 {
01018 WrappingCursor c( this, m_cursor );
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028 KateHighlighting* h = m_doc->highlight();
01029 if( !c.atEdge( left ) ) {
01030
01031 while( !c.atEdge( left ) && m_doc->line( c.line() )[ c.column() - 1 ].isSpace() )
01032 --c;
01033 }
01034 if( c.atEdge( left ) )
01035 {
01036 --c;
01037 }
01038 else if( h->isInWord( m_doc->line( c.line() )[ c.column() - 1 ] ) )
01039 {
01040 while( !c.atEdge( left ) && h->isInWord( m_doc->line( c.line() )[ c.column() - 1 ] ) )
01041 --c;
01042 }
01043 else
01044 {
01045 while( !c.atEdge( left )
01046 && !h->isInWord( m_doc->line( c.line() )[ c.column() - 1 ] )
01047
01048
01049 && !m_doc->line( c.line() )[ c.column() - 1 ].isSpace() )
01050 {
01051 --c;
01052 }
01053 }
01054
01055 updateSelection( c, sel );
01056 updateCursor( c );
01057 }
01058
01059 void KateViewInternal::wordRight( bool sel )
01060 {
01061 WrappingCursor c( this, m_cursor );
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 KateHighlighting* h = m_doc->highlight();
01072 if( c.atEdge( right ) )
01073 {
01074 ++c;
01075 }
01076 else if( h->isInWord( m_doc->line( c.line() )[ c.column() ] ) )
01077 {
01078 while( !c.atEdge( right ) && h->isInWord( m_doc->line( c.line() )[ c.column() ] ) )
01079 ++c;
01080 }
01081 else
01082 {
01083 while( !c.atEdge( right )
01084 && !h->isInWord( m_doc->line( c.line() )[ c.column() ] )
01085
01086
01087 && !m_doc->line( c.line() )[ c.column() ].isSpace() )
01088 {
01089 ++c;
01090 }
01091 }
01092
01093 while( !c.atEdge( right ) && m_doc->line( c.line() )[ c.column() ].isSpace() )
01094 ++c;
01095
01096 updateSelection( c, sel );
01097 updateCursor( c );
01098 }
01099
01100 void KateViewInternal::moveEdge( KateViewInternal::Bias bias, bool sel )
01101 {
01102 BoundedCursor c( this, m_cursor );
01103 c.toEdge( bias );
01104 updateSelection( c, sel );
01105 updateCursor( c );
01106 }
01107
01108 void KateViewInternal::home( bool sel )
01109 {
01110 if (m_view->dynWordWrap() && currentLayout().startCol()) {
01111
01112 if (m_cursor.column() != currentLayout().startCol()) {
01113 KTextEditor::Cursor c = currentLayout().start();
01114 updateSelection( c, sel );
01115 updateCursor( c );
01116 return;
01117 }
01118 }
01119
01120 if( !(m_doc->config()->configFlags() & KateDocumentConfig::cfSmartHome) ) {
01121 moveEdge( left, sel );
01122 return;
01123 }
01124
01125 KateTextLine::Ptr l = textLine( m_cursor.line() );
01126
01127 if (!l)
01128 return;
01129
01130 KTextEditor::Cursor c = m_cursor;
01131 int lc = l->firstChar();
01132
01133 if( lc < 0 || c.column() == lc ) {
01134 c.setColumn(0);
01135 } else {
01136 c.setColumn(lc);
01137 }
01138
01139 updateSelection( c, sel );
01140 updateCursor( c, true );
01141 }
01142
01143 void KateViewInternal::end( bool sel )
01144 {
01145 if (m_view->isCompletionActive()) {
01146 view()->completionWidget()->bottom();
01147 return;
01148 }
01149
01150 KateTextLayout layout = currentLayout();
01151
01152 if (m_view->dynWordWrap() && layout.wrap()) {
01153
01154 if (m_cursor.column() < layout.endCol() - 1) {
01155 KTextEditor::Cursor c(m_cursor.line(), layout.endCol() - 1);
01156 updateSelection( c, sel );
01157 updateCursor( c );
01158 return;
01159 }
01160 }
01161
01162 if( !(m_doc->config()->configFlags() & KateDocumentConfig::cfSmartHome) ) {
01163 moveEdge( right, sel );
01164 return;
01165 }
01166
01167 KateTextLine::Ptr l = textLine( m_cursor.line() );
01168
01169 if (!l)
01170 return;
01171
01172
01173 if (m_cursor.column() == m_doc->lineLength(m_cursor.line())) {
01174 KTextEditor::Cursor c = m_cursor;
01175 c.setColumn(l->lastChar() + 1);
01176 updateSelection(c, sel);
01177 updateCursor(c, true);
01178 } else {
01179 moveEdge(right, sel);
01180 }
01181 }
01182
01183 KateTextLayout KateViewInternal::currentLayout() const
01184 {
01185 return cache()->textLayout(m_cursor);
01186 }
01187
01188 KateTextLayout KateViewInternal::previousLayout() const
01189 {
01190 int currentViewLine = cache()->viewLine(m_cursor);
01191
01192 if (currentViewLine)
01193 return cache()->textLayout(m_cursor.line(), currentViewLine - 1);
01194 else
01195 return cache()->textLayout(m_doc->getRealLine(m_displayCursor.line() - 1), -1);
01196 }
01197
01198 KateTextLayout KateViewInternal::nextLayout() const
01199 {
01200 int currentViewLine = cache()->viewLine(m_cursor) + 1;
01201
01202 if (currentViewLine >= cache()->line(m_cursor.line())->viewLineCount()) {
01203 currentViewLine = 0;
01204 return cache()->textLayout(m_doc->getRealLine(m_displayCursor.line() + 1), currentViewLine);
01205 } else {
01206 return cache()->textLayout(m_cursor.line(), currentViewLine);
01207 }
01208 }
01209
01210
01211
01212
01213
01214
01215
01216
01217 KTextEditor::Cursor KateViewInternal::viewLineOffset(const KTextEditor::Cursor& virtualCursor, int offset, bool keepX)
01218 {
01219 if (!m_view->dynWordWrap()) {
01220 KTextEditor::Cursor ret(qMin((int)m_doc->visibleLines() - 1, virtualCursor.line() + offset), 0);
01221
01222 if (ret.line() < 0)
01223 ret.setLine(0);
01224
01225 if (keepX) {
01226 int realLine = m_doc->getRealLine(ret.line());
01227 KateTextLayout t = cache()->textLayout(realLine, 0);
01228 Q_ASSERT(t.isValid());
01229
01230 if (m_currentMaxX > m_cursorX)
01231 m_cursorX = m_currentMaxX;
01232
01233 ret.setColumn(renderer()->xToCursor(t, m_cursorX, !m_view->wrapCursor()).column());
01234 }
01235
01236 return ret;
01237 }
01238
01239 KTextEditor::Cursor realCursor = virtualCursor;
01240 realCursor.setLine(m_doc->getRealLine(virtualCursor.line()));
01241
01242 int cursorViewLine = cache()->viewLine(realCursor);
01243
01244 int currentOffset = 0;
01245 int virtualLine = 0;
01246
01247 bool forwards = (offset > 0) ? true : false;
01248
01249 if (forwards) {
01250 currentOffset = cache()->lastViewLine(realCursor.line()) - cursorViewLine;
01251 if (offset <= currentOffset) {
01252
01253 KateTextLayout thisLine = cache()->textLayout(realCursor.line(), cursorViewLine + offset);
01254 Q_ASSERT(thisLine.virtualLine() == virtualCursor.line());
01255 return KTextEditor::Cursor(virtualCursor.line(), thisLine.startCol());
01256 }
01257
01258 virtualLine = virtualCursor.line() + 1;
01259
01260 } else {
01261 offset = -offset;
01262 currentOffset = cursorViewLine;
01263 if (offset <= currentOffset) {
01264
01265 KateTextLayout thisLine = cache()->textLayout(realCursor.line(), cursorViewLine - offset);
01266 Q_ASSERT(thisLine.virtualLine() == virtualCursor.line());
01267 return KTextEditor::Cursor(virtualCursor.line(), thisLine.startCol());
01268 }
01269
01270 virtualLine = virtualCursor.line() - 1;
01271 }
01272
01273 currentOffset++;
01274
01275 while (virtualLine >= 0 && virtualLine < (int)m_doc->visibleLines())
01276 {
01277 int realLine = m_doc->getRealLine(virtualLine);
01278 KateLineLayoutPtr thisLine = cache()->line(realLine, virtualLine);
01279 if (!thisLine)
01280 break;
01281
01282 for (int i = 0; i < thisLine->viewLineCount(); ++i) {
01283 if (offset == currentOffset) {
01284 KateTextLayout thisViewLine = thisLine->viewLine(i);
01285
01286 if (!forwards) {
01287
01288 int requiredViewLine = cache()->lastViewLine(realLine) - thisViewLine.viewLine();
01289 if (requiredViewLine != thisViewLine.viewLine()) {
01290 thisViewLine = thisLine->viewLine(requiredViewLine);
01291 }
01292 }
01293
01294 KTextEditor::Cursor ret(virtualLine, thisViewLine.startCol());
01295
01296
01297 if (keepX) {
01298 KTextEditor::Cursor realCursor = toRealCursor(virtualCursor);
01299 KateTextLayout t = cache()->textLayout(realCursor);
01300 m_cursorX = renderer()->cursorToX(t, realCursor);
01301
01302 if (m_currentMaxX > m_cursorX) {
01303 m_cursorX = m_currentMaxX;
01304 }
01305
01306 realCursor = renderer()->xToCursor(thisViewLine, m_cursorX, !m_view->wrapCursor());
01307 ret.setColumn(realCursor.column());
01308 }
01309
01310 return ret;
01311 }
01312
01313 currentOffset++;
01314 }
01315
01316 if (forwards)
01317 virtualLine++;
01318 else
01319 virtualLine--;
01320 }
01321
01322
01323
01324 if (forwards)
01325 return KTextEditor::Cursor(m_doc->visibleLines() - 1, m_doc->lineLength(m_doc->getRealLine (m_doc->visibleLines() - 1)));
01326 else
01327 return KTextEditor::Cursor(0, 0);
01328 }
01329
01330 int KateViewInternal::lineMaxCursorX(const KateTextLayout& range)
01331 {
01332 if (!m_view->wrapCursor() && !range.wrap())
01333 return INT_MAX;
01334
01335 int maxX = range.endX();
01336
01337 if (maxX && range.wrap()) {
01338 QChar lastCharInLine = textLine(range.line())->at(range.endCol() - 1);
01339 maxX -= renderer()->config()->fontMetrics().width(lastCharInLine);
01340 }
01341
01342 return maxX;
01343 }
01344
01345 int KateViewInternal::lineMaxCol(const KateTextLayout& range)
01346 {
01347 int maxCol = range.endCol();
01348
01349 if (maxCol && range.wrap())
01350 maxCol--;
01351
01352 return maxCol;
01353 }
01354
01355 void KateViewInternal::cursorUp(bool sel)
01356 {
01357 if (m_view->isCompletionActive()) {
01358 view()->completionWidget()->cursorUp(sel);
01359 return;
01360 }
01361
01362 if (m_displayCursor.line() == 0 && (!m_view->dynWordWrap() || cache()->viewLine(m_cursor) == 0))
01363 return;
01364
01365 m_preserveMaxX = true;
01366
01367 KateTextLayout thisLine = currentLayout();
01368
01369 KateTextLayout pRange = previousLayout();
01370
01371
01372 Q_ASSERT(m_cursor.line() == thisLine.line());
01373 Q_ASSERT(m_cursor.column() >= thisLine.startCol());
01374 Q_ASSERT(!thisLine.wrap() || m_cursor.column() < thisLine.endCol());
01375
01376
01377 m_cursorX = renderer()->cursorToX(thisLine, m_cursor);
01378
01379 if (m_currentMaxX > m_cursorX)
01380 m_cursorX = m_currentMaxX;
01381
01382 KTextEditor::Cursor c = renderer()->xToCursor(pRange, m_cursorX, !m_view->wrapCursor());
01383
01384 updateSelection( c, sel );
01385 updateCursor( c );
01386 }
01387
01388 void KateViewInternal::cursorDown(bool sel)
01389 {
01390 if (m_view->isCompletionActive()) {
01391 view()->completionWidget()->cursorDown(sel);
01392 return;
01393 }
01394
01395 if ((m_displayCursor.line() >= m_doc->numVisLines() - 1) && (!m_view->dynWordWrap() || cache()->viewLine(m_cursor) == cache()->lastViewLine(m_cursor.line())))
01396 return;
01397
01398 m_preserveMaxX = true;
01399
01400 KateTextLayout thisLine = currentLayout();
01401
01402 KateTextLayout nRange = nextLayout();
01403
01404
01405 Q_ASSERT((m_cursor.line() == thisLine.line()) &&
01406 (m_cursor.column() >= thisLine.startCol()) &&
01407 (!thisLine.wrap() || m_cursor.column() < thisLine.endCol()));
01408
01409
01410 m_cursorX = renderer()->cursorToX(thisLine, m_cursor);
01411
01412 if (m_currentMaxX > m_cursorX)
01413 m_cursorX = m_currentMaxX;
01414
01415 KTextEditor::Cursor c = renderer()->xToCursor(nRange, m_cursorX, !m_view->wrapCursor());
01416
01417 updateSelection(c, sel);
01418 updateCursor(c);
01419 }
01420
01421 void KateViewInternal::cursorToMatchingBracket( bool sel )
01422 {
01423 if (!m_bm->isValid())
01424 return;
01425
01426 KTextEditor::Cursor c;
01427
01428 if (m_bmStart->contains(m_cursor) || m_bmStart->end() == m_cursor) {
01429 c = m_bm->end();
01430 } else if (m_bmEnd->contains(m_cursor) || m_bmEnd->end() == m_cursor) {
01431 c = m_bm->start();
01432 } else {
01433
01434
01435 return;
01436 }
01437
01438 updateSelection( c, sel );
01439 updateCursor( c );
01440 }
01441
01442 void KateViewInternal::topOfView( bool sel )
01443 {
01444 KTextEditor::Cursor c = viewLineOffset(startPos(), m_minLinesVisible);
01445 updateSelection( c, sel );
01446 updateCursor( c );
01447 }
01448
01449 void KateViewInternal::bottomOfView( bool sel )
01450 {
01451
01452 KTextEditor::Cursor c = viewLineOffset(endPos(), -m_minLinesVisible);
01453 updateSelection( c, sel );
01454 updateCursor( c );
01455 }
01456
01457
01458 void KateViewInternal::scrollLines( int lines, bool sel )
01459 {
01460 KTextEditor::Cursor c = viewLineOffset(m_displayCursor, lines, true);
01461
01462
01463 c.setLine(m_doc->getRealLine(c.line()));
01464
01465 updateSelection( c, sel );
01466 updateCursor( c );
01467 }
01468
01469
01470 void KateViewInternal::scrollUp()
01471 {
01472 KTextEditor::Cursor newPos = viewLineOffset(startPos(), -1);
01473 scrollPos(newPos);
01474 }
01475
01476 void KateViewInternal::scrollDown()
01477 {
01478 KTextEditor::Cursor newPos = viewLineOffset(startPos(), 1);
01479 scrollPos(newPos);
01480 }
01481
01482 void KateViewInternal::setAutoCenterLines(int viewLines, bool updateView)
01483 {
01484 m_autoCenterLines = viewLines;
01485 m_minLinesVisible = qMin(int((linesDisplayed() - 1)/2), m_autoCenterLines);
01486 if (updateView)
01487 KateViewInternal::updateView();
01488 }
01489
01490 void KateViewInternal::pageUp( bool sel )
01491 {
01492 if (m_view->isCompletionActive()) {
01493 view()->completionWidget()->pageUp();
01494 return;
01495 }
01496
01497
01498 int viewLine = cache()->displayViewLine(m_displayCursor);
01499 bool atTop = startPos().atStartOfDocument();
01500
01501
01502 int lineadj = 2 * m_minLinesVisible;
01503 int cursorStart = (linesDisplayed() - 1) - viewLine;
01504 if (cursorStart < m_minLinesVisible)
01505 lineadj -= m_minLinesVisible - cursorStart;
01506
01507 int linesToScroll = -qMax( (linesDisplayed() - 1) - lineadj, 0 );
01508 m_preserveMaxX = true;
01509
01510 if (!m_doc->pageUpDownMovesCursor () && !atTop) {
01511 m_cursorX = renderer()->cursorToX(currentLayout(), m_cursor);
01512
01513 KTextEditor::Cursor newStartPos = viewLineOffset(startPos(), linesToScroll - 1);
01514 scrollPos(newStartPos);
01515
01516
01517 KTextEditor::Cursor newPos = toRealCursor(viewLineOffset(newStartPos, viewLine, true));
01518
01519 KateTextLayout newLine = cache()->textLayout(newPos);
01520
01521 if (m_currentMaxX> m_cursorX)
01522 m_cursorX = m_currentMaxX;
01523
01524 newPos = renderer()->xToCursor(newLine, m_cursorX, !view()->wrapCursor());
01525
01526 m_preserveMaxX = true;
01527 updateSelection( newPos, sel );
01528 updateCursor(newPos);
01529
01530 } else {
01531 scrollLines( linesToScroll, sel );
01532 }
01533 }
01534
01535 void KateViewInternal::pageDown( bool sel )
01536 {
01537 if (m_view->isCompletionActive()) {
01538 view()->completionWidget()->pageDown();
01539 return;
01540 }
01541
01542
01543 int viewLine = cache()->displayViewLine(m_displayCursor);
01544 bool atEnd = startPos() >= m_cachedMaxStartPos;
01545
01546
01547 int lineadj = 2 * m_minLinesVisible;
01548 int cursorStart = m_minLinesVisible - viewLine;
01549 if (cursorStart > 0)
01550 lineadj -= cursorStart;
01551
01552 int linesToScroll = qMax( (linesDisplayed() - 1) - lineadj, 0 );
01553 m_preserveMaxX = true;
01554
01555 if (!m_doc->pageUpDownMovesCursor () && !atEnd) {
01556 m_cursorX = renderer()->cursorToX(currentLayout(), m_cursor);
01557
01558 KTextEditor::Cursor newStartPos = viewLineOffset(startPos(), linesToScroll + 1);
01559 scrollPos(newStartPos);
01560
01561
01562 KTextEditor::Cursor newPos = toRealCursor(viewLineOffset(newStartPos, viewLine, true));
01563
01564 KateTextLayout newLine = cache()->textLayout(newPos);
01565
01566 if (m_currentMaxX> m_cursorX)
01567 m_cursorX = m_currentMaxX;
01568
01569 newPos = renderer()->xToCursor(newLine, m_cursorX, !view()->wrapCursor());
01570
01571 m_preserveMaxX = true;
01572 updateSelection( newPos, sel );
01573 updateCursor(newPos);
01574
01575 } else {
01576 scrollLines( linesToScroll, sel );
01577 }
01578 }
01579
01580 int KateViewInternal::maxLen(int startLine)
01581 {
01582 Q_ASSERT(!m_view->dynWordWrap());
01583
01584 int displayLines = (m_view->height() / renderer()->fontHeight()) + 1;
01585
01586 int maxLen = 0;
01587
01588 for (int z = 0; z < displayLines; z++) {
01589 int virtualLine = startLine + z;
01590
01591 if (virtualLine < 0 || virtualLine >= (int)m_doc->visibleLines())
01592 break;
01593
01594 maxLen = qMax(maxLen, cache()->line(m_doc->getRealLine(virtualLine))->width());
01595 }
01596
01597 return maxLen;
01598 }
01599
01600 bool KateViewInternal::columnScrollingPossible ()
01601 {
01602 return !m_view->dynWordWrap() && m_columnScroll->isEnabled() && (m_columnScroll->maximum() > 0);
01603 }
01604
01605 void KateViewInternal::top( bool sel )
01606 {
01607 m_cursorX = renderer()->cursorToX(currentLayout(), m_cursor);
01608
01609 KTextEditor::Cursor newCursor(0, 0);
01610
01611 if (m_currentMaxX > m_cursorX)
01612 m_cursorX = m_currentMaxX;
01613
01614 newCursor = renderer()->xToCursor(cache()->textLayout(newCursor), m_cursorX, !view()->wrapCursor());
01615
01616 updateSelection( newCursor, sel );
01617 updateCursor( newCursor );
01618 }
01619
01620 void KateViewInternal::bottom( bool sel )
01621 {
01622 KTextEditor::Cursor newCursor(m_doc->lastLine(), 0);
01623
01624 if (m_currentMaxX > m_cursorX)
01625 m_cursorX = m_currentMaxX;
01626
01627 newCursor = renderer()->xToCursor(cache()->textLayout(newCursor), m_cursorX, !view()->wrapCursor());
01628
01629 updateSelection( newCursor, sel );
01630 updateCursor( newCursor );
01631 }
01632
01633 void KateViewInternal::top_home( bool sel )
01634 {
01635 if (m_view->isCompletionActive()) {
01636 view()->completionWidget()->top();
01637 return;
01638 }
01639
01640 KTextEditor::Cursor c( 0, 0 );
01641 updateSelection( c, sel );
01642 updateCursor( c );
01643 }
01644
01645 void KateViewInternal::bottom_end( bool sel )
01646 {
01647 if (m_view->isCompletionActive()) {
01648 view()->completionWidget()->bottom();
01649 return;
01650 }
01651
01652 KTextEditor::Cursor c( m_doc->lastLine(), m_doc->lineLength( m_doc->lastLine() ) );
01653 updateSelection( c, sel );
01654 updateCursor( c );
01655 }
01656
01657 void KateViewInternal::updateSelection( const KTextEditor::Cursor& _newCursor, bool keepSel )
01658 {
01659 KTextEditor::Cursor newCursor = _newCursor;
01660 if( keepSel )
01661 {
01662 if ( !m_view->selection() || (m_selectAnchor.line() == -1)
01663
01664
01665 || (m_view->config()->persistentSelection()
01666 && !(m_view->selectionRange().contains(m_cursor)
01667 || m_view->selectionRange().boundaryAtCursor(m_cursor))) )
01668 {
01669 m_selectAnchor = m_cursor;
01670 m_view->setSelection( KTextEditor::Range(m_cursor, newCursor) );
01671 }
01672 else
01673 {
01674 bool doSelect = true;
01675 switch (m_selectionMode)
01676 {
01677 case Word:
01678 {
01679
01680
01681
01682
01683
01684
01685
01686 if ( !m_selectionCached.isValid() )
01687 m_selectionCached.start() = m_selectionCached.end();
01688
01689 int c;
01690 if ( newCursor > m_selectionCached.start() )
01691 {
01692 m_selectAnchor = m_selectionCached.start();
01693
01694 KateTextLine::Ptr l = m_doc->kateTextLine( newCursor.line() );
01695
01696 c = newCursor.column();
01697 if ( c > 0 && m_doc->highlight()->isInWord( l->at( c-1 ) ) ) {
01698 for ( ; c < l->length(); c++ )
01699 if ( !m_doc->highlight()->isInWord( l->at( c ) ) )
01700 break;
01701 }
01702
01703 newCursor.setColumn( c );
01704 }
01705 else if ( newCursor < m_selectionCached.start() )
01706 {
01707 m_selectAnchor = m_selectionCached.end();
01708
01709 KateTextLine::Ptr l = m_doc->kateTextLine( newCursor.line() );
01710
01711 c = newCursor.column();
01712 if ( c > 0 && c < m_doc->lineLength( newCursor.line() )
01713 && m_doc->highlight()->isInWord( l->at( c ) )
01714 && m_doc->highlight()->isInWord( l->at( c-1 ) ) ) {
01715 for ( c -= 2; c >= 0; c-- )
01716 if ( !m_doc->highlight()->isInWord( l->at( c ) ) )
01717 break;
01718 newCursor.setColumn( c+1 );
01719 }
01720 }
01721 else
01722 doSelect = false;
01723
01724 }
01725 break;
01726 case Line:
01727 if ( newCursor.line() > m_selectionCached.start().line() )
01728 {
01729 if (newCursor.line() + 1 >= m_doc->lines() )
01730 newCursor.setColumn( m_doc->line( newCursor.line() ).length() );
01731 else
01732 newCursor.setPosition( newCursor.line() + 1, 0 );
01733
01734 m_selectAnchor = m_selectionCached.start();
01735 m_selectAnchor.setColumn( 0 );
01736 }
01737 else if ( newCursor.line() < m_selectionCached.start().line() )
01738 {
01739 newCursor.setColumn( 0 );
01740
01741 m_selectAnchor = m_selectionCached.end();
01742 if ( m_selectAnchor.column() > 0 )
01743 {
01744 if ( m_selectAnchor.line()+1 >= m_doc->lines() )
01745 m_selectAnchor.setColumn( m_doc->line( newCursor.line() ).length() );
01746 else
01747 m_selectAnchor.setPosition( m_selectAnchor.line() + 1, 0 );
01748 }
01749 }
01750 else
01751 doSelect = false;
01752 break;
01753 case Mouse:
01754 {
01755 if ( !m_selectionCached.isValid() )
01756 break;
01757
01758 if ( newCursor > m_selectionCached.end() )
01759 m_selectAnchor = m_selectionCached.start();
01760 else if ( newCursor < m_selectionCached.start() )
01761 m_selectAnchor = m_selectionCached.end();
01762 else
01763 doSelect = false;
01764 }
01765 break;
01766 default: ;
01767 }
01768
01769 if ( doSelect )
01770 m_view->setSelection( KTextEditor::Range(m_selectAnchor, newCursor) );
01771 else if ( m_selectionCached.isValid() )
01772 m_view->setSelection( m_selectionCached );
01773 }
01774
01775 m_selChangedByUser = true;
01776 }
01777 else if ( !m_view->config()->persistentSelection() )
01778 {
01779 m_view->clearSelection();
01780
01781 m_selectionCached = KTextEditor::Range::invalid();
01782 }
01783 }
01784
01785 void KateViewInternal::updateCursor( const KTextEditor::Cursor& newCursor, bool force, bool center, bool calledExternally )
01786 {
01787 if ( !force && (m_cursor == newCursor) )
01788 {
01789 if ( !m_madeVisible && m_view == m_doc->activeView() )
01790 {
01791
01792 m_doc->foldingTree()->ensureVisible( newCursor.line() );
01793
01794 makeVisible ( m_displayCursor, m_displayCursor.column(), false, center, calledExternally );
01795 }
01796
01797 return;
01798 }
01799
01800
01801 m_doc->foldingTree()->ensureVisible( newCursor.line() );
01802
01803 KTextEditor::Cursor oldDisplayCursor = m_displayCursor;
01804
01805 m_cursor = newCursor;
01806 m_displayCursor = toVirtualCursor(m_cursor);
01807
01808 m_cursorX = renderer()->cursorToX(cache()->textLayout(m_cursor), m_cursor);
01809 if ( m_view == m_doc->activeView() )
01810 makeVisible ( m_displayCursor, m_displayCursor.column(), false, center, calledExternally );
01811
01812 updateBracketMarks();
01813
01814
01815 tagLine(oldDisplayCursor);
01816 tagLine(m_displayCursor);
01817
01818 updateMicroFocus();
01819
01820 if (m_cursorTimer.isActive ())
01821 {
01822 if ( KApplication::cursorFlashTime() > 0 )
01823 m_cursorTimer.start( KApplication::cursorFlashTime() / 2 );
01824 renderer()->setDrawCaret(true);
01825 }
01826
01827
01828 if (m_preserveMaxX)
01829 m_preserveMaxX = false;
01830 else
01831 m_currentMaxX = m_cursorX;
01832
01833
01834
01835
01836 cursorMoved();
01837
01838 if(!m_doc->isEditRunning())
01839 m_doc->setUndoDontMerge(true);
01840
01841 updateDirty();
01842
01843 emit m_view->cursorPositionChanged(m_view, m_cursor);
01844 }
01845
01846 void KateViewInternal::updateBracketMarkAttributes()
01847 {
01848 KTextEditor::Attribute::Ptr bracketFill = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute());
01849 bracketFill->setBackground(m_view->m_renderer->config()->highlightedBracketColor());
01850 bracketFill->setBackgroundFillWhitespace(false);
01851 bracketFill->setFontBold();
01852
01853 m_bmStart->setAttribute(bracketFill);
01854 m_bmEnd->setAttribute(bracketFill);
01855
01856 if (m_view->m_renderer->config()->showWholeBracketExpression()) {
01857
01858 KTextEditor::Attribute::Ptr expressionFill = KTextEditor::Attribute::Ptr(new KTextEditor::Attribute());
01859 expressionFill->setBackground(m_view->m_renderer->config()->highlightedBracketColor());
01860 expressionFill->setBackgroundFillWhitespace(false);
01861
01862 m_bm->setAttribute(expressionFill);
01863 } else {
01864 m_bm->setAttribute(KTextEditor::Attribute::Ptr(new KTextEditor::Attribute()));
01865 }
01866 }
01867
01868 void KateViewInternal::updateBracketMarks()
01869 {
01870 bool showWholeBracketExpression = m_view->m_renderer->config()->showWholeBracketExpression();
01871
01872 QMutexLocker lock(m_doc->smartMutex());
01873 if (m_bmHighlighted) {
01874 view()->removeInternalHighlight(m_bmStart);
01875 view()->removeInternalHighlight(m_bmEnd);
01876 view()->removeInternalHighlight(m_bm);
01877 m_bmHighlighted = false;
01878 }
01879
01880 if ( m_bm->isValid() ) {
01881 tagRange(*m_bmStart, true);
01882 tagRange(*m_bmEnd, true);
01883 tagRange(*m_bm, true);
01884 }
01885
01886
01887 int maxLines = linesDisplayed () * 3;
01888 m_doc->newBracketMark( m_cursor, *m_bm, maxLines );
01889
01890 if ( m_bm->isValid() ) {
01891 m_bmStart->start() = m_bm->start();
01892 m_bmStart->end().setPosition(m_bm->start().line(), m_bm->start().column() + 1);
01893
01894 m_bmEnd->start() = m_bm->end();
01895 m_bmEnd->end().setPosition(m_bm->end().line(), m_bm->end().column() + 1);
01896
01897 tagRange(*m_bmStart, true);
01898 tagRange(*m_bmEnd, true);
01899 if (showWholeBracketExpression) {
01900 tagRange(*m_bm, true);
01901 }
01902
01903 view()->addInternalHighlight(m_bmStart);
01904 view()->addInternalHighlight(m_bmEnd);
01905 if (showWholeBracketExpression) {
01906 view()->addInternalHighlight(m_bm);
01907 }
01908 m_bmHighlighted = true;
01909 }
01910 }
01911
01912 bool KateViewInternal::tagLine(const KTextEditor::Cursor& virtualCursor)
01913 {
01914 QMutexLocker lock(m_doc->smartMutex());
01915
01916 if ((int)m_doc->getRealLine(virtualCursor.line()) > m_doc->lastLine())
01917 return false;
01918
01919
01920 int viewLine = cache()->displayViewLine(virtualCursor, true);
01921 if (viewLine >= 0 && viewLine < cache()->viewCacheLineCount()) {
01922 cache()->viewLine(viewLine).setDirty();
01923 m_leftBorder->update (0, lineToY(viewLine), m_leftBorder->width(), renderer()->fontHeight());
01924 return true;
01925 }
01926 return false;
01927 }
01928
01929 bool KateViewInternal::tagLines( int start, int end, bool realLines )
01930 {
01931 return tagLines(KTextEditor::Cursor(start, 0), KTextEditor::Cursor(end, -1), realLines);
01932 }
01933
01934 bool KateViewInternal::tagLines(KTextEditor::Cursor start, KTextEditor::Cursor end, bool realCursors)
01935 {
01936 QMutexLocker lock(m_doc->smartMutex());
01937 if (realCursors)
01938 {
01939 cache()->relayoutLines(start.line(), end.line());
01940
01941
01942 start = toVirtualCursor(start);
01943 end = toVirtualCursor(end);
01944
01945 } else {
01946 cache()->relayoutLines(toRealCursor(start).line(), toRealCursor(end).line());
01947 }
01948
01949 if (end.line() < startLine())
01950 {
01951
01952 return false;
01953 }
01954
01955
01956 if (start.line() > startLine() + cache()->viewCacheLineCount())
01957 {
01958
01959 return false;
01960 }
01961
01962 cache()->updateViewCache(startPos());
01963
01964
01965
01966 bool ret = false;
01967
01968 for (int z = 0; z < cache()->viewCacheLineCount(); z++)
01969 {
01970 KateTextLayout& line = cache()->viewLine(z);
01971 if ((line.virtualLine() > start.line() || (line.virtualLine() == start.line() && line.endCol() >= start.column() && start.column() != -1)) &&
01972 (line.virtualLine() < end.line() || (line.virtualLine() == end.line() && (line.startCol() <= end.column() || end.column() == -1)))) {
01973 ret = true;
01974 break;
01975
01976 }
01977 }
01978
01979 if (!m_view->dynWordWrap())
01980 {
01981 int y = lineToY( start.line() );
01982
01983 int h = (end.line() - start.line() + 2) * renderer()->fontHeight();
01984 if (end.line() == m_doc->numVisLines() - 1)
01985 h = height();
01986
01987 m_leftBorder->update (0, y, m_leftBorder->width(), h);
01988 }
01989 else
01990 {
01991
01992
01993 for (int z = 0; z < cache()->viewCacheLineCount(); z++)
01994 {
01995 KateTextLayout& line = cache()->viewLine(z);
01996 if (!line.isValid() ||
01997 ((line.virtualLine() > start.line() || (line.virtualLine() == start.line() && line.endCol() >= start.column() && start.column() != -1)) &&
01998 (line.virtualLine() < end.line() || (line.virtualLine() == end.line() && (line.startCol() <= end.column() || end.column() == -1)))))
01999 {
02000
02001 m_leftBorder->update (0, z * renderer()->fontHeight(), m_leftBorder->width(), m_leftBorder->height());
02002 break;
02003 }
02004
02005
02006
02007
02008
02009
02010 }
02011 }
02012
02013 return ret;
02014 }
02015
02016 bool KateViewInternal::tagRange(const KTextEditor::Range& range, bool realCursors)
02017 {
02018 return tagLines(range.start(), range.end(), realCursors);
02019 }
02020
02021 void KateViewInternal::tagAll()
02022 {
02023 QMutexLocker lock(m_doc->smartMutex());
02024
02025 for (int z = 0; z < cache()->viewCacheLineCount(); z++)
02026 cache()->viewLine(z).setDirty();
02027
02028 m_leftBorder->updateFont();
02029 m_leftBorder->update();
02030 }
02031
02032 void KateViewInternal::paintCursor()
02033 {
02034 if (tagLine(m_displayCursor))
02035 updateDirty();
02036 }
02037
02038
02039 void KateViewInternal::placeCursor( const QPoint& p, bool keepSelection, bool updateSelection )
02040 {
02041 KateTextLayout thisLine = yToKateTextLayout(p.y());
02042 KTextEditor::Cursor c;
02043
02044 if (!thisLine.isValid())
02045 thisLine = cache()->textLayout(m_doc->lines() - 1, -1);
02046
02047 c = renderer()->xToCursor(thisLine, startX() + p.x(), !view()->wrapCursor());
02048
02049 if (c.line () < 0 || c.line() >= m_doc->lines()) {
02050 return;
02051 }
02052 if (updateSelection)
02053 KateViewInternal::updateSelection( c, keepSelection );
02054
02055 updateCursor( c );
02056 }
02057
02058
02059 bool KateViewInternal::isTargetSelected( const QPoint& p )
02060 {
02061 const KateTextLayout& thisLine = yToKateTextLayout(p.y());
02062 if (!thisLine.isValid())
02063 return false;
02064
02065 return m_view->cursorSelected(renderer()->xToCursor(thisLine, startX() + p.x(), !view()->wrapCursor()));
02066 }
02067
02068
02069
02070 bool KateViewInternal::eventFilter( QObject *obj, QEvent *e )
02071 {
02072 if (obj == m_lineScroll)
02073 {
02074
02075 if (e->type() == QEvent::Wheel && m_lineScroll->minimum() != m_lineScroll->maximum())
02076 {
02077 wheelEvent((QWheelEvent*)e);
02078 return true;
02079 }
02080
02081
02082 return QWidget::eventFilter( obj, e );
02083 }
02084
02085 switch( e->type() )
02086 {
02087 case QEvent::ChildAdded:
02088 case QEvent::ChildRemoved: {
02089 QChildEvent* c = static_cast<QChildEvent*>(e);
02090 if (c->added()) {
02091 c->child()->installEventFilter(this);
02092
02093
02094
02095 } else if (c->removed()) {
02096 c->child()->removeEventFilter(this);
02097
02098
02099
02100 }
02101 } break;
02102
02103 case QEvent::ShortcutOverride:
02104 {
02105 QKeyEvent *k = static_cast<QKeyEvent *>(e);
02106
02107 if (k->key() == Qt::Key_Escape) {
02108 if (m_view->isCompletionActive()) {
02109 m_view->abortCompletion();
02110 k->accept();
02111
02112 return true;
02113 } else if (m_view->viewBar()->isVisible()) {
02114 m_view->viewBar()->hide();
02115 k->accept();
02116
02117 return true;
02118 } else if (!m_view->config()->persistentSelection() && m_view->selection()) {
02119 m_view->clearSelection();
02120 k->accept();
02121
02122 return true;
02123 }
02124 }
02125 } break;
02126
02127 case QEvent::KeyPress:
02128 {
02129 QKeyEvent *k = static_cast<QKeyEvent *>(e);
02130
02131
02132 if (obj == this && (!k->modifiers() || k->modifiers() == Qt::ShiftModifier)) {
02133 keyPressEvent( k );
02134 if (k->isAccepted()) {
02135
02136 return true;
02137 }
02138 }
02139
02140
02141 } break;
02142
02143 case QEvent::DragMove:
02144 {
02145 QPoint currentPoint = ((QDragMoveEvent*) e)->pos();
02146
02147 QRect doNotScrollRegion( s_scrollMargin, s_scrollMargin,
02148 width() - s_scrollMargin * 2,
02149 height() - s_scrollMargin * 2 );
02150
02151 if ( !doNotScrollRegion.contains( currentPoint ) )
02152 {
02153 startDragScroll();
02154
02155 ( (QDragMoveEvent*)e )->accept( QRect(0,0,0,0) );
02156 }
02157
02158 dragMoveEvent((QDragMoveEvent*)e);
02159 } break;
02160
02161 case QEvent::DragLeave:
02162
02163 stopDragScroll();
02164 break;
02165
02166 case QEvent::WindowBlocked:
02167
02168
02169 m_doc->ignoreModifiedOnDiskOnce();
02170 break;
02171
02172 default:
02173 break;
02174 }
02175
02176 return QWidget::eventFilter( obj, e );
02177 }
02178
02179 void KateViewInternal::keyPressEvent( QKeyEvent* e )
02180 {
02181
02182 const int key = e->key() | (e->modifiers() & Qt::ShiftModifier);
02183
02184 if (m_view->isCompletionActive())
02185 {
02186 if( key == Qt::Key_Enter || key == Qt::Key_Return ||
02187 (key == Qt::SHIFT + Qt::Key_Return) || (key == Qt::SHIFT + Qt::Key_Enter)) {
02188 m_view->completionWidget()->execute(key & Qt::SHIFT);
02189 e->accept();
02190 return;
02191 }
02192 }
02193
02194 if( !m_doc->isReadWrite() )
02195 {
02196 e->ignore();
02197 return;
02198 }
02199
02200 if ((key == Qt::Key_Return) || (key == Qt::Key_Enter))
02201 {
02202 doReturn();
02203 e->accept();
02204 return;
02205 }
02206
02207 if ((key == Qt::SHIFT + Qt::Key_Return) || (key == Qt::SHIFT + Qt::Key_Enter))
02208 {
02209 int ln = m_cursor.line();
02210 int col = m_cursor.column();
02211 KateTextLine::Ptr line = m_doc->kateTextLine( ln );
02212 int pos = line->firstChar();
02213 if (pos > m_cursor.column()) pos = m_cursor.column();
02214 if (pos != -1) {
02215 while (line->length() > pos &&
02216 !line->at(pos).isLetterOrNumber() &&
02217 pos < m_cursor.column()) ++pos;
02218 } else {
02219 pos = line->length();
02220 }
02221 m_doc->editStart();
02222 m_doc->insertText( KTextEditor::Cursor(m_cursor.line(), line->length()), '\n' + line->string(0, pos)
02223 + line->string().right( line->length() - m_cursor.column() ) );
02224 m_cursor.setPosition(KTextEditor::Cursor(ln + 1, pos));
02225 if (col < int(line->length()))
02226 m_doc->editRemoveText(ln, col, line->length() - col);
02227 m_doc->editEnd();
02228 updateCursor(m_cursor, true);
02229 updateView();
02230 e->accept();
02231
02232 return;
02233 }
02234
02235 if (key == Qt::Key_Backspace || key == Qt::SHIFT + Qt::Key_Backspace)
02236 {
02237
02238 e->accept();
02239
02240 return;
02241 }
02242
02243 if (key == Qt::Key_Tab || key == Qt::SHIFT+Qt::Key_Backtab || key == Qt::Key_Backtab)
02244 {
02245 if (m_doc->invokeTabInterceptor(key)) {
02246 e->accept();
02247 return;
02248 }
02249
02250 if( key == Qt::Key_Tab )
02251 {
02252 uint tabHandling = m_doc->config()->tabHandling();
02253
02254 if (tabHandling == KateDocumentConfig::tabSmart)
02255 {
02256 if (m_view->selection())
02257 {
02258 tabHandling = KateDocumentConfig::tabIndents;
02259 }
02260 else
02261 {
02262
02263
02264
02265 KateTextLine::Ptr line = m_doc->kateTextLine( m_cursor.line() );
02266 int first = line->firstChar();
02267 if (first < 0 || m_cursor.column() <= first)
02268 tabHandling = KateDocumentConfig::tabIndents;
02269 else
02270 tabHandling = KateDocumentConfig::tabInsertsTab;
02271 }
02272 }
02273
02274 if (tabHandling == KateDocumentConfig::tabInsertsTab)
02275 m_doc->typeChars( m_view, QString("\t") );
02276 else
02277 m_doc->indent( m_view, m_cursor.line(), 1 );
02278
02279 e->accept();
02280
02281 return;
02282 }
02283 else if (m_doc->config()->tabHandling() != KateDocumentConfig::tabInsertsTab)
02284 {
02285
02286 m_doc->indent( m_view, m_cursor.line(), -1 );
02287 e->accept();
02288
02289 return;
02290 }
02291 }
02292
02293 if ( !(e->modifiers() & Qt::ControlModifier) && !e->text().isEmpty() && m_doc->typeChars ( m_view, e->text() ) )
02294 {
02295 e->accept();
02296
02297 return;
02298 }
02299
02300
02301 static const int altGR = Qt::ControlModifier | Qt::AltModifier;
02302 if( (e->modifiers() & altGR) == altGR && !e->text().isEmpty() && m_doc->typeChars ( m_view, e->text() ) )
02303 {
02304 e->accept();
02305
02306 return;
02307 }
02308
02309 e->ignore();
02310 }
02311
02312 void KateViewInternal::keyReleaseEvent( QKeyEvent* e )
02313 {
02314 if (e->key() == Qt::SHIFT)
02315 m_shiftKeyPressed = true;
02316 else
02317 {
02318 if (m_shiftKeyPressed)
02319 {
02320 m_shiftKeyPressed = false;
02321
02322 if (m_selChangedByUser)
02323 {
02324 if (m_view->selection())
02325 QApplication::clipboard()->setText(m_view->selectionText (), QClipboard::Selection);
02326
02327 m_selChangedByUser = false;
02328 }
02329 }
02330 }
02331
02332 e->ignore();
02333 return;
02334 }
02335
02336 void KateViewInternal::contextMenuEvent ( QContextMenuEvent * e )
02337 {
02338
02339
02340 QPoint p = e->pos();
02341
02342 if ( m_view->m_doc->browserView() )
02343 {
02344 m_view->contextMenuEvent( e );
02345 return;
02346 }
02347
02348 if ( e->reason() == QContextMenuEvent::Keyboard )
02349 {
02350 makeVisible( m_cursor, 0 );
02351 p = cursorCoordinates();
02352 }
02353 else if ( ! m_view->selection() || m_view->config()->persistentSelection() )
02354 placeCursor( e->pos() );
02355
02356
02357 if (m_view->contextMenu()) {
02358 m_view->contextMenu()->popup( mapToGlobal( p ) );
02359 e->accept ();
02360 }
02361 }
02362
02363 void KateViewInternal::mousePressEvent( QMouseEvent* e )
02364 {
02365 switch (e->button())
02366 {
02367 case Qt::LeftButton:
02368 m_selChangedByUser = false;
02369
02370 if (m_possibleTripleClick)
02371 {
02372 m_possibleTripleClick = false;
02373
02374 m_selectionMode = Line;
02375
02376 if ( e->modifiers() & Qt::ShiftModifier )
02377 {
02378 updateSelection( m_cursor, true );
02379 }
02380 else
02381 {
02382 m_view->selectLine( m_cursor );
02383 }
02384
02385 if (m_view->selection())
02386 QApplication::clipboard()->setText(m_view->selectionText (), QClipboard::Selection);
02387
02388
02389
02390 if ( m_selectAnchor.line() > m_view->selectionRange().start().line() )
02391 {
02392
02393 if ( m_selectAnchor == m_view->selectionRange().end() && m_selectAnchor.column() == 0 )
02394 m_selectionCached.start().setPosition( m_selectAnchor.line()-1, 0 );
02395 else
02396 m_selectionCached.start().setPosition( m_selectAnchor.line(), 0 );
02397 m_selectionCached.end() = m_view->selectionRange().end();
02398 }
02399 else
02400 {
02401
02402 m_selectionCached.start() = m_view->selectionRange().start();
02403 if ( m_view->selectionRange().end().line() > m_view->selectionRange().start().line() )
02404 m_selectionCached.end().setPosition( m_view->selectionRange().start().line()+1, 0 );
02405 else
02406 m_selectionCached.end() = m_view->selectionRange().end();
02407 }
02408
02409
02410
02411 if ( m_view->selectionRange().start() < m_selectAnchor
02412 && m_selectAnchor.line() != m_view->selectionRange().start().line() )
02413 updateCursor( m_view->selectionRange().start() );
02414 else
02415 updateCursor( m_view->selectionRange().end() );
02416
02417 e->accept();
02418 return;
02419 }
02420 else if ( m_selectionMode == Default )
02421 {
02422 m_selectionMode = Mouse;
02423 }
02424
02425 if ( e->modifiers() & Qt::ShiftModifier )
02426 {
02427 if ( !m_selectAnchor.isValid() )
02428 m_selectAnchor = m_cursor;
02429 }
02430 else
02431 {
02432 m_selectionCached = KTextEditor::Range::invalid();
02433 }
02434
02435 if( !(e->modifiers() & Qt::ShiftModifier) && isTargetSelected( e->pos() ) )
02436 {
02437 m_dragInfo.state = diPending;
02438 m_dragInfo.start = e->pos();
02439 }
02440 else
02441 {
02442 m_dragInfo.state = diNone;
02443
02444 if ( e->modifiers() & Qt::ShiftModifier )
02445 {
02446 placeCursor( e->pos(), true, false );
02447 if ( m_selectionCached.start().isValid() )
02448 {
02449 if ( m_cursor < m_selectionCached.start() )
02450 m_selectAnchor = m_selectionCached.end();
02451 else
02452 m_selectAnchor = m_selectionCached.start();
02453 }
02454 m_view->setSelection( KTextEditor::Range( m_selectAnchor, m_cursor ) );
02455 }
02456 else
02457 {
02458 placeCursor( e->pos() );
02459 }
02460
02461 m_scrollX = 0;
02462 m_scrollY = 0;
02463
02464 m_scrollTimer.start (50);
02465 }
02466
02467 e->accept ();
02468 break;
02469
02470 default:
02471 e->ignore ();
02472 break;
02473 }
02474 }
02475
02476 void KateViewInternal::mouseDoubleClickEvent(QMouseEvent *e)
02477 {
02478 switch (e->button())
02479 {
02480 case Qt::LeftButton:
02481 m_selectionMode = Word;
02482
02483 if ( e->modifiers() & Qt::ShiftModifier )
02484 {
02485 KTextEditor::Range oldSelection = m_view->selectionRange();
02486
02487
02488 int cs, ce;
02489 KateTextLine::Ptr l = m_doc->kateTextLine( m_selectAnchor.line() );
02490
02491 ce = m_selectAnchor.column();
02492 if ( ce > 0 && m_doc->highlight()->isInWord( l->at(ce) ) ) {
02493 for (; ce < l->length(); ce++ )
02494 if ( !m_doc->highlight()->isInWord( l->at(ce) ) )
02495 break;
02496 }
02497
02498 cs = m_selectAnchor.column() - 1;
02499 if ( cs < m_doc->lineLength( m_selectAnchor.line() )
02500 && m_doc->highlight()->isInWord( l->at(cs) ) ) {
02501 for ( cs--; cs >= 0; cs-- )
02502 if ( !m_doc->highlight()->isInWord( l->at(cs) ) )
02503 break;
02504 }
02505
02506
02507 if (cs+1 < ce)
02508 {
02509 m_selectionCached.start().setPosition( m_selectAnchor.line(), cs+1 );
02510 m_selectionCached.end().setPosition( m_selectAnchor.line(), ce );
02511 }
02512 else
02513 {
02514 m_selectionCached.start() = m_selectAnchor;
02515 m_selectionCached.end() = m_selectAnchor;
02516 }
02517
02518 placeCursor( e->pos(), true );
02519 }
02520 else
02521 {
02522
02523
02524
02525
02526
02527 m_view->clearSelection( false, false );
02528 placeCursor( e->pos() );
02529 m_view->selectWord( m_cursor );
02530
02531 if (m_view->selection())
02532 {
02533 m_selectAnchor = m_view->selectionRange().start();
02534 m_selectionCached = m_view->selectionRange();
02535 }
02536 else
02537 {
02538
02539
02540 m_selectionMode = Default;
02541 }
02542 }
02543
02544
02545 if (m_view->selection())
02546 {
02547 QApplication::clipboard()->setText( m_view->selectionText(), QClipboard::Selection );
02548
02549
02550
02551 if (m_view->selectionRange().start() < m_selectionCached.start())
02552 updateCursor( m_view->selectionRange().start() );
02553 else
02554 updateCursor( m_view->selectionRange().end() );
02555 }
02556
02557 m_possibleTripleClick = true;
02558 QTimer::singleShot ( QApplication::doubleClickInterval(), this, SLOT(tripleClickTimeout()) );
02559
02560 m_scrollX = 0;
02561 m_scrollY = 0;
02562
02563 m_scrollTimer.start (50);
02564
02565 e->accept ();
02566 break;
02567
02568 default:
02569 e->ignore ();
02570 break;
02571 }
02572 }
02573
02574 void KateViewInternal::tripleClickTimeout()
02575 {
02576 m_possibleTripleClick = false;
02577 }
02578
02579 void KateViewInternal::mouseReleaseEvent( QMouseEvent* e )
02580 {
02581 switch (e->button())
02582 {
02583 case Qt::LeftButton:
02584 m_selectionMode = Default;
02585
02586
02587 if (m_selChangedByUser)
02588 {
02589 if (m_view->selection()) {
02590 QApplication::clipboard()->setText(m_view->selectionText (), QClipboard::Selection);
02591
02592
02593
02594 if ( m_view->selectionRange().start() < m_selectAnchor )
02595 updateCursor( m_view->selectionRange().start() );
02596 else
02597 updateCursor( m_view->selectionRange().end() );
02598 }
02599
02600 m_selChangedByUser = false;
02601 }
02602
02603 if (m_dragInfo.state == diPending)
02604 placeCursor( e->pos(), e->modifiers() & Qt::ShiftModifier );
02605 else if (m_dragInfo.state == diNone)
02606 m_scrollTimer.stop ();
02607
02608 m_dragInfo.state = diNone;
02609
02610 e->accept ();
02611 break;
02612
02613 case Qt::MidButton:
02614 placeCursor( e->pos() );
02615
02616 if( m_doc->isReadWrite() )
02617 {
02618 m_doc->paste( m_view, QClipboard::Selection );
02619 repaint();
02620 }
02621
02622 e->accept ();
02623 break;
02624
02625 default:
02626 e->ignore ();
02627 break;
02628 }
02629 }
02630
02631 void KateViewInternal::leaveEvent( QEvent* )
02632 {
02633 m_textHintTimer.stop();
02634 }
02635
02636 void KateViewInternal::mouseMoveEvent( QMouseEvent* e )
02637 {
02638
02639 const KateTextLayout& thisLine = yToKateTextLayout(e->y());
02640 if (thisLine.isValid()) {
02641 KTextEditor::Cursor newPosition = renderer()->xToCursor(thisLine, e->x(), !view()->wrapCursor());
02642 if (newPosition != m_mouse) {
02643 m_mouse = newPosition;
02644 mouseMoved();
02645 }
02646 } else {
02647 if (m_mouse.isValid()) {
02648 m_mouse = KTextEditor::Cursor::invalid();
02649 mouseMoved();
02650 }
02651 }
02652
02653 if( e->buttons() & Qt::LeftButton )
02654 {
02655 if (m_dragInfo.state == diPending)
02656 {
02657
02658
02659 QPoint p( e->pos() - m_dragInfo.start );
02660
02661
02662 if( p.manhattanLength() > KGlobalSettings::dndEventDelay() )
02663 doDrag();
02664
02665 return;
02666 }
02667 else if (m_dragInfo.state == diDragging)
02668 {
02669
02670
02671 return;
02672 }
02673
02674 m_mouseX = e->x();
02675 m_mouseY = e->y();
02676
02677 m_scrollX = 0;
02678 m_scrollY = 0;
02679 int d = renderer()->fontHeight();
02680
02681 if (m_mouseX < 0)
02682 m_scrollX = -d;
02683
02684 if (m_mouseX > width())
02685 m_scrollX = d;
02686
02687 if (m_mouseY < 0)
02688 {
02689 m_mouseY = 0;
02690 m_scrollY = -d;
02691 }
02692
02693 if (m_mouseY > height())
02694 {
02695 m_mouseY = height();
02696 m_scrollY = d;
02697 }
02698
02699 placeCursor( QPoint( m_mouseX, m_mouseY ), true );
02700
02701 }
02702 else
02703 {
02704 if (isTargetSelected( e->pos() ) ) {
02705
02706
02707 if (m_mouseCursor != Qt::ArrowCursor) {
02708 m_mouseCursor = Qt::ArrowCursor;
02709 setCursor(m_mouseCursor);
02710 }
02711 } else {
02712
02713 if (m_mouseCursor != Qt::IBeamCursor) {
02714 m_mouseCursor = Qt::IBeamCursor;
02715 setCursor(m_mouseCursor);
02716 }
02717 }
02718
02719
02720
02721 if (m_textHintEnabled && geometry().contains(mapFromGlobal(e->globalPos())))
02722 {
02723 m_textHintTimer.start(m_textHintTimeout);
02724 m_textHintMouseX=e->x();
02725 m_textHintMouseY=e->y();
02726 }
02727 }
02728 }
02729
02730 void KateViewInternal::updateDirty( )
02731 {
02732 uint h = renderer()->fontHeight();
02733
02734 int currentRectStart = -1;
02735 int currentRectEnd = -1;
02736
02737 QRegion updateRegion;
02738
02739 for (int i = 0; i < cache()->viewCacheLineCount(); ++i) {
02740 if (cache()->viewLine(i).isDirty()) {
02741 if (currentRectStart == -1) {
02742 currentRectStart = h * i;
02743 currentRectEnd = h;
02744 } else {
02745 currentRectEnd += h;
02746 }
02747
02748 } else if (currentRectStart != -1) {
02749 updateRegion += QRect(0, currentRectStart, width(), currentRectEnd);
02750 currentRectStart = -1;
02751 currentRectEnd = -1;
02752 }
02753 }
02754
02755 if (currentRectStart != -1)
02756 updateRegion += QRect(0, currentRectStart, width(), currentRectEnd);
02757
02758 if (!updateRegion.isEmpty()) {
02759 if (debugPainting) kDebug( 13030 ) << k_funcinfo << "Update dirty region " << updateRegion;
02760 update(updateRegion);
02761 }
02762 }
02763
02764 void KateViewInternal::hideEvent(QHideEvent* e)
02765 {
02766 Q_UNUSED(e);
02767 if(m_view->isCompletionActive())
02768 m_view->completionWidget()->abortCompletion();
02769 }
02770
02771 void KateViewInternal::paintEvent(QPaintEvent *e)
02772 {
02773 QMutexLocker lock(m_doc->smartMutex());
02774
02775 if (m_smartDirty)
02776 doUpdateView();
02777
02778 if (debugPainting) kDebug (13030) << "GOT PAINT EVENT: Region" << e->region();
02779
02780 const QRect& unionRect = e->rect();
02781
02782 int xStart = startX() + unionRect.x();
02783 int xEnd = xStart + unionRect.width();
02784 uint h = renderer()->fontHeight();
02785 uint startz = (unionRect.y() / h);
02786 uint endz = startz + 1 + (unionRect.height() / h);
02787 uint lineRangesSize = cache()->viewCacheLineCount();
02788
02789 QPainter paint(this);
02790 paint.setRenderHints (QPainter::Antialiasing);
02791
02792
02793 renderer()->setCaretStyle(m_view->isOverwriteMode() ? KateRenderer::Block : KateRenderer::Line);
02794 renderer()->setShowTabs(m_doc->config()->configFlags() & KateDocumentConfig::cfShowTabs);
02795 renderer()->setShowTrailingSpaces(m_doc->config()->configFlags() & KateDocumentConfig::cfShowSpaces);
02796
02797 int sy = startz * h;
02798 paint.translate(unionRect.x(), startz * h);
02799
02800 for (uint z=startz; z <= endz; z++)
02801 {
02802 if ( (z >= lineRangesSize) || (cache()->viewLine(z).line() == -1) )
02803 {
02804 if (!(z >= lineRangesSize))
02805 cache()->viewLine(z).setDirty(false);
02806
02807 paint.fillRect( 0, 0, unionRect.width(), h, renderer()->config()->backgroundColor() );
02808 }
02809 else
02810 {
02811
02812 KateTextLayout& thisLine = cache()->viewLine(z);
02813
02814 if (!thisLine.viewLine() || z == startz) {
02815
02816 if (!e->region().contains(QRect(unionRect.x(), startz * h, unionRect.width(), h)))
02817 continue;
02818
02819
02820
02821
02822 if (thisLine.viewLine())
02823 paint.translate(QPoint(0, h * - thisLine.viewLine()));
02824
02825
02826
02827
02828 renderer()->paintTextLine(paint, thisLine.kateLineLayout(), xStart, xEnd, &m_cursor);
02829
02830
02831
02832 if (thisLine.viewLine())
02833 paint.translate(0, h * thisLine.viewLine());
02834
02835 thisLine.setDirty(false);
02836 }
02837 }
02838
02839 paint.translate(0, h);
02840 sy += h;
02841 }
02842 }
02843
02844 void KateViewInternal::resizeEvent(QResizeEvent* e)
02845 {
02846 bool expandedHorizontally = width() > e->oldSize().width();
02847 bool expandedVertically = height() > e->oldSize().height();
02848 bool heightChanged = height() != e->oldSize().height();
02849
02850 m_madeVisible = false;
02851
02852 if (heightChanged) {
02853 setAutoCenterLines(m_autoCenterLines, false);
02854 m_cachedMaxStartPos.setPosition(-1, -1);
02855 }
02856
02857 if (m_view->dynWordWrap()) {
02858 bool dirtied = false;
02859
02860 for (int i = 0; i < cache()->viewCacheLineCount(); i++) {
02861
02862
02863 if (cache()->viewLine(i).wrap() ||
02864 (!expandedHorizontally && (cache()->viewLine(i).endX() - cache()->viewLine(i).startX()) > width())) {
02865 dirtied = true;
02866 cache()->viewLine(i).setDirty();
02867 break;
02868 }
02869 }
02870
02871 if (dirtied || heightChanged) {
02872 updateView(true);
02873 m_leftBorder->update();
02874 }
02875
02876 if (width() < e->oldSize().width()) {
02877 if (!m_view->wrapCursor()) {
02878
02879 if (m_cursor.column() > m_doc->lineLength(m_cursor.line())) {
02880 KateTextLayout thisLine = currentLayout();
02881
02882 KTextEditor::Cursor newCursor(m_cursor.line(), thisLine.endCol() + ((width() - thisLine.xOffset() - thisLine.width()) / renderer()->spaceWidth()) - 1);
02883 updateCursor(newCursor);
02884 }
02885 }
02886 }
02887
02888 } else {
02889 updateView();
02890
02891 if (expandedHorizontally && startX() > 0)
02892 scrollColumns(startX() - (width() - e->oldSize().width()));
02893 }
02894
02895 if (expandedVertically) {
02896 KTextEditor::Cursor max = maxStartPos();
02897 if (startPos() > max)
02898 scrollPos(max);
02899 }
02900 }
02901
02902 void KateViewInternal::scrollTimeout ()
02903 {
02904 if (m_scrollX || m_scrollY)
02905 {
02906 scrollLines (startPos().line() + (m_scrollY / (int) renderer()->fontHeight()));
02907 placeCursor( QPoint( m_mouseX, m_mouseY ), true );
02908 }
02909 }
02910
02911 void KateViewInternal::cursorTimeout ()
02912 {
02913 if (!debugPainting) {
02914 renderer()->setDrawCaret(!renderer()->drawCaret());
02915 paintCursor();
02916 }
02917 }
02918
02919 void KateViewInternal::textHintTimeout ()
02920 {
02921 m_textHintTimer.stop ();
02922
02923 KateTextLayout thisLine = yToKateTextLayout(m_textHintMouseY);
02924
02925 if (!thisLine.isValid()) return;
02926
02927 if (m_textHintMouseX> (lineMaxCursorX(thisLine) - thisLine.startX())) return;
02928
02929 KTextEditor::Cursor c = thisLine.start();
02930 c = renderer()->xToCursor(cache()->textLayout(c), m_textHintMouseX, !view()->wrapCursor());
02931
02932 QString tmp;
02933
02934 emit m_view->needTextHint(c, tmp);
02935
02936 if (!tmp.isEmpty()) kDebug(13030)<<"Hint text: "<<tmp;
02937 }
02938
02939 void KateViewInternal::focusInEvent (QFocusEvent *)
02940 {
02941 if (KApplication::cursorFlashTime() > 0)
02942 m_cursorTimer.start ( KApplication::cursorFlashTime() / 2 );
02943
02944 paintCursor();
02945
02946 m_doc->setActiveView( m_view );
02947
02948
02949 m_view->slotGotFocus ();
02950 }
02951
02952 void KateViewInternal::focusOutEvent (QFocusEvent *)
02953 {
02954
02955
02956
02957 m_cursorTimer.stop();
02958 m_view->renderer()->setDrawCaret(true);
02959 paintCursor();
02960
02961 m_textHintTimer.stop();
02962
02963 m_view->slotLostFocus ();
02964 }
02965
02966 void KateViewInternal::doDrag()
02967 {
02968 m_dragInfo.state = diDragging;
02969 m_dragInfo.dragObject = new QDrag(this);
02970 QMimeData *mimeData=new QMimeData();
02971 mimeData->setText(m_view->selectionText());
02972 m_dragInfo.dragObject->setMimeData(mimeData);
02973 m_dragInfo.dragObject->start(Qt::MoveAction);
02974 }
02975
02976 void KateViewInternal::dragEnterEvent( QDragEnterEvent* event )
02977 {
02978 if (event->source()==this) event->setDropAction(Qt::MoveAction);
02979 event->setAccepted( (event->mimeData()->hasText() && m_doc->isReadWrite()) ||
02980 KUrl::List::canDecode(event->mimeData()) );
02981 }
02982
02983 void KateViewInternal::fixDropEvent(QDropEvent* event) {
02984 if (event->source()!=this) event->setDropAction(Qt::CopyAction);
02985 else {
02986 Qt::DropAction action=Qt::MoveAction;
02987 #ifdef Q_WS_MAC
02988 if(event->keyboardModifiers() & Qt::AltModifier)
02989 action = Qt::CopyAction;
02990 #else
02991 if (event->keyboardModifiers() & Qt::ControlModifier)
02992 action = Qt::CopyAction;
02993 #endif
02994 event->setDropAction(action);
02995 }
02996 }
02997
02998 void KateViewInternal::dragMoveEvent( QDragMoveEvent* event )
02999 {
03000
03001 placeCursor( event->pos(), true, false );
03002
03003
03004
03005 fixDropEvent(event);
03006 }
03007
03008 void KateViewInternal::dropEvent( QDropEvent* event )
03009 {
03010 if ( KUrl::List::canDecode(event->mimeData()) ) {
03011
03012 emit dropEventPass(event);
03013
03014 } else if ( event->mimeData()->hasText() && m_doc->isReadWrite() ) {
03015
03016 QString text=event->mimeData()->text();
03017
03018
03019 bool priv = false;
03020 if (KateViewInternal* vi = qobject_cast<KateViewInternal*>(event->source()))
03021 priv = m_doc->ownedView( vi->m_view );
03022
03023
03024 bool selected = m_view->cursorSelected(m_cursor);
03025
03026 if( priv && selected ) {
03027
03028
03029 return;
03030 }
03031
03032 fixDropEvent(event);
03033
03034
03035 m_doc->editStart ();
03036
03037
03038
03039
03040 KTextEditor::Cursor startCursor1(m_cursor);
03041 m_doc->insertText(m_cursor, text );
03042
03043 KateSmartCursor startCursor(startCursor1,m_doc);
03044
03045 if ( event->dropAction() != Qt::CopyAction )
03046 m_view->removeSelectedText();
03047
03048
03049
03050 m_doc->editEnd ();
03051
03052 placeCursor( event->pos() );
03053 event->acceptProposedAction();
03054 updateView();
03055
03056 KateSmartCursor endCursor1(startCursor,m_doc);
03057 endCursor1.advance(text.length(),KTextEditor::SmartCursor::ByCharacter);
03058 KTextEditor::Cursor endCursor(endCursor1);
03059 kDebug( 13030 )<<startCursor<<"---("<<text.length()<<")---"<<endCursor;
03060 m_view->setSelection(KTextEditor::Range(startCursor,endCursor));
03061
03062 updateView();
03063 }
03064
03065
03066 m_dragInfo.state = diNone;
03067
03068 stopDragScroll();
03069 }
03070
03071
03072 void KateViewInternal::clear()
03073 {
03074 m_startPos = m_displayCursor = m_cursor = KTextEditor::Cursor(0, 0);
03075 updateView(true);
03076 }
03077
03078 void KateViewInternal::wheelEvent(QWheelEvent* e)
03079 {
03080 if (m_lineScroll->minimum() != m_lineScroll->maximum() && e->orientation() != Qt::Horizontal) {
03081
03082 if ( ( e->modifiers() & Qt::ControlModifier ) || ( e->modifiers() & Qt::ShiftModifier ) ) {
03083 if (e->delta() > 0)
03084 scrollPrevPage();
03085 else
03086 scrollNextPage();
03087 } else {
03088 scrollViewLines(-((e->delta() / 120) * QApplication::wheelScrollLines()));
03089 }
03090
03091 } else if (columnScrollingPossible()) {
03092 QWheelEvent copy = *e;
03093 QApplication::sendEvent(m_columnScroll, ©);
03094
03095 } else {
03096 e->ignore();
03097 }
03098 }
03099
03100 void KateViewInternal::startDragScroll()
03101 {
03102 if ( !m_dragScrollTimer.isActive() ) {
03103 m_dragScrollTimer.start( s_scrollTime );
03104 }
03105 }
03106
03107 void KateViewInternal::stopDragScroll()
03108 {
03109 m_dragScrollTimer.stop();
03110 updateView();
03111 }
03112
03113 void KateViewInternal::doDragScroll()
03114 {
03115 QPoint p = this->mapFromGlobal( QCursor::pos() );
03116
03117 int dx = 0, dy = 0;
03118 if ( p.y() < s_scrollMargin ) {
03119 dy = p.y() - s_scrollMargin;
03120 } else if ( p.y() > height() - s_scrollMargin ) {
03121 dy = s_scrollMargin - (height() - p.y());
03122 }
03123
03124 if ( p.x() < s_scrollMargin ) {
03125 dx = p.x() - s_scrollMargin;
03126 } else if ( p.x() > width() - s_scrollMargin ) {
03127 dx = s_scrollMargin - (width() - p.x());
03128 }
03129
03130 dy /= 4;
03131
03132 if (dy)
03133 scrollLines(startPos().line() + dy);
03134
03135 if (columnScrollingPossible () && dx)
03136 scrollColumns(qMin (m_startX + dx, m_columnScroll->maximum()));
03137
03138 if (!dy && !dx)
03139 stopDragScroll();
03140 }
03141
03142 void KateViewInternal::enableTextHints(int timeout)
03143 {
03144 m_textHintTimeout=timeout;
03145 m_textHintEnabled=true;
03146 m_textHintTimer.start(timeout);
03147 }
03148
03149 void KateViewInternal::disableTextHints()
03150 {
03151 m_textHintEnabled=false;
03152 m_textHintTimer.stop ();
03153 }
03154
03155
03156 void KateViewInternal::editStart()
03157 {
03158 editSessionNumber++;
03159
03160 if (editSessionNumber > 1)
03161 return;
03162
03163 editIsRunning = true;
03164 editOldCursor = m_cursor;
03165 }
03166
03167 void KateViewInternal::editEnd(int editTagLineStart, int editTagLineEnd, bool tagFrom)
03168 {
03169 if (editSessionNumber == 0)
03170 return;
03171
03172 editSessionNumber--;
03173
03174 if (editSessionNumber > 0)
03175 return;
03176
03177 if (tagFrom && (editTagLineStart <= int(m_doc->getRealLine(startLine()))))
03178 tagAll();
03179 else
03180 tagLines (editTagLineStart, tagFrom ? qMax(m_doc->lastLine() + 1, editTagLineEnd) : editTagLineEnd, true);
03181
03182 if (editOldCursor == m_cursor)
03183 updateBracketMarks();
03184
03185 updateView(true);
03186
03187 if (editOldCursor != m_cursor)
03188 {
03189 m_madeVisible = false;
03190 updateCursor ( m_cursor, true );
03191 }
03192 else if ( m_view == m_doc->activeView() )
03193 {
03194 makeVisible(m_displayCursor, m_displayCursor.column());
03195 }
03196
03197 editIsRunning = false;
03198 }
03199
03200 void KateViewInternal::editSetCursor (const KTextEditor::Cursor &_cursor)
03201 {
03202 if (m_cursor != _cursor)
03203 {
03204 m_cursor = _cursor;
03205 }
03206 }
03207
03208
03209 void KateViewInternal::viewSelectionChanged ()
03210 {
03211 if (!m_view->selection())
03212 {
03213 m_selectAnchor = KTextEditor::Cursor::invalid();
03214
03215
03216
03217
03218
03219 m_selectionCached.start() = KTextEditor::Cursor::invalid();
03220
03221 }
03222 }
03223
03224 KateLayoutCache* KateViewInternal::cache( ) const
03225 {
03226 return m_layoutCache;
03227 }
03228
03229 KTextEditor::Cursor KateViewInternal::toRealCursor( const KTextEditor::Cursor & virtualCursor ) const
03230 {
03231 return KTextEditor::Cursor(m_doc->getRealLine(virtualCursor.line()), virtualCursor.column());
03232 }
03233
03234 KTextEditor::Cursor KateViewInternal::toVirtualCursor( const KTextEditor::Cursor & realCursor ) const
03235 {
03236 return KTextEditor::Cursor(m_doc->getVirtualLine(realCursor.line()), realCursor.column());
03237 }
03238
03239 KateRenderer * KateViewInternal::renderer( ) const
03240 {
03241 return m_view->renderer();
03242 }
03243
03244 void KateViewInternal::dynamicHighlightAdded( KateSmartRange * range )
03245 {
03246 QMutexLocker lock(m_doc->smartMutex());
03247
03248 DynamicRangeHL* hl = new DynamicRangeHL(range);
03249 hl->isView = view() == sender();
03250
03251 m_dynamicHighlights.insert(range, hl);
03252
03253 if (m_mouse.isValid())
03254
03255 dynamicMoved(true);
03256
03257 dynamicMoved(false);
03258 }
03259
03260 void KateViewInternal::dynamicHighlightRemoved( KateSmartRange * range )
03261 {
03262 QMutexLocker lock(m_doc->smartMutex());
03263
03264 removeWatcher(range, this);
03265
03266 delete m_dynamicHighlights.take(range);
03267 }
03268
03269 void KateViewInternal::rangeDeleted( KateSmartRange * range )
03270 {
03271 QMutexLocker lock(m_doc->smartMutex());
03272
03273 if (m_dynamicHighlights.contains(range)) {
03274 delete m_dynamicHighlights.take(range);
03275 return;
03276 }
03277
03278 foreach (DynamicRangeHL* hl, m_dynamicHighlights) {
03279
03280 if (hl->mouseAnimations.contains(range))
03281 delete hl->mouseAnimations.take(range);
03282
03283 if (hl->mouseOver && (hl->mouseOver == range || hl->mouseOver->hasParent(range))) {
03284 hl->mouseOver = static_cast<KateSmartRange*>(range->parentRange());
03285 }
03286
03287 if (hl->caretAnimations.contains(range))
03288 delete hl->caretAnimations.take(range);
03289
03290 if (hl->caretOver && (hl->caretOver == range || hl->caretOver->hasParent(range))) {
03291 hl->caretOver = static_cast<KateSmartRange*>(range->parentRange());
03292 }
03293 }
03294 }
03295
03296 void KateViewInternal::startDynamic( DynamicRangeHL* hl, KateSmartRange* range, KTextEditor::Attribute::ActivationType type )
03297 {
03298 QMutexLocker lock(m_doc->smartMutex());
03299
03300 if (type == KTextEditor::Attribute::ActivateMouseIn)
03301 range->setMouseOver(true);
03302 else
03303 range->setCaretOver(true);
03304
03305 if (!range->attribute() || !range->attribute()->dynamicAttribute(type))
03306 return;
03307
03308 KateDynamicAnimation* anim;
03309 if (hl->isView)
03310 anim = new KateDynamicAnimation(view(), range, type);
03311 else
03312 anim = new KateDynamicAnimation(m_doc, range, type);
03313
03314 connect(anim, SIGNAL(redraw(KateSmartRange*)), SLOT(updateRange(KateSmartRange*)));
03315
03316 if (type == KTextEditor::Attribute::ActivateMouseIn)
03317 hl->mouseAnimations.insert(range, anim);
03318 else
03319 hl->caretAnimations.insert(range, anim);
03320
03321 renderer()->dynamicRegion().addRange(range);
03322 }
03323
03324 void KateViewInternal::endDynamic( DynamicRangeHL* hl, KateSmartRange* range, KTextEditor::Attribute::ActivationType type )
03325 {
03326 QMutexLocker lock(m_doc->smartMutex());
03327
03328 if (type == KTextEditor::Attribute::ActivateMouseIn)
03329 range->setMouseOver(false);
03330 else
03331 range->setCaretOver(false);
03332
03333 if (!range->attribute() || !range->attribute()->dynamicAttribute(type))
03334 return;
03335
03336 KateDynamicAnimation* anim = 0L;
03337 if (type == KTextEditor::Attribute::ActivateMouseIn) {
03338 Q_ASSERT(hl->mouseAnimations.contains(range));
03339 anim = hl->mouseAnimations.take(range);
03340
03341 } else {
03342 Q_ASSERT(hl->caretAnimations.contains(range));
03343 anim = hl->caretAnimations.take(range);
03344 }
03345
03346 if (anim)
03347 anim->finish();
03348
03349
03350
03351
03352
03353
03354 }
03355
03356 void KateViewInternal::updateRange(KateSmartRange* range)
03357 {
03358
03359 tagRange(*range, true);
03360 updateDirty();
03361 }
03362
03363 void KateViewInternal::dynamicMoved( bool mouse )
03364 {
03365 QMutexLocker lock(m_doc->smartMutex());
03366
03367 foreach (DynamicRangeHL* hl, m_dynamicHighlights) {
03368 QStack<KTextEditor::SmartRange*> enterStack, exitStack;
03369 KTextEditor::SmartRange* oldRange = mouse ? hl->mouseOver : hl->caretOver;
03370 KTextEditor::SmartRange* newRange;
03371 if (mouse)
03372 newRange = (hl->mouseOver ? hl->mouseOver : hl->top)->deepestRangeContaining(m_mouse, &enterStack, &exitStack);
03373 else
03374 newRange = (hl->caretOver ? hl->caretOver : hl->top)->deepestRangeContaining(m_cursor, &enterStack, &exitStack);
03375
03376 if (newRange != oldRange) {
03377 if (newRange && !oldRange)
03378 enterStack.prepend(newRange);
03379
03380 foreach (KTextEditor::SmartRange* exitedRange, exitStack) {
03381 endDynamic(hl, static_cast<KateSmartRange*>(exitedRange), mouse ? KTextEditor::Attribute::ActivateMouseIn : KTextEditor::Attribute::ActivateCaretIn);
03382 static_cast<KateSmartRange*>(exitedRange)->feedbackMouseCaretChange(m_view, mouse, false);
03383 }
03384
03385 foreach (KTextEditor::SmartRange* enteredRange, enterStack) {
03386 static_cast<KateSmartRange*>(enteredRange)->feedbackMouseCaretChange(m_view, mouse, true);
03387 startDynamic(hl, static_cast<KateSmartRange*>(enteredRange), mouse ? KTextEditor::Attribute::ActivateMouseIn : KTextEditor::Attribute::ActivateCaretIn);
03388 }
03389
03390 if (mouse)
03391 hl->mouseOver = static_cast<KateSmartRange*>(newRange);
03392 else
03393 hl->caretOver = static_cast<KateSmartRange*>(newRange);
03394 }
03395 }
03396 }
03397
03398 void KateViewInternal::mouseMoved( )
03399 {
03400 view()->notifyMousePositionChanged(m_mouse);
03401
03402 dynamicMoved(true);
03403 }
03404
03405 KateViewInternal::DynamicRangeHL::DynamicRangeHL(KateSmartRange* _top)
03406 : top(_top)
03407 , isView(false)
03408 , caretOver(0L)
03409 , mouseOver(0L)
03410 {
03411 }
03412
03413 KateViewInternal::DynamicRangeHL::~ DynamicRangeHL( )
03414 {
03415 qDeleteAll(caretAnimations);
03416 qDeleteAll(mouseAnimations);
03417 }
03418
03419 void KateViewInternal::cursorMoved( )
03420 {
03421 dynamicMoved(false);
03422 }
03423
03424 void KateViewInternal::relayoutRange( const KTextEditor::Range & range, bool realCursors )
03425 {
03426 int startLine = realCursors ? range.start().line() : toRealCursor(range.start()).line();
03427 int endLine = realCursors ? range.end().line() : toRealCursor(range.end()).line();
03428
03429
03430 cache()->relayoutLines(startLine, endLine);
03431
03432 if (!m_smartDirty) {
03433 m_smartDirty = true;
03434 emit requestViewUpdate(true);
03435 }
03436 }
03437
03438 void KateViewInternal::rangePositionChanged( KTextEditor::SmartRange * range )
03439 {
03440 relayoutRange(*range);
03441 }
03442
03443 void KateViewInternal::rangeDeleted( KTextEditor::SmartRange * range )
03444 {
03445 relayoutRange(*range);
03446 }
03447
03448 void KateViewInternal::childRangeInserted( KTextEditor::SmartRange *, KTextEditor::SmartRange * child )
03449 {
03450 QMutexLocker lock(m_doc->smartMutex());
03451
03452 relayoutRange(*child);
03453 addWatcher(child, this);
03454 }
03455
03456 void KateViewInternal::rangeAttributeChanged( KTextEditor::SmartRange * range, KTextEditor::Attribute::Ptr currentAttribute, KTextEditor::Attribute::Ptr previousAttribute )
03457 {
03458 if (currentAttribute != previousAttribute)
03459 relayoutRange(*range);
03460 }
03461
03462 void KateViewInternal::childRangeRemoved( KTextEditor::SmartRange *, KTextEditor::SmartRange * child )
03463 {
03464 QMutexLocker lock(m_doc->smartMutex());
03465
03466 relayoutRange(*child);
03467 removeWatcher(child, this);
03468 }
03469
03470 void KateViewInternal::addHighlightRange(KTextEditor::SmartRange* range)
03471 {
03472 QMutexLocker lock(m_doc->smartMutex());
03473
03474 relayoutRange(*range);
03475 ++m_watcherCount3;
03476 addWatcher(range, this);
03477 }
03478
03479 void KateViewInternal::removeHighlightRange(KTextEditor::SmartRange* range)
03480 {
03481 QMutexLocker lock(m_doc->smartMutex());
03482
03483 relayoutRange(*range);
03484 --m_watcherCount3;
03485 removeWatcher(range, this);
03486 }
03487
03488
03489 QVariant KateViewInternal::inputMethodQuery ( Qt::InputMethodQuery query ) const
03490 {
03491 switch (query) {
03492 case Qt::ImMicroFocus: {
03493
03494
03495
03496
03497
03498 KTextEditor::Cursor c = m_cursor;
03499 if (m_imPreedit)
03500 c = m_imPreedit->start();
03501 return QRect(cursorToCoordinate(c, true, false), QSize(0, renderer()->fontHeight()));
03502 }
03503
03504 case Qt::ImFont:
03505 return renderer()->currentFont();
03506
03507 case Qt::ImCursorPosition:
03508 if (m_imPreedit)
03509 return cursorToCoordinate(m_imPreedit->start(), true, false);
03510 else
03511 return cursorCoordinates(false);
03512
03513 case Qt::ImSurroundingText:
03514 if (KateTextLine::Ptr l = textLine(m_cursor.line()))
03515 return l->string();
03516 else
03517 return QString();
03518
03519 case Qt::ImCurrentSelection:
03520 if (view()->selection())
03521 return view()->selectionText();
03522 else
03523 return QString();
03524 }
03525
03526 return QWidget::inputMethodQuery(query);
03527 }
03528
03529 void KateViewInternal::inputMethodEvent(QInputMethodEvent* e)
03530 {
03531 if ( m_doc->readOnly() ) {
03532 e->ignore();
03533 return;
03534 }
03535
03536
03537
03538 if ( m_view->selection() )
03539 m_view->removeSelectedText();
03540
03541 bool createdPreedit = false;
03542 if (!m_imPreedit) {
03543 createdPreedit = true;
03544 m_imPreedit = m_view->doc()->smartManager()->newSmartRange(KTextEditor::Range(m_cursor, m_cursor), 0L, KTextEditor::SmartRange::ExpandLeft | KTextEditor::SmartRange::ExpandRight);
03545 }
03546
03547 if (!m_imPreedit->isEmpty()) {
03548 m_view->doc()->editStart(false);
03549 m_view->doc()->removeText(*m_imPreedit);
03550 m_view->doc()->editEnd();
03551 }
03552
03553 if (!e->commitString().isEmpty() || e->replacementLength()) {
03554 KTextEditor::Range preeditRange = *m_imPreedit;
03555
03556 KTextEditor::Cursor start(m_imPreedit->start().line(), m_imPreedit->start().column() + e->replacementStart());
03557 KTextEditor::Cursor removeEnd = start + KTextEditor::Cursor(0, e->replacementLength());
03558
03559 m_view->doc()->editStart(true);
03560 if (start != removeEnd)
03561 m_view->doc()->removeText(KTextEditor::Range(start, removeEnd));
03562 if (!e->commitString().isEmpty())
03563 m_view->doc()->insertText(start, e->commitString());
03564 m_view->doc()->editEnd();
03565
03566
03567 m_imPreedit->setRange(preeditRange);
03568 }
03569
03570 if (!e->preeditString().isEmpty()) {
03571 m_view->doc()->editStart(false);
03572 m_view->doc()->insertText(m_imPreedit->start(), e->preeditString());
03573 m_view->doc()->editEnd();
03574
03575 }
03576
03577
03578 if (m_imPreedit && e->preeditString().isEmpty()) {
03579 if (!createdPreedit)
03580 m_view->removeInternalHighlight(m_imPreedit);
03581
03582 delete m_imPreedit;
03583 m_imPreedit = 0L;
03584
03585 renderer()->setDrawCaret(false);
03586 renderer()->setCaretOverrideColor(QColor());
03587
03588 return;
03589 }
03590
03591 KTextEditor::Cursor newCursor = m_cursor;
03592 bool hideCursor = false;
03593 QColor caretColor;
03594
03595 if (m_imPreedit) {
03596 m_imPreedit->clearAndDeleteChildRanges();
03597
03598 int decorationColumn = 0;
03599 foreach (const QInputMethodEvent::Attribute &a, e->attributes()) {
03600 if (a.type == QInputMethodEvent::Cursor) {
03601 newCursor = m_imPreedit->start() + KTextEditor::Cursor(0, a.start);
03602 hideCursor = !a.length;
03603 QColor c = qvariant_cast<QColor>(a.value);
03604 if (c.isValid())
03605 caretColor = c;
03606
03607 } else if (a.type == QInputMethodEvent::TextFormat) {
03608 QTextCharFormat f = qvariant_cast<QTextFormat>(a.value).toCharFormat();
03609 if (f.isValid() && decorationColumn <= a.start) {
03610 KTextEditor::Range fr(m_imPreedit->start().line(), m_imPreedit->start().column() + a.start, m_imPreedit->start().line(), m_imPreedit->start().column() + a.start + a.length);
03611 KTextEditor::SmartRange* formatRange = m_view->doc()->smartManager()->newSmartRange(fr, m_imPreedit);
03612 KTextEditor::Attribute::Ptr attribute(new KTextEditor::Attribute());
03613 attribute->merge(f);
03614 formatRange->setAttribute(attribute);
03615 decorationColumn = a.start + a.length;
03616 }
03617 }
03618 }
03619
03620 if (createdPreedit)
03621 m_view->addInternalHighlight(m_imPreedit);
03622 }
03623
03624 renderer()->setDrawCaret(hideCursor);
03625 renderer()->setCaretOverrideColor(caretColor);
03626
03627 if (newCursor != m_cursor)
03628 updateCursor(newCursor);
03629
03630 e->accept();
03631 }
03632
03633
03634
03635