kate Library API Documentation

kateviewinternal.cpp

00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org> 00003 Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org> 00004 Copyright (C) 2002,2003 Christoph Cullmann <cullmann@kde.org> 00005 Copyright (C) 2002,2003 Hamish Rodda <rodda@kde.org> 00006 Copyright (C) 2003 Anakim Border <aborder@sources.sourceforge.net> 00007 00008 Based on: 00009 KWriteView : Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de> 00010 00011 This library is free software; you can redistribute it and/or 00012 modify it under the terms of the GNU Library General Public 00013 License version 2 as published by the Free Software Foundation. 00014 00015 This library is distributed in the hope that it will be useful, 00016 but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 Library General Public License for more details. 00019 00020 You should have received a copy of the GNU Library General Public License 00021 along with this library; see the file COPYING.LIB. If not, write to 00022 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00023 Boston, MA 02111-1307, USA. 00024 */ 00025 00026 #include "kateviewinternal.h" 00027 #include "kateviewinternal.moc" 00028 00029 #include "kateview.h" 00030 #include "katedocument.h" 00031 #include "katecodefoldinghelpers.h" 00032 #include "kateviewhelpers.h" 00033 #include "katehighlight.h" 00034 #include "katesupercursor.h" 00035 #include "katerenderer.h" 00036 #include "katecodecompletion.h" 00037 #include "kateconfig.h" 00038 00039 #include <kcursor.h> 00040 #include <kdebug.h> 00041 #include <kapplication.h> 00042 #include <kglobalsettings.h> 00043 #include <kurldrag.h> 00044 00045 #include <qstyle.h> 00046 #include <qdragobject.h> 00047 #include <qpopupmenu.h> 00048 #include <qdropsite.h> 00049 #include <qpainter.h> 00050 #include <qlayout.h> 00051 #include <qclipboard.h> 00052 #include <qpixmap.h> 00053 00054 KateViewInternal::KateViewInternal(KateView *view, KateDocument *doc) 00055 : QWidget (view, "", Qt::WStaticContents | Qt::WRepaintNoErase | Qt::WResizeNoErase ) 00056 , editSessionNumber (0) 00057 , editIsRunning (false) 00058 , m_view (view) 00059 , m_doc (doc) 00060 , cursor (doc, true, 0, 0, this) 00061 , possibleTripleClick (false) 00062 , m_dummy (0) 00063 , m_startPos(0,0) 00064 , m_oldStartPos(0,0) 00065 , m_madeVisible(false) 00066 , m_shiftKeyPressed (false) 00067 , m_autoCenterLines (false) 00068 , m_columnScrollDisplayed(false) 00069 , m_selChangedByUser (false) 00070 , selectAnchor (-1, -1) 00071 , m_preserveMaxX(false) 00072 , m_currentMaxX(0) 00073 , m_usePlainLines(false) 00074 , m_updatingView(true) 00075 , m_cachedMaxStartPos(-1, -1) 00076 , m_dragScrollTimer(this) 00077 , m_scrollTimer (this) 00078 , m_cursorTimer (this) 00079 , m_textHintTimer (this) 00080 , m_suppressColumnScrollBar(false) 00081 , m_textHintEnabled(false) 00082 , m_textHintMouseX(-1) 00083 , m_textHintMouseY(-1) 00084 , m_imPreeditStartLine(0) 00085 , m_imPreeditStart(0) 00086 , m_imPreeditLength(0) 00087 { 00088 setMinimumSize (0,0); 00089 00090 // cursor 00091 cursor.setMoveOnInsert (true); 00092 00093 // 00094 // scrollbar for lines 00095 // 00096 m_lineScroll = new KateScrollBar(QScrollBar::Vertical, m_view); 00097 m_lineScroll->show(); 00098 m_lineScroll->setTracking (true); 00099 00100 m_lineLayout = new QVBoxLayout(); 00101 m_colLayout = new QHBoxLayout(); 00102 00103 m_colLayout->addWidget(m_lineScroll); 00104 m_lineLayout->addLayout(m_colLayout); 00105 00106 if (!m_view->dynWordWrap()) 00107 { 00108 // bottom corner box 00109 m_dummy = new QWidget(m_view); 00110 m_dummy->setFixedHeight(style().scrollBarExtent().width()); 00111 m_dummy->show(); 00112 m_lineLayout->addWidget(m_dummy); 00113 } 00114 00115 // Hijack the line scroller's controls, so we can scroll nicely for word-wrap 00116 connect(m_lineScroll, SIGNAL(prevPage()), SLOT(scrollPrevPage())); 00117 connect(m_lineScroll, SIGNAL(nextPage()), SLOT(scrollNextPage())); 00118 00119 connect(m_lineScroll, SIGNAL(prevLine()), SLOT(scrollPrevLine())); 00120 connect(m_lineScroll, SIGNAL(nextLine()), SLOT(scrollNextLine())); 00121 00122 connect(m_lineScroll, SIGNAL(sliderMoved(int)), SLOT(scrollLines(int))); 00123 connect(m_lineScroll, SIGNAL(sliderMMBMoved(int)), SLOT(scrollLines(int))); 00124 00125 // catch wheel events, completing the hijack 00126 m_lineScroll->installEventFilter(this); 00127 00128 // 00129 // scrollbar for columns 00130 // 00131 m_columnScroll = new QScrollBar(QScrollBar::Horizontal,m_view); 00132 m_columnScroll->hide(); 00133 m_columnScroll->setTracking(true); 00134 m_startX = 0; 00135 m_oldStartX = 0; 00136 00137 connect( m_columnScroll, SIGNAL( valueChanged (int) ), 00138 this, SLOT( scrollColumns (int) ) ); 00139 00140 // 00141 // iconborder ;) 00142 // 00143 leftBorder = new KateIconBorder( this, m_view ); 00144 leftBorder->show (); 00145 00146 connect( leftBorder, SIGNAL(toggleRegionVisibility(unsigned int)), 00147 m_doc->foldingTree(), SLOT(toggleRegionVisibility(unsigned int))); 00148 00149 connect( doc->foldingTree(), SIGNAL(regionVisibilityChangedAt(unsigned int)), 00150 this, SLOT(slotRegionVisibilityChangedAt(unsigned int))); 00151 connect( doc, SIGNAL(codeFoldingUpdated()), 00152 this, SLOT(slotCodeFoldingChanged()) ); 00153 00154 displayCursor.setPos(0, 0); 00155 cursor.setPos(0, 0); 00156 cXPos = 0; 00157 00158 setAcceptDrops( true ); 00159 setBackgroundMode( NoBackground ); 00160 00161 // event filter 00162 installEventFilter(this); 00163 00164 // im 00165 setInputMethodEnabled(true); 00166 00167 // set cursor 00168 setCursor( KCursor::ibeamCursor() ); 00169 00170 dragInfo.state = diNone; 00171 00172 // timers 00173 connect( &m_dragScrollTimer, SIGNAL( timeout() ), 00174 this, SLOT( doDragScroll() ) ); 00175 00176 connect( &m_scrollTimer, SIGNAL( timeout() ), 00177 this, SLOT( scrollTimeout() ) ); 00178 00179 connect( &m_cursorTimer, SIGNAL( timeout() ), 00180 this, SLOT( cursorTimeout() ) ); 00181 00182 connect( &m_textHintTimer, SIGNAL( timeout() ), 00183 this, SLOT( textHintTimeout() ) ); 00184 00185 // selection changed to set anchor 00186 connect( m_doc, SIGNAL( selectionChanged() ), 00187 this, SLOT( docSelectionChanged() ) ); 00188 00189 00190 // this is a work arround for RTL desktops 00191 // should be changed in kde 3.3 00192 // BTW: this comment has been "ported" from 3.1.X tree 00193 // any hacker with BIDI knowlege is welcomed to fix kate problems :) 00194 if (QApplication::reverseLayout()){ 00195 m_view->m_grid->addMultiCellWidget(leftBorder, 0, 1, 2, 2); 00196 m_view->m_grid->addMultiCellWidget(m_columnScroll, 1, 1, 0, 1); 00197 m_view->m_grid->addMultiCellLayout(m_lineLayout, 0, 0, 0, 0); 00198 } 00199 else{ 00200 m_view->m_grid->addMultiCellLayout(m_lineLayout, 0, 1, 2, 2); 00201 m_view->m_grid->addMultiCellWidget(m_columnScroll, 1, 1, 0, 1); 00202 m_view->m_grid->addWidget(leftBorder, 0, 0); 00203 } 00204 00205 updateView (); 00206 } 00207 00208 KateViewInternal::~KateViewInternal () 00209 { 00210 } 00211 00212 void KateViewInternal::prepareForDynWrapChange() 00213 { 00214 // Which is the current view line? 00215 m_wrapChangeViewLine = displayViewLine(displayCursor, true); 00216 } 00217 00218 void KateViewInternal::dynWrapChanged() 00219 { 00220 if (m_view->dynWordWrap()) 00221 { 00222 delete m_dummy; 00223 m_dummy = 0; 00224 m_columnScroll->hide(); 00225 m_columnScrollDisplayed = false; 00226 00227 } 00228 else 00229 { 00230 // bottom corner box 00231 m_dummy = new QWidget(m_view); 00232 m_dummy->setFixedSize( style().scrollBarExtent().width(), 00233 style().scrollBarExtent().width() ); 00234 m_dummy->show(); 00235 m_lineLayout->addWidget(m_dummy); 00236 } 00237 00238 tagAll(); 00239 updateView(); 00240 00241 if (m_view->dynWordWrap()) 00242 scrollColumns(0); 00243 00244 // Determine where the cursor should be to get the cursor on the same view line 00245 if (m_wrapChangeViewLine != -1) { 00246 KateTextCursor newStart = viewLineOffset(displayCursor, -m_wrapChangeViewLine); 00247 00248 // Account for the scrollbar in non-dyn-word-wrap mode 00249 if (!m_view->dynWordWrap() && scrollbarVisible(newStart.line())) { 00250 int lines = linesDisplayed() - 1; 00251 00252 if (m_view->height() != height()) 00253 lines++; 00254 00255 if (newStart.line() + lines == displayCursor.line()) 00256 newStart = viewLineOffset(displayCursor, 1 - m_wrapChangeViewLine); 00257 } 00258 00259 makeVisible(newStart, newStart.col(), true); 00260 00261 } else { 00262 update(); 00263 } 00264 } 00265 00266 KateTextCursor KateViewInternal::endPos() const 00267 { 00268 int viewLines = linesDisplayed() - 1; 00269 00270 if (viewLines < 0) { 00271 kdDebug(13030) << "WARNING: viewLines wrong!" << endl; 00272 viewLines = 0; 00273 } 00274 00275 // Check to make sure that lineRanges isn't invalid 00276 if (!lineRanges.count() || lineRanges[0].line == -1 || viewLines >= (int)lineRanges.count()) { 00277 // Switch off use of the cache 00278 return KateTextCursor(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1))); 00279 } 00280 00281 for (int i = viewLines; i >= 0; i--) { 00282 LineRange& thisRange = lineRanges[i]; 00283 00284 if (thisRange.line == -1) continue; 00285 00286 if (thisRange.virtualLine >= (int)m_doc->numVisLines()) { 00287 // Cache is too out of date 00288 return KateTextCursor(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1))); 00289 } 00290 00291 return KateTextCursor(thisRange.virtualLine, thisRange.wrap ? thisRange.endCol - 1 : thisRange.endCol); 00292 } 00293 00294 Q_ASSERT(false); 00295 kdDebug(13030) << "WARNING: could not find a lineRange at all" << endl; 00296 return KateTextCursor(-1, -1); 00297 } 00298 00299 uint KateViewInternal::endLine() const 00300 { 00301 return endPos().line(); 00302 } 00303 00304 LineRange KateViewInternal::yToLineRange(uint y) const 00305 { 00306 return lineRanges[y / m_view->renderer()->fontHeight()]; 00307 } 00308 00309 int KateViewInternal::lineToY(uint viewLine) const 00310 { 00311 return (viewLine-startLine()) * m_view->renderer()->fontHeight(); 00312 } 00313 00314 void KateViewInternal::slotIncFontSizes() 00315 { 00316 m_view->renderer()->increaseFontSizes(); 00317 } 00318 00319 void KateViewInternal::slotDecFontSizes() 00320 { 00321 m_view->renderer()->decreaseFontSizes(); 00322 } 00323 00327 void KateViewInternal::scrollLines ( int line ) 00328 { 00329 KateTextCursor newPos(line, 0); 00330 scrollPos(newPos); 00331 } 00332 00333 // This can scroll less than one true line 00334 void KateViewInternal::scrollViewLines(int offset) 00335 { 00336 KateTextCursor c = viewLineOffset(startPos(), offset); 00337 scrollPos(c); 00338 00339 m_lineScroll->blockSignals(true); 00340 m_lineScroll->setValue(startLine()); 00341 m_lineScroll->blockSignals(false); 00342 } 00343 00344 void KateViewInternal::scrollNextPage() 00345 { 00346 scrollViewLines(QMAX( linesDisplayed() - 1, 0 )); 00347 } 00348 00349 void KateViewInternal::scrollPrevPage() 00350 { 00351 scrollViewLines(-QMAX( linesDisplayed() - 1, 0 )); 00352 } 00353 00354 void KateViewInternal::scrollPrevLine() 00355 { 00356 scrollViewLines(-1); 00357 } 00358 00359 void KateViewInternal::scrollNextLine() 00360 { 00361 scrollViewLines(1); 00362 } 00363 00364 KateTextCursor KateViewInternal::maxStartPos(bool changed) 00365 { 00366 m_usePlainLines = true; 00367 00368 if (m_cachedMaxStartPos.line() == -1 || changed) 00369 { 00370 KateTextCursor end(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1))); 00371 00372 m_cachedMaxStartPos = viewLineOffset(end, -(linesDisplayed() - 1)); 00373 } 00374 00375 // If we're not dynamic word-wrapping, the horizontal scrollbar is hidden and will appear, increment the maxStart by 1 00376 if (!m_view->dynWordWrap() && m_columnScroll->isHidden() && scrollbarVisible(m_cachedMaxStartPos.line())) 00377 { 00378 KateTextCursor end(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1))); 00379 00380 return viewLineOffset(end, -linesDisplayed()); 00381 } 00382 00383 m_usePlainLines = false; 00384 00385 return m_cachedMaxStartPos; 00386 } 00387 00388 // c is a virtual cursor 00389 void KateViewInternal::scrollPos(KateTextCursor& c, bool force, bool calledExternally) 00390 { 00391 if (!force && ((!m_view->dynWordWrap() && c.line() == (int)startLine()) || c == startPos())) 00392 return; 00393 00394 if (c.line() < 0) 00395 c.setLine(0); 00396 00397 KateTextCursor limit = maxStartPos(); 00398 if (c > limit) { 00399 c = limit; 00400 00401 // overloading this variable, it's not used in non-word wrap 00402 // used to set the lineScroll to the max value 00403 if (m_view->dynWordWrap()) 00404 m_suppressColumnScrollBar = true; 00405 00406 // Re-check we're not just scrolling to the same place 00407 if (!force && ((!m_view->dynWordWrap() && c.line() == (int)startLine()) || c == startPos())) 00408 return; 00409 } 00410 00411 int viewLinesScrolled = displayViewLine(c); 00412 00413 m_oldStartPos = m_startPos; 00414 m_startPos = c; 00415 00416 // set false here but reversed if we return to makeVisible 00417 m_madeVisible = false; 00418 00419 if (!force) { 00420 int lines = linesDisplayed(); 00421 if ((int)m_doc->numVisLines() < lines) { 00422 KateTextCursor end(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1))); 00423 lines = QMIN((int)linesDisplayed(), displayViewLine(end) + 1); 00424 } 00425 00426 Q_ASSERT(lines >= 0); 00427 00428 if (!calledExternally && QABS(viewLinesScrolled) < lines) 00429 { 00430 updateView(false, viewLinesScrolled); 00431 00432 int scrollHeight = -(viewLinesScrolled * m_view->renderer()->fontHeight()); 00433 int scrollbarWidth = style().scrollBarExtent().width(); 00434 00435 // 00436 // updates are for working around the scrollbar leaving blocks in the view 00437 // 00438 scroll(0, scrollHeight); 00439 update(0, height()+scrollHeight-scrollbarWidth, width(), 2*scrollbarWidth); 00440 00441 leftBorder->scroll(0, scrollHeight); 00442 leftBorder->update(0, leftBorder->height()+scrollHeight-scrollbarWidth, leftBorder->width(), 2*scrollbarWidth); 00443 00444 return; 00445 } 00446 } 00447 00448 updateView(); 00449 update(); 00450 leftBorder->update(); 00451 } 00452 00453 void KateViewInternal::scrollColumns ( int x ) 00454 { 00455 if (x == m_startX) 00456 return; 00457 00458 if (x < 0) 00459 x = 0; 00460 00461 int dx = m_startX - x; 00462 m_oldStartX = m_startX; 00463 m_startX = x; 00464 00465 if (QABS(dx) < width()) 00466 scroll(dx, 0); 00467 else 00468 update(); 00469 00470 m_columnScroll->blockSignals(true); 00471 m_columnScroll->setValue(m_startX); 00472 m_columnScroll->blockSignals(false); 00473 } 00474 00475 // If changed is true, the lines that have been set dirty have been updated. 00476 void KateViewInternal::updateView(bool changed, int viewLinesScrolled) 00477 { 00478 m_updatingView = true; 00479 00480 uint contentLines = m_doc->visibleLines(); 00481 00482 m_lineScroll->blockSignals(true); 00483 00484 KateTextCursor maxStart = maxStartPos(changed); 00485 int maxLineScrollRange = maxStart.line(); 00486 if (m_view->dynWordWrap() && maxStart.col() != 0) 00487 maxLineScrollRange++; 00488 m_lineScroll->setRange(0, maxLineScrollRange); 00489 00490 if (m_view->dynWordWrap() && m_suppressColumnScrollBar) { 00491 m_suppressColumnScrollBar = false; 00492 m_lineScroll->setValue(maxStart.line()); 00493 } else { 00494 m_lineScroll->setValue(startPos().line()); 00495 } 00496 m_lineScroll->setSteps(1, height() / m_view->renderer()->fontHeight()); 00497 m_lineScroll->blockSignals(false); 00498 00499 uint oldSize = lineRanges.size (); 00500 uint newSize = (height() / m_view->renderer()->fontHeight()) + 1; 00501 if (oldSize != newSize) { 00502 lineRanges.resize((height() / m_view->renderer()->fontHeight()) + 1); 00503 if (newSize > oldSize) { 00504 static LineRange blank; 00505 for (uint i = oldSize; i < newSize; i++) { 00506 lineRanges[i] = blank; 00507 } 00508 } 00509 } 00510 00511 if (oldSize < lineRanges.size ()) 00512 { 00513 for (uint i=oldSize; i < lineRanges.size(); i++) 00514 lineRanges[i].dirty = true; 00515 } 00516 00517 // Move the lineRanges data if we've just scrolled... 00518 if (viewLinesScrolled != 0) { 00519 // loop backwards if we've just scrolled up... 00520 bool forwards = viewLinesScrolled >= 0 ? true : false; 00521 for (uint z = forwards ? 0 : lineRanges.count() - 1; z < lineRanges.count(); forwards ? z++ : z--) { 00522 uint oldZ = z + viewLinesScrolled; 00523 if (oldZ < lineRanges.count()) { 00524 lineRanges[z] = lineRanges[oldZ]; 00525 } else { 00526 lineRanges[z].dirty = true; 00527 } 00528 } 00529 } 00530 00531 if (m_view->dynWordWrap()) 00532 { 00533 KateTextCursor realStart = startPos(); 00534 realStart.setLine(m_doc->getRealLine(realStart.line())); 00535 00536 LineRange startRange = range(realStart); 00537 uint line = startRange.virtualLine; 00538 int realLine = startRange.line; 00539 uint oldLine = line; 00540 int startCol = startRange.startCol; 00541 int startX = startRange.startX; 00542 int endX = startRange.startX; 00543 int shiftX = startRange.startCol ? startRange.shiftX : 0; 00544 bool wrap = false; 00545 int newViewLine = startRange.viewLine; 00546 // z is the current display view line 00547 TextLine::Ptr text = textLine(realLine); 00548 00549 bool alreadyDirty = false; 00550 00551 for (uint z = 0; z < lineRanges.size(); z++) 00552 { 00553 if (oldLine != line) { 00554 realLine = (int)m_doc->getRealLine(line); 00555 00556 if (z) 00557 lineRanges[z-1].startsInvisibleBlock = (realLine != lineRanges[z-1].line + 1); 00558 00559 text = textLine(realLine); 00560 startCol = 0; 00561 startX = 0; 00562 endX = 0; 00563 shiftX = 0; 00564 newViewLine = 0; 00565 oldLine = line; 00566 } 00567 00568 if (line >= contentLines || !text) 00569 { 00570 if (lineRanges[z].line != -1) 00571 lineRanges[z].dirty = true; 00572 00573 lineRanges[z].clear(); 00574 00575 line++; 00576 } 00577 else 00578 { 00579 if (lineRanges[z].line != realLine || lineRanges[z].startCol != startCol) 00580 alreadyDirty = lineRanges[z].dirty = true; 00581 00582 if (lineRanges[z].dirty || changed || alreadyDirty) { 00583 alreadyDirty = true; 00584 00585 lineRanges[z].virtualLine = line; 00586 lineRanges[z].line = realLine; 00587 lineRanges[z].startsInvisibleBlock = false; 00588 00589 int tempEndX = 0; 00590 00591 int endCol = m_view->renderer()->textWidth(text, startCol, width() - shiftX, &wrap, &tempEndX); 00592 00593 endX += tempEndX; 00594 00595 if (wrap) 00596 { 00597 if (m_view->config()->dynWordWrapAlignIndent() > 0) 00598 { 00599 if (startX == 0) 00600 { 00601 int pos = text->nextNonSpaceChar(0); 00602 00603 if (pos > 0) 00604 shiftX = m_view->renderer()->textWidth(text, pos); 00605 00606 if (shiftX > ((double)width() / 100 * m_view->config()->dynWordWrapAlignIndent())) 00607 shiftX = 0; 00608 } 00609 } 00610 00611 if ((lineRanges[z].startX != startX) || (lineRanges[z].endX != endX) || 00612 (lineRanges[z].startCol != startCol) || (lineRanges[z].endCol != endCol) || 00613 (lineRanges[z].shiftX != shiftX)) 00614 lineRanges[z].dirty = true; 00615 00616 lineRanges[z].startCol = startCol; 00617 lineRanges[z].endCol = endCol; 00618 lineRanges[z].startX = startX; 00619 lineRanges[z].endX = endX; 00620 lineRanges[z].viewLine = newViewLine; 00621 lineRanges[z].wrap = true; 00622 00623 startCol = endCol; 00624 startX = endX; 00625 } 00626 else 00627 { 00628 if ((lineRanges[z].startX != startX) || (lineRanges[z].endX != endX) || 00629 (lineRanges[z].startCol != startCol) || (lineRanges[z].endCol != endCol)) 00630 lineRanges[z].dirty = true; 00631 00632 lineRanges[z].startCol = startCol; 00633 lineRanges[z].endCol = endCol; 00634 lineRanges[z].startX = startX; 00635 lineRanges[z].endX = endX; 00636 lineRanges[z].viewLine = newViewLine; 00637 lineRanges[z].wrap = false; 00638 00639 line++; 00640 } 00641 00642 lineRanges[z].shiftX = shiftX; 00643 00644 } else { 00645 // The cached data is still intact 00646 if (lineRanges[z].wrap) { 00647 startCol = lineRanges[z].endCol; 00648 startX = lineRanges[z].endX; 00649 endX = lineRanges[z].endX; 00650 } else { 00651 line++; 00652 } 00653 shiftX = lineRanges[z].shiftX; 00654 } 00655 } 00656 newViewLine++; 00657 } 00658 } 00659 else 00660 { 00661 uint z = 0; 00662 00663 for(; (z + startLine() < contentLines) && (z < lineRanges.size()); z++) 00664 { 00665 if (lineRanges[z].dirty || lineRanges[z].line != (int)m_doc->getRealLine(z + startLine())) { 00666 lineRanges[z].dirty = true; 00667 00668 lineRanges[z].line = m_doc->getRealLine( z + startLine() ); 00669 if (z) 00670 lineRanges[z-1].startsInvisibleBlock = (lineRanges[z].line != lineRanges[z-1].line + 1); 00671 00672 lineRanges[z].virtualLine = z + startLine(); 00673 lineRanges[z].startCol = 0; 00674 lineRanges[z].endCol = m_doc->lineLength(lineRanges[z].line); 00675 lineRanges[z].startX = 0; 00676 lineRanges[z].endX = m_view->renderer()->textWidth( textLine( lineRanges[z].line ), -1 ); 00677 lineRanges[z].shiftX = 0; 00678 lineRanges[z].viewLine = 0; 00679 lineRanges[z].wrap = false; 00680 } 00681 else if (z && lineRanges[z-1].dirty) 00682 { 00683 lineRanges[z-1].startsInvisibleBlock = (lineRanges[z].line != lineRanges[z-1].line + 1); 00684 } 00685 } 00686 00687 for (; z < lineRanges.size(); z++) 00688 { 00689 if (lineRanges[z].line != -1) 00690 lineRanges[z].dirty = true; 00691 00692 lineRanges[z].clear(); 00693 } 00694 00695 if (scrollbarVisible(startLine())) 00696 { 00697 m_columnScroll->blockSignals(true); 00698 00699 int max = maxLen(startLine()) - width(); 00700 if (max < 0) 00701 max = 0; 00702 00703 m_columnScroll->setRange(0, max); 00704 00705 m_columnScroll->setValue(m_startX); 00706 00707 // Approximate linescroll 00708 m_columnScroll->setSteps(m_view->renderer()->config()->fontMetrics()->width('a'), width()); 00709 00710 m_columnScroll->blockSignals(false); 00711 00712 if (!m_columnScroll->isVisible () && !m_suppressColumnScrollBar) 00713 { 00714 m_columnScroll->show(); 00715 m_columnScrollDisplayed = true; 00716 } 00717 } 00718 else if (m_columnScroll->isVisible () && !m_suppressColumnScrollBar && (startX() == 0)) 00719 { 00720 m_columnScroll->hide(); 00721 m_columnScrollDisplayed = false; 00722 } 00723 } 00724 00725 m_updatingView = false; 00726 00727 if (changed) 00728 paintText(0, 0, width(), height(), true); 00729 } 00730 00731 void KateViewInternal::paintText (int x, int y, int width, int height, bool paintOnlyDirty) 00732 { 00733 //kdDebug() << k_funcinfo << x << " " << y << " " << width << " " << height << " " << paintOnlyDirty << endl; 00734 int xStart = startX() + x; 00735 int xEnd = xStart + width; 00736 uint h = m_view->renderer()->fontHeight(); 00737 uint startz = (y / h); 00738 uint endz = startz + 1 + (height / h); 00739 uint lineRangesSize = lineRanges.size(); 00740 00741 static QPixmap drawBuffer; 00742 00743 if (drawBuffer.width() < KateViewInternal::width() || drawBuffer.height() < (int)h) 00744 drawBuffer.resize(KateViewInternal::width(), (int)h); 00745 00746 if (drawBuffer.isNull()) 00747 return; 00748 00749 QPainter paint(this); 00750 QPainter paintDrawBuffer(&drawBuffer); 00751 00752 // TODO put in the proper places 00753 m_view->renderer()->setCaretStyle(m_view->isOverwriteMode() ? KateRenderer::Replace : KateRenderer::Insert); 00754 m_view->renderer()->setShowTabs(m_doc->configFlags() & KateDocument::cfShowTabs); 00755 00756 for (uint z=startz; z <= endz; z++) 00757 { 00758 if ( (z >= lineRangesSize) || ((lineRanges[z].line == -1) && (!paintOnlyDirty || lineRanges[z].dirty)) ) 00759 { 00760 if (!(z >= lineRangesSize)) 00761 lineRanges[z].dirty = false; 00762 00763 paint.fillRect( x, z * h, width, h, *m_view->renderer()->config()->backgroundColor() ); 00764 } 00765 else if (!paintOnlyDirty || lineRanges[z].dirty) 00766 { 00767 lineRanges[z].dirty = false; 00768 00769 m_view->renderer()->paintTextLine(paintDrawBuffer, &lineRanges[z], xStart, xEnd, &cursor, &bm); 00770 00771 paint.drawPixmap (x, z * h, drawBuffer, 0, 0, width, h); 00772 } 00773 } 00774 } 00775 00780 void KateViewInternal::makeVisible (const KateTextCursor& c, uint endCol, bool force, bool center, bool calledExternally) 00781 { 00782 //kdDebug() << "MakeVisible start [" << startPos().line << "," << startPos().col << "] end [" << endPos().line << "," << endPos().col << "] -> request: [" << c.line << "," << c.col << "]" <<endl;// , new start [" << scroll.line << "," << scroll.col << "] lines " << (linesDisplayed() - 1) << " height " << height() << endl; 00783 // if the line is in a folded region, unfold all the way up 00784 //if ( m_doc->foldingTree()->findNodeForLine( c.line )->visible ) 00785 // kdDebug()<<"line ("<<c.line<<") should be visible"<<endl; 00786 00787 if ( force ) 00788 { 00789 KateTextCursor scroll = c; 00790 scrollPos(scroll, force, calledExternally); 00791 } 00792 else if (center && (c < startPos() || c > endPos())) 00793 { 00794 KateTextCursor scroll = viewLineOffset(c, -int(linesDisplayed()) / 2); 00795 scrollPos(scroll, false, calledExternally); 00796 } 00797 else if ( c > viewLineOffset(endPos(), -m_minLinesVisible) ) 00798 { 00799 KateTextCursor scroll = viewLineOffset(c, -(linesDisplayed() - m_minLinesVisible - 1)); 00800 00801 if (!m_view->dynWordWrap() && m_columnScroll->isHidden()) 00802 if (scrollbarVisible(scroll.line())) 00803 scroll.setLine(scroll.line() + 1); 00804 00805 scrollPos(scroll, false, calledExternally); 00806 } 00807 else if ( c < viewLineOffset(startPos(), m_minLinesVisible) ) 00808 { 00809 KateTextCursor scroll = viewLineOffset(c, -m_minLinesVisible); 00810 scrollPos(scroll, false, calledExternally); 00811 } 00812 else 00813 { 00814 // Check to see that we're not showing blank lines 00815 KateTextCursor max = maxStartPos(); 00816 if (startPos() > max) { 00817 scrollPos(max, max.col(), calledExternally); 00818 } 00819 } 00820 00821 if (!m_view->dynWordWrap() && endCol != (uint)-1) 00822 { 00823 int sX = (int)m_view->renderer()->textWidth (textLine( m_doc->getRealLine( c.line() ) ), c.col() ); 00824 00825 int sXborder = sX-8; 00826 if (sXborder < 0) 00827 sXborder = 0; 00828 00829 if (sX < m_startX) 00830 scrollColumns (sXborder); 00831 else if (sX > m_startX + width()) 00832 scrollColumns (sX - width() + 8); 00833 } 00834 00835 m_madeVisible = !force; 00836 } 00837 00838 void KateViewInternal::slotRegionVisibilityChangedAt(unsigned int) 00839 { 00840 kdDebug(13030) << "slotRegionVisibilityChangedAt()" << endl; 00841 m_cachedMaxStartPos.setLine(-1); 00842 KateTextCursor max = maxStartPos(); 00843 if (startPos() > max) 00844 scrollPos(max); 00845 00846 updateView(); 00847 update(); 00848 leftBorder->update(); 00849 } 00850 00851 void KateViewInternal::slotCodeFoldingChanged() 00852 { 00853 leftBorder->update(); 00854 } 00855 00856 void KateViewInternal::slotRegionBeginEndAddedRemoved(unsigned int) 00857 { 00858 kdDebug(13030) << "slotRegionBeginEndAddedRemoved()" << endl; 00859 // FIXME: performance problem 00860 leftBorder->update(); 00861 } 00862 00863 void KateViewInternal::showEvent ( QShowEvent *e ) 00864 { 00865 updateView (); 00866 00867 QWidget::showEvent (e); 00868 } 00869 00870 uint KateViewInternal::linesDisplayed() const 00871 { 00872 int h = height(); 00873 int fh = m_view->renderer()->fontHeight(); 00874 00875 return (h - (h % fh)) / fh; 00876 } 00877 00878 QPoint KateViewInternal::cursorCoordinates() 00879 { 00880 int viewLine = displayViewLine(displayCursor, true); 00881 00882 if (viewLine == -1) 00883 return QPoint(-1, -1); 00884 00885 uint y = viewLine * m_view->renderer()->fontHeight(); 00886 uint x = cXPos - m_startX - lineRanges[viewLine].startX + leftBorder->width() + lineRanges[viewLine].xOffset(); 00887 00888 return QPoint(x, y); 00889 } 00890 00891 void KateViewInternal::doReturn() 00892 { 00893 KateTextCursor c = cursor; 00894 m_doc->newLine( c, this ); 00895 updateCursor( c ); 00896 updateView(); 00897 } 00898 00899 void KateViewInternal::doDelete() 00900 { 00901 m_doc->del( cursor ); 00902 } 00903 00904 void KateViewInternal::doBackspace() 00905 { 00906 m_doc->backspace( cursor ); 00907 } 00908 00909 void KateViewInternal::doPaste() 00910 { 00911 m_doc->paste( m_view ); 00912 } 00913 00914 void KateViewInternal::doTranspose() 00915 { 00916 m_doc->transpose( cursor ); 00917 } 00918 00919 void KateViewInternal::doDeleteWordLeft() 00920 { 00921 wordLeft( true ); 00922 m_doc->removeSelectedText(); 00923 update(); 00924 } 00925 00926 void KateViewInternal::doDeleteWordRight() 00927 { 00928 wordRight( true ); 00929 m_doc->removeSelectedText(); 00930 update(); 00931 } 00932 00933 class CalculatingCursor : public KateTextCursor { 00934 public: 00935 CalculatingCursor(KateViewInternal* vi) 00936 : KateTextCursor() 00937 , m_vi(vi) 00938 { 00939 Q_ASSERT(valid()); 00940 } 00941 00942 CalculatingCursor(KateViewInternal* vi, const KateTextCursor& c) 00943 : KateTextCursor(c) 00944 , m_vi(vi) 00945 { 00946 Q_ASSERT(valid()); 00947 } 00948 00949 // This one constrains its arguments to valid positions 00950 CalculatingCursor(KateViewInternal* vi, uint line, uint col) 00951 : KateTextCursor(line, col) 00952 , m_vi(vi) 00953 { 00954 makeValid(); 00955 } 00956 00957 00958 virtual CalculatingCursor& operator+=( int n ) = 0; 00959 00960 virtual CalculatingCursor& operator-=( int n ) = 0; 00961 00962 CalculatingCursor& operator++() { return operator+=( 1 ); } 00963 00964 CalculatingCursor& operator--() { return operator-=( 1 ); } 00965 00966 void makeValid() { 00967 m_line = QMAX( 0, QMIN( int( m_vi->m_doc->numLines() - 1 ), line() ) ); 00968 if (m_vi->m_doc->wrapCursor()) 00969 m_col = QMAX( 0, QMIN( m_vi->m_doc->lineLength( line() ), col() ) ); 00970 else 00971 m_col = QMAX( 0, col() ); 00972 Q_ASSERT( valid() ); 00973 } 00974 00975 void toEdge( Bias bias ) { 00976 if( bias == left ) m_col = 0; 00977 else if( bias == right ) m_col = m_vi->m_doc->lineLength( line() ); 00978 } 00979 00980 bool atEdge() const { return atEdge( left ) || atEdge( right ); } 00981 00982 bool atEdge( Bias bias ) const { 00983 switch( bias ) { 00984 case left: return col() == 0; 00985 case none: return atEdge(); 00986 case right: return col() == m_vi->m_doc->lineLength( line() ); 00987 default: Q_ASSERT(false); return false; 00988 } 00989 } 00990 00991 protected: 00992 bool valid() const { 00993 return line() >= 0 && 00994 uint( line() ) < m_vi->m_doc->numLines() && 00995 col() >= 0 && 00996 (!m_vi->m_doc->wrapCursor() || col() <= m_vi->m_doc->lineLength( line() )); 00997 } 00998 KateViewInternal* m_vi; 00999 }; 01000 01001 class BoundedCursor : public CalculatingCursor { 01002 public: 01003 BoundedCursor(KateViewInternal* vi) 01004 : CalculatingCursor( vi ) {}; 01005 BoundedCursor(KateViewInternal* vi, const KateTextCursor& c ) 01006 : CalculatingCursor( vi, c ) {}; 01007 BoundedCursor(KateViewInternal* vi, uint line, uint col ) 01008 : CalculatingCursor( vi, line, col ) {}; 01009 virtual CalculatingCursor& operator+=( int n ) { 01010 m_col += n; 01011 01012 if (n > 0 && m_vi->m_view->dynWordWrap()) { 01013 // Need to constrain to current visible text line for dynamic wrapping mode 01014 if (m_col > m_vi->m_doc->lineLength(m_line)) { 01015 LineRange currentRange = m_vi->range(*this); 01016 01017 int endX; 01018 bool crap; 01019 m_vi->m_view->renderer()->textWidth(m_vi->textLine(m_line), currentRange.startCol, m_vi->width() - currentRange.xOffset(), &crap, &endX); 01020 endX += (m_col - currentRange.endCol + 1) * m_vi->m_view->renderer()->spaceWidth(); 01021 01022 // Constraining if applicable NOTE: some code duplication in KateViewInternal::resize() 01023 if (endX >= m_vi->width() - currentRange.xOffset()) { 01024 m_col -= n; 01025 if ( uint( line() ) < m_vi->m_doc->numLines() - 1 ) { 01026 m_line++; 01027 m_col = 0; 01028 } 01029 } 01030 } 01031 01032 } else if (n < 0 && col() < 0 && line() > 0 ) { 01033 m_line--; 01034 m_col = m_vi->m_doc->lineLength( line() ); 01035 } 01036 01037 m_col = QMAX( 0, col() ); 01038 01039 Q_ASSERT( valid() ); 01040 return *this; 01041 } 01042 virtual CalculatingCursor& operator-=( int n ) { 01043 return operator+=( -n ); 01044 } 01045 }; 01046 01047 class WrappingCursor : public CalculatingCursor { 01048 public: 01049 WrappingCursor(KateViewInternal* vi) 01050 : CalculatingCursor( vi) {}; 01051 WrappingCursor(KateViewInternal* vi, const KateTextCursor& c ) 01052 : CalculatingCursor( vi, c ) {}; 01053 WrappingCursor(KateViewInternal* vi, uint line, uint col ) 01054 : CalculatingCursor( vi, line, col ) {}; 01055 01056 virtual CalculatingCursor& operator+=( int n ) { 01057 if( n < 0 ) return operator-=( -n ); 01058 int len = m_vi->m_doc->lineLength( line() ); 01059 if( col() + n <= len ) { 01060 m_col += n; 01061 } else if( uint( line() ) < m_vi->m_doc->numLines() - 1 ) { 01062 n -= len - col() + 1; 01063 m_col = 0; 01064 m_line++; 01065 operator+=( n ); 01066 } else { 01067 m_col = len; 01068 } 01069 Q_ASSERT( valid() ); 01070 return *this; 01071 } 01072 virtual CalculatingCursor& operator-=( int n ) { 01073 if( n < 0 ) return operator+=( -n ); 01074 if( col() - n >= 0 ) { 01075 m_col -= n; 01076 } else if( line() > 0 ) { 01077 n -= col() + 1; 01078 m_line--; 01079 m_col = m_vi->m_doc->lineLength( line() ); 01080 operator-=( n ); 01081 } else { 01082 m_col = 0; 01083 } 01084 Q_ASSERT( valid() ); 01085 return *this; 01086 } 01087 }; 01088 01089 void KateViewInternal::moveChar( Bias bias, bool sel ) 01090 { 01091 KateTextCursor c; 01092 if ( m_doc->wrapCursor() ) { 01093 c = WrappingCursor( this, cursor ) += bias; 01094 } else { 01095 c = BoundedCursor( this, cursor ) += bias; 01096 } 01097 updateSelection( c, sel ); 01098 updateCursor( c ); 01099 } 01100 01101 void KateViewInternal::cursorLeft( bool sel ) { moveChar( left, sel ); } 01102 void KateViewInternal::cursorRight( bool sel ) { moveChar( right, sel ); } 01103 01104 void KateViewInternal::moveWord( Bias bias, bool sel ) 01105 { 01106 // This matches the word-moving in QTextEdit, QLineEdit etc. 01107 01108 WrappingCursor c( this, cursor ); 01109 if( !c.atEdge( bias ) ) { 01110 Highlight* h = m_doc->highlight(); 01111 01112 bool moved = false; 01113 while( !c.atEdge( bias ) && !h->isInWord( m_doc->textLine( c.line() )[ c.col() - (bias == left ? 1 : 0) ] ) ) 01114 { 01115 c += bias; 01116 moved = true; 01117 } 01118 01119 if ( bias != right || !moved ) 01120 { 01121 while( !c.atEdge( bias ) && h->isInWord( m_doc->textLine( c.line() )[ c.col() - (bias == left ? 1 : 0) ] ) ) 01122 c += bias; 01123 if ( bias == right ) 01124 { 01125 while ( !c.atEdge( bias ) && m_doc->textLine( c.line() )[ c.col() ].isSpace() ) 01126 c+= bias; 01127 } 01128 } 01129 01130 } else { 01131 c += bias; 01132 } 01133 updateSelection( c, sel ); 01134 updateCursor( c ); 01135 } 01136 01137 void KateViewInternal::wordLeft ( bool sel ) { moveWord( left, sel ); } 01138 void KateViewInternal::wordRight( bool sel ) { moveWord( right, sel ); } 01139 01140 void KateViewInternal::moveEdge( Bias bias, bool sel ) 01141 { 01142 BoundedCursor c( this, cursor ); 01143 c.toEdge( bias ); 01144 updateSelection( c, sel ); 01145 updateCursor( c ); 01146 } 01147 01148 void KateViewInternal::home( bool sel ) 01149 { 01150 if (m_view->dynWordWrap() && currentRange().startCol) { 01151 // Allow us to go to the real start if we're already at the start of the view line 01152 if (cursor.col() != currentRange().startCol) { 01153 KateTextCursor c(cursor.line(), currentRange().startCol); 01154 updateSelection( c, sel ); 01155 updateCursor( c ); 01156 return; 01157 } 01158 } 01159 01160 if( !(m_doc->configFlags() & KateDocument::cfSmartHome) ) { 01161 moveEdge( left, sel ); 01162 return; 01163 } 01164 01165 KateTextCursor c = cursor; 01166 int lc = textLine( c.line() )->firstChar(); 01167 01168 if( lc < 0 || c.col() == lc ) { 01169 c.setCol(0); 01170 } else { 01171 c.setCol(lc); 01172 } 01173 01174 updateSelection( c, sel ); 01175 updateCursor( c ); 01176 } 01177 01178 void KateViewInternal::end( bool sel ) 01179 { 01180 if (m_view->dynWordWrap() && currentRange().wrap) { 01181 // Allow us to go to the real end if we're already at the end of the view line 01182 if (cursor.col() < currentRange().endCol - 1) { 01183 KateTextCursor c(cursor.line(), currentRange().endCol - 1); 01184 updateSelection( c, sel ); 01185 updateCursor( c ); 01186 return; 01187 } 01188 } 01189 01190 moveEdge( right, sel ); 01191 } 01192 01193 LineRange KateViewInternal::range(int realLine, const LineRange* previous) 01194 { 01195 // look at the cache first 01196 if (!m_updatingView && realLine >= lineRanges[0].line && realLine <= lineRanges[lineRanges.count() - 1].line) 01197 for (uint i = 0; i < lineRanges.count(); i++) 01198 if (realLine == lineRanges[i].line) 01199 if (!m_view->dynWordWrap() || (!previous && lineRanges[i].startCol == 0) || (previous && lineRanges[i].startCol == previous->endCol)) 01200 return lineRanges[i]; 01201 01202 // Not in the cache, we have to create it 01203 LineRange ret; 01204 01205 TextLine::Ptr text = textLine(realLine); 01206 if (!text) { 01207 return LineRange(); 01208 } 01209 01210 if (!m_view->dynWordWrap()) { 01211 Q_ASSERT(!previous); 01212 ret.line = realLine; 01213 ret.virtualLine = m_doc->getVirtualLine(realLine); 01214 ret.startCol = 0; 01215 ret.endCol = m_doc->lineLength(realLine); 01216 ret.startX = 0; 01217 ret.endX = m_view->renderer()->textWidth(text, -1); 01218 ret.viewLine = 0; 01219 ret.wrap = false; 01220 return ret; 01221 } 01222 01223 ret.endCol = (int)m_view->renderer()->textWidth(text, previous ? previous->endCol : 0, width() - (previous ? previous->shiftX : 0), &ret.wrap, &ret.endX); 01224 01225 Q_ASSERT(ret.endCol > ret.startCol); 01226 01227 ret.line = realLine; 01228 01229 if (previous) { 01230 ret.virtualLine = previous->virtualLine; 01231 ret.startCol = previous->endCol; 01232 ret.startX = previous->endX; 01233 ret.endX += previous->endX; 01234 ret.shiftX = previous->shiftX; 01235 ret.viewLine = previous->viewLine + 1; 01236 01237 } else { 01238 // TODO worthwhile optimising this to get the data out of the initial textWidth call? 01239 if (m_view->config()->dynWordWrapAlignIndent() > 0) { 01240 int pos = text->nextNonSpaceChar(0); 01241 01242 if (pos > 0) 01243 ret.shiftX = m_view->renderer()->textWidth(text, pos); 01244 01245 if (ret.shiftX > ((double)width() / 100 * m_view->config()->dynWordWrapAlignIndent())) 01246 ret.shiftX = 0; 01247 } 01248 01249 ret.virtualLine = m_doc->getVirtualLine(realLine); 01250 ret.startCol = 0; 01251 ret.startX = 0; 01252 ret.viewLine = 0; 01253 } 01254 01255 return ret; 01256 } 01257 01258 LineRange KateViewInternal::currentRange() 01259 { 01260 // Q_ASSERT(m_view->dynWordWrap()); 01261 01262 return range(cursor); 01263 } 01264 01265 LineRange KateViewInternal::previousRange() 01266 { 01267 uint currentViewLine = viewLine(cursor); 01268 01269 if (currentViewLine) 01270 return range(cursor.line(), currentViewLine - 1); 01271 else 01272 return range(m_doc->getRealLine(displayCursor.line() - 1), -1); 01273 } 01274 01275 LineRange KateViewInternal::nextRange() 01276 { 01277 uint currentViewLine = viewLine(cursor) + 1; 01278 01279 if (currentViewLine >= viewLineCount(cursor.line())) { 01280 currentViewLine = 0; 01281 return range(cursor.line() + 1, currentViewLine); 01282 } else { 01283 return range(cursor.line(), currentViewLine); 01284 } 01285 } 01286 01287 LineRange KateViewInternal::range(const KateTextCursor& realCursor) 01288 { 01289 // Q_ASSERT(m_view->dynWordWrap()); 01290 01291 LineRange thisRange; 01292 bool first = true; 01293 01294 do { 01295 thisRange = range(realCursor.line(), first ? 0L : &thisRange); 01296 first = false; 01297 } while (thisRange.wrap && !(realCursor.col() >= thisRange.startCol && realCursor.col() < thisRange.endCol) && thisRange.startCol != thisRange.endCol); 01298 01299 return thisRange; 01300 } 01301 01302 LineRange KateViewInternal::range(uint realLine, int viewLine) 01303 { 01304 // Q_ASSERT(m_view->dynWordWrap()); 01305 01306 LineRange thisRange; 01307 bool first = true; 01308 01309 do { 01310 thisRange = range(realLine, first ? 0L : &thisRange); 01311 first = false; 01312 } while (thisRange.wrap && viewLine != thisRange.viewLine && thisRange.startCol != thisRange.endCol); 01313 01314 if (viewLine != -1 && viewLine != thisRange.viewLine) 01315 kdDebug(13030) << "WARNING: viewLine " << viewLine << " of line " << realLine << " does not exist." << endl; 01316 01317 return thisRange; 01318 } 01319 01325 uint KateViewInternal::viewLine(const KateTextCursor& realCursor) 01326 { 01327 if (!m_view->dynWordWrap()) return 0; 01328 01329 if (realCursor.col() == 0) return 0; 01330 01331 LineRange thisRange; 01332 bool first = true; 01333 01334 do { 01335 thisRange = range(realCursor.line(), first ? 0L : &thisRange); 01336 first = false; 01337 } while (thisRange.wrap && !(realCursor.col() >= thisRange.startCol && realCursor.col() < thisRange.endCol) && thisRange.startCol != thisRange.endCol); 01338 01339 return thisRange.viewLine; 01340 } 01341 01342 int KateViewInternal::displayViewLine(const KateTextCursor& virtualCursor, bool limitToVisible) 01343 { 01344 KateTextCursor work = startPos(); 01345 01346 int limit = linesDisplayed(); 01347 01348 // Efficient non-word-wrapped path 01349 if (!m_view->dynWordWrap()) { 01350 int ret = virtualCursor.line() - startLine(); 01351 if (limitToVisible && (ret < 0 || ret > limit)) 01352 return -1; 01353 else 01354 return ret; 01355 } 01356 01357 if (work == virtualCursor) { 01358 return 0; 01359 } 01360 01361 int ret = -viewLine(work); 01362 bool forwards = (work < virtualCursor) ? true : false; 01363 01364 // FIXME switch to using ranges? faster? 01365 if (forwards) { 01366 while (work.line() != virtualCursor.line()) { 01367 ret += viewLineCount(m_doc->getRealLine(work.line())); 01368 work.setLine(work.line() + 1); 01369 if (limitToVisible && ret > limit) 01370 return -1; 01371 } 01372 } else { 01373 while (work.line() != virtualCursor.line()) { 01374 work.setLine(work.line() - 1); 01375 ret -= viewLineCount(m_doc->getRealLine(work.line())); 01376 if (limitToVisible && ret < 0) 01377 return -1; 01378 } 01379 } 01380 01381 // final difference 01382 KateTextCursor realCursor = virtualCursor; 01383 realCursor.setLine(m_doc->getRealLine(realCursor.line())); 01384 if (realCursor.col() == -1) realCursor.setCol(m_doc->lineLength(realCursor.line())); 01385 ret += viewLine(realCursor); 01386 01387 if (limitToVisible && (ret < 0 || ret > limit)) 01388 return -1; 01389 01390 return ret; 01391 } 01392 01393 uint KateViewInternal::lastViewLine(uint realLine) 01394 { 01395 if (!m_view->dynWordWrap()) return 0; 01396 01397 LineRange thisRange; 01398 bool first = true; 01399 01400 do { 01401 thisRange = range(realLine, first ? 0L : &thisRange); 01402 first = false; 01403 } while (thisRange.wrap && thisRange.startCol != thisRange.endCol); 01404 01405 return thisRange.viewLine; 01406 } 01407 01408 uint KateViewInternal::viewLineCount(uint realLine) 01409 { 01410 return lastViewLine(realLine) + 1; 01411 } 01412 01413 /* 01414 * This returns the cursor which is offset by (offset) view lines. 01415 * This is the main function which is called by code not specifically dealing with word-wrap. 01416 * The opposite conversion (cursor to offset) can be done with displayViewLine. 01417 * 01418 * The cursors involved are virtual cursors (ie. equivalent to displayCursor) 01419 */ 01420 KateTextCursor KateViewInternal::viewLineOffset(const KateTextCursor& virtualCursor, int offset, bool keepX) 01421 { 01422 if (!m_view->dynWordWrap()) { 01423 KateTextCursor ret(QMIN((int)m_doc->visibleLines() - 1, virtualCursor.line() + offset), 0); 01424 01425 if (ret.line() < 0) 01426 ret.setLine(0); 01427 01428 if (keepX) { 01429 int realLine = m_doc->getRealLine(ret.line()); 01430 ret.setCol(m_doc->lineLength(realLine) - 1); 01431 01432 if (m_currentMaxX > cXPos) 01433 cXPos = m_currentMaxX; 01434 01435 if (m_doc->wrapCursor()) 01436 cXPos = QMIN(cXPos, (int)m_view->renderer()->textWidth(textLine(realLine), m_doc->lineLength(realLine))); 01437 01438 m_view->renderer()->textWidth(ret, cXPos); 01439 } 01440 01441 return ret; 01442 } 01443 01444 KateTextCursor realCursor = virtualCursor; 01445 realCursor.setLine(m_doc->getRealLine(virtualCursor.line())); 01446 01447 uint cursorViewLine = viewLine(realCursor); 01448 01449 int currentOffset = 0; 01450 int virtualLine = 0; 01451 01452 bool forwards = (offset > 0) ? true : false; 01453 01454 if (forwards) { 01455 currentOffset = lastViewLine(realCursor.line()) - cursorViewLine; 01456 if (offset <= currentOffset) { 01457 // the answer is on the same line 01458 LineRange thisRange = range(realCursor.line(), cursorViewLine + offset); 01459 Q_ASSERT(thisRange.virtualLine == virtualCursor.line()); 01460 return KateTextCursor(virtualCursor.line(), thisRange.startCol); 01461 } 01462 01463 virtualLine = virtualCursor.line() + 1; 01464 01465 } else { 01466 offset = -offset; 01467 currentOffset = cursorViewLine; 01468 if (offset <= currentOffset) { 01469 // the answer is on the same line 01470 LineRange thisRange = range(realCursor.line(), cursorViewLine - offset); 01471 Q_ASSERT(thisRange.virtualLine == virtualCursor.line()); 01472 return KateTextCursor(virtualCursor.line(), thisRange.startCol); 01473 } 01474 01475 virtualLine = virtualCursor.line() - 1; 01476 } 01477 01478 currentOffset++; 01479 01480 while (virtualLine >= 0 && virtualLine < (int)m_doc->visibleLines()) 01481 { 01482 LineRange thisRange; 01483 bool first = true; 01484 int realLine = m_doc->getRealLine(virtualLine); 01485 01486 do { 01487 thisRange = range(realLine, first ? 0L : &thisRange); 01488 first = false; 01489 01490 if (offset == currentOffset) { 01491 if (!forwards) { 01492 // We actually want it the other way around 01493 int requiredViewLine = lastViewLine(realLine) - thisRange.viewLine; 01494 if (requiredViewLine != thisRange.viewLine) { 01495 thisRange = range(realLine, requiredViewLine); 01496 } 01497 } 01498 01499 KateTextCursor ret(virtualLine, thisRange.startCol); 01500 01501 // keep column position 01502 if (keepX) { 01503 ret.setCol(thisRange.endCol - 1); 01504 KateTextCursor realCursorTemp(m_doc->getRealLine(virtualCursor.line()), virtualCursor.col()); 01505 int visibleX = m_view->renderer()->textWidth(realCursorTemp) - range(realCursorTemp).startX; 01506 int xOffset = thisRange.startX; 01507 01508 if (m_currentMaxX > visibleX) 01509 visibleX = m_currentMaxX; 01510 01511 cXPos = xOffset + visibleX; 01512 01513 cXPos = QMIN(cXPos, lineMaxCursorX(thisRange)); 01514 01515 m_view->renderer()->textWidth(ret, cXPos); 01516 } 01517 01518 return ret; 01519 } 01520 01521 currentOffset++; 01522 01523 } while (thisRange.wrap); 01524 01525 if (forwards) 01526 virtualLine++; 01527 else 01528 virtualLine--; 01529 } 01530 01531 // Looks like we were asked for something a bit exotic. 01532 // Return the max/min valid position. 01533 if (forwards) 01534 return KateTextCursor(m_doc->visibleLines() - 1, m_doc->lineLength(m_doc->visibleLines() - 1)); 01535 else 01536 return KateTextCursor(0, 0); 01537 } 01538 01539 int KateViewInternal::lineMaxCursorX(const LineRange& range) 01540 { 01541 if (!m_doc->wrapCursor() && !range.wrap) 01542 return INT_MAX; 01543 01544 int maxX = range.endX; 01545 01546 if (maxX && range.wrap) { 01547 QChar lastCharInLine = textLine(range.line)->getChar(range.endCol - 1); 01548 maxX -= m_view->renderer()->config()->fontMetrics()->width(lastCharInLine); 01549 } 01550 01551 return maxX; 01552 } 01553 01554 int KateViewInternal::lineMaxCol(const LineRange& range) 01555 { 01556 int maxCol = range.endCol; 01557 01558 if (maxCol && range.wrap) 01559 maxCol--; 01560 01561 return maxCol; 01562 } 01563 01564 void KateViewInternal::cursorUp(bool sel) 01565 { 01566 if (displayCursor.line() == 0 && (!m_view->dynWordWrap() || viewLine(cursor) == 0)) 01567 return; 01568 01569 int newLine = cursor.line(), newCol = 0, xOffset = 0, startCol = 0; 01570 m_preserveMaxX = true; 01571 01572 if (m_view->dynWordWrap()) { 01573 // Dynamic word wrapping - navigate on visual lines rather than real lines 01574 LineRange thisRange = currentRange(); 01575 // This is not the first line because that is already simplified out above 01576 LineRange pRange = previousRange(); 01577 01578 // Ensure we're in the right spot 01579 Q_ASSERT((cursor.line() == thisRange.line) && 01580 (cursor.col() >= thisRange.startCol) && 01581 (!thisRange.wrap || cursor.col() < thisRange.endCol)); 01582 01583 // VisibleX is the distance from the start of the text to the cursor on the current line. 01584 int visibleX = m_view->renderer()->textWidth(cursor) - thisRange.startX; 01585 int currentLineVisibleX = visibleX; 01586 01587 // Translate to new line 01588 visibleX += thisRange.xOffset(); 01589 visibleX -= pRange.xOffset(); 01590 01591 // Limit to >= 0 01592 visibleX = QMAX(0, visibleX); 01593 01594 startCol = pRange.startCol; 01595 xOffset = pRange.startX; 01596 newLine = pRange.line; 01597 01598 // Take into account current max X (ie. if the current line was smaller 01599 // than the last definitely specified width) 01600 if (thisRange.xOffset() && !pRange.xOffset() && currentLineVisibleX == 0) // Special case for where xOffset may be > m_currentMaxX 01601 visibleX = m_currentMaxX; 01602 else if (visibleX < m_currentMaxX - pRange.xOffset()) 01603 visibleX = m_currentMaxX - pRange.xOffset(); 01604 01605 cXPos = xOffset + visibleX; 01606 01607 cXPos = QMIN(cXPos, lineMaxCursorX(pRange)); 01608 01609 newCol = QMIN((int)m_view->renderer()->textPos(newLine, visibleX, startCol), lineMaxCol(pRange)); 01610 01611 } else { 01612 newLine = m_doc->getRealLine(displayCursor.line() - 1); 01613 01614 if ((m_doc->wrapCursor()) && m_currentMaxX > cXPos) 01615 cXPos = m_currentMaxX; 01616 } 01617 01618 KateTextCursor c(newLine, newCol); 01619 m_view->renderer()->textWidth(c, cXPos); 01620 01621 updateSelection( c, sel ); 01622 updateCursor( c ); 01623 } 01624 01625 void KateViewInternal::cursorDown(bool sel) 01626 { 01627 if ((displayCursor.line() >= (int)m_doc->numVisLines() - 1) && (!m_view->dynWordWrap() || viewLine(cursor) == lastViewLine(cursor.line()))) 01628 return; 01629 01630 int newLine = cursor.line(), newCol = 0, xOffset = 0, startCol = 0; 01631 m_preserveMaxX = true; 01632 01633 if (m_view->dynWordWrap()) { 01634 // Dynamic word wrapping - navigate on visual lines rather than real lines 01635 LineRange thisRange = currentRange(); 01636 // This is not the last line because that is already simplified out above 01637 LineRange nRange = nextRange(); 01638 01639 // Ensure we're in the right spot 01640 Q_ASSERT((cursor.line() == thisRange.line) && 01641 (cursor.col() >= thisRange.startCol) && 01642 (!thisRange.wrap || cursor.col() < thisRange.endCol)); 01643 01644 // VisibleX is the distance from the start of the text to the cursor on the current line. 01645 int visibleX = m_view->renderer()->textWidth(cursor) - thisRange.startX; 01646 int currentLineVisibleX = visibleX; 01647 01648 // Translate to new line 01649 visibleX += thisRange.xOffset(); 01650 visibleX -= nRange.xOffset(); 01651 01652 // Limit to >= 0 01653 visibleX = QMAX(0, visibleX); 01654 01655 if (!thisRange.wrap) { 01656 newLine = m_doc->getRealLine(displayCursor.line() + 1); 01657 } else { 01658 startCol = thisRange.endCol; 01659 xOffset = thisRange.endX; 01660 } 01661 01662 // Take into account current max X (ie. if the current line was smaller 01663 // than the last definitely specified width) 01664 if (thisRange.xOffset() && !nRange.xOffset() && currentLineVisibleX == 0) // Special case for where xOffset may be > m_currentMaxX 01665 visibleX = m_currentMaxX; 01666 else if (visibleX < m_currentMaxX - nRange.xOffset()) 01667 visibleX = m_currentMaxX - nRange.xOffset(); 01668 01669 cXPos = xOffset + visibleX; 01670 01671 cXPos = QMIN(cXPos, lineMaxCursorX(nRange)); 01672 01673 newCol = QMIN((int)m_view->renderer()->textPos(newLine, visibleX, startCol), lineMaxCol(nRange)); 01674 01675 } else { 01676 newLine = m_doc->getRealLine(displayCursor.line() + 1); 01677 01678 if ((m_doc->wrapCursor()) && m_currentMaxX > cXPos) 01679 cXPos = m_currentMaxX; 01680 } 01681 01682 KateTextCursor c(newLine, newCol); 01683 m_view->renderer()->textWidth(c, cXPos); 01684 01685 updateSelection(c, sel); 01686 updateCursor(c); 01687 } 01688 01689 void KateViewInternal::cursorToMatchingBracket( bool sel ) 01690 { 01691 KateTextCursor start( cursor ), end; 01692 01693 if( !m_doc->findMatchingBracket( start, end ) ) 01694 return; 01695 01696 // The cursor is now placed just to the left of the matching bracket. 01697 // If it's an ending bracket, put it to the right (so we can easily 01698 // get back to the original bracket). 01699 if( end > start ) 01700 end.setCol(end.col() + 1); 01701 01702 updateSelection( end, sel ); 01703 updateCursor( end ); 01704 } 01705 01706 void KateViewInternal::topOfView( bool sel ) 01707 { 01708 KateTextCursor c = viewLineOffset(startPos(), m_minLinesVisible); 01709 updateSelection( c, sel ); 01710 updateCursor( c ); 01711 } 01712 01713 void KateViewInternal::bottomOfView( bool sel ) 01714 { 01715 // FIXME account for wordwrap 01716 KateTextCursor c = viewLineOffset(endPos(), -m_minLinesVisible); 01717 updateSelection( c, sel ); 01718 updateCursor( c ); 01719 } 01720 01721 // lines is the offset to scroll by 01722 void KateViewInternal::scrollLines( int lines, bool sel ) 01723 { 01724 KateTextCursor c = viewLineOffset(displayCursor, lines, true); 01725 01726 // Fix the virtual cursor -> real cursor 01727 c.setLine(m_doc->getRealLine(c.line())); 01728 01729 updateSelection( c, sel ); 01730 updateCursor( c ); 01731 } 01732 01733 // This is a bit misleading... it's asking for the view to be scrolled, not the cursor 01734 void KateViewInternal::scrollUp() 01735 { 01736 KateTextCursor newPos = viewLineOffset(m_startPos, -1); 01737 scrollPos(newPos); 01738 } 01739 01740 void KateViewInternal::scrollDown() 01741 { 01742 KateTextCursor newPos = viewLineOffset(m_startPos, 1); 01743 scrollPos(newPos); 01744 } 01745 01746 void KateViewInternal::setAutoCenterLines(int viewLines, bool updateView) 01747 { 01748 m_autoCenterLines = viewLines; 01749 m_minLinesVisible = QMIN(int((linesDisplayed() - 1)/2), m_autoCenterLines); 01750 if (updateView) 01751 KateViewInternal::updateView(); 01752 } 01753 01754 void KateViewInternal::pageUp( bool sel ) 01755 { 01756 // remember the view line and x pos 01757 int viewLine = displayViewLine(displayCursor); 01758 bool atTop = (startPos().line() == 0 && startPos().col() == 0); 01759 01760 // Adjust for an auto-centering cursor 01761 int lineadj = 2 * m_minLinesVisible; 01762 int cursorStart = (linesDisplayed() - 1) - viewLine; 01763 if (cursorStart < m_minLinesVisible) 01764 lineadj -= m_minLinesVisible - cursorStart; 01765 01766 int linesToScroll = -QMAX( (linesDisplayed() - 1) - lineadj, 0 ); 01767 m_preserveMaxX = true; 01768 01769 // don't scroll the full view in case the scrollbar appears 01770 if (!m_view->dynWordWrap()) { 01771 if (scrollbarVisible(startLine() + linesToScroll + viewLine)) { 01772 if (!m_columnScrollDisplayed) { 01773 linesToScroll++; 01774 } 01775 } else { 01776 if (m_columnScrollDisplayed) { 01777 linesToScroll--; 01778 } 01779 } 01780 } 01781 01782 if (!m_doc->pageUpDownMovesCursor () && !atTop) { 01783 int xPos = m_view->renderer()->textWidth(cursor) - currentRange().startX; 01784 01785 KateTextCursor newStartPos = viewLineOffset(startPos(), linesToScroll - 1); 01786 scrollPos(newStartPos); 01787 01788 // put the cursor back approximately where it was 01789 KateTextCursor newPos = viewLineOffset(newStartPos, viewLine, true); 01790 newPos.setLine(m_doc->getRealLine(newPos.line())); 01791 01792 LineRange newLine = range(newPos); 01793 01794 if (m_currentMaxX - newLine.xOffset() > xPos) 01795 xPos = m_currentMaxX - newLine.xOffset(); 01796 01797 cXPos = QMIN(newLine.startX + xPos, lineMaxCursorX(newLine)); 01798 01799 m_view->renderer()->textWidth( newPos, cXPos ); 01800 01801 m_preserveMaxX = true; 01802 updateSelection( newPos, sel ); 01803 updateCursor(newPos); 01804 01805 } else { 01806 scrollLines( linesToScroll, sel ); 01807 } 01808 } 01809 01810 void KateViewInternal::pageDown( bool sel ) 01811 { 01812 // remember the view line 01813 int viewLine = displayViewLine(displayCursor); 01814 bool atEnd = startPos() >= m_cachedMaxStartPos; 01815 01816 // Adjust for an auto-centering cursor 01817 int lineadj = 2 * m_minLinesVisible; 01818 int cursorStart = m_minLinesVisible - viewLine; 01819 if (cursorStart > 0) 01820 lineadj -= cursorStart; 01821 01822 int linesToScroll = QMAX( (linesDisplayed() - 1) - lineadj, 0 ); 01823 m_preserveMaxX = true; 01824 01825 // don't scroll the full view in case the scrollbar appears 01826 if (!m_view->dynWordWrap()) { 01827 if (scrollbarVisible(startLine() + linesToScroll + viewLine - (linesDisplayed() - 1))) { 01828 if (!m_columnScrollDisplayed) { 01829 linesToScroll--; 01830 } 01831 } else { 01832 if (m_columnScrollDisplayed) { 01833 linesToScroll--; 01834 } 01835 } 01836 } 01837 01838 if (!m_doc->pageUpDownMovesCursor () && !atEnd) { 01839 int xPos = m_view->renderer()->textWidth(cursor) - currentRange().startX; 01840 01841 KateTextCursor newStartPos = viewLineOffset(startPos(), linesToScroll + 1); 01842 scrollPos(newStartPos); 01843 01844 // put the cursor back approximately where it was 01845 KateTextCursor newPos = viewLineOffset(newStartPos, viewLine, true); 01846 newPos.setLine(m_doc->getRealLine(newPos.line())); 01847 01848 LineRange newLine = range(newPos); 01849 01850 if (m_currentMaxX - newLine.xOffset() > xPos) 01851 xPos = m_currentMaxX - newLine.xOffset(); 01852 01853 cXPos = QMIN(newLine.startX + xPos, lineMaxCursorX(newLine)); 01854 01855 m_view->renderer()->textWidth( newPos, cXPos ); 01856 01857 m_preserveMaxX = true; 01858 updateSelection( newPos, sel ); 01859 updateCursor(newPos); 01860 01861 } else { 01862 scrollLines( linesToScroll, sel ); 01863 } 01864 } 01865 01866 bool KateViewInternal::scrollbarVisible(uint startLine) 01867 { 01868 return maxLen(startLine) > width() - 8; 01869 } 01870 01871 int KateViewInternal::maxLen(uint startLine) 01872 { 01873 Q_ASSERT(!m_view->dynWordWrap()); 01874 01875 int displayLines = (m_view->height() / m_view->renderer()->fontHeight()) + 1; 01876 01877 int maxLen = 0; 01878 01879 for (int z = 0; z < displayLines; z++) { 01880 int virtualLine = startLine + z; 01881 01882 if (virtualLine < 0 || virtualLine >= (int)m_doc->visibleLines()) 01883 break; 01884 01885 LineRange thisRange = range((int)m_doc->getRealLine(virtualLine)); 01886 01887 maxLen = QMAX(maxLen, thisRange.endX); 01888 } 01889 01890 return maxLen; 01891 } 01892 01893 void KateViewInternal::top( bool sel ) 01894 { 01895 KateTextCursor c( 0, cursor.col() ); 01896 m_view->renderer()->textWidth( c, cXPos ); 01897 updateSelection( c, sel ); 01898 updateCursor( c ); 01899 } 01900 01901 void KateViewInternal::bottom( bool sel ) 01902 { 01903 KateTextCursor c( m_doc->lastLine(), cursor.col() ); 01904 m_view->renderer()->textWidth( c, cXPos ); 01905 updateSelection( c, sel ); 01906 updateCursor( c ); 01907 } 01908 01909 void KateViewInternal::top_home( bool sel ) 01910 { 01911 KateTextCursor c( 0, 0 ); 01912 updateSelection( c, sel ); 01913 updateCursor( c ); 01914 } 01915 01916 void KateViewInternal::bottom_end( bool sel ) 01917 { 01918 KateTextCursor c( m_doc->lastLine(), m_doc->lineLength( m_doc->lastLine() ) ); 01919 updateSelection( c, sel ); 01920 updateCursor( c ); 01921 } 01922 01923 void KateViewInternal::updateSelection( const KateTextCursor& newCursor, bool keepSel ) 01924 { 01925 if( keepSel ) 01926 { 01927 if ( !m_doc->hasSelection() || (selectAnchor.line() == -1) 01928 || ((m_doc->configFlags() & KateDocument::cfPersistent) 01929 && ((cursor < m_doc->selectStart) || (cursor > m_doc->selectEnd))) ) 01930 { 01931 selectAnchor = cursor; 01932 m_doc->setSelection( cursor, newCursor ); 01933 } 01934 else 01935 m_doc->setSelection( selectAnchor, newCursor); 01936 01937 m_selChangedByUser = true; 01938 } 01939 else if ( !(m_doc->configFlags() & KateDocument::cfPersistent) ) 01940 m_doc->clearSelection(); 01941 } 01942 01943 void KateViewInternal::updateCursor( const KateTextCursor& newCursor, bool force, bool center, bool calledExternally ) 01944 { 01945 TextLine::Ptr l = textLine( newCursor.line() ); 01946 01947 if ( !force && (cursor == newCursor) ) 01948 { 01949 if ( !m_madeVisible ) 01950 { 01951 // unfold if required 01952 if ( l && ! l->isVisible() ) 01953 m_doc->foldingTree()->ensureVisible( newCursor.line() ); 01954 01955 makeVisible ( displayCursor, displayCursor.col(), false, center, calledExternally ); 01956 } 01957 01958 return; 01959 } 01960 01961 // unfold if required 01962 if ( l && ! l->isVisible() ) 01963 m_doc->foldingTree()->ensureVisible( newCursor.line() ); 01964 01965 KateTextCursor oldDisplayCursor = displayCursor; 01966 01967 cursor.setPos (newCursor); 01968 displayCursor.setPos (m_doc->getVirtualLine(cursor.line()), cursor.col()); 01969 01970 cXPos = m_view->renderer()->textWidth( cursor ); 01971 makeVisible ( displayCursor, displayCursor.col(), false, center, calledExternally ); 01972 01973 updateBracketMarks(); 01974 01975 // It's efficient enough to just tag them both without checking to see if they're on the same view line 01976 tagLine(oldDisplayCursor); 01977 tagLine(displayCursor); 01978 01979 QPoint cursorP = cursorCoordinates(); 01980 setMicroFocusHint( cursorP.x(), cursorP.y(), 0, m_view->renderer()->fontHeight() ); 01981 01982 if (m_cursorTimer.isActive ()) 01983 { 01984 m_cursorTimer.start( KApplication::cursorFlashTime() / 2 ); 01985 m_view->renderer()->setDrawCaret(true); 01986 } 01987 01988 // Remember the maximum X position if requested 01989 if (m_preserveMaxX) 01990 m_preserveMaxX = false; 01991 else 01992 if (m_view->dynWordWrap()) 01993 m_currentMaxX = m_view->renderer()->textWidth(displayCursor) - currentRange().startX + currentRange().xOffset(); 01994 else 01995 m_currentMaxX = cXPos; 01996 01997 //kdDebug() << "m_currentMaxX: " << m_currentMaxX << " (was "<< oldmaxx << "), cXPos: " << cXPos << endl; 01998 //kdDebug(13030) << "Cursor now located at real " << cursor.line << "," << cursor.col << ", virtual " << displayCursor.line << ", " << displayCursor.col << "; Top is " << startLine() << ", " << startPos().col << "; Old top is " << m_oldStartPos.line << ", " << m_oldStartPos.col << endl; 01999 02000 paintText(0, 0, width(), height(), true); 02001 02002 emit m_view->cursorPositionChanged(); 02003 } 02004 02005 void KateViewInternal::updateBracketMarks() 02006 { 02007 if ( bm.isValid() ) { 02008 KateTextCursor bmStart(m_doc->getVirtualLine(bm.start().line()), bm.start().col()); 02009 KateTextCursor bmEnd(m_doc->getVirtualLine(bm.end().line()), bm.end().col()); 02010 tagLine(bmStart); 02011 tagLine(bmEnd); 02012 } 02013 02014 m_doc->newBracketMark( cursor, bm ); 02015 02016 if ( bm.isValid() ) { 02017 KateTextCursor bmStart(m_doc->getVirtualLine(bm.start().line()), bm.start().col()); 02018 KateTextCursor bmEnd(m_doc->getVirtualLine(bm.end().line()), bm.end().col()); 02019 tagLine(bmStart); 02020 tagLine(bmEnd); 02021 } 02022 } 02023 02024 bool KateViewInternal::tagLine(const KateTextCursor& virtualCursor) 02025 { 02026 int viewLine = displayViewLine(virtualCursor, true); 02027 if (viewLine >= 0 && viewLine < (int)lineRanges.count()) { 02028 lineRanges[viewLine].dirty = true; 02029 leftBorder->update (0, lineToY(viewLine), leftBorder->width(), m_view->renderer()->fontHeight()); 02030 return true; 02031 } 02032 return false; 02033 } 02034 02035 bool KateViewInternal::tagLines( int start, int end, bool realLines ) 02036 { 02037 return tagLines(KateTextCursor(start, 0), KateTextCursor(end, -1), realLines); 02038 } 02039 02040 bool KateViewInternal::tagLines(KateTextCursor start, KateTextCursor end, bool realCursors) 02041 { 02042 if (realCursors) 02043 { 02044 //kdDebug()<<"realLines is true"<<endl; 02045 start.setLine(m_doc->getVirtualLine( start.line() )); 02046 end.setLine(m_doc->getVirtualLine( end.line() )); 02047 } 02048 02049 if (end.line() < (int)startLine()) 02050 { 02051 //kdDebug()<<"end<startLine"<<endl; 02052 return false; 02053 } 02054 if (start.line() > (int)endLine()) 02055 { 02056 //kdDebug()<<"start> endLine"<<start<<" "<<((int)endLine())<<endl; 02057 return false; 02058 } 02059 02060 //kdDebug(13030) << "tagLines( [" << start.line << "," << start.col << "], [" << end.line << "," << end.col << "] )\n"; 02061 02062 bool ret = false; 02063 02064 for (uint z = 0; z < lineRanges.size(); z++) 02065 { 02066 if ((lineRanges[z].virtualLine > start.line() || (lineRanges[z].virtualLine == start.line() && lineRanges[z].endCol >= start.col() && start.col() != -1)) && (lineRanges[z].virtualLine < end.line() || (lineRanges[z].virtualLine == end.line() && (lineRanges[z].startCol <= end.col() || end.col() == -1)))) { 02067 ret = lineRanges[z].dirty = true; 02068 //kdDebug() << "Tagged line " << lineRanges[z].line << endl; 02069 } 02070 } 02071 02072 if (!m_view->dynWordWrap()) 02073 { 02074 int y = lineToY( start.line() ); 02075 // FIXME is this enough for when multiple lines are deleted 02076 int h = (end.line() - start.line() + 2) * m_view->renderer()->fontHeight(); 02077 if (end.line() == (int)m_doc->numVisLines() - 1) 02078 h = height(); 02079 02080 leftBorder->update (0, y, leftBorder->width(), h); 02081 } 02082 else 02083 { 02084 // FIXME Do we get enough good info in editRemoveText to optimise this more? 02085 //bool justTagged = false; 02086 for (uint z = 0; z < lineRanges.size(); z++) 02087 { 02088 if ((lineRanges[z].virtualLine > start.line() || (lineRanges[z].virtualLine == start.line() && lineRanges[z].endCol >= start.col() && start.col() != -1)) && (lineRanges[z].virtualLine < end.line() || (lineRanges[z].virtualLine == end.line() && (lineRanges[z].startCol <= end.col() || end.col() == -1)))) 02089 { 02090 //justTagged = true; 02091 leftBorder->update (0, z * m_view->renderer()->fontHeight(), leftBorder->width(), leftBorder->height()); 02092 break; 02093 } 02094 /*else if (justTagged) 02095 { 02096 justTagged = false; 02097 leftBorder->update (0, z * m_doc->viewFont.fontHeight, leftBorder->width(), m_doc->viewFont.fontHeight); 02098 break; 02099 }*/ 02100 } 02101 } 02102 02103 return ret; 02104 } 02105 02106 void KateViewInternal::tagAll() 02107 { 02108 //kdDebug(13030) << "tagAll()" << endl; 02109 for (uint z = 0; z < lineRanges.size(); z++) 02110 { 02111 lineRanges[z].dirty = true; 02112 } 02113 02114 leftBorder->updateFont(); 02115 leftBorder->update (); 02116 } 02117 02118 void KateViewInternal::paintCursor() 02119 { 02120 if (tagLine(displayCursor)) 02121 paintText (0,0,width(), height(), true); 02122 } 02123 02124 // Point in content coordinates 02125 void KateViewInternal::placeCursor( const QPoint& p, bool keepSelection, bool updateSelection ) 02126 { 02127 LineRange thisRange = yToLineRange(p.y()); 02128 02129 if (thisRange.line == -1) { 02130 for (int i = (p.y() / m_view->renderer()->fontHeight()); i >= 0; i--) { 02131 thisRange = lineRanges[i]; 02132 if (thisRange.line != -1) 02133 break; 02134 } 02135 Q_ASSERT(thisRange.line != -1); 02136 } 02137 02138 int realLine = thisRange.line; 02139 int visibleLine = thisRange.virtualLine; 02140 uint startCol = thisRange.startCol; 02141 02142 visibleLine = QMAX( 0, QMIN( visibleLine, int(m_doc->numVisLines()) - 1 ) ); 02143 02144 KateTextCursor c(realLine, 0); 02145 02146 int x = QMIN(QMAX(0, p.x() - thisRange.xOffset()), lineMaxCursorX(thisRange) - thisRange.startX); 02147 02148 m_view->renderer()->textWidth( c, startX() + x, startCol); 02149 02150 if (updateSelection) 02151 KateViewInternal::updateSelection( c, keepSelection ); 02152 updateCursor( c ); 02153 } 02154 02155 // Point in content coordinates 02156 bool KateViewInternal::isTargetSelected( const QPoint& p ) 02157 { 02158 LineRange thisRange = yToLineRange(p.y()); 02159 02160 TextLine::Ptr l = textLine( thisRange.line ); 02161 if( !l ) 02162 return false; 02163 02164 int col = m_view->renderer()->textPos( l, p.x() - thisRange.xOffset(), thisRange.startCol ); 02165 02166 return m_doc->lineColSelected( thisRange.line, col ); 02167 } 02168 02169 // 02170 // START EVENT HANDLING STUFF !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 02171 // 02172 02173 bool KateViewInternal::eventFilter( QObject *obj, QEvent *e ) 02174 { 02175 if (obj == m_lineScroll) 02176 { 02177 // the second condition is to make sure a scroll on the vertical bar doesn't cause a horizontal scroll ;) 02178 if (e->type() == QEvent::Wheel && m_lineScroll->minValue() != m_lineScroll->maxValue()) 02179 { 02180 wheelEvent((QWheelEvent*)e); 02181 return true; 02182 } 02183 02184 // continue processing 02185 return QWidget::eventFilter( obj, e ); 02186 } 02187 02188 switch( e->type() ) 02189 { 02190 case QEvent::KeyPress: 02191 { 02192 QKeyEvent *k = (QKeyEvent *)e; 02193 02194 if ((k->key() == Qt::Key_Escape) && !(m_doc->configFlags() & KateDocument::cfPersistent) ) 02195 { 02196 m_doc->clearSelection(); 02197 return true; 02198 } 02199 else if ( !((k->state() & ControlButton) || (k->state() & AltButton)) ) 02200 { 02201 keyPressEvent( k ); 02202 return k->isAccepted(); 02203 } 02204 02205 } break; 02206 02207 case QEvent::DragMove: 02208 { 02209 QPoint currentPoint = ((QDragMoveEvent*) e)->pos(); 02210 02211 QRect doNotScrollRegion( scrollMargin, scrollMargin, 02212 width() - scrollMargin * 2, 02213 height() - scrollMargin * 2 ); 02214 02215 if ( !doNotScrollRegion.contains( currentPoint ) ) 02216 { 02217 startDragScroll(); 02218 // Keep sending move events 02219 ( (QDragMoveEvent*)e )->accept( QRect(0,0,0,0) ); 02220 } 02221 02222 dragMoveEvent((QDragMoveEvent*)e); 02223 } break; 02224 02225 case QEvent::DragLeave: 02226 stopDragScroll(); 02227 break; 02228 02229 default: 02230 break; 02231 } 02232 02233 return QWidget::eventFilter( obj, e ); 02234 } 02235 02236 void KateViewInternal::keyPressEvent( QKeyEvent* e ) 02237 { 02238 KKey key(e); 02239 02240 if (key == Qt::Key_Left) 02241 { 02242 m_view->cursorLeft(); 02243 e->accept(); 02244 return; 02245 } 02246 02247 if (key == Qt::Key_Right) 02248 { 02249 m_view->cursorRight(); 02250 e->accept(); 02251 return; 02252 } 02253 02254 if (key == Qt::Key_Down) 02255 { 02256 m_view->down(); 02257 e->accept(); 02258 return; 02259 } 02260 02261 if (key == Qt::Key_Up) 02262 { 02263 m_view->up(); 02264 e->accept(); 02265 return; 02266 } 02267 02268 if( !m_doc->isReadWrite() ) 02269 { 02270 e->ignore(); 02271 return; 02272 } 02273 02274 if ((key == Qt::Key_Return) || (key == Qt::Key_Enter) || 02275 (key == SHIFT + Qt::Key_Return) || (key == SHIFT + Qt::Key_Enter)) 02276 { 02277 m_view->keyReturn(); 02278 e->accept(); 02279 return; 02280 } 02281 02282 if (key == Qt::Key_Backspace || key == SHIFT + Qt::Key_Backspace) 02283 { 02284 m_view->backspace(); 02285 e->accept(); 02286 return; 02287 } 02288 02289 if (key == Qt::Key_Delete) 02290 { 02291 m_view->keyDelete(); 02292 e->accept(); 02293 return; 02294 } 02295 02296 if( (key == Qt::Key_Tab || key == SHIFT+Qt::Key_Backtab || key == Qt::Key_Backtab) 02297 && (m_doc->configFlags() & KateDocumentConfig::cfTabIndents) ) 02298 { 02299 if( key == Qt::Key_Tab ) 02300 { 02301 if (m_doc->hasSelection() || (m_doc->configFlags() & KateDocumentConfig::cfTabIndentsMode)) 02302 m_doc->indent( m_view, cursor.line(), 1 ); 02303 else if (m_doc->configFlags() & KateDocumentConfig::cfTabInsertsTab) 02304 m_doc->typeChars ( m_view, QString ("\t") ); 02305 else 02306 m_doc->insertIndentChars ( m_view ); 02307 02308 e->accept(); 02309 return; 02310 } 02311 02312 if (key == SHIFT+Qt::Key_Backtab || key == Qt::Key_Backtab) 02313 { 02314 m_doc->indent( m_view, cursor.line(), -1 ); 02315 e->accept(); 02316 return; 02317 } 02318 } 02319 02320 if ( !(e->state() & ControlButton) && !(e->state() & AltButton) 02321 && m_doc->typeChars ( m_view, e->text() ) ) 02322 { 02323 e->accept(); 02324 return; 02325 } 02326 02327 e->ignore(); 02328 } 02329 02330 void KateViewInternal::keyReleaseEvent( QKeyEvent* e ) 02331 { 02332 KKey key(e); 02333 02334 if (key == SHIFT) 02335 m_shiftKeyPressed = true; 02336 else 02337 { 02338 if (m_shiftKeyPressed) 02339 { 02340 m_shiftKeyPressed = false; 02341 02342 if (m_selChangedByUser) 02343 { 02344 QApplication::clipboard()->setSelectionMode( true ); 02345 m_doc->copy(); 02346 QApplication::clipboard()->setSelectionMode( false ); 02347 02348 m_selChangedByUser = false; 02349 } 02350 } 02351 } 02352 02353 e->ignore(); 02354 return; 02355 } 02356 02357 void KateViewInternal::mousePressEvent( QMouseEvent* e ) 02358 { 02359 switch (e->button()) 02360 { 02361 case LeftButton: 02362 m_selChangedByUser = false; 02363 02364 if (possibleTripleClick) 02365 { 02366 possibleTripleClick = false; 02367 02368 m_doc->selectLine( cursor ); 02369 QApplication::clipboard()->setSelectionMode( true ); 02370 m_doc->copy(); 02371 QApplication::clipboard()->setSelectionMode( false ); 02372 02373 cursor.setCol(0); 02374 updateCursor( cursor ); 02375 return; 02376 } 02377 02378 if( isTargetSelected( e->pos() ) ) 02379 { 02380 dragInfo.state = diPending; 02381 dragInfo.start = e->pos(); 02382 } 02383 else 02384 { 02385 dragInfo.state = diNone; 02386 02387 placeCursor( e->pos(), e->state() & ShiftButton ); 02388 scrollX = 0; 02389 scrollY = 0; 02390 02391 m_scrollTimer.start (50); 02392 } 02393 02394 e->accept (); 02395 break; 02396 02397 case RightButton: 02398 if ( !isTargetSelected( e->pos() ) ) 02399 placeCursor( e->pos() ); 02400 02401 // popup is a qguardedptr now 02402 if (m_view->popup()) 02403 m_view->popup()->popup( mapToGlobal( e->pos() ) ); 02404 02405 e->accept (); 02406 break; 02407 02408 default: 02409 e->ignore (); 02410 break; 02411 } 02412 } 02413 02414 void KateViewInternal::mouseDoubleClickEvent(QMouseEvent *e) 02415 { 02416 switch (e->button()) 02417 { 02418 case LeftButton: 02419 m_doc->selectWord( cursor ); 02420 02421 // Move cursor to end of selected word 02422 if (m_doc->hasSelection()) 02423 { 02424 QApplication::clipboard()->setSelectionMode( true ); 02425 m_doc->copy(); 02426 QApplication::clipboard()->setSelectionMode( false ); 02427 02428 cursor.setPos(m_doc->selectEnd); 02429 updateCursor( cursor ); 02430 } 02431 02432 possibleTripleClick = true; 02433 QTimer::singleShot ( QApplication::doubleClickInterval(), this, SLOT(tripleClickTimeout()) ); 02434 02435 e->accept (); 02436 break; 02437 02438 default: 02439 e->ignore (); 02440 break; 02441 } 02442 } 02443 02444 void KateViewInternal::tripleClickTimeout() 02445 { 02446 possibleTripleClick = false; 02447 } 02448 02449 void KateViewInternal::mouseReleaseEvent( QMouseEvent* e ) 02450 { 02451 switch (e->button()) 02452 { 02453 case LeftButton: 02454 if (m_selChangedByUser) 02455 { 02456 QApplication::clipboard()->setSelectionMode( true ); 02457 m_doc->copy(); 02458 QApplication::clipboard()->setSelectionMode( false ); 02459 02460 m_selChangedByUser = false; 02461 } 02462 02463 if (dragInfo.state == diPending) 02464 placeCursor( e->pos() ); 02465 else if (dragInfo.state == diNone) 02466 m_scrollTimer.stop (); 02467 02468 dragInfo.state = diNone; 02469 02470 e->accept (); 02471 break; 02472 02473 case MidButton: 02474 placeCursor( e->pos() ); 02475 02476 if( m_doc->isReadWrite() ) 02477 { 02478 QApplication::clipboard()->setSelectionMode( true ); 02479 doPaste(); 02480 QApplication::clipboard()->setSelectionMode( false ); 02481 } 02482 02483 e->accept (); 02484 break; 02485 02486 default: 02487 e->ignore (); 02488 break; 02489 } 02490 } 02491 02492 void KateViewInternal::mouseMoveEvent( QMouseEvent* e ) 02493 { 02494 if( e->state() & LeftButton ) 02495 { 02496 if (dragInfo.state == diPending) 02497 { 02498 // we had a mouse down, but haven't confirmed a drag yet 02499 // if the mouse has moved sufficiently, we will confirm 02500 QPoint p( e->pos() - dragInfo.start ); 02501 02502 // we've left the drag square, we can start a real drag operation now 02503 if( p.manhattanLength() > KGlobalSettings::dndEventDelay() ) 02504 doDrag(); 02505 02506 return; 02507 } 02508 02509 mouseX = e->x(); 02510 mouseY = e->y(); 02511 02512 scrollX = 0; 02513 scrollY = 0; 02514 int d = m_view->renderer()->fontHeight(); 02515 02516 if (mouseX < 0) 02517 scrollX = -d; 02518 02519 if (mouseX > width()) 02520 scrollX = d; 02521 02522 if (mouseY < 0) 02523 { 02524 mouseY = 0; 02525 scrollY = -d; 02526 } 02527 02528 if (mouseY > height()) 02529 { 02530 mouseY = height(); 02531 scrollY = d; 02532 } 02533 02534 placeCursor( QPoint( mouseX, mouseY ), true ); 02535 } 02536 else 02537 { 02538 if (m_textHintEnabled) 02539 { 02540 m_textHintTimer.start(m_textHintTimeout); 02541 m_textHintMouseX=e->x(); 02542 m_textHintMouseY=e->y(); 02543 } 02544 } 02545 } 02546 02547 void KateViewInternal::paintEvent(QPaintEvent *e) 02548 { 02549 paintText(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height()); 02550 } 02551 02552 void KateViewInternal::resizeEvent(QResizeEvent* e) 02553 { 02554 bool expandedHorizontally = width() > e->oldSize().width(); 02555 bool expandedVertically = height() > e->oldSize().height(); 02556 bool heightChanged = height() != e->oldSize().height(); 02557 02558 m_madeVisible = false; 02559 02560 if (heightChanged) { 02561 setAutoCenterLines(m_autoCenterLines, false); 02562 m_cachedMaxStartPos.setPos(-1, -1); 02563 } 02564 02565 if (m_view->dynWordWrap()) { 02566 bool dirtied = false; 02567 02568 for (uint i = 0; i < lineRanges.count(); i++) { 02569 // find the first dirty line 02570 // the word wrap updateView algorithm is forced to check all lines after a dirty one 02571 if (lineRanges[i].wrap || 02572 (!expandedHorizontally && (lineRanges[i].endX - lineRanges[i].startX) > width())) { 02573 dirtied = lineRanges[i].dirty = true; 02574 break; 02575 } 02576 } 02577 02578 if (dirtied || heightChanged) { 02579 updateView(true); 02580 leftBorder->update(); 02581 } 02582 02583 if (width() < e->oldSize().width()) { 02584 if (!m_doc->wrapCursor()) { 02585 // May have to restrain cursor to new smaller width... 02586 if (cursor.col() > m_doc->lineLength(cursor.line())) { 02587 LineRange thisRange = currentRange(); 02588 02589 KateTextCursor newCursor(cursor.line(), thisRange.endCol + ((width() - thisRange.xOffset() - (thisRange.endX - thisRange.startX)) / m_view->renderer()->spaceWidth()) - 1); 02590 updateCursor(newCursor); 02591 } 02592 } 02593 } 02594 02595 } else { 02596 updateView(); 02597 02598 if (expandedHorizontally && startX() > 0) 02599 scrollColumns(startX() - (width() - e->oldSize().width())); 02600 } 02601 02602 if (expandedVertically) { 02603 KateTextCursor max = maxStartPos(); 02604 if (startPos() > max) 02605 scrollPos(max); 02606 } 02607 } 02608 02609 void KateViewInternal::scrollTimeout () 02610 { 02611 if (scrollX || scrollY) 02612 { 02613 scrollLines (startPos().line() + (scrollY / (int)m_view->renderer()->fontHeight())); 02614 placeCursor( QPoint( mouseX, mouseY ), true ); 02615 } 02616 } 02617 02618 void KateViewInternal::cursorTimeout () 02619 { 02620 m_view->renderer()->setDrawCaret(!m_view->renderer()->drawCaret()); 02621 paintCursor(); 02622 } 02623 02624 void KateViewInternal::textHintTimeout () 02625 { 02626 m_textHintTimer.stop (); 02627 02628 LineRange thisRange = yToLineRange(m_textHintMouseY); 02629 02630 if (thisRange.line == -1) return; 02631 02632 if (m_textHintMouseX> (lineMaxCursorX(thisRange) - thisRange.startX)) return; 02633 02634 int realLine = thisRange.line; 02635 int startCol = thisRange.startCol; 02636 02637 KateTextCursor c(realLine, 0); 02638 m_view->renderer()->textWidth( c, startX() + m_textHintMouseX, startCol); 02639 02640 QString tmp; 02641 02642 emit m_view->needTextHint(c.line(), c.col(), tmp); 02643 02644 if (!tmp.isEmpty()) kdDebug(13030)<<"Hint text: "<<tmp<<endl; 02645 } 02646 02647 void KateViewInternal::focusInEvent (QFocusEvent *) 02648 { 02649 m_cursorTimer.start ( KApplication::cursorFlashTime() / 2 ); 02650 02651 if (m_textHintEnabled) 02652 m_textHintTimer.start( m_textHintTimeout ); 02653 02654 paintCursor(); 02655 02656 m_doc->m_activeView = m_view; 02657 02658 emit m_view->gotFocus( m_view ); 02659 } 02660 02661 void KateViewInternal::focusOutEvent (QFocusEvent *) 02662 { 02663 if( ! m_view->m_codeCompletion->codeCompletionVisible() ) 02664 { 02665 m_cursorTimer.stop(); 02666 02667 m_view->renderer()->setDrawCaret(true); 02668 paintCursor(); 02669 emit m_view->lostFocus( m_view ); 02670 } 02671 02672 m_textHintTimer.stop(); 02673 } 02674 02675 void KateViewInternal::doDrag() 02676 { 02677 dragInfo.state = diDragging; 02678 dragInfo.dragObject = new QTextDrag(m_doc->selection(), this); 02679 dragInfo.dragObject->drag(); 02680 } 02681 02682 void KateViewInternal::dragEnterEvent( QDragEnterEvent* event ) 02683 { 02684 event->accept( (QTextDrag::canDecode(event) && m_doc->isReadWrite()) || 02685 KURLDrag::canDecode(event) ); 02686 } 02687 02688 void KateViewInternal::dragMoveEvent( QDragMoveEvent* event ) 02689 { 02690 // track the cursor to the current drop location 02691 placeCursor( event->pos(), true, false ); 02692 // important: accept action to switch between copy and move mode 02693 // without this, the text will always be copied. 02694 event->acceptAction(); 02695 } 02696 02697 void KateViewInternal::dropEvent( QDropEvent* event ) 02698 { 02699 if ( KURLDrag::canDecode(event) ) { 02700 02701 emit dropEventPass(event); 02702 02703 } else if ( QTextDrag::canDecode(event) && m_doc->isReadWrite() ) { 02704 02705 QString text; 02706 02707 if (!QTextDrag::decode(event, text)) 02708 return; 02709 02710 // is the source our own document? 02711 bool priv = false; 02712 if (event->source() && event->source()->inherits("KateViewInternal")) 02713 priv = m_doc->ownedView( ((KateViewInternal*)(event->source()))->m_view ); 02714 02715 // dropped on a text selection area? 02716 bool selected = isTargetSelected( event->pos() ); 02717 02718 if( priv && selected ) { 02719 // this is a drag that we started and dropped on our selection 02720 // ignore this case 02721 return; 02722 } 02723 02724 // on move: remove selected text; on copy: duplicate text 02725 if ( event->action() != QDropEvent::Copy ) 02726 m_doc->removeSelectedText(); 02727 m_doc->insertText( cursor.line(), cursor.col(), text ); 02728 placeCursor( event->pos() ); 02729 event->acceptAction(); 02730 updateView(); 02731 } 02732 // finally finish drag and drop mode 02733 dragInfo.state = diNone; 02734 // important, because the eventFilter`s DragLeave does not occure 02735 stopDragScroll(); 02736 } 02737 02738 void KateViewInternal::imStartEvent( QIMEvent *e ) 02739 { 02740 if ( m_doc->m_bReadOnly ) { 02741 e->ignore(); 02742 return; 02743 } 02744 02745 if ( m_doc->hasSelection() ) 02746 m_doc->removeSelectedText(); 02747 02748 m_imPreeditStartLine = cursor.line(); 02749 m_imPreeditStart = cursor.col(); 02750 m_imPreeditLength = 0; 02751 02752 m_doc->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, 0, 0, 0, true ); 02753 } 02754 02755 void KateViewInternal::imComposeEvent( QIMEvent *e ) 02756 { 02757 if ( m_doc->m_bReadOnly ) { 02758 e->ignore(); 02759 return; 02760 } 02761 02762 if ( m_imPreeditLength > 0 ) { 02763 m_doc->removeText( cursor.line(), m_imPreeditStart, 02764 cursor.line(), m_imPreeditStart + m_imPreeditLength ); 02765 } 02766 02767 m_doc->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, m_imPreeditStart + e->text().length(), 02768 m_imPreeditStart + e->cursorPos(), m_imPreeditStart + e->cursorPos() + e->selectionLength(), 02769 true ); 02770 02771 m_doc->insertText( cursor.line(), cursor.col(), e->text() ); 02772 02773 updateView( true ); 02774 updateCursor( cursor, true ); 02775 m_imPreeditLength = e->text().length(); 02776 } 02777 02778 void KateViewInternal::imEndEvent( QIMEvent *e ) 02779 { 02780 if ( m_doc->m_bReadOnly ) { 02781 e->ignore(); 02782 return; 02783 } 02784 02785 if ( m_imPreeditLength > 0 ) { 02786 m_doc->removeText( cursor.line(), m_imPreeditStart, 02787 cursor.line(), m_imPreeditStart + m_imPreeditLength ); 02788 } 02789 02790 m_doc->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, 0, 0, 0, false ); 02791 02792 if ( e->text().length() > 0 ) { 02793 m_doc->insertText( cursor.line(), cursor.col(), e->text() ); 02794 02795 if ( !m_cursorTimer.isActive() ) 02796 m_cursorTimer.start ( KApplication::cursorFlashTime() / 2 ); 02797 02798 updateView( true ); 02799 updateCursor( cursor, true ); 02800 02801 } 02802 02803 m_imPreeditStart = 0; 02804 m_imPreeditLength = 0; 02805 } 02806 02807 // 02808 // END EVENT HANDLING STUFF !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 02809 // 02810 02811 void KateViewInternal::clear() 02812 { 02813 cursor.setPos(0, 0); 02814 displayCursor.setPos(0, 0); 02815 } 02816 02817 void KateViewInternal::wheelEvent(QWheelEvent* e) 02818 { 02819 if (m_lineScroll->minValue() != m_lineScroll->maxValue() && e->orientation() != Qt::Horizontal) { 02820 // React to this as a vertical event 02821 if ( ( e->state() & ControlButton ) || ( e->state() & ShiftButton ) ) { 02822 if (e->delta() > 0) 02823 scrollPrevPage(); 02824 else 02825 scrollNextPage(); 02826 } else { 02827 scrollViewLines(-((e->delta() / 120) * QApplication::wheelScrollLines())); 02828 // maybe a menu was opened or a bubbled window title is on us -> we shall erase it 02829 update(); 02830 leftBorder->update(); 02831 } 02832 02833 } else if (!m_columnScroll->isHidden()) { 02834 QWheelEvent copy = *e; 02835 QApplication::sendEvent(m_columnScroll, &copy); 02836 02837 } else { 02838 e->ignore(); 02839 } 02840 } 02841 02842 void KateViewInternal::startDragScroll() 02843 { 02844 if ( !m_dragScrollTimer.isActive() ) { 02845 m_suppressColumnScrollBar = true; 02846 m_dragScrollTimer.start( scrollTime ); 02847 } 02848 } 02849 02850 void KateViewInternal::stopDragScroll() 02851 { 02852 m_suppressColumnScrollBar = false; 02853 m_dragScrollTimer.stop(); 02854 updateView(); 02855 } 02856 02857 void KateViewInternal::doDragScroll() 02858 { 02859 QPoint p = this->mapFromGlobal( QCursor::pos() ); 02860 02861 int dx = 0, dy = 0; 02862 if ( p.y() < scrollMargin ) { 02863 dy = p.y() - scrollMargin; 02864 } else if ( p.y() > height() - scrollMargin ) { 02865 dy = scrollMargin - (height() - p.y()); 02866 } 02867 if ( p.x() < scrollMargin ) { 02868 dx = p.x() - scrollMargin; 02869 } else if ( p.x() > width() - scrollMargin ) { 02870 dx = scrollMargin - (width() - p.x()); 02871 } 02872 dy /= 4; 02873 02874 if (dy) 02875 scrollLines(startPos().line() + dy); 02876 if (dx) 02877 scrollColumns(m_startX + dx); 02878 if (!dy && !dx) 02879 stopDragScroll(); 02880 } 02881 02882 void KateViewInternal::enableTextHints(int timeout) 02883 { 02884 m_textHintTimeout=timeout; 02885 m_textHintEnabled=true; 02886 m_textHintTimer.start(timeout); 02887 } 02888 02889 void KateViewInternal::disableTextHints() 02890 { 02891 m_textHintEnabled=false; 02892 m_textHintTimer.stop (); 02893 } 02894 02895 // BEGIN EDIT STUFF 02896 void KateViewInternal::editStart() 02897 { 02898 editSessionNumber++; 02899 02900 if (editSessionNumber > 1) 02901 return; 02902 02903 editIsRunning = true; 02904 editOldCursor = cursor; 02905 } 02906 02907 void KateViewInternal::editEnd(int editTagLineStart, int editTagLineEnd, bool tagFrom) 02908 { 02909 if (editSessionNumber == 0) 02910 return; 02911 02912 editSessionNumber--; 02913 02914 if (editSessionNumber > 0) 02915 return; 02916 02917 if (tagFrom && (editTagLineStart <= int(m_doc->getRealLine(startLine())))) 02918 tagAll(); 02919 else 02920 tagLines (editTagLineStart, tagFrom ? m_doc->lastLine() : editTagLineEnd, true); 02921 02922 if (editOldCursor == cursor) 02923 updateBracketMarks(); 02924 02925 if (m_imPreeditLength <= 0) 02926 updateView(true); 02927 02928 if ((editOldCursor != cursor) && (m_imPreeditLength <= 0)) 02929 { 02930 m_madeVisible = false; 02931 updateCursor ( cursor, true ); 02932 } 02933 else if ( m_view->isActive() ) 02934 { 02935 makeVisible(displayCursor, displayCursor.col()); 02936 } 02937 02938 editIsRunning = false; 02939 } 02940 02941 void KateViewInternal::editSetCursor (const KateTextCursor &cursor) 02942 { 02943 if (this->cursor != cursor) 02944 { 02945 this->cursor.setPos (cursor); 02946 } 02947 } 02948 // END 02949 02950 void KateViewInternal::docSelectionChanged () 02951 { 02952 if (!m_doc->hasSelection()) 02953 selectAnchor.setPos (-1, -1); 02954 } 02955 02956 // BEGIN KateScrollBar 02957 KateScrollBar::KateScrollBar (Orientation orientation, QWidget* parent, const char* name) 02958 : QScrollBar (orientation, parent, name) 02959 , m_middleMouseDown (false) 02960 { 02961 connect(this, SIGNAL(valueChanged(int)), SLOT(sliderMaybeMoved(int))); 02962 } 02963 02964 void KateScrollBar::mousePressEvent(QMouseEvent* e) 02965 { 02966 if (e->button() == MidButton) 02967 m_middleMouseDown = true; 02968 02969 QScrollBar::mousePressEvent(e); 02970 } 02971 02972 void KateScrollBar::mouseReleaseEvent(QMouseEvent* e) 02973 { 02974 QScrollBar::mouseReleaseEvent(e); 02975 02976 m_middleMouseDown = false; 02977 } 02978 02979 void KateScrollBar::sliderMaybeMoved(int value) 02980 { 02981 if (m_middleMouseDown) 02982 emit sliderMMBMoved(value); 02983 } 02984 02985 TextLine::Ptr KateViewInternal::textLine( int realLine ) 02986 { 02987 if (m_usePlainLines) 02988 return m_doc->plainKateTextLine(realLine); 02989 else 02990 return m_doc->kateTextLine(realLine); 02991 } 02992 02993 // END 02994 02995 // kate: space-indent on; indent-width 2; replace-tabs on;
KDE Logo
This file is part of the documentation for kate Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sun Oct 10 18:56:24 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003