# kate Library API Documentation

Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

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

This file is part of the documentation for kate Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:36:40 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003