• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kate
 

kate

  • kate
  • part
kateviewinternal.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
3  Copyright (C) 2002 Joseph Wenninger <jowenn@kde.org>
4  Copyright (C) 2002,2003 Christoph Cullmann <cullmann@kde.org>
5  Copyright (C) 2002,2003 Hamish Rodda <rodda@kde.org>
6  Copyright (C) 2003 Anakim Border <aborder@sources.sourceforge.net>
7 
8  Based on:
9  KWriteView : Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
10 
11  This library is free software; you can redistribute it and/or
12  modify it under the terms of the GNU Library General Public
13  License version 2 as published by the Free Software Foundation.
14 
15  This library is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18  Library General Public License for more details.
19 
20  You should have received a copy of the GNU Library General Public License
21  along with this library; see the file COPYING.LIB. If not, write to
22  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23  Boston, MA 02110-1301, USA.
24 */
25 
26 #include "kateviewinternal.h"
27 #include "kateviewinternal.moc"
28 
29 #include "kateview.h"
30 #include "katecodefoldinghelpers.h"
31 #include "kateviewhelpers.h"
32 #include "katehighlight.h"
33 #include "katesupercursor.h"
34 #include "katerenderer.h"
35 #include "katecodecompletion.h"
36 #include "kateconfig.h"
37 
38 #include <kcursor.h>
39 #include <kdebug.h>
40 #include <tdeapplication.h>
41 #include <tdeglobalsettings.h>
42 #include <kurldrag.h>
43 
44 #include <tqstyle.h>
45 #include <tqdragobject.h>
46 #include <tqpopupmenu.h>
47 #include <tqdropsite.h>
48 #include <tqpainter.h>
49 #include <tqlayout.h>
50 #include <tqclipboard.h>
51 #include <tqpixmap.h>
52 #include <tqvbox.h>
53 
54 KateViewInternal::KateViewInternal(KateView *view, KateDocument *doc)
55  : TQWidget (view, "", (WFlags)(WStaticContents | WRepaintNoErase | WResizeNoErase) )
56  , editSessionNumber (0)
57  , editIsRunning (false)
58  , m_view (view)
59  , m_doc (doc)
60  , cursor (doc, true, 0, 0, this)
61  , possibleTripleClick (false)
62  , m_dummy (0)
63  , m_startPos(doc, true, 0,0)
64  , m_madeVisible(false)
65  , m_shiftKeyPressed (false)
66  , m_autoCenterLines (false)
67  , m_selChangedByUser (false)
68  , selectAnchor (-1, -1)
69  , m_selectionMode( Default )
70  , m_preserveMaxX(false)
71  , m_currentMaxX(0)
72  , m_usePlainLines(false)
73  , m_updatingView(true)
74  , m_cachedMaxStartPos(-1, -1)
75  , m_dragScrollTimer(this)
76  , m_scrollTimer (this)
77  , m_cursorTimer (this)
78  , m_textHintTimer (this)
79  , m_textHintEnabled(false)
80  , m_textHintMouseX(-1)
81  , m_textHintMouseY(-1)
82  , m_imPreeditStartLine(0)
83  , m_imPreeditStart(0)
84  , m_imPreeditLength(0)
85  , m_imPreeditSelStart(0)
86 {
87  setMinimumSize (0,0);
88 
89  // cursor
90  cursor.setMoveOnInsert (true);
91 
92  // invalidate selStartCached, or keyb selection is screwed initially
93  selStartCached.setLine( -1 );
94  //
95  // scrollbar for lines
96  //
97  m_lineScroll = new KateScrollBar(TQt::Vertical, this);
98  m_lineScroll->show();
99  m_lineScroll->setTracking (true);
100 
101  m_lineLayout = new TQVBoxLayout();
102  m_colLayout = new TQHBoxLayout();
103 
104  m_colLayout->addWidget(m_lineScroll);
105  m_lineLayout->addLayout(m_colLayout);
106 
107  // bottom corner box
108  m_dummy = new TQWidget(m_view);
109  m_dummy->setFixedHeight(style().scrollBarExtent().width());
110 
111  if (m_view->dynWordWrap())
112  m_dummy->hide();
113  else
114  m_dummy->show();
115 
116  m_lineLayout->addWidget(m_dummy);
117 
118  // Hijack the line scroller's controls, so we can scroll nicely for word-wrap
119  connect(m_lineScroll, TQ_SIGNAL(prevPage()), TQ_SLOT(scrollPrevPage()));
120  connect(m_lineScroll, TQ_SIGNAL(nextPage()), TQ_SLOT(scrollNextPage()));
121 
122  connect(m_lineScroll, TQ_SIGNAL(prevLine()), TQ_SLOT(scrollPrevLine()));
123  connect(m_lineScroll, TQ_SIGNAL(nextLine()), TQ_SLOT(scrollNextLine()));
124 
125  connect(m_lineScroll, TQ_SIGNAL(sliderMoved(int)), TQ_SLOT(scrollLines(int)));
126  connect(m_lineScroll, TQ_SIGNAL(sliderMMBMoved(int)), TQ_SLOT(scrollLines(int)));
127 
128  // catch wheel events, completing the hijack
129  m_lineScroll->installEventFilter(this);
130 
131  //
132  // scrollbar for columns
133  //
134  m_columnScroll = new TQScrollBar(TQt::Horizontal,m_view);
135 
136  // hide the column scrollbar in the dynamic word wrap mode
137  if (m_view->dynWordWrap())
138  m_columnScroll->hide();
139  else
140  m_columnScroll->show();
141 
142  m_columnScroll->setTracking(true);
143  m_startX = 0;
144 
145  connect( m_columnScroll, TQ_SIGNAL( valueChanged (int) ),
146  this, TQ_SLOT( scrollColumns (int) ) );
147 
148  //
149  // iconborder ;)
150  //
151  leftBorder = new KateIconBorder( this, m_view );
152  leftBorder->show ();
153 
154  connect( leftBorder, TQ_SIGNAL(toggleRegionVisibility(unsigned int)),
155  m_doc->foldingTree(), TQ_SLOT(toggleRegionVisibility(unsigned int)));
156 
157  connect( doc->foldingTree(), TQ_SIGNAL(regionVisibilityChangedAt(unsigned int)),
158  this, TQ_SLOT(slotRegionVisibilityChangedAt(unsigned int)));
159  connect( doc, TQ_SIGNAL(codeFoldingUpdated()),
160  this, TQ_SLOT(slotCodeFoldingChanged()) );
161 
162  displayCursor.setPos(0, 0);
163  cursor.setPos(0, 0);
164  cXPos = 0;
165 
166  setAcceptDrops( true );
167  setBackgroundMode( NoBackground );
168 
169  // event filter
170  installEventFilter(this);
171 
172  // im
173  setInputMethodEnabled(true);
174 
175  // set initial cursor
176  setCursor( KCursor::ibeamCursor() );
177  m_mouseCursor = TQt::IbeamCursor;
178 
179  // call mouseMoveEvent also if no mouse button is pressed
180  setMouseTracking(true);
181 
182  dragInfo.state = diNone;
183 
184  // timers
185  connect( &m_dragScrollTimer, TQ_SIGNAL( timeout() ),
186  this, TQ_SLOT( doDragScroll() ) );
187 
188  connect( &m_scrollTimer, TQ_SIGNAL( timeout() ),
189  this, TQ_SLOT( scrollTimeout() ) );
190 
191  connect( &m_cursorTimer, TQ_SIGNAL( timeout() ),
192  this, TQ_SLOT( cursorTimeout() ) );
193 
194  connect( &m_textHintTimer, TQ_SIGNAL( timeout() ),
195  this, TQ_SLOT( textHintTimeout() ) );
196 
197  // selection changed to set anchor
198  connect( m_view, TQ_SIGNAL( selectionChanged() ),
199  this, TQ_SLOT( viewSelectionChanged() ) );
200 
201 
202 // this is a work arround for RTL desktops
203 // should be changed in kde 3.3
204 // BTW: this comment has been "ported" from 3.1.X tree
205 // any hacker with BIDI knowlege is welcomed to fix kate problems :)
206  if (TQApplication::reverseLayout()){
207  m_view->m_grid->addMultiCellWidget(leftBorder, 0, 1, 2, 2);
208  m_view->m_grid->addMultiCellWidget(m_columnScroll, 1, 1, 0, 1);
209  m_view->m_grid->addMultiCellLayout(m_lineLayout, 0, 0, 0, 0);
210  }
211  else{
212  m_view->m_grid->addMultiCellLayout(m_lineLayout, 0, 1, 2, 2);
213  m_view->m_grid->addMultiCellWidget(m_columnScroll, 1, 1, 0, 1);
214  m_view->m_grid->addWidget(leftBorder, 0, 0);
215  }
216 
217  updateView ();
218 }
219 
220 KateViewInternal::~KateViewInternal ()
221 {
222 }
223 
224 void KateViewInternal::prepareForDynWrapChange()
225 {
226  // Which is the current view line?
227  m_wrapChangeViewLine = displayViewLine(displayCursor, true);
228 }
229 
230 void KateViewInternal::dynWrapChanged()
231 {
232  if (m_view->dynWordWrap())
233  {
234  m_columnScroll->hide();
235  m_dummy->hide ();
236  }
237  else
238  {
239  m_columnScroll->show();
240  m_dummy->show ();
241  }
242 
243  tagAll();
244  updateView();
245 
246  if (m_view->dynWordWrap())
247  scrollColumns(0);
248 
249  // Determine where the cursor should be to get the cursor on the same view line
250  if (m_wrapChangeViewLine != -1) {
251  KateTextCursor newStart = viewLineOffset(displayCursor, -m_wrapChangeViewLine);
252  makeVisible(newStart, newStart.col(), true);
253  } else {
254  update();
255  }
256 }
257 
258 KateTextCursor KateViewInternal::endPos() const
259 {
260  int viewLines = linesDisplayed() - 1;
261 
262  if (viewLines < 0) {
263  kdDebug(13030) << "WARNING: viewLines wrong!" << endl;
264  viewLines = 0;
265  }
266 
267  // Check to make sure that lineRanges isn't invalid
268  if (!lineRanges.count() || lineRanges[0].line == -1 || viewLines >= (int)lineRanges.count()) {
269  // Switch off use of the cache
270  return KateTextCursor(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1)));
271  }
272 
273  for (int i = viewLines; i >= 0; i--) {
274  KateLineRange& thisRange = lineRanges[i];
275 
276  if (thisRange.line == -1) continue;
277 
278  if (thisRange.virtualLine >= (int)m_doc->numVisLines()) {
279  // Cache is too out of date
280  return KateTextCursor(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1)));
281  }
282 
283  return KateTextCursor(thisRange.virtualLine, thisRange.wrap ? thisRange.endCol - 1 : thisRange.endCol);
284  }
285 
286  Q_ASSERT(false);
287  kdDebug(13030) << "WARNING: could not find a lineRange at all" << endl;
288  return KateTextCursor(-1, -1);
289 }
290 
291 uint KateViewInternal::endLine() const
292 {
293  return endPos().line();
294 }
295 
296 KateLineRange KateViewInternal::yToKateLineRange(uint y) const
297 {
298  uint range = y / m_view->renderer()->fontHeight();
299 
300  // lineRanges is always bigger than 0, after the initial updateView call
301  if (range >= lineRanges.size())
302  return lineRanges[lineRanges.size()-1];
303 
304  return lineRanges[range];
305 }
306 
307 int KateViewInternal::lineToY(uint viewLine) const
308 {
309  return (viewLine-startLine()) * m_view->renderer()->fontHeight();
310 }
311 
312 void KateViewInternal::slotIncFontSizes()
313 {
314  m_view->renderer()->increaseFontSizes();
315 }
316 
317 void KateViewInternal::slotDecFontSizes()
318 {
319  m_view->renderer()->decreaseFontSizes();
320 }
321 
325 void KateViewInternal::scrollLines ( int line )
326 {
327  KateTextCursor newPos(line, 0);
328  scrollPos(newPos);
329 }
330 
331 // This can scroll less than one true line
332 void KateViewInternal::scrollViewLines(int offset)
333 {
334  KateTextCursor c = viewLineOffset(startPos(), offset);
335  scrollPos(c);
336 
337  m_lineScroll->blockSignals(true);
338  m_lineScroll->setValue(startLine());
339  m_lineScroll->blockSignals(false);
340 }
341 
342 void KateViewInternal::scrollNextPage()
343 {
344  scrollViewLines(kMax( (int)linesDisplayed() - 1, 0 ));
345 }
346 
347 void KateViewInternal::scrollPrevPage()
348 {
349  scrollViewLines(-kMax( (int)linesDisplayed() - 1, 0 ));
350 }
351 
352 void KateViewInternal::scrollPrevLine()
353 {
354  scrollViewLines(-1);
355 }
356 
357 void KateViewInternal::scrollNextLine()
358 {
359  scrollViewLines(1);
360 }
361 
362 KateTextCursor KateViewInternal::maxStartPos(bool changed)
363 {
364  m_usePlainLines = true;
365 
366  if (m_cachedMaxStartPos.line() == -1 || changed)
367  {
368  KateTextCursor end(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1)));
369 
370  m_cachedMaxStartPos = viewLineOffset(end, -((int)linesDisplayed() - 1));
371  }
372 
373  m_usePlainLines = false;
374 
375  return m_cachedMaxStartPos;
376 }
377 
378 // c is a virtual cursor
379 void KateViewInternal::scrollPos(KateTextCursor& c, bool force, bool calledExternally)
380 {
381  if (!force && ((!m_view->dynWordWrap() && c.line() == (int)startLine()) || c == startPos()))
382  return;
383 
384  if (c.line() < 0)
385  c.setLine(0);
386 
387  KateTextCursor limit = maxStartPos();
388  if (c > limit) {
389  c = limit;
390 
391  // Re-check we're not just scrolling to the same place
392  if (!force && ((!m_view->dynWordWrap() && c.line() == (int)startLine()) || c == startPos()))
393  return;
394  }
395 
396  int viewLinesScrolled = 0;
397 
398  // only calculate if this is really used and usefull, could be wrong here, please recheck
399  // for larger scrolls this makes 2-4 seconds difference on my xeon with dyn. word wrap on
400  // try to get it really working ;)
401  bool viewLinesScrolledUsable = !force
402  && (c.line() >= (int)startLine()-(int)linesDisplayed()-1)
403  && (c.line() <= (int)endLine()+(int)linesDisplayed()+1);
404 
405  if (viewLinesScrolledUsable)
406  viewLinesScrolled = displayViewLine(c);
407 
408  m_startPos.setPos(c);
409 
410  // set false here but reversed if we return to makeVisible
411  m_madeVisible = false;
412 
413  if (viewLinesScrolledUsable)
414  {
415  int lines = linesDisplayed();
416  if ((int)m_doc->numVisLines() < lines) {
417  KateTextCursor end(m_doc->numVisLines() - 1, m_doc->lineLength(m_doc->getRealLine(m_doc->numVisLines() - 1)));
418  lines = kMin((int)linesDisplayed(), displayViewLine(end) + 1);
419  }
420 
421  Q_ASSERT(lines >= 0);
422 
423  if (!calledExternally && TQABS(viewLinesScrolled) < lines)
424  {
425  updateView(false, viewLinesScrolled);
426 
427  int scrollHeight = -(viewLinesScrolled * (int)m_view->renderer()->fontHeight());
428  int scrollbarWidth = style().scrollBarExtent().width();
429 
430  //
431  // updates are for working around the scrollbar leaving blocks in the view
432  //
433  scroll(0, scrollHeight);
434  update(0, height()+scrollHeight-scrollbarWidth, width(), 2*scrollbarWidth);
435 
436  leftBorder->scroll(0, scrollHeight);
437  leftBorder->update(0, leftBorder->height()+scrollHeight-scrollbarWidth, leftBorder->width(), 2*scrollbarWidth);
438 
439  return;
440  }
441  }
442 
443  updateView();
444  update();
445  leftBorder->update();
446 }
447 
448 void KateViewInternal::scrollColumns ( int x )
449 {
450  if (x == m_startX)
451  return;
452 
453  if (x < 0)
454  x = 0;
455 
456  int dx = m_startX - x;
457  m_startX = x;
458 
459  if (TQABS(dx) < width())
460  scroll(dx, 0);
461  else
462  update();
463 
464  m_columnScroll->blockSignals(true);
465  m_columnScroll->setValue(m_startX);
466  m_columnScroll->blockSignals(false);
467 }
468 
469 // If changed is true, the lines that have been set dirty have been updated.
470 void KateViewInternal::updateView(bool changed, int viewLinesScrolled)
471 {
472  m_updatingView = true;
473 
474  uint contentLines = m_doc->visibleLines();
475 
476  m_lineScroll->blockSignals(true);
477 
478  KateTextCursor maxStart = maxStartPos(changed);
479  int maxLineScrollRange = maxStart.line();
480  if (m_view->dynWordWrap() && maxStart.col() != 0)
481  maxLineScrollRange++;
482  m_lineScroll->setRange(0, maxLineScrollRange);
483 
484  m_lineScroll->setValue(startPos().line());
485  m_lineScroll->setSteps(1, height() / m_view->renderer()->fontHeight());
486  m_lineScroll->blockSignals(false);
487 
488  uint oldSize = lineRanges.size ();
489  uint newSize = (height() / m_view->renderer()->fontHeight()) + 1;
490  if (oldSize != newSize) {
491  lineRanges.resize((height() / m_view->renderer()->fontHeight()) + 1);
492  if (newSize > oldSize) {
493  static KateLineRange blank;
494  for (uint i = oldSize; i < newSize; i++) {
495  lineRanges[i] = blank;
496  }
497  }
498  }
499 
500  if (oldSize < lineRanges.size ())
501  {
502  for (uint i=oldSize; i < lineRanges.size(); i++)
503  lineRanges[i].dirty = true;
504  }
505 
506  // Move the lineRanges data if we've just scrolled...
507  if (viewLinesScrolled != 0) {
508  // loop backwards if we've just scrolled up...
509  bool forwards = viewLinesScrolled >= 0 ? true : false;
510  for (uint z = forwards ? 0 : lineRanges.count() - 1; z < lineRanges.count(); forwards ? z++ : z--) {
511  uint oldZ = z + viewLinesScrolled;
512  if (oldZ < lineRanges.count()) {
513  lineRanges[z] = lineRanges[oldZ];
514  } else {
515  lineRanges[z].dirty = true;
516  }
517  }
518  }
519 
520  if (m_view->dynWordWrap())
521  {
522  KateTextCursor realStart = startPos();
523  realStart.setLine(m_doc->getRealLine(realStart.line()));
524 
525  KateLineRange startRange = range(realStart);
526  uint line = startRange.virtualLine;
527  int realLine = startRange.line;
528  uint oldLine = line;
529  int startCol = startRange.startCol;
530  int startX = startRange.startX;
531  int endX = startRange.startX;
532  int shiftX = startRange.startCol ? startRange.shiftX : 0;
533  bool wrap = false;
534  int newViewLine = startRange.viewLine;
535  // z is the current display view line
536  KateTextLine::Ptr text = textLine(realLine);
537 
538  bool alreadyDirty = false;
539 
540  for (uint z = 0; z < lineRanges.size(); z++)
541  {
542  if (oldLine != line) {
543  realLine = (int)m_doc->getRealLine(line);
544 
545  if (z)
546  lineRanges[z-1].startsInvisibleBlock = (realLine != lineRanges[z-1].line + 1);
547 
548  text = textLine(realLine);
549  startCol = 0;
550  startX = 0;
551  endX = 0;
552  shiftX = 0;
553  newViewLine = 0;
554  oldLine = line;
555  }
556 
557  if (line >= contentLines || !text)
558  {
559  if (lineRanges[z].line != -1)
560  lineRanges[z].dirty = true;
561 
562  lineRanges[z].clear();
563 
564  line++;
565  }
566  else
567  {
568  if (lineRanges[z].line != realLine || lineRanges[z].startCol != startCol)
569  alreadyDirty = lineRanges[z].dirty = true;
570 
571  if (lineRanges[z].dirty || changed || alreadyDirty) {
572  alreadyDirty = true;
573 
574  lineRanges[z].virtualLine = line;
575  lineRanges[z].line = realLine;
576  lineRanges[z].startsInvisibleBlock = false;
577 
578  int tempEndX = 0;
579 
580  int endCol = m_view->renderer()->textWidth(text, startCol, width() - shiftX, &wrap, &tempEndX);
581 
582  endX += tempEndX;
583 
584  if (wrap)
585  {
586  if (m_view->config()->dynWordWrapAlignIndent() > 0)
587  {
588  if (startX == 0)
589  {
590  int pos = text->nextNonSpaceChar(0);
591 
592  if (pos > 0)
593  shiftX = m_view->renderer()->textWidth(text, pos);
594 
595  if (shiftX > ((double)width() / 100 * m_view->config()->dynWordWrapAlignIndent()))
596  shiftX = 0;
597  }
598  }
599 
600  if ((lineRanges[z].startX != startX) || (lineRanges[z].endX != endX) ||
601  (lineRanges[z].startCol != startCol) || (lineRanges[z].endCol != endCol) ||
602  (lineRanges[z].shiftX != shiftX))
603  lineRanges[z].dirty = true;
604 
605  lineRanges[z].startCol = startCol;
606  lineRanges[z].endCol = endCol;
607  lineRanges[z].startX = startX;
608  lineRanges[z].endX = endX;
609  lineRanges[z].viewLine = newViewLine;
610  lineRanges[z].wrap = true;
611 
612  startCol = endCol;
613  startX = endX;
614  }
615  else
616  {
617  if ((lineRanges[z].startX != startX) || (lineRanges[z].endX != endX) ||
618  (lineRanges[z].startCol != startCol) || (lineRanges[z].endCol != endCol))
619  lineRanges[z].dirty = true;
620 
621  lineRanges[z].startCol = startCol;
622  lineRanges[z].endCol = endCol;
623  lineRanges[z].startX = startX;
624  lineRanges[z].endX = endX;
625  lineRanges[z].viewLine = newViewLine;
626  lineRanges[z].wrap = false;
627 
628  line++;
629  }
630 
631  lineRanges[z].shiftX = shiftX;
632 
633  } else {
634  // The cached data is still intact
635  if (lineRanges[z].wrap) {
636  startCol = lineRanges[z].endCol;
637  startX = lineRanges[z].endX;
638  endX = lineRanges[z].endX;
639  } else {
640  line++;
641  }
642  shiftX = lineRanges[z].shiftX;
643  }
644  }
645  newViewLine++;
646  }
647  }
648  else
649  {
650  uint z = 0;
651 
652  for(; (z + startLine() < contentLines) && (z < lineRanges.size()); z++)
653  {
654  if (lineRanges[z].dirty || lineRanges[z].line != (int)m_doc->getRealLine(z + startLine())) {
655  lineRanges[z].dirty = true;
656 
657  lineRanges[z].line = m_doc->getRealLine( z + startLine() );
658  if (z)
659  lineRanges[z-1].startsInvisibleBlock = (lineRanges[z].line != lineRanges[z-1].line + 1);
660 
661  lineRanges[z].virtualLine = z + startLine();
662  lineRanges[z].startCol = 0;
663  lineRanges[z].endCol = m_doc->lineLength(lineRanges[z].line);
664  lineRanges[z].startX = 0;
665  lineRanges[z].endX = m_view->renderer()->textWidth( textLine( lineRanges[z].line ), -1 );
666  lineRanges[z].shiftX = 0;
667  lineRanges[z].viewLine = 0;
668  lineRanges[z].wrap = false;
669  }
670  else if (z && lineRanges[z-1].dirty)
671  {
672  lineRanges[z-1].startsInvisibleBlock = (lineRanges[z].line != lineRanges[z-1].line + 1);
673  }
674  }
675 
676  for (; z < lineRanges.size(); z++)
677  {
678  if (lineRanges[z].line != -1)
679  lineRanges[z].dirty = true;
680 
681  lineRanges[z].clear();
682  }
683 
684  int max = maxLen(startLine()) - width();
685  if (max < 0)
686  max = 0;
687 
688  // if we lose the ability to scroll horizontally, move view to the far-left
689  if (max == 0)
690  {
691  scrollColumns(0);
692  }
693 
694  m_columnScroll->blockSignals(true);
695 
696  // disable scrollbar
697  m_columnScroll->setDisabled (max == 0);
698 
699  m_columnScroll->setRange(0, max);
700 
701  m_columnScroll->setValue(m_startX);
702 
703  // Approximate linescroll
704  m_columnScroll->setSteps(m_view->renderer()->config()->fontMetrics()->width('a'), width());
705 
706  m_columnScroll->blockSignals(false);
707  }
708 
709  m_updatingView = false;
710 
711  if (changed)
712  paintText(0, 0, width(), height(), true);
713 }
714 
715 void KateViewInternal::paintText (int x, int y, int width, int height, bool paintOnlyDirty)
716 {
717  //kdDebug() << k_funcinfo << x << " " << y << " " << width << " " << height << " " << paintOnlyDirty << endl;
718  int xStart = startX() + x;
719  int xEnd = xStart + width;
720  uint h = m_view->renderer()->fontHeight();
721  uint startz = (y / h);
722  uint endz = startz + 1 + (height / h);
723  uint lineRangesSize = lineRanges.size();
724 
725  static TQPixmap drawBuffer;
726 
727  if (drawBuffer.width() < KateViewInternal::width() || drawBuffer.height() < (int)h)
728  drawBuffer.resize(KateViewInternal::width(), (int)h);
729 
730  if (drawBuffer.isNull())
731  return;
732 
733  TQPainter paint(this);
734  TQPainter paintDrawBuffer(&drawBuffer);
735 
736  // TODO put in the proper places
737  m_view->renderer()->setCaretStyle(m_view->isOverwriteMode() ? KateRenderer::Replace : KateRenderer::Insert);
738  m_view->renderer()->setShowTabs(m_doc->configFlags() & KateDocument::cfShowTabs);
739 
740  for (uint z=startz; z <= endz; z++)
741  {
742  if ( (z >= lineRangesSize) || ((lineRanges[z].line == -1) && (!paintOnlyDirty || lineRanges[z].dirty)) )
743  {
744  if (!(z >= lineRangesSize))
745  lineRanges[z].dirty = false;
746 
747  paint.fillRect( x, z * h, width, h, m_view->renderer()->config()->backgroundColor() );
748  }
749  else if (!paintOnlyDirty || lineRanges[z].dirty)
750  {
751  lineRanges[z].dirty = false;
752 
753  m_view->renderer()->paintTextLine(paintDrawBuffer, &lineRanges[z], xStart, xEnd, &cursor, &bm);
754 
755  paint.drawPixmap (x, z * h, drawBuffer, 0, 0, width, h);
756  }
757  }
758 }
759 
764 void KateViewInternal::makeVisible (const KateTextCursor& c, uint endCol, bool force, bool center, bool calledExternally)
765 {
766  //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;
767  // if the line is in a folded region, unfold all the way up
768  //if ( m_doc->foldingTree()->findNodeForLine( c.line )->visible )
769  // kdDebug()<<"line ("<<c.line<<") should be visible"<<endl;
770 
771  if ( force )
772  {
773  KateTextCursor scroll = c;
774  scrollPos(scroll, force, calledExternally);
775  }
776  else if (center && (c < startPos() || c > endPos()))
777  {
778  KateTextCursor scroll = viewLineOffset(c, -int(linesDisplayed()) / 2);
779  scrollPos(scroll, false, calledExternally);
780  }
781  else if ( c > viewLineOffset(endPos(), -m_minLinesVisible) )
782  {
783  KateTextCursor scroll = viewLineOffset(c, -((int)linesDisplayed() - m_minLinesVisible - 1));
784  scrollPos(scroll, false, calledExternally);
785  }
786  else if ( c < viewLineOffset(startPos(), m_minLinesVisible) )
787  {
788  KateTextCursor scroll = viewLineOffset(c, -m_minLinesVisible);
789  scrollPos(scroll, false, calledExternally);
790  }
791  else
792  {
793  // Check to see that we're not showing blank lines
794  KateTextCursor max = maxStartPos();
795  if (startPos() > max) {
796  scrollPos(max, max.col(), calledExternally);
797  }
798  }
799 
800  if (!m_view->dynWordWrap() && endCol != (uint)-1)
801  {
802  int sX = (int)m_view->renderer()->textWidth (textLine( m_doc->getRealLine( c.line() ) ), c.col() );
803 
804  int sXborder = sX-8;
805  if (sXborder < 0)
806  sXborder = 0;
807 
808  if (sX < m_startX)
809  scrollColumns (sXborder);
810  else if (sX > m_startX + width())
811  scrollColumns (sX - width() + 8);
812  }
813 
814  m_madeVisible = !force;
815 }
816 
817 void KateViewInternal::slotRegionVisibilityChangedAt(unsigned int)
818 {
819  kdDebug(13030) << "slotRegionVisibilityChangedAt()" << endl;
820  m_cachedMaxStartPos.setLine(-1);
821  KateTextCursor max = maxStartPos();
822  if (startPos() > max)
823  scrollPos(max);
824 
825  updateView();
826  update();
827  leftBorder->update();
828 }
829 
830 void KateViewInternal::slotCodeFoldingChanged()
831 {
832  leftBorder->update();
833 }
834 
835 void KateViewInternal::slotRegionBeginEndAddedRemoved(unsigned int)
836 {
837  kdDebug(13030) << "slotRegionBeginEndAddedRemoved()" << endl;
838  // FIXME: performance problem
839  leftBorder->update();
840 }
841 
842 void KateViewInternal::showEvent ( TQShowEvent *e )
843 {
844  updateView ();
845 
846  TQWidget::showEvent (e);
847 }
848 
849 uint KateViewInternal::linesDisplayed() const
850 {
851  int h = height();
852  int fh = m_view->renderer()->fontHeight();
853 
854  return (h - (h % fh)) / fh;
855 }
856 
857 TQPoint KateViewInternal::cursorCoordinates()
858 {
859  int viewLine = displayViewLine(displayCursor, true);
860 
861  if (viewLine == -1)
862  return TQPoint(-1, -1);
863 
864  uint y = viewLine * m_view->renderer()->fontHeight();
865  uint x = cXPos - m_startX - lineRanges[viewLine].startX + leftBorder->width() + lineRanges[viewLine].xOffset();
866 
867  return TQPoint(x, y);
868 }
869 
870 void KateViewInternal::updateMicroFocusHint()
871 {
872  int line = displayViewLine(displayCursor, true);
873  /* Check for hasFocus() to avoid crashes in QXIMInputContext as in bug #131266.
874  This is only a workaround until somebody can find the real reason of the crash
875  (probably it's in Qt). */
876  if (line == -1 || !hasFocus())
877  return;
878 
879  KateRenderer *renderer = m_view->renderer();
880 
881  // Cursor placement code is changed for Asian input method that
882  // shows candidate window. This behavior is same as Qt/E 2.3.7
883  // which supports Asian input methods. Asian input methods need
884  // start point of IM selection text to place candidate window as
885  // adjacent to the selection text.
886  uint preeditStrLen = renderer->textWidth(textLine(m_imPreeditStartLine), cursor.col()) - renderer->textWidth(textLine(m_imPreeditStartLine), m_imPreeditSelStart);
887  uint x = cXPos - m_startX - lineRanges[line].startX + lineRanges[line].xOffset() - preeditStrLen;
888  uint y = line * renderer->fontHeight();
889 
890  setMicroFocusHint(x, y, 0, renderer->fontHeight());
891 }
892 
893 void KateViewInternal::doReturn()
894 {
895  KateTextCursor c = cursor;
896  m_doc->newLine( c, this );
897  updateCursor( c );
898  updateView();
899 }
900 
901 void KateViewInternal::doDelete()
902 {
903  m_doc->del( m_view, cursor );
904  if (m_view->m_codeCompletion->codeCompletionVisible()) {
905  m_view->m_codeCompletion->updateBox();
906  }
907 }
908 
909 void KateViewInternal::doBackspace()
910 {
911  m_doc->backspace( m_view, cursor );
912  if (m_view->m_codeCompletion->codeCompletionVisible()) {
913  m_view->m_codeCompletion->updateBox();
914  }
915 }
916 
917 void KateViewInternal::doTranspose()
918 {
919  m_doc->transpose( cursor );
920 }
921 
922 void KateViewInternal::doDeleteWordLeft()
923 {
924  wordLeft( true );
925  m_view->removeSelectedText();
926  update();
927 }
928 
929 void KateViewInternal::doDeleteWordRight()
930 {
931  wordRight( true );
932  m_view->removeSelectedText();
933  update();
934 }
935 
936 class CalculatingCursor : public KateTextCursor {
937 public:
938  CalculatingCursor(KateViewInternal* vi)
939  : KateTextCursor()
940  , m_vi(vi)
941  {
942  Q_ASSERT(valid());
943  }
944 
945  CalculatingCursor(KateViewInternal* vi, const KateTextCursor& c)
946  : KateTextCursor(c)
947  , m_vi(vi)
948  {
949  Q_ASSERT(valid());
950  }
951 
952  // This one constrains its arguments to valid positions
953  CalculatingCursor(KateViewInternal* vi, uint line, uint col)
954  : KateTextCursor(line, col)
955  , m_vi(vi)
956  {
957  makeValid();
958  }
959 
960 
961  virtual CalculatingCursor& operator+=( int n ) = 0;
962 
963  virtual CalculatingCursor& operator-=( int n ) = 0;
964 
965  CalculatingCursor& operator++() { return operator+=( 1 ); }
966 
967  CalculatingCursor& operator--() { return operator-=( 1 ); }
968 
969  void makeValid() {
970  m_line = kMax( 0, kMin( int( m_vi->m_doc->numLines() - 1 ), line() ) );
971  if (m_vi->m_view->wrapCursor())
972  m_col = kMax( 0, kMin( m_vi->m_doc->lineLength( line() ), col() ) );
973  else
974  m_col = kMax( 0, col() );
975  Q_ASSERT( valid() );
976  }
977 
978  void toEdge( Bias bias ) {
979  if( bias == left_b ) m_col = 0;
980  else if( bias == right_b ) m_col = m_vi->m_doc->lineLength( line() );
981  }
982 
983  bool atEdge() const { return atEdge( left_b ) || atEdge( right_b ); }
984 
985  bool atEdge( Bias bias ) const {
986  switch( bias ) {
987  case left_b: return col() == 0;
988  case none: return atEdge();
989  case right_b: return col() == m_vi->m_doc->lineLength( line() );
990  default: Q_ASSERT(false); return false;
991  }
992  }
993 
994 protected:
995  bool valid() const {
996  return line() >= 0 &&
997  uint( line() ) < m_vi->m_doc->numLines() &&
998  col() >= 0 &&
999  (!m_vi->m_view->wrapCursor() || col() <= m_vi->m_doc->lineLength( line() ));
1000  }
1001  KateViewInternal* m_vi;
1002 };
1003 
1004 class BoundedCursor : public CalculatingCursor {
1005 public:
1006  BoundedCursor(KateViewInternal* vi)
1007  : CalculatingCursor( vi ) {};
1008  BoundedCursor(KateViewInternal* vi, const KateTextCursor& c )
1009  : CalculatingCursor( vi, c ) {};
1010  BoundedCursor(KateViewInternal* vi, uint line, uint col )
1011  : CalculatingCursor( vi, line, col ) {};
1012  virtual CalculatingCursor& operator+=( int n ) {
1013  m_col += n;
1014 
1015  if (n > 0 && m_vi->m_view->dynWordWrap()) {
1016  // Need to constrain to current visible text line for dynamic wrapping mode
1017  if (m_col > m_vi->m_doc->lineLength(m_line)) {
1018  KateLineRange currentRange = m_vi->range(*this);
1019 
1020  int endX;
1021  bool crap;
1022  m_vi->m_view->renderer()->textWidth(m_vi->textLine(m_line), currentRange.startCol, m_vi->width() - currentRange.xOffset(), &crap, &endX);
1023  endX += (m_col - currentRange.endCol + 1) * m_vi->m_view->renderer()->spaceWidth();
1024 
1025  // Constraining if applicable NOTE: some code duplication in KateViewInternal::resize()
1026  if (endX >= m_vi->width() - currentRange.xOffset()) {
1027  m_col -= n;
1028  if ( uint( line() ) < m_vi->m_doc->numLines() - 1 ) {
1029  m_line++;
1030  m_col = 0;
1031  }
1032  }
1033  }
1034 
1035  } else if (n < 0 && col() < 0 && line() > 0 ) {
1036  m_line--;
1037  m_col = m_vi->m_doc->lineLength( line() );
1038  }
1039 
1040  m_col = kMax( 0, col() );
1041 
1042  Q_ASSERT( valid() );
1043  return *this;
1044  }
1045  virtual CalculatingCursor& operator-=( int n ) {
1046  return operator+=( -n );
1047  }
1048 };
1049 
1050 class WrappingCursor : public CalculatingCursor {
1051 public:
1052  WrappingCursor(KateViewInternal* vi)
1053  : CalculatingCursor( vi) {};
1054  WrappingCursor(KateViewInternal* vi, const KateTextCursor& c )
1055  : CalculatingCursor( vi, c ) {};
1056  WrappingCursor(KateViewInternal* vi, uint line, uint col )
1057  : CalculatingCursor( vi, line, col ) {};
1058 
1059  virtual CalculatingCursor& operator+=( int n ) {
1060  if( n < 0 ) return operator-=( -n );
1061  int len = m_vi->m_doc->lineLength( line() );
1062  if( col() + n <= len ) {
1063  m_col += n;
1064  } else if( uint( line() ) < m_vi->m_doc->numLines() - 1 ) {
1065  n -= len - col() + 1;
1066  m_col = 0;
1067  m_line++;
1068  operator+=( n );
1069  } else {
1070  m_col = len;
1071  }
1072  Q_ASSERT( valid() );
1073  return *this;
1074  }
1075  virtual CalculatingCursor& operator-=( int n ) {
1076  if( n < 0 ) return operator+=( -n );
1077  if( col() - n >= 0 ) {
1078  m_col -= n;
1079  } else if( line() > 0 ) {
1080  n -= col() + 1;
1081  m_line--;
1082  m_col = m_vi->m_doc->lineLength( line() );
1083  operator-=( n );
1084  } else {
1085  m_col = 0;
1086  }
1087  Q_ASSERT( valid() );
1088  return *this;
1089  }
1090 };
1091 
1092 void KateViewInternal::moveChar( Bias bias, bool sel )
1093 {
1094  KateTextCursor c;
1095  if ( m_view->wrapCursor() ) {
1096  c = WrappingCursor( this, cursor ) += bias;
1097  } else {
1098  c = BoundedCursor( this, cursor ) += bias;
1099  }
1100 
1101  updateSelection( c, sel );
1102  updateCursor( c );
1103 }
1104 
1105 void KateViewInternal::cursorLeft( bool sel )
1106 {
1107  if ( ! m_view->wrapCursor() && cursor.col() == 0 )
1108  return;
1109 
1110  moveChar( left_b, sel );
1111  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1112  m_view->m_codeCompletion->updateBox();
1113  }
1114 }
1115 
1116 void KateViewInternal::cursorRight( bool sel )
1117 {
1118  moveChar( right_b, sel );
1119  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1120  m_view->m_codeCompletion->updateBox();
1121  }
1122 }
1123 
1124 void KateViewInternal::wordLeft ( bool sel )
1125 {
1126  WrappingCursor c( this, cursor );
1127 
1128  // First we skip backwards all space.
1129  // Then we look up into which category the current position falls:
1130  // 1. a "word" character
1131  // 2. a "non-word" character (except space)
1132  // 3. the beginning of the line
1133  // and skip all preceding characters that fall into this class.
1134  // The code assumes that space is never part of the word character class.
1135 
1136  KateHighlighting* h = m_doc->highlight();
1137  if( !c.atEdge( left_b ) ) {
1138 
1139  while( !c.atEdge( left_b ) && m_doc->textLine( c.line() )[ c.col() - 1 ].isSpace() )
1140  --c;
1141  }
1142  if( c.atEdge( left_b ) )
1143  {
1144  --c;
1145  }
1146  else if( h->isInWord( m_doc->textLine( c.line() )[ c.col() - 1 ] ) )
1147  {
1148  while( !c.atEdge( left_b ) && h->isInWord( m_doc->textLine( c.line() )[ c.col() - 1 ] ) )
1149  --c;
1150  }
1151  else
1152  {
1153  while( !c.atEdge( left_b )
1154  && !h->isInWord( m_doc->textLine( c.line() )[ c.col() - 1 ] )
1155  // in order to stay symmetric to wordLeft()
1156  // we must not skip space preceding a non-word sequence
1157  && !m_doc->textLine( c.line() )[ c.col() - 1 ].isSpace() )
1158  {
1159  --c;
1160  }
1161  }
1162 
1163  updateSelection( c, sel );
1164  updateCursor( c );
1165 }
1166 
1167 void KateViewInternal::wordRight( bool sel )
1168 {
1169  WrappingCursor c( this, cursor );
1170 
1171  // We look up into which category the current position falls:
1172  // 1. a "word" character
1173  // 2. a "non-word" character (except space)
1174  // 3. the end of the line
1175  // and skip all following characters that fall into this class.
1176  // If the skipped characters are followed by space, we skip that too.
1177  // The code assumes that space is never part of the word character class.
1178 
1179  KateHighlighting* h = m_doc->highlight();
1180  if( c.atEdge( right_b ) )
1181  {
1182  ++c;
1183  }
1184  else if( h->isInWord( m_doc->textLine( c.line() )[ c.col() ] ) )
1185  {
1186  while( !c.atEdge( right_b ) && h->isInWord( m_doc->textLine( c.line() )[ c.col() ] ) )
1187  ++c;
1188  }
1189  else
1190  {
1191  while( !c.atEdge( right_b )
1192  && !h->isInWord( m_doc->textLine( c.line() )[ c.col() ] )
1193  // we must not skip space, because if that space is followed
1194  // by more non-word characters, we would skip them, too
1195  && !m_doc->textLine( c.line() )[ c.col() ].isSpace() )
1196  {
1197  ++c;
1198  }
1199  }
1200 
1201  while( !c.atEdge( right_b ) && m_doc->textLine( c.line() )[ c.col() ].isSpace() )
1202  ++c;
1203 
1204  updateSelection( c, sel );
1205  updateCursor( c );
1206 }
1207 
1208 void KateViewInternal::moveEdge( Bias bias, bool sel )
1209 {
1210  BoundedCursor c( this, cursor );
1211  c.toEdge( bias );
1212  updateSelection( c, sel );
1213  updateCursor( c );
1214 }
1215 
1216 void KateViewInternal::home( bool sel )
1217 {
1218  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1219  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Home, 0, 0);
1220  m_view->m_codeCompletion->handleKey(&e);
1221  return;
1222  }
1223 
1224  if (m_view->dynWordWrap() && currentRange().startCol) {
1225  // Allow us to go to the real start if we're already at the start of the view line
1226  if (cursor.col() != currentRange().startCol) {
1227  KateTextCursor c(cursor.line(), currentRange().startCol);
1228  updateSelection( c, sel );
1229  updateCursor( c );
1230  return;
1231  }
1232  }
1233 
1234  if( !(m_doc->configFlags() & KateDocument::cfSmartHome) ) {
1235  moveEdge( left_b, sel );
1236  return;
1237  }
1238 
1239  KateTextLine::Ptr l = textLine( cursor.line() );
1240 
1241  if (!l)
1242  return;
1243 
1244  KateTextCursor c = cursor;
1245  int lc = l->firstChar();
1246 
1247  if( lc < 0 || c.col() == lc ) {
1248  c.setCol(0);
1249  } else {
1250  c.setCol(lc);
1251  }
1252 
1253  updateSelection( c, sel );
1254  updateCursor( c, true );
1255 }
1256 
1257 void KateViewInternal::end( bool sel )
1258 {
1259  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1260  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_End, 0, 0);
1261  m_view->m_codeCompletion->handleKey(&e);
1262  return;
1263  }
1264 
1265  KateLineRange range = currentRange();
1266 
1267  if (m_view->dynWordWrap() && range.wrap) {
1268  // Allow us to go to the real end if we're already at the end of the view line
1269  if (cursor.col() < range.endCol - 1) {
1270  KateTextCursor c(cursor.line(), range.endCol - 1);
1271  updateSelection( c, sel );
1272  updateCursor( c );
1273  return;
1274  }
1275  }
1276 
1277  if( !(m_doc->configFlags() & KateDocument::cfSmartHome) ) {
1278  moveEdge( right_b, sel );
1279  return;
1280  }
1281 
1282  KateTextLine::Ptr l = textLine( cursor.line() );
1283 
1284  if (!l)
1285  return;
1286 
1287  // "Smart End", as requested in bugs #78258 and #106970
1288  KateTextCursor c = cursor;
1289 
1290  // If the cursor is already the real end, jump to last non-space character.
1291  // Otherwise, go to the real end ... obviously.
1292  if (c.col() == m_doc->lineLength(c.line())) {
1293  c.setCol(l->lastChar() + 1);
1294  updateSelection(c, sel);
1295  updateCursor(c, true);
1296  } else {
1297  moveEdge(right_b, sel);
1298  }
1299 }
1300 
1301 KateLineRange KateViewInternal::range(int realLine, const KateLineRange* previous)
1302 {
1303  // look at the cache first
1304  if (!m_updatingView && realLine >= lineRanges[0].line && realLine <= lineRanges[lineRanges.count() - 1].line)
1305  for (uint i = 0; i < lineRanges.count(); i++)
1306  if (realLine == lineRanges[i].line)
1307  if (!m_view->dynWordWrap() || (!previous && lineRanges[i].startCol == 0) || (previous && lineRanges[i].startCol == previous->endCol))
1308  return lineRanges[i];
1309 
1310  // Not in the cache, we have to create it
1311  KateLineRange ret;
1312 
1313  KateTextLine::Ptr text = textLine(realLine);
1314  if (!text) {
1315  return KateLineRange();
1316  }
1317 
1318  if (!m_view->dynWordWrap()) {
1319  Q_ASSERT(!previous);
1320  ret.line = realLine;
1321  ret.virtualLine = m_doc->getVirtualLine(realLine);
1322  ret.startCol = 0;
1323  ret.endCol = m_doc->lineLength(realLine);
1324  ret.startX = 0;
1325  ret.endX = m_view->renderer()->textWidth(text, -1);
1326  ret.viewLine = 0;
1327  ret.wrap = false;
1328  return ret;
1329  }
1330 
1331  ret.endCol = (int)m_view->renderer()->textWidth(text, previous ? previous->endCol : 0, width() - (previous ? previous->shiftX : 0), &ret.wrap, &ret.endX);
1332 
1333  Q_ASSERT(ret.endCol > ret.startCol);
1334 
1335  ret.line = realLine;
1336 
1337  if (previous) {
1338  ret.virtualLine = previous->virtualLine;
1339  ret.startCol = previous->endCol;
1340  ret.startX = previous->endX;
1341  ret.endX += previous->endX;
1342  ret.shiftX = previous->shiftX;
1343  ret.viewLine = previous->viewLine + 1;
1344 
1345  } else {
1346  // TODO worthwhile optimising this to get the data out of the initial textWidth call?
1347  if (m_view->config()->dynWordWrapAlignIndent() > 0) {
1348  int pos = text->nextNonSpaceChar(0);
1349 
1350  if (pos > 0)
1351  ret.shiftX = m_view->renderer()->textWidth(text, pos);
1352 
1353  if (ret.shiftX > ((double)width() / 100 * m_view->config()->dynWordWrapAlignIndent()))
1354  ret.shiftX = 0;
1355  }
1356 
1357  ret.virtualLine = m_doc->getVirtualLine(realLine);
1358  ret.startCol = 0;
1359  ret.startX = 0;
1360  ret.viewLine = 0;
1361  }
1362 
1363  return ret;
1364 }
1365 
1366 KateLineRange KateViewInternal::currentRange()
1367 {
1368 // Q_ASSERT(m_view->dynWordWrap());
1369 
1370  return range(cursor);
1371 }
1372 
1373 KateLineRange KateViewInternal::previousRange()
1374 {
1375  uint currentViewLine = viewLine(cursor);
1376 
1377  if (currentViewLine)
1378  return range(cursor.line(), currentViewLine - 1);
1379  else
1380  return range(m_doc->getRealLine(displayCursor.line() - 1), -1);
1381 }
1382 
1383 KateLineRange KateViewInternal::nextRange()
1384 {
1385  uint currentViewLine = viewLine(cursor) + 1;
1386 
1387  if (currentViewLine >= viewLineCount(cursor.line())) {
1388  currentViewLine = 0;
1389  return range(cursor.line() + 1, currentViewLine);
1390  } else {
1391  return range(cursor.line(), currentViewLine);
1392  }
1393 }
1394 
1395 KateLineRange KateViewInternal::range(const KateTextCursor& realCursor)
1396 {
1397 // Q_ASSERT(m_view->dynWordWrap());
1398 
1399  KateLineRange thisRange;
1400  bool first = true;
1401 
1402  do {
1403  thisRange = range(realCursor.line(), first ? 0L : &thisRange);
1404  first = false;
1405  } while (thisRange.wrap && !(realCursor.col() >= thisRange.startCol && realCursor.col() < thisRange.endCol) && thisRange.startCol != thisRange.endCol);
1406 
1407  return thisRange;
1408 }
1409 
1410 KateLineRange KateViewInternal::range(uint realLine, int viewLine)
1411 {
1412 // Q_ASSERT(m_view->dynWordWrap());
1413 
1414  KateLineRange thisRange;
1415  bool first = true;
1416 
1417  do {
1418  thisRange = range(realLine, first ? 0L : &thisRange);
1419  first = false;
1420  } while (thisRange.wrap && viewLine != thisRange.viewLine && thisRange.startCol != thisRange.endCol);
1421 
1422  if (viewLine != -1 && viewLine != thisRange.viewLine)
1423  kdDebug(13030) << "WARNING: viewLine " << viewLine << " of line " << realLine << " does not exist." << endl;
1424 
1425  return thisRange;
1426 }
1427 
1433 uint KateViewInternal::viewLine(const KateTextCursor& realCursor)
1434 {
1435  if (!m_view->dynWordWrap()) return 0;
1436 
1437  if (realCursor.col() == 0) return 0;
1438 
1439  KateLineRange thisRange;
1440  bool first = true;
1441 
1442  do {
1443  thisRange = range(realCursor.line(), first ? 0L : &thisRange);
1444  first = false;
1445  } while (thisRange.wrap && !(realCursor.col() >= thisRange.startCol && realCursor.col() < thisRange.endCol) && thisRange.startCol != thisRange.endCol);
1446 
1447  return thisRange.viewLine;
1448 }
1449 
1450 int KateViewInternal::displayViewLine(const KateTextCursor& virtualCursor, bool limitToVisible)
1451 {
1452  KateTextCursor work = startPos();
1453 
1454  int limit = linesDisplayed();
1455 
1456  // Efficient non-word-wrapped path
1457  if (!m_view->dynWordWrap()) {
1458  int ret = virtualCursor.line() - startLine();
1459  if (limitToVisible && (ret < 0 || ret > limit))
1460  return -1;
1461  else
1462  return ret;
1463  }
1464 
1465  if (work == virtualCursor) {
1466  return 0;
1467  }
1468 
1469  int ret = -(int)viewLine(work);
1470  bool forwards = (work < virtualCursor) ? true : false;
1471 
1472  // FIXME switch to using ranges? faster?
1473  if (forwards) {
1474  while (work.line() != virtualCursor.line()) {
1475  ret += viewLineCount(m_doc->getRealLine(work.line()));
1476  work.setLine(work.line() + 1);
1477  if (limitToVisible && ret > limit)
1478  return -1;
1479  }
1480  } else {
1481  while (work.line() != virtualCursor.line()) {
1482  work.setLine(work.line() - 1);
1483  ret -= viewLineCount(m_doc->getRealLine(work.line()));
1484  if (limitToVisible && ret < 0)
1485  return -1;
1486  }
1487  }
1488 
1489  // final difference
1490  KateTextCursor realCursor = virtualCursor;
1491  realCursor.setLine(m_doc->getRealLine(realCursor.line()));
1492  if (realCursor.col() == -1) realCursor.setCol(m_doc->lineLength(realCursor.line()));
1493  ret += viewLine(realCursor);
1494 
1495  if (limitToVisible && (ret < 0 || ret > limit))
1496  return -1;
1497 
1498  return ret;
1499 }
1500 
1501 uint KateViewInternal::lastViewLine(uint realLine)
1502 {
1503  if (!m_view->dynWordWrap()) return 0;
1504 
1505  KateLineRange thisRange;
1506  bool first = true;
1507 
1508  do {
1509  thisRange = range(realLine, first ? 0L : &thisRange);
1510  first = false;
1511  } while (thisRange.wrap && thisRange.startCol != thisRange.endCol);
1512 
1513  return thisRange.viewLine;
1514 }
1515 
1516 uint KateViewInternal::viewLineCount(uint realLine)
1517 {
1518  return lastViewLine(realLine) + 1;
1519 }
1520 
1521 /*
1522  * This returns the cursor which is offset by (offset) view lines.
1523  * This is the main function which is called by code not specifically dealing with word-wrap.
1524  * The opposite conversion (cursor to offset) can be done with displayViewLine.
1525  *
1526  * The cursors involved are virtual cursors (ie. equivalent to displayCursor)
1527  */
1528 KateTextCursor KateViewInternal::viewLineOffset(const KateTextCursor& virtualCursor, int offset, bool keepX)
1529 {
1530  if (!m_view->dynWordWrap()) {
1531  KateTextCursor ret(kMin((int)m_doc->visibleLines() - 1, virtualCursor.line() + offset), 0);
1532 
1533  if (ret.line() < 0)
1534  ret.setLine(0);
1535 
1536  if (keepX) {
1537  int realLine = m_doc->getRealLine(ret.line());
1538  ret.setCol(m_doc->lineLength(realLine) - 1);
1539 
1540  if (m_currentMaxX > cXPos)
1541  cXPos = m_currentMaxX;
1542 
1543  if (m_view->wrapCursor())
1544  cXPos = kMin(cXPos, (int)m_view->renderer()->textWidth(textLine(realLine), m_doc->lineLength(realLine)));
1545 
1546  m_view->renderer()->textWidth(ret, cXPos);
1547  }
1548 
1549  return ret;
1550  }
1551 
1552  KateTextCursor realCursor = virtualCursor;
1553  realCursor.setLine(m_doc->getRealLine(virtualCursor.line()));
1554 
1555  uint cursorViewLine = viewLine(realCursor);
1556 
1557  int currentOffset = 0;
1558  int virtualLine = 0;
1559 
1560  bool forwards = (offset > 0) ? true : false;
1561 
1562  if (forwards) {
1563  currentOffset = lastViewLine(realCursor.line()) - cursorViewLine;
1564  if (offset <= currentOffset) {
1565  // the answer is on the same line
1566  KateLineRange thisRange = range(realCursor.line(), cursorViewLine + offset);
1567  Q_ASSERT(thisRange.virtualLine == virtualCursor.line());
1568  return KateTextCursor(virtualCursor.line(), thisRange.startCol);
1569  }
1570 
1571  virtualLine = virtualCursor.line() + 1;
1572 
1573  } else {
1574  offset = -offset;
1575  currentOffset = cursorViewLine;
1576  if (offset <= currentOffset) {
1577  // the answer is on the same line
1578  KateLineRange thisRange = range(realCursor.line(), cursorViewLine - offset);
1579  Q_ASSERT(thisRange.virtualLine == virtualCursor.line());
1580  return KateTextCursor(virtualCursor.line(), thisRange.startCol);
1581  }
1582 
1583  virtualLine = virtualCursor.line() - 1;
1584  }
1585 
1586  currentOffset++;
1587 
1588  while (virtualLine >= 0 && virtualLine < (int)m_doc->visibleLines())
1589  {
1590  KateLineRange thisRange;
1591  bool first = true;
1592  int realLine = m_doc->getRealLine(virtualLine);
1593 
1594  do {
1595  thisRange = range(realLine, first ? 0L : &thisRange);
1596  first = false;
1597 
1598  if (offset == currentOffset) {
1599  if (!forwards) {
1600  // We actually want it the other way around
1601  int requiredViewLine = lastViewLine(realLine) - thisRange.viewLine;
1602  if (requiredViewLine != thisRange.viewLine) {
1603  thisRange = range(realLine, requiredViewLine);
1604  }
1605  }
1606 
1607  KateTextCursor ret(virtualLine, thisRange.startCol);
1608 
1609  // keep column position
1610  if (keepX) {
1611  ret.setCol(thisRange.endCol - 1);
1612  KateTextCursor realCursorTemp(m_doc->getRealLine(virtualCursor.line()), virtualCursor.col());
1613  int visibleX = m_view->renderer()->textWidth(realCursorTemp) - range(realCursorTemp).startX;
1614  int xOffset = thisRange.startX;
1615 
1616  if (m_currentMaxX > visibleX)
1617  visibleX = m_currentMaxX;
1618 
1619  cXPos = xOffset + visibleX;
1620 
1621  cXPos = kMin(cXPos, lineMaxCursorX(thisRange));
1622 
1623  m_view->renderer()->textWidth(ret, cXPos);
1624  }
1625 
1626  return ret;
1627  }
1628 
1629  currentOffset++;
1630 
1631  } while (thisRange.wrap);
1632 
1633  if (forwards)
1634  virtualLine++;
1635  else
1636  virtualLine--;
1637  }
1638 
1639  // Looks like we were asked for something a bit exotic.
1640  // Return the max/min valid position.
1641  if (forwards)
1642  return KateTextCursor(m_doc->visibleLines() - 1, m_doc->lineLength(m_doc->visibleLines() - 1));
1643  else
1644  return KateTextCursor(0, 0);
1645 }
1646 
1647 int KateViewInternal::lineMaxCursorX(const KateLineRange& range)
1648 {
1649  if (!m_view->wrapCursor() && !range.wrap)
1650  return INT_MAX;
1651 
1652  int maxX = range.endX;
1653 
1654  if (maxX && range.wrap) {
1655  TQChar lastCharInLine = textLine(range.line)->getChar(range.endCol - 1);
1656 
1657  if (lastCharInLine == TQChar('\t')) {
1658  int lineSize = 0;
1659  int lastTabSize = 0;
1660  for(int i = range.startCol; i < range.endCol; i++) {
1661  if (textLine(range.line)->getChar(i) == TQChar('\t')) {
1662  lastTabSize = m_view->tabWidth() - (lineSize % m_view->tabWidth());
1663  lineSize += lastTabSize;
1664  } else {
1665  lineSize++;
1666  }
1667  }
1668  maxX -= lastTabSize * m_view->renderer()->spaceWidth();
1669  } else {
1670  maxX -= m_view->renderer()->config()->fontMetrics()->width(lastCharInLine);
1671  }
1672  }
1673 
1674  return maxX;
1675 }
1676 
1677 int KateViewInternal::lineMaxCol(const KateLineRange& range)
1678 {
1679  int maxCol = range.endCol;
1680 
1681  if (maxCol && range.wrap)
1682  maxCol--;
1683 
1684  return maxCol;
1685 }
1686 
1687 void KateViewInternal::cursorUp(bool sel)
1688 {
1689  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1690  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Up, 0, 0);
1691  m_view->m_codeCompletion->handleKey(&e);
1692  return;
1693  }
1694 
1695  if (displayCursor.line() == 0 && (!m_view->dynWordWrap() || viewLine(cursor) == 0))
1696  return;
1697 
1698  int newLine = cursor.line(), newCol = 0, xOffset = 0, startCol = 0;
1699  m_preserveMaxX = true;
1700 
1701  if (m_view->dynWordWrap()) {
1702  // Dynamic word wrapping - navigate on visual lines rather than real lines
1703  KateLineRange thisRange = currentRange();
1704  // This is not the first line because that is already simplified out above
1705  KateLineRange pRange = previousRange();
1706 
1707  // Ensure we're in the right spot
1708  Q_ASSERT((cursor.line() == thisRange.line) &&
1709  (cursor.col() >= thisRange.startCol) &&
1710  (!thisRange.wrap || cursor.col() < thisRange.endCol));
1711 
1712  // VisibleX is the distance from the start of the text to the cursor on the current line.
1713  int visibleX = m_view->renderer()->textWidth(cursor) - thisRange.startX;
1714  int currentLineVisibleX = visibleX;
1715 
1716  // Translate to new line
1717  visibleX += thisRange.xOffset();
1718  visibleX -= pRange.xOffset();
1719 
1720  // Limit to >= 0
1721  visibleX = kMax(0, visibleX);
1722 
1723  startCol = pRange.startCol;
1724  xOffset = pRange.startX;
1725  newLine = pRange.line;
1726 
1727  // Take into account current max X (ie. if the current line was smaller
1728  // than the last definitely specified width)
1729  if (thisRange.xOffset() && !pRange.xOffset() && currentLineVisibleX == 0) // Special case for where xOffset may be > m_currentMaxX
1730  visibleX = m_currentMaxX;
1731  else if (visibleX < m_currentMaxX - pRange.xOffset())
1732  visibleX = m_currentMaxX - pRange.xOffset();
1733 
1734  cXPos = xOffset + visibleX;
1735 
1736  cXPos = kMin(cXPos, lineMaxCursorX(pRange));
1737 
1738  newCol = kMin((int)m_view->renderer()->textPos(newLine, visibleX, startCol), lineMaxCol(pRange));
1739 
1740  } else {
1741  newLine = m_doc->getRealLine(displayCursor.line() - 1);
1742 
1743  if ((m_view->wrapCursor()) && m_currentMaxX > cXPos)
1744  cXPos = m_currentMaxX;
1745  }
1746 
1747  KateTextCursor c(newLine, newCol);
1748  m_view->renderer()->textWidth(c, cXPos);
1749 
1750  updateSelection( c, sel );
1751  updateCursor( c );
1752 }
1753 
1754 void KateViewInternal::cursorDown(bool sel)
1755 {
1756  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1757  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Down, 0, 0);
1758  m_view->m_codeCompletion->handleKey(&e);
1759  return;
1760  }
1761 
1762  if ((displayCursor.line() >= (int)m_doc->numVisLines() - 1) && (!m_view->dynWordWrap() || viewLine(cursor) == lastViewLine(cursor.line())))
1763  return;
1764 
1765  int newLine = cursor.line(), newCol = 0, xOffset = 0, startCol = 0;
1766  m_preserveMaxX = true;
1767 
1768  if (m_view->dynWordWrap()) {
1769  // Dynamic word wrapping - navigate on visual lines rather than real lines
1770  KateLineRange thisRange = currentRange();
1771  // This is not the last line because that is already simplified out above
1772  KateLineRange nRange = nextRange();
1773 
1774  // Ensure we're in the right spot
1775  Q_ASSERT((cursor.line() == thisRange.line) &&
1776  (cursor.col() >= thisRange.startCol) &&
1777  (!thisRange.wrap || cursor.col() < thisRange.endCol));
1778 
1779  // VisibleX is the distance from the start of the text to the cursor on the current line.
1780  int visibleX = m_view->renderer()->textWidth(cursor) - thisRange.startX;
1781  int currentLineVisibleX = visibleX;
1782 
1783  // Translate to new line
1784  visibleX += thisRange.xOffset();
1785  visibleX -= nRange.xOffset();
1786 
1787  // Limit to >= 0
1788  visibleX = kMax(0, visibleX);
1789 
1790  if (!thisRange.wrap) {
1791  newLine = m_doc->getRealLine(displayCursor.line() + 1);
1792  } else {
1793  startCol = thisRange.endCol;
1794  xOffset = thisRange.endX;
1795  }
1796 
1797  // Take into account current max X (ie. if the current line was smaller
1798  // than the last definitely specified width)
1799  if (thisRange.xOffset() && !nRange.xOffset() && currentLineVisibleX == 0) // Special case for where xOffset may be > m_currentMaxX
1800  visibleX = m_currentMaxX;
1801  else if (visibleX < m_currentMaxX - nRange.xOffset())
1802  visibleX = m_currentMaxX - nRange.xOffset();
1803 
1804  cXPos = xOffset + visibleX;
1805 
1806  cXPos = kMin(cXPos, lineMaxCursorX(nRange));
1807 
1808  newCol = kMin((int)m_view->renderer()->textPos(newLine, visibleX, startCol), lineMaxCol(nRange));
1809 
1810  } else {
1811  newLine = m_doc->getRealLine(displayCursor.line() + 1);
1812 
1813  if ((m_view->wrapCursor()) && m_currentMaxX > cXPos)
1814  cXPos = m_currentMaxX;
1815  }
1816 
1817  KateTextCursor c(newLine, newCol);
1818  m_view->renderer()->textWidth(c, cXPos);
1819 
1820  updateSelection(c, sel);
1821  updateCursor(c);
1822 }
1823 
1824 void KateViewInternal::cursorToMatchingBracket( bool sel )
1825 {
1826  KateTextCursor start( cursor ), end;
1827 
1828  if( !m_doc->findMatchingBracket( start, end ) )
1829  return;
1830 
1831  // The cursor is now placed just to the left of the matching bracket.
1832  // If it's an ending bracket, put it to the right (so we can easily
1833  // get back to the original bracket).
1834  if( end > start )
1835  end.setCol(end.col() + 1);
1836 
1837  updateSelection( end, sel );
1838  updateCursor( end );
1839 }
1840 
1841 void KateViewInternal::topOfView( bool sel )
1842 {
1843  KateTextCursor c = viewLineOffset(startPos(), m_minLinesVisible);
1844  updateSelection( c, sel );
1845  updateCursor( c );
1846 }
1847 
1848 void KateViewInternal::bottomOfView( bool sel )
1849 {
1850  // FIXME account for wordwrap
1851  KateTextCursor c = viewLineOffset(endPos(), -m_minLinesVisible);
1852  updateSelection( c, sel );
1853  updateCursor( c );
1854 }
1855 
1856 // lines is the offset to scroll by
1857 void KateViewInternal::scrollLines( int lines, bool sel )
1858 {
1859  KateTextCursor c = viewLineOffset(displayCursor, lines, true);
1860 
1861  // Fix the virtual cursor -> real cursor
1862  c.setLine(m_doc->getRealLine(c.line()));
1863 
1864  updateSelection( c, sel );
1865  updateCursor( c );
1866 }
1867 
1868 // This is a bit misleading... it's asking for the view to be scrolled, not the cursor
1869 void KateViewInternal::scrollUp()
1870 {
1871  KateTextCursor newPos = viewLineOffset(m_startPos, -1);
1872  scrollPos(newPos);
1873 }
1874 
1875 void KateViewInternal::scrollDown()
1876 {
1877  KateTextCursor newPos = viewLineOffset(m_startPos, 1);
1878  scrollPos(newPos);
1879 }
1880 
1881 void KateViewInternal::setAutoCenterLines(int viewLines, bool updateView)
1882 {
1883  m_autoCenterLines = viewLines;
1884  m_minLinesVisible = kMin(int((linesDisplayed() - 1)/2), m_autoCenterLines);
1885  if (updateView)
1886  KateViewInternal::updateView();
1887 }
1888 
1889 void KateViewInternal::pageUp( bool sel )
1890 {
1891  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1892  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_PageUp, 0, 0);
1893  m_view->m_codeCompletion->handleKey(&e);
1894  return;
1895  }
1896 
1897  // remember the view line and x pos
1898  int viewLine = displayViewLine(displayCursor);
1899  bool atTop = (startPos().line() == 0 && startPos().col() == 0);
1900 
1901  // Adjust for an auto-centering cursor
1902  int lineadj = 2 * m_minLinesVisible;
1903  int cursorStart = (linesDisplayed() - 1) - viewLine;
1904  if (cursorStart < m_minLinesVisible)
1905  lineadj -= m_minLinesVisible - cursorStart;
1906 
1907  int linesToScroll = -kMax( ((int)linesDisplayed() - 1) - lineadj, 0 );
1908  m_preserveMaxX = true;
1909 
1910  if (!m_doc->pageUpDownMovesCursor () && !atTop) {
1911  int xPos = m_view->renderer()->textWidth(cursor) - currentRange().startX;
1912 
1913  KateTextCursor newStartPos = viewLineOffset(startPos(), linesToScroll - 1);
1914  scrollPos(newStartPos);
1915 
1916  // put the cursor back approximately where it was
1917  KateTextCursor newPos = viewLineOffset(newStartPos, viewLine, true);
1918  newPos.setLine(m_doc->getRealLine(newPos.line()));
1919 
1920  KateLineRange newLine = range(newPos);
1921 
1922  if (m_currentMaxX - newLine.xOffset() > xPos)
1923  xPos = m_currentMaxX - newLine.xOffset();
1924 
1925  cXPos = kMin(newLine.startX + xPos, lineMaxCursorX(newLine));
1926 
1927  m_view->renderer()->textWidth( newPos, cXPos );
1928 
1929  m_preserveMaxX = true;
1930  updateSelection( newPos, sel );
1931  updateCursor(newPos);
1932 
1933  } else {
1934  scrollLines( linesToScroll, sel );
1935  }
1936 }
1937 
1938 void KateViewInternal::pageDown( bool sel )
1939 {
1940  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1941  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_PageDown, 0, 0);
1942  m_view->m_codeCompletion->handleKey(&e);
1943  return;
1944  }
1945 
1946  // remember the view line
1947  int viewLine = displayViewLine(displayCursor);
1948  bool atEnd = startPos() >= m_cachedMaxStartPos;
1949 
1950  // Adjust for an auto-centering cursor
1951  int lineadj = 2 * m_minLinesVisible;
1952  int cursorStart = m_minLinesVisible - viewLine;
1953  if (cursorStart > 0)
1954  lineadj -= cursorStart;
1955 
1956  int linesToScroll = kMax( ((int)linesDisplayed() - 1) - lineadj, 0 );
1957  m_preserveMaxX = true;
1958 
1959  if (!m_doc->pageUpDownMovesCursor () && !atEnd) {
1960  int xPos = m_view->renderer()->textWidth(cursor) - currentRange().startX;
1961 
1962  KateTextCursor newStartPos = viewLineOffset(startPos(), linesToScroll + 1);
1963  scrollPos(newStartPos);
1964 
1965  // put the cursor back approximately where it was
1966  KateTextCursor newPos = viewLineOffset(newStartPos, viewLine, true);
1967  newPos.setLine(m_doc->getRealLine(newPos.line()));
1968 
1969  KateLineRange newLine = range(newPos);
1970 
1971  if (m_currentMaxX - newLine.xOffset() > xPos)
1972  xPos = m_currentMaxX - newLine.xOffset();
1973 
1974  cXPos = kMin(newLine.startX + xPos, lineMaxCursorX(newLine));
1975 
1976  m_view->renderer()->textWidth( newPos, cXPos );
1977 
1978  m_preserveMaxX = true;
1979  updateSelection( newPos, sel );
1980  updateCursor(newPos);
1981 
1982  } else {
1983  scrollLines( linesToScroll, sel );
1984  }
1985 }
1986 
1987 int KateViewInternal::maxLen(uint startLine)
1988 {
1989 // Q_ASSERT(!m_view->dynWordWrap());
1990 
1991  int displayLines = (m_view->height() / m_view->renderer()->fontHeight()) + 1;
1992 
1993  int maxLen = 0;
1994 
1995  for (int z = 0; z < displayLines; z++) {
1996  int virtualLine = startLine + z;
1997 
1998  if (virtualLine < 0 || virtualLine >= (int)m_doc->visibleLines())
1999  break;
2000 
2001  KateLineRange thisRange = range((int)m_doc->getRealLine(virtualLine));
2002 
2003  maxLen = kMax(maxLen, thisRange.endX);
2004  }
2005 
2006  return maxLen;
2007 }
2008 
2009 void KateViewInternal::top( bool sel )
2010 {
2011  KateTextCursor c( 0, cursor.col() );
2012  m_view->renderer()->textWidth( c, cXPos );
2013  updateSelection( c, sel );
2014  updateCursor( c );
2015 }
2016 
2017 void KateViewInternal::bottom( bool sel )
2018 {
2019  KateTextCursor c( m_doc->lastLine(), cursor.col() );
2020  m_view->renderer()->textWidth( c, cXPos );
2021  updateSelection( c, sel );
2022  updateCursor( c );
2023 }
2024 
2025 void KateViewInternal::top_home( bool sel )
2026 {
2027  if (m_view->m_codeCompletion->codeCompletionVisible()) {
2028  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Home, 0, 0);
2029  m_view->m_codeCompletion->handleKey(&e);
2030  return;
2031  }
2032  KateTextCursor c( 0, 0 );
2033  updateSelection( c, sel );
2034  updateCursor( c );
2035 }
2036 
2037 void KateViewInternal::bottom_end( bool sel )
2038 {
2039  if (m_view->m_codeCompletion->codeCompletionVisible()) {
2040  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_End, 0, 0);
2041  m_view->m_codeCompletion->handleKey(&e);
2042  return;
2043  }
2044  KateTextCursor c( m_doc->lastLine(), m_doc->lineLength( m_doc->lastLine() ) );
2045  updateSelection( c, sel );
2046  updateCursor( c );
2047 }
2048 
2049 void KateViewInternal::updateSelection( const KateTextCursor& _newCursor, bool keepSel )
2050 {
2051  KateTextCursor newCursor = _newCursor;
2052  if( keepSel )
2053  {
2054  if ( !m_view->hasSelection() || (selectAnchor.line() == -1)
2055  || (m_view->config()->persistentSelection()
2056  && ((cursor < m_view->selectStart) || (cursor > m_view->selectEnd))) )
2057  {
2058  selectAnchor = cursor;
2059  m_view->setSelection( cursor, newCursor );
2060  }
2061  else
2062  {
2063  bool doSelect = true;
2064  switch (m_selectionMode)
2065  {
2066  case Word:
2067  {
2068  // Restore selStartCached if needed. It gets nuked by
2069  // viewSelectionChanged if we drag the selection into non-existence,
2070  // which can legitimately happen if a shift+DC selection is unable to
2071  // set a "proper" (i.e. non-empty) cached selection, e.g. because the
2072  // start was on something that isn't a word. Word select mode relies
2073  // on the cached selection being set properly, even if it is empty
2074  // (i.e. selStartCached == selEndCached).
2075  if ( selStartCached.line() == -1 )
2076  selStartCached = selEndCached;
2077 
2078  int c;
2079  if ( newCursor > selEndCached )
2080  {
2081  selectAnchor = selStartCached;
2082 
2083  KateTextLine::Ptr l = m_doc->kateTextLine( newCursor.line() );
2084 
2085  c = newCursor.col();
2086  if ( c > 0 && m_doc->highlight()->isInWord( l->getChar( c-1 ) ) ) {
2087  for (; c < l->length(); c++ )
2088  if ( !m_doc->highlight()->isInWord( l->getChar( c ) ) )
2089  break;
2090  }
2091 
2092  newCursor.setCol( c );
2093  }
2094  else if ( newCursor < selStartCached )
2095  {
2096  selectAnchor = selEndCached;
2097 
2098  KateTextLine::Ptr l = m_doc->kateTextLine( newCursor.line() );
2099 
2100  c = newCursor.col();
2101  if ( c > 0 && c < m_doc->textLine( newCursor.line() ).length()
2102  && m_doc->highlight()->isInWord( l->getChar( c ) )
2103  && m_doc->highlight()->isInWord( l->getChar( c-1 ) ) ) {
2104  for ( c -= 2; c >= 0; c-- )
2105  if ( !m_doc->highlight()->isInWord( l->getChar( c ) ) )
2106  break;
2107  newCursor.setCol( c+1 );
2108  }
2109 
2110  }
2111  else
2112  doSelect = false;
2113 
2114  }
2115  break;
2116  case Line:
2117  if ( newCursor.line() > selStartCached.line() )
2118  {
2119  if ( newCursor.line()+1 >= m_doc->numLines() )
2120  newCursor.setCol( m_doc->textLine( newCursor.line() ).length() );
2121  else
2122  newCursor.setPos( newCursor.line() + 1, 0 );
2123  // Grow to include entire line
2124  selectAnchor = selStartCached;
2125  selectAnchor.setCol( 0 );
2126  }
2127  else if ( newCursor.line() < selStartCached.line() )
2128  {
2129  newCursor.setCol( 0 );
2130  // Grow to include entire line
2131  selectAnchor = selEndCached;
2132  if ( selectAnchor.col() > 0 )
2133  {
2134  if ( selectAnchor.line()+1 >= m_doc->numLines() )
2135  selectAnchor.setCol( m_doc->textLine( selectAnchor.line() ).length() );
2136  else
2137  selectAnchor.setPos( selectAnchor.line() + 1, 0 );
2138  }
2139  }
2140  else // same line, ignore
2141  doSelect = false;
2142  break;
2143  case Mouse:
2144  {
2145  if ( selStartCached.line() < 0 ) // invalid
2146  break;
2147 
2148  if ( newCursor > selEndCached )
2149  selectAnchor = selStartCached;
2150  else if ( newCursor < selStartCached )
2151  selectAnchor = selEndCached;
2152  else
2153  doSelect = false;
2154  }
2155  break;
2156  default:
2157  {
2158  if ( selectAnchor.line() < 0 ) // invalid
2159  break;
2160  }
2161  }
2162 
2163  if ( doSelect )
2164  m_view->setSelection( selectAnchor, newCursor);
2165  else if ( selStartCached.line() >= 0 ) // we have a cached selection, so we restore that
2166  m_view->setSelection( selStartCached, selEndCached );
2167  }
2168 
2169  m_selChangedByUser = true;
2170  }
2171  else if ( !m_view->config()->persistentSelection() )
2172  {
2173  m_view->clearSelection();
2174  selStartCached.setLine( -1 );
2175  selectAnchor.setLine( -1 );
2176  }
2177 }
2178 
2179 void KateViewInternal::updateCursor( const KateTextCursor& newCursor, bool force, bool center, bool calledExternally )
2180 {
2181  if ( !force && (cursor == newCursor) )
2182  {
2183  if ( !m_madeVisible && m_view == m_doc->activeView() )
2184  {
2185  // unfold if required
2186  m_doc->foldingTree()->ensureVisible( newCursor.line() );
2187 
2188  makeVisible ( displayCursor, displayCursor.col(), false, center, calledExternally );
2189  }
2190 
2191  return;
2192  }
2193 
2194  // unfold if required
2195  m_doc->foldingTree()->ensureVisible( newCursor.line() );
2196 
2197  KateTextCursor oldDisplayCursor = displayCursor;
2198 
2199  cursor.setPos (newCursor);
2200  displayCursor.setPos (m_doc->getVirtualLine(cursor.line()), cursor.col());
2201 
2202  cXPos = m_view->renderer()->textWidth( cursor );
2203  if (m_view == m_doc->activeView())
2204  makeVisible ( displayCursor, displayCursor.col(), false, center, calledExternally );
2205 
2206  updateBracketMarks();
2207 
2208  // It's efficient enough to just tag them both without checking to see if they're on the same view line
2209  tagLine(oldDisplayCursor);
2210  tagLine(displayCursor);
2211 
2212  updateMicroFocusHint();
2213 
2214  if (m_cursorTimer.isActive ())
2215  {
2216  if ( TDEApplication::cursorFlashTime() > 0 )
2217  m_cursorTimer.start( TDEApplication::cursorFlashTime() / 2 );
2218  m_view->renderer()->setDrawCaret(true);
2219  }
2220 
2221  // Remember the maximum X position if requested
2222  if (m_preserveMaxX)
2223  m_preserveMaxX = false;
2224  else
2225  if (m_view->dynWordWrap())
2226  m_currentMaxX = m_view->renderer()->textWidth(displayCursor) - currentRange().startX + currentRange().xOffset();
2227  else
2228  m_currentMaxX = cXPos;
2229 
2230  //kdDebug() << "m_currentMaxX: " << m_currentMaxX << " (was "<< oldmaxx << "), cXPos: " << cXPos << endl;
2231  //kdDebug(13030) << "Cursor now located at real " << cursor.line << "," << cursor.col << ", virtual " << displayCursor.line << ", " << displayCursor.col << "; Top is " << startLine() << ", " << startPos().col << endl;
2232 
2233  paintText(0, 0, width(), height(), true);
2234 
2235  emit m_view->cursorPositionChanged();
2236 }
2237 
2238 void KateViewInternal::updateBracketMarks()
2239 {
2240  if ( bm.isValid() ) {
2241  KateTextCursor bmStart(m_doc->getVirtualLine(bm.start().line()), bm.start().col());
2242  KateTextCursor bmEnd(m_doc->getVirtualLine(bm.end().line()), bm.end().col());
2243 
2244  if( bm.getMinIndent() != 0 )
2245  {
2246  // @@ Do this only when cursor near start/end.
2247  if( bmStart > bmEnd )
2248  {
2249  tagLines(bmEnd, bmStart);
2250  }
2251  else
2252  {
2253  tagLines(bmStart, bmEnd);
2254  }
2255  }
2256  else
2257  {
2258  tagLine(bmStart);
2259  tagLine(bmEnd);
2260  }
2261  }
2262 
2263  // add some limit to this, this is really endless on big files without limit
2264  int maxLines = linesDisplayed () * 3;
2265  m_doc->newBracketMark( cursor, bm, maxLines );
2266 
2267  if ( bm.isValid() ) {
2268  KateTextCursor bmStart(m_doc->getVirtualLine(bm.start().line()), bm.start().col());
2269  KateTextCursor bmEnd(m_doc->getVirtualLine(bm.end().line()), bm.end().col());
2270 
2271  if( bm.getMinIndent() != 0 )
2272  {
2273  // @@ Do this only when cursor near start/end.
2274  if( bmStart > bmEnd )
2275  {
2276  tagLines(bmEnd, bmStart);
2277  }
2278  else
2279  {
2280  tagLines(bmStart, bmEnd);
2281  }
2282  }
2283  else
2284  {
2285  tagLine(bmStart);
2286  tagLine(bmEnd);
2287  }
2288  }
2289 }
2290 
2291 bool KateViewInternal::tagLine(const KateTextCursor& virtualCursor)
2292 {
2293  int viewLine = displayViewLine(virtualCursor, true);
2294  if (viewLine >= 0 && viewLine < (int)lineRanges.count()) {
2295  lineRanges[viewLine].dirty = true;
2296  leftBorder->update (0, lineToY(viewLine), leftBorder->width(), m_view->renderer()->fontHeight());
2297  return true;
2298  }
2299  return false;
2300 }
2301 
2302 bool KateViewInternal::tagLines( int start, int end, bool realLines )
2303 {
2304  return tagLines(KateTextCursor(start, 0), KateTextCursor(end, -1), realLines);
2305 }
2306 
2307 bool KateViewInternal::tagLines(KateTextCursor start, KateTextCursor end, bool realCursors)
2308 {
2309  if (realCursors)
2310  {
2311  //kdDebug()<<"realLines is true"<<endl;
2312  start.setLine(m_doc->getVirtualLine( start.line() ));
2313  end.setLine(m_doc->getVirtualLine( end.line() ));
2314  }
2315 
2316  if (end.line() < (int)startLine())
2317  {
2318  //kdDebug()<<"end<startLine"<<endl;
2319  return false;
2320  }
2321  if (start.line() > (int)endLine())
2322  {
2323  //kdDebug()<<"start> endLine"<<start<<" "<<((int)endLine())<<endl;
2324  return false;
2325  }
2326 
2327  //kdDebug(13030) << "tagLines( [" << start.line << "," << start.col << "], [" << end.line << "," << end.col << "] )\n";
2328 
2329  bool ret = false;
2330 
2331  for (uint z = 0; z < lineRanges.size(); z++)
2332  {
2333  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)))) {
2334  ret = lineRanges[z].dirty = true;
2335  //kdDebug() << "Tagged line " << lineRanges[z].line << endl;
2336  }
2337  }
2338 
2339  if (!m_view->dynWordWrap())
2340  {
2341  int y = lineToY( start.line() );
2342  // FIXME is this enough for when multiple lines are deleted
2343  int h = (end.line() - start.line() + 2) * m_view->renderer()->fontHeight();
2344  if (end.line() == (int)m_doc->numVisLines() - 1)
2345  h = height();
2346 
2347  leftBorder->update (0, y, leftBorder->width(), h);
2348  }
2349  else
2350  {
2351  // FIXME Do we get enough good info in editRemoveText to optimise this more?
2352  //bool justTagged = false;
2353  for (uint z = 0; z < lineRanges.size(); z++)
2354  {
2355  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))))
2356  {
2357  //justTagged = true;
2358  leftBorder->update (0, z * m_view->renderer()->fontHeight(), leftBorder->width(), leftBorder->height());
2359  break;
2360  }
2361  /*else if (justTagged)
2362  {
2363  justTagged = false;
2364  leftBorder->update (0, z * m_doc->viewFont.fontHeight, leftBorder->width(), m_doc->viewFont.fontHeight);
2365  break;
2366  }*/
2367  }
2368  }
2369 
2370  return ret;
2371 }
2372 
2373 void KateViewInternal::tagAll()
2374 {
2375  //kdDebug(13030) << "tagAll()" << endl;
2376  for (uint z = 0; z < lineRanges.size(); z++)
2377  {
2378  lineRanges[z].dirty = true;
2379  }
2380 
2381  leftBorder->updateFont();
2382  leftBorder->update ();
2383 }
2384 
2385 void KateViewInternal::paintCursor()
2386 {
2387  if (tagLine(displayCursor))
2388  paintText (0,0,width(), height(), true);
2389 }
2390 
2391 // Point in content coordinates
2392 void KateViewInternal::placeCursor( const TQPoint& p, bool keepSelection, bool updateSelection )
2393 {
2394  KateLineRange thisRange = yToKateLineRange(p.y());
2395 
2396  if (thisRange.line == -1) {
2397  for (int i = (p.y() / m_view->renderer()->fontHeight()); i >= 0; i--) {
2398  thisRange = lineRanges[i];
2399  if (thisRange.line != -1)
2400  break;
2401  }
2402  Q_ASSERT(thisRange.line != -1);
2403  }
2404 
2405  int realLine = thisRange.line;
2406  int visibleLine = thisRange.virtualLine;
2407  uint startCol = thisRange.startCol;
2408 
2409  visibleLine = kMax( 0, kMin( visibleLine, int(m_doc->numVisLines()) - 1 ) );
2410 
2411  KateTextCursor c(realLine, 0);
2412 
2413  int x = kMin(kMax(-m_startX, p.x() - thisRange.xOffset()), lineMaxCursorX(thisRange) - thisRange.startX);
2414 
2415  m_view->renderer()->textWidth( c, startX() + x, startCol);
2416 
2417  if (updateSelection)
2418  KateViewInternal::updateSelection( c, keepSelection );
2419 
2420  updateCursor( c );
2421 }
2422 
2423 // Point in content coordinates
2424 bool KateViewInternal::isTargetSelected( const TQPoint& p )
2425 {
2426  KateLineRange thisRange = yToKateLineRange(p.y());
2427 
2428  KateTextLine::Ptr l = textLine( thisRange.line );
2429  if( !l )
2430  return false;
2431 
2432  int col = m_view->renderer()->textPos( l, startX() + p.x() - thisRange.xOffset(), thisRange.startCol, false );
2433 
2434  return m_view->lineColSelected( thisRange.line, col );
2435 }
2436 
2437 //BEGIN EVENT HANDLING STUFF
2438 
2439 bool KateViewInternal::eventFilter( TQObject *obj, TQEvent *e )
2440 {
2441  if (obj == m_lineScroll)
2442  {
2443  // the second condition is to make sure a scroll on the vertical bar doesn't cause a horizontal scroll ;)
2444  if (e->type() == TQEvent::Wheel && m_lineScroll->minValue() != m_lineScroll->maxValue())
2445  {
2446  wheelEvent((TQWheelEvent*)e);
2447  return true;
2448  }
2449 
2450  // continue processing
2451  return TQWidget::eventFilter( obj, e );
2452  }
2453 
2454  switch( e->type() )
2455  {
2456  case TQEvent::KeyPress:
2457  {
2458  TQKeyEvent *k = (TQKeyEvent *)e;
2459 
2460  if (m_view->m_codeCompletion->codeCompletionVisible ())
2461  {
2462  kdDebug (13030) << "hint around" << endl;
2463 
2464  if( k->key() == Key_Escape )
2465  m_view->m_codeCompletion->abortCompletion();
2466  }
2467 
2468  if ((k->key() == TQt::Key_Escape) && !m_view->config()->persistentSelection() )
2469  {
2470  m_view->clearSelection();
2471  return true;
2472  }
2473  else if ( !((k->state() & ControlButton) || (k->state() & AltButton)) )
2474  {
2475  keyPressEvent( k );
2476  return k->isAccepted();
2477  }
2478 
2479  } break;
2480 
2481  case TQEvent::DragMove:
2482  {
2483  TQPoint currentPoint = ((TQDragMoveEvent*) e)->pos();
2484 
2485  TQRect doNotScrollRegion( scrollMargin, scrollMargin,
2486  width() - scrollMargin * 2,
2487  height() - scrollMargin * 2 );
2488 
2489  if ( !doNotScrollRegion.contains( currentPoint ) )
2490  {
2491  startDragScroll();
2492  // Keep sending move events
2493  ( (TQDragMoveEvent*)e )->accept( TQRect(0,0,0,0) );
2494  }
2495 
2496  dragMoveEvent((TQDragMoveEvent*)e);
2497  } break;
2498 
2499  case TQEvent::DragLeave:
2500  // happens only when pressing ESC while dragging
2501  stopDragScroll();
2502  break;
2503 
2504  case TQEvent::WindowBlocked:
2505  // next focus originates from an internal dialog:
2506  // don't show the modonhd prompt
2507  m_doc->m_isasking = -1;
2508  break;
2509 
2510  default:
2511  break;
2512  }
2513 
2514  return TQWidget::eventFilter( obj, e );
2515 }
2516 
2517 void KateViewInternal::keyPressEvent( TQKeyEvent* e )
2518 {
2519  KKey key(e);
2520 
2521  bool codeComp = m_view->m_codeCompletion->codeCompletionVisible ();
2522 
2523  if (codeComp)
2524  {
2525  kdDebug (13030) << "hint around" << endl;
2526 
2527  if( e->key() == Key_Enter || e->key() == Key_Return ||
2528  (key == SHIFT + TQt::Key_Return) || (key == SHIFT + TQt::Key_Enter)) {
2529  m_view->m_codeCompletion->doComplete();
2530  e->accept();
2531  return;
2532  }
2533  }
2534 
2535  if( !m_doc->isReadWrite() )
2536  {
2537  e->ignore();
2538  return;
2539  }
2540 
2541  if ((key == TQt::Key_Return) || (key == TQt::Key_Enter))
2542  {
2543  m_view->keyReturn();
2544  e->accept();
2545  return;
2546  }
2547 
2548  if ((key == SHIFT + TQt::Key_Return) || (key == SHIFT + TQt::Key_Enter))
2549  {
2550  uint ln = cursor.line();
2551  int col = cursor.col();
2552  KateTextLine::Ptr line = m_doc->kateTextLine( ln );
2553  int pos = line->firstChar();
2554  if (pos > cursor.col()) pos = cursor.col();
2555  if (pos != -1) {
2556  while ((int)line->length() > pos &&
2557  !line->getChar(pos).isLetterOrNumber() &&
2558  pos < cursor.col()) ++pos;
2559  } else {
2560  pos = line->length(); // stay indented
2561  }
2562  m_doc->editStart();
2563  m_doc->insertText( cursor.line(), line->length(), "\n" + line->string(0, pos)
2564  + line->string().right( line->length() - cursor.col() ) );
2565  cursor.setPos(ln + 1, pos);
2566  if (col < int(line->length()))
2567  m_doc->editRemoveText(ln, col, line->length() - col);
2568  m_doc->editEnd();
2569  updateCursor(cursor, true);
2570  updateView();
2571  e->accept();
2572 
2573  return;
2574  }
2575 
2576  if (key == TQt::Key_Backspace || key == SHIFT + TQt::Key_Backspace)
2577  {
2578  m_view->backspace();
2579  e->accept();
2580 
2581  if (codeComp)
2582  m_view->m_codeCompletion->updateBox ();
2583 
2584  return;
2585  }
2586 
2587  if (key == TQt::Key_Tab || key == SHIFT+TQt::Key_Backtab || key == TQt::Key_Backtab)
2588  {
2589  if (m_doc->invokeTabInterceptor(key)) {
2590  e->accept();
2591  return;
2592  } else
2593  if (m_doc->configFlags() & KateDocumentConfig::cfTabIndents)
2594  {
2595  if( key == TQt::Key_Tab )
2596  {
2597  if (m_view->hasSelection() || (m_doc->configFlags() & KateDocumentConfig::cfTabIndentsMode))
2598  m_doc->indent( m_view, cursor.line(), 1 );
2599  else if (m_doc->configFlags() & KateDocumentConfig::cfTabInsertsTab)
2600  m_doc->typeChars ( m_view, TQString ("\t") );
2601  else
2602  m_doc->insertIndentChars ( m_view );
2603 
2604  e->accept();
2605 
2606  if (codeComp)
2607  m_view->m_codeCompletion->updateBox ();
2608 
2609  return;
2610  }
2611 
2612  if (key == SHIFT+TQt::Key_Backtab || key == TQt::Key_Backtab)
2613  {
2614  m_doc->indent( m_view, cursor.line(), -1 );
2615  e->accept();
2616 
2617  if (codeComp)
2618  m_view->m_codeCompletion->updateBox ();
2619 
2620  return;
2621  }
2622  }
2623 }
2624  if ( !(e->state() & ControlButton) && !(e->state() & AltButton)
2625  && m_doc->typeChars ( m_view, e->text() ) )
2626  {
2627  e->accept();
2628 
2629  if (codeComp)
2630  m_view->m_codeCompletion->updateBox ();
2631 
2632  return;
2633  }
2634 
2635  e->ignore();
2636 }
2637 
2638 void KateViewInternal::keyReleaseEvent( TQKeyEvent* e )
2639 {
2640  KKey key(e);
2641 
2642  if (key == SHIFT)
2643  m_shiftKeyPressed = true;
2644  else
2645  {
2646  if (m_shiftKeyPressed)
2647  {
2648  m_shiftKeyPressed = false;
2649 
2650  if (m_selChangedByUser)
2651  {
2652  TQApplication::clipboard()->setSelectionMode( true );
2653  m_view->copy();
2654  TQApplication::clipboard()->setSelectionMode( false );
2655 
2656  m_selChangedByUser = false;
2657  }
2658  }
2659  }
2660 
2661  e->ignore();
2662  return;
2663 }
2664 
2665 void KateViewInternal::contextMenuEvent ( TQContextMenuEvent * e )
2666 {
2667  // try to show popup menu
2668 
2669  TQPoint p = e->pos();
2670 
2671  if ( m_view->m_doc->browserView() )
2672  {
2673  m_view->contextMenuEvent( e );
2674  return;
2675  }
2676 
2677  if ( e->reason() == TQContextMenuEvent::Keyboard )
2678  {
2679  makeVisible( cursor, 0 );
2680  p = cursorCoordinates();
2681  }
2682  else if ( ! m_view->hasSelection() || m_view->config()->persistentSelection() )
2683  placeCursor( e->pos() );
2684 
2685  // popup is a qguardedptr now
2686  if (m_view->popup()) {
2687  m_view->popup()->popup( mapToGlobal( p ) );
2688  e->accept ();
2689  }
2690 }
2691 
2692 void KateViewInternal::mousePressEvent( TQMouseEvent* e )
2693 {
2694  switch (e->button())
2695  {
2696  case TQt::LeftButton:
2697  m_selChangedByUser = false;
2698 
2699  if (possibleTripleClick)
2700  {
2701  possibleTripleClick = false;
2702 
2703  m_selectionMode = Line;
2704 
2705  if ( e->state() & TQt::ShiftButton )
2706  {
2707  updateSelection( cursor, true );
2708  }
2709  else
2710  {
2711  m_view->selectLine( cursor );
2712  }
2713 
2714  TQApplication::clipboard()->setSelectionMode( true );
2715  m_view->copy();
2716  TQApplication::clipboard()->setSelectionMode( false );
2717 
2718  // Keep the line at the select anchor selected during further
2719  // mouse selection
2720  if ( selectAnchor.line() > m_view->selectStart.line() )
2721  {
2722  // Preserve the last selected line
2723  if ( selectAnchor == m_view->selectEnd && selectAnchor.col() == 0 )
2724  selStartCached = KateTextCursor( selectAnchor.line()-1, 0 );
2725  else
2726  selStartCached = KateTextCursor( selectAnchor.line(), 0 );
2727  selEndCached = m_view->selectEnd;
2728  }
2729  else
2730  {
2731  // Preserve the first selected line
2732  selStartCached = m_view->selectStart;
2733  if ( m_view->selectEnd.line() > m_view->selectStart.line() )
2734  selEndCached = KateTextCursor( m_view->selectStart.line()+1, 0 );
2735  else
2736  selEndCached = m_view->selectEnd;
2737  }
2738 
2739  // Set cursor to edge of selection... which edge depends on what
2740  // "direction" the selection was made in
2741  if ( m_view->selectStart < selectAnchor
2742  && selectAnchor.line() != m_view->selectStart.line() )
2743  updateCursor( m_view->selectStart );
2744  else
2745  updateCursor( m_view->selectEnd );
2746 
2747  e->accept ();
2748  return;
2749  }
2750  else if (m_selectionMode == Default)
2751  {
2752  m_selectionMode = Mouse;
2753  }
2754 
2755  if ( e->state() & TQt::ShiftButton )
2756  {
2757  if (selectAnchor.line() < 0)
2758  selectAnchor = cursor;
2759  }
2760  else
2761  {
2762  selStartCached.setLine( -1 ); // invalidate
2763  }
2764 
2765  if( !( e->state() & TQt::ShiftButton ) && isTargetSelected( e->pos() ) )
2766  {
2767  dragInfo.state = diPending;
2768  dragInfo.start = e->pos();
2769  }
2770  else
2771  {
2772  dragInfo.state = diNone;
2773 
2774  if ( e->state() & TQt::ShiftButton )
2775  {
2776  placeCursor( e->pos(), true, false );
2777  if ( selStartCached.line() >= 0 )
2778  {
2779  if ( cursor > selEndCached )
2780  {
2781  m_view->setSelection( selStartCached, cursor );
2782  selectAnchor = selStartCached;
2783  }
2784  else if ( cursor < selStartCached )
2785  {
2786  m_view->setSelection( cursor, selEndCached );
2787  selectAnchor = selEndCached;
2788  }
2789  else
2790  {
2791  m_view->setSelection( selStartCached, cursor );
2792  }
2793  }
2794  else
2795  {
2796  m_view->setSelection( selectAnchor, cursor );
2797  }
2798  }
2799  else
2800  {
2801  placeCursor( e->pos() );
2802  }
2803 
2804  scrollX = 0;
2805  scrollY = 0;
2806 
2807  m_scrollTimer.start (50);
2808  }
2809 
2810  e->accept ();
2811  break;
2812 
2813  default:
2814  e->ignore ();
2815  break;
2816  }
2817 }
2818 
2819 void KateViewInternal::mouseDoubleClickEvent(TQMouseEvent *e)
2820 {
2821  switch (e->button())
2822  {
2823  case TQt::LeftButton:
2824  m_selectionMode = Word;
2825 
2826  if ( e->state() & TQt::ShiftButton )
2827  {
2828  KateTextCursor oldSelectStart = m_view->selectStart;
2829  KateTextCursor oldSelectEnd = m_view->selectEnd;
2830 
2831  // Now select the word under the select anchor
2832  int cs, ce;
2833  KateTextLine::Ptr l = m_doc->kateTextLine( selectAnchor.line() );
2834 
2835  ce = selectAnchor.col();
2836  if ( ce > 0 && m_doc->highlight()->isInWord( l->getChar( ce ) ) ) {
2837  for (; ce < l->length(); ce++ )
2838  if ( !m_doc->highlight()->isInWord( l->getChar( ce ) ) )
2839  break;
2840  }
2841 
2842  cs = selectAnchor.col() - 1;
2843  if ( cs < m_doc->textLine( selectAnchor.line() ).length()
2844  && m_doc->highlight()->isInWord( l->getChar( cs ) ) ) {
2845  for ( cs--; cs >= 0; cs-- )
2846  if ( !m_doc->highlight()->isInWord( l->getChar( cs ) ) )
2847  break;
2848  }
2849 
2850  // ...and keep it selected
2851  if (cs+1 < ce)
2852  {
2853  selStartCached = KateTextCursor( selectAnchor.line(), cs+1 );
2854  selEndCached = KateTextCursor( selectAnchor.line(), ce );
2855  }
2856  else
2857  {
2858  selStartCached = selectAnchor;
2859  selEndCached = selectAnchor;
2860  }
2861  // Now word select to the mouse cursor
2862  placeCursor( e->pos(), true );
2863  }
2864  else
2865  {
2866  // first clear the selection, otherwise we run into bug #106402
2867  // ...and set the cursor position, for the same reason (otherwise there
2868  // are *other* idiosyncrasies we can't fix without reintroducing said
2869  // bug)
2870  // Parameters: 1st false: don't redraw
2871  // 2nd false: don't emit selectionChanged signals, as
2872  // selectWord() emits this already
2873  m_view->clearSelection( false, false );
2874  placeCursor( e->pos() );
2875  m_view->selectWord( cursor );
2876  if (m_view->hasSelection())
2877  {
2878  selectAnchor = selStartCached = m_view->selectStart;
2879  selEndCached = m_view->selectEnd;
2880  }
2881  else
2882  {
2883  // if we didn't actually select anything, restore the selection mode
2884  // -- see bug #131369 (kling)
2885  m_selectionMode = Default;
2886  }
2887  }
2888 
2889  // Move cursor to end (or beginning) of selected word
2890  if (m_view->hasSelection())
2891  {
2892  TQApplication::clipboard()->setSelectionMode( true );
2893  m_view->copy();
2894  TQApplication::clipboard()->setSelectionMode( false );
2895 
2896  // Shift+DC before the "cached" word should move the cursor to the
2897  // beginning of the selection, not the end
2898  if (m_view->selectStart < selStartCached)
2899  updateCursor( m_view->selectStart );
2900  else
2901  updateCursor( m_view->selectEnd );
2902  }
2903 
2904  possibleTripleClick = true;
2905  TQTimer::singleShot ( TQApplication::doubleClickInterval(), this, TQ_SLOT(tripleClickTimeout()) );
2906 
2907  scrollX = 0;
2908  scrollY = 0;
2909 
2910  m_scrollTimer.start (50);
2911 
2912  e->accept ();
2913  break;
2914 
2915  default:
2916  e->ignore ();
2917  break;
2918  }
2919 }
2920 
2921 void KateViewInternal::tripleClickTimeout()
2922 {
2923  possibleTripleClick = false;
2924 }
2925 
2926 void KateViewInternal::mouseReleaseEvent( TQMouseEvent* e )
2927 {
2928  switch (e->button())
2929  {
2930  case TQt::LeftButton:
2931  m_selectionMode = Default;
2932 // selStartCached.setLine( -1 );
2933 
2934  if (m_selChangedByUser)
2935  {
2936  TQApplication::clipboard()->setSelectionMode( true );
2937  m_view->copy();
2938  TQApplication::clipboard()->setSelectionMode( false );
2939  // Set cursor to edge of selection... which edge depends on what
2940  // "direction" the selection was made in
2941  if ( m_view->selectStart < selectAnchor )
2942  updateCursor( m_view->selectStart );
2943  else
2944  updateCursor( m_view->selectEnd );
2945 
2946  m_selChangedByUser = false;
2947  }
2948 
2949  if (dragInfo.state == diPending)
2950  placeCursor( e->pos(), e->state() & ShiftButton );
2951  else if (dragInfo.state == diNone)
2952  m_scrollTimer.stop ();
2953 
2954  dragInfo.state = diNone;
2955 
2956  e->accept ();
2957  break;
2958 
2959  case TQt::MidButton:
2960  placeCursor( e->pos() );
2961 
2962  if( m_doc->isReadWrite() )
2963  {
2964  TQApplication::clipboard()->setSelectionMode( true );
2965  m_view->paste ();
2966  TQApplication::clipboard()->setSelectionMode( false );
2967  }
2968 
2969  e->accept ();
2970  break;
2971 
2972  default:
2973  e->ignore ();
2974  break;
2975  }
2976 }
2977 
2978 void KateViewInternal::mouseMoveEvent( TQMouseEvent* e )
2979 {
2980  if( e->state() & TQt::LeftButton )
2981  {
2982  if (dragInfo.state == diPending)
2983  {
2984  // we had a mouse down, but haven't confirmed a drag yet
2985  // if the mouse has moved sufficiently, we will confirm
2986  TQPoint p( e->pos() - dragInfo.start );
2987 
2988  // we've left the drag square, we can start a real drag operation now
2989  if( p.manhattanLength() > TDEGlobalSettings::dndEventDelay() )
2990  doDrag();
2991 
2992  return;
2993  }
2994  else if (dragInfo.state == diDragging)
2995  {
2996  // Don't do anything after a canceled drag until the user lets go of
2997  // the mouse button!
2998  return;
2999  }
3000 
3001  mouseX = e->x();
3002  mouseY = e->y();
3003 
3004  scrollX = 0;
3005  scrollY = 0;
3006  int d = m_view->renderer()->fontHeight();
3007 
3008  if (mouseX < 0)
3009  scrollX = -d;
3010 
3011  if (mouseX > width())
3012  scrollX = d;
3013 
3014  if (mouseY < 0)
3015  {
3016  mouseY = 0;
3017  scrollY = -d;
3018  }
3019 
3020  if (mouseY > height())
3021  {
3022  mouseY = height();
3023  scrollY = d;
3024  }
3025 
3026  placeCursor( TQPoint( mouseX, mouseY ), true );
3027 
3028  }
3029  else
3030  {
3031  if (isTargetSelected( e->pos() ) ) {
3032  // mouse is over selected text. indicate that the text is draggable by setting
3033  // the arrow cursor as other Qt text editing widgets do
3034  if (m_mouseCursor != ArrowCursor) {
3035  setCursor( KCursor::arrowCursor() );
3036  m_mouseCursor = TQt::ArrowCursor;
3037  }
3038  } else {
3039  // normal text cursor
3040  if (m_mouseCursor != IbeamCursor) {
3041  setCursor( KCursor::ibeamCursor() );
3042  m_mouseCursor = TQt::IbeamCursor;
3043  }
3044  }
3045 
3046  if (m_textHintEnabled)
3047  {
3048  m_textHintTimer.start(m_textHintTimeout);
3049  m_textHintMouseX=e->x();
3050  m_textHintMouseY=e->y();
3051  }
3052  }
3053 }
3054 
3055 void KateViewInternal::paintEvent(TQPaintEvent *e)
3056 {
3057  paintText(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
3058 }
3059 
3060 void KateViewInternal::resizeEvent(TQResizeEvent* e)
3061 {
3062  bool expandedHorizontally = width() > e->oldSize().width();
3063  bool expandedVertically = height() > e->oldSize().height();
3064  bool heightChanged = height() != e->oldSize().height();
3065 
3066  m_madeVisible = false;
3067 
3068  if (heightChanged) {
3069  setAutoCenterLines(m_autoCenterLines, false);
3070  m_cachedMaxStartPos.setPos(-1, -1);
3071  }
3072 
3073  if (m_view->dynWordWrap()) {
3074  bool dirtied = false;
3075 
3076  for (uint i = 0; i < lineRanges.count(); i++) {
3077  // find the first dirty line
3078  // the word wrap updateView algorithm is forced to check all lines after a dirty one
3079  if (lineRanges[i].wrap ||
3080  (!expandedHorizontally && (lineRanges[i].endX - lineRanges[i].startX) > width())) {
3081  dirtied = lineRanges[i].dirty = true;
3082  break;
3083  }
3084  }
3085 
3086  if (dirtied || heightChanged) {
3087  updateView(true);
3088  leftBorder->update();
3089  }
3090 
3091  if (width() < e->oldSize().width()) {
3092  if (!m_view->wrapCursor()) {
3093  // May have to restrain cursor to new smaller width...
3094  if (cursor.col() > m_doc->lineLength(cursor.line())) {
3095  KateLineRange thisRange = currentRange();
3096 
3097  KateTextCursor newCursor(cursor.line(), thisRange.endCol + ((width() - thisRange.xOffset() - (thisRange.endX - thisRange.startX)) / m_view->renderer()->spaceWidth()) - 1);
3098  updateCursor(newCursor);
3099  }
3100  }
3101  }
3102 
3103  } else {
3104  updateView();
3105 
3106  if (expandedHorizontally && startX() > 0)
3107  scrollColumns(startX() - (width() - e->oldSize().width()));
3108  }
3109 
3110  if (expandedVertically) {
3111  KateTextCursor max = maxStartPos();
3112  if (startPos() > max)
3113  scrollPos(max);
3114  }
3115 }
3116 
3117 void KateViewInternal::scrollTimeout ()
3118 {
3119  if (scrollX || scrollY)
3120  {
3121  scrollLines (startPos().line() + (scrollY / (int)m_view->renderer()->fontHeight()));
3122  placeCursor( TQPoint( mouseX, mouseY ), true );
3123  }
3124 }
3125 
3126 void KateViewInternal::cursorTimeout ()
3127 {
3128  m_view->renderer()->setDrawCaret(!m_view->renderer()->drawCaret());
3129  paintCursor();
3130 }
3131 
3132 void KateViewInternal::textHintTimeout ()
3133 {
3134  m_textHintTimer.stop ();
3135 
3136  KateLineRange thisRange = yToKateLineRange(m_textHintMouseY);
3137 
3138  if (thisRange.line == -1) return;
3139 
3140  if (m_textHintMouseX> (lineMaxCursorX(thisRange) - thisRange.startX)) return;
3141 
3142  int realLine = thisRange.line;
3143  int startCol = thisRange.startCol;
3144 
3145  KateTextCursor c(realLine, 0);
3146  m_view->renderer()->textWidth( c, startX() + m_textHintMouseX, startCol);
3147 
3148  TQString tmp;
3149 
3150  emit m_view->needTextHint(c.line(), c.col(), tmp);
3151 
3152  if (!tmp.isEmpty()) kdDebug(13030)<<"Hint text: "<<tmp<<endl;
3153 }
3154 
3155 void KateViewInternal::focusInEvent (TQFocusEvent *)
3156 {
3157  if (TDEApplication::cursorFlashTime() > 0)
3158  m_cursorTimer.start ( TDEApplication::cursorFlashTime() / 2 );
3159 
3160  if (m_textHintEnabled)
3161  m_textHintTimer.start( m_textHintTimeout );
3162 
3163  paintCursor();
3164 
3165  m_doc->setActiveView( m_view );
3166 
3167  emit m_view->gotFocus( m_view );
3168 }
3169 
3170 void KateViewInternal::focusOutEvent (TQFocusEvent *)
3171 {
3172  if( m_view->renderer() && ! m_view->m_codeCompletion->codeCompletionVisible() )
3173  {
3174  m_cursorTimer.stop();
3175 
3176  m_view->renderer()->setDrawCaret(true);
3177  paintCursor();
3178  emit m_view->lostFocus( m_view );
3179  }
3180 
3181  m_textHintTimer.stop();
3182 }
3183 
3184 void KateViewInternal::doDrag()
3185 {
3186  dragInfo.state = diDragging;
3187  dragInfo.dragObject = new TQTextDrag(m_view->selection(), this);
3188  dragInfo.dragObject->drag();
3189 }
3190 
3191 void KateViewInternal::dragEnterEvent( TQDragEnterEvent* event )
3192 {
3193  event->accept( (TQTextDrag::canDecode(event) && m_doc->isReadWrite()) ||
3194  KURLDrag::canDecode(event) );
3195 }
3196 
3197 void KateViewInternal::dragMoveEvent( TQDragMoveEvent* event )
3198 {
3199  // track the cursor to the current drop location
3200  placeCursor( event->pos(), true, false );
3201 
3202  // important: accept action to switch between copy and move mode
3203  // without this, the text will always be copied.
3204  event->acceptAction();
3205 }
3206 
3207 void KateViewInternal::dropEvent( TQDropEvent* event )
3208 {
3209  if ( KURLDrag::canDecode(event) ) {
3210 
3211  emit dropEventPass(event);
3212 
3213  } else if ( TQTextDrag::canDecode(event) && m_doc->isReadWrite() ) {
3214 
3215  TQString text;
3216 
3217  if (!TQTextDrag::decode(event, text))
3218  return;
3219 
3220  // is the source our own document?
3221  bool priv = false;
3222  if (event->source() && event->source()->inherits("KateViewInternal"))
3223  priv = m_doc->ownedView( ((KateViewInternal*)(event->source()))->m_view );
3224 
3225  // dropped on a text selection area?
3226  bool selected = isTargetSelected( event->pos() );
3227 
3228  if( priv && selected ) {
3229  // this is a drag that we started and dropped on our selection
3230  // ignore this case
3231  return;
3232  }
3233 
3234  // use one transaction
3235  m_doc->editStart ();
3236 
3237  // on move: remove selected text; on copy: duplicate text
3238  if ( event->action() != TQDropEvent::Copy )
3239  m_view->removeSelectedText();
3240 
3241  m_doc->insertText( cursor.line(), cursor.col(), text );
3242 
3243  m_doc->editEnd ();
3244 
3245  placeCursor( event->pos() );
3246 
3247  event->acceptAction();
3248  updateView();
3249  }
3250 
3251  // finally finish drag and drop mode
3252  dragInfo.state = diNone;
3253  // important, because the eventFilter`s DragLeave does not occur
3254  stopDragScroll();
3255 }
3256 //END EVENT HANDLING STUFF
3257 
3258 void KateViewInternal::clear()
3259 {
3260  cursor.setPos(0, 0);
3261  displayCursor.setPos(0, 0);
3262 }
3263 
3264 void KateViewInternal::wheelEvent(TQWheelEvent* e)
3265 {
3266  if (e->state() & ControlButton)
3267  {
3268  if (e->delta() > 0)
3269  {
3270  slotIncFontSizes();
3271  }
3272  else
3273  {
3274  slotDecFontSizes();
3275  }
3276  }
3277  else
3278  {
3279  if (m_lineScroll->minValue() != m_lineScroll->maxValue() && e->orientation() != TQt::Horizontal)
3280  {
3281  // React to this as a vertical event
3282  if ( e->state() & ShiftButton )
3283  {
3284  if (e->delta() > 0)
3285  scrollPrevPage();
3286  else
3287  scrollNextPage();
3288  }
3289  else
3290  {
3291  scrollViewLines(-((e->delta() / 120) * TQApplication::wheelScrollLines()));
3292  // maybe a menu was opened or a bubbled window title is on us -> we shall erase it
3293  update();
3294  leftBorder->update();
3295  }
3296  } else if (columnScrollingPossible()) {
3297  TQWheelEvent copy = *e;
3298  TQApplication::sendEvent(m_columnScroll, &copy);
3299 
3300  } else {
3301  e->ignore();
3302  }
3303  }
3304 }
3305 
3306 void KateViewInternal::startDragScroll()
3307 {
3308  if ( !m_dragScrollTimer.isActive() ) {
3309  m_dragScrollTimer.start( scrollTime );
3310  }
3311 }
3312 
3313 void KateViewInternal::stopDragScroll()
3314 {
3315  m_dragScrollTimer.stop();
3316  updateView();
3317 }
3318 
3319 void KateViewInternal::doDragScroll()
3320 {
3321  TQPoint p = this->mapFromGlobal( TQCursor::pos() );
3322 
3323  int dx = 0, dy = 0;
3324  if ( p.y() < scrollMargin ) {
3325  dy = p.y() - scrollMargin;
3326  } else if ( p.y() > height() - scrollMargin ) {
3327  dy = scrollMargin - (height() - p.y());
3328  }
3329 
3330  if ( p.x() < scrollMargin ) {
3331  dx = p.x() - scrollMargin;
3332  } else if ( p.x() > width() - scrollMargin ) {
3333  dx = scrollMargin - (width() - p.x());
3334  }
3335 
3336  dy /= 4;
3337 
3338  if (dy)
3339  scrollLines(startPos().line() + dy);
3340 
3341  if (columnScrollingPossible () && dx)
3342  scrollColumns(kMin (m_startX + dx, m_columnScroll->maxValue()));
3343 
3344  if (!dy && !dx)
3345  stopDragScroll();
3346 }
3347 
3348 void KateViewInternal::enableTextHints(int timeout)
3349 {
3350  m_textHintTimeout=timeout;
3351  m_textHintEnabled=true;
3352  m_textHintTimer.start(timeout);
3353 }
3354 
3355 void KateViewInternal::disableTextHints()
3356 {
3357  m_textHintEnabled=false;
3358  m_textHintTimer.stop ();
3359 }
3360 
3361 bool KateViewInternal::columnScrollingPossible ()
3362 {
3363  return !m_view->dynWordWrap() && m_columnScroll->isEnabled() && (m_columnScroll->maxValue() > 0);
3364 }
3365 
3366 //BEGIN EDIT STUFF
3367 void KateViewInternal::editStart()
3368 {
3369  editSessionNumber++;
3370 
3371  if (editSessionNumber > 1)
3372  return;
3373 
3374  editIsRunning = true;
3375  editOldCursor = cursor;
3376 }
3377 
3378 void KateViewInternal::editEnd(int editTagLineStart, int editTagLineEnd, bool tagFrom)
3379 {
3380  if (editSessionNumber == 0)
3381  return;
3382 
3383  editSessionNumber--;
3384 
3385  if (editSessionNumber > 0)
3386  return;
3387 
3388  if (tagFrom && (editTagLineStart <= int(m_doc->getRealLine(startLine()))))
3389  tagAll();
3390  else
3391  tagLines (editTagLineStart, tagFrom ? m_doc->lastLine() : editTagLineEnd, true);
3392 
3393  if (editOldCursor == cursor)
3394  updateBracketMarks();
3395 
3396  if (m_imPreeditLength <= 0)
3397  updateView(true);
3398 
3399  if ((editOldCursor != cursor) && (m_imPreeditLength <= 0))
3400  {
3401  m_madeVisible = false;
3402  updateCursor ( cursor, true );
3403  }
3404  else if ( m_view == m_doc->activeView() )
3405  {
3406  makeVisible(displayCursor, displayCursor.col());
3407  }
3408 
3409  editIsRunning = false;
3410 }
3411 
3412 void KateViewInternal::editSetCursor (const KateTextCursor &cursor)
3413 {
3414  if (this->cursor != cursor)
3415  {
3416  this->cursor.setPos (cursor);
3417  }
3418 }
3419 //END
3420 
3421 void KateViewInternal::viewSelectionChanged ()
3422 {
3423  if (!m_view->hasSelection())
3424  {
3425  selectAnchor.setPos (-1, -1);
3426  selStartCached.setPos (-1, -1);
3427  }
3428 }
3429 
3430 //BEGIN IM INPUT STUFF
3431 void KateViewInternal::imStartEvent( TQIMEvent *e )
3432 {
3433  if ( m_doc->m_bReadOnly ) {
3434  e->ignore();
3435  return;
3436  }
3437 
3438  if ( m_view->hasSelection() )
3439  m_view->removeSelectedText();
3440 
3441  m_imPreeditStartLine = cursor.line();
3442  m_imPreeditStart = cursor.col();
3443  m_imPreeditLength = 0;
3444  m_imPreeditSelStart = m_imPreeditStart;
3445 
3446  m_view->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, 0, 0, 0, true );
3447 }
3448 
3449 void KateViewInternal::imComposeEvent( TQIMEvent *e )
3450 {
3451  if ( m_doc->m_bReadOnly ) {
3452  e->ignore();
3453  return;
3454  }
3455 
3456  // remove old preedit
3457  if ( m_imPreeditLength > 0 ) {
3458  cursor.setPos( m_imPreeditStartLine, m_imPreeditStart );
3459  m_doc->removeText( m_imPreeditStartLine, m_imPreeditStart,
3460  m_imPreeditStartLine, m_imPreeditStart + m_imPreeditLength );
3461  }
3462 
3463  m_imPreeditLength = e->text().length();
3464  m_imPreeditSelStart = m_imPreeditStart + e->cursorPos();
3465 
3466  // update selection
3467  m_view->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, m_imPreeditStart + m_imPreeditLength,
3468  m_imPreeditSelStart, m_imPreeditSelStart + e->selectionLength(),
3469  true );
3470 
3471  // insert new preedit
3472  m_doc->insertText( m_imPreeditStartLine, m_imPreeditStart, e->text() );
3473 
3474 
3475  // update cursor
3476  cursor.setPos( m_imPreeditStartLine, m_imPreeditSelStart );
3477  updateCursor( cursor, true );
3478 
3479  updateView( true );
3480 }
3481 
3482 void KateViewInternal::imEndEvent( TQIMEvent *e )
3483 {
3484  if ( m_doc->m_bReadOnly ) {
3485  e->ignore();
3486  return;
3487  }
3488 
3489  if ( m_imPreeditLength > 0 ) {
3490  cursor.setPos( m_imPreeditStartLine, m_imPreeditStart );
3491  m_doc->removeText( m_imPreeditStartLine, m_imPreeditStart,
3492  m_imPreeditStartLine, m_imPreeditStart + m_imPreeditLength );
3493  }
3494 
3495  m_view->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, 0, 0, 0, false );
3496 
3497  if ( e->text().length() > 0 ) {
3498  m_doc->insertText( cursor.line(), cursor.col(), e->text() );
3499 
3500  if ( !m_cursorTimer.isActive() && TDEApplication::cursorFlashTime() > 0 )
3501  m_cursorTimer.start ( TDEApplication::cursorFlashTime() / 2 );
3502 
3503  updateView( true );
3504  updateCursor( cursor, true );
3505  }
3506 
3507  m_imPreeditStart = 0;
3508  m_imPreeditLength = 0;
3509  m_imPreeditSelStart = 0;
3510 }
3511 //END IM INPUT STUFF
KCursor::arrowCursor
static TQCursor arrowCursor()
KCursor::ibeamCursor
static TQCursor ibeamCursor()
KKey
KateRenderer
Handles all of the work of rendering the text (used for the views and printing)
Definition: katerenderer.h:43
KateScrollBar
This class is required because QScrollBar's sliderMoved() signal is really supposed to be a sliderDra...
Definition: kateviewhelpers.h:49
KateTextCursor
Simple cursor class with no document pointer.
Definition: katecursor.h:34
TDEGlobalSettings::dndEventDelay
static int dndEventDelay()
TDESharedPtr
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
KNotifyClient::event
int event(const TQString &message, const TQString &text=TQString::null) TDE_DEPRECATED
TDEStdAccel::copy
const TDEShortcut & copy()
TDEStdAccel::key
int key(StdAccel id)
TDEStdAccel::end
const TDEShortcut & end()

kate

Skip menu "kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kate

Skip menu "kate"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kate by doxygen 1.9.1
This website is maintained by Timothy Pearson.