kate Library API Documentation

kateviewinternal.cpp

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