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