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