• 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  if (bias == Bias::none)
1095  {
1096  return;
1097  }
1098 
1099  KateTextLine::Ptr tl = m_doc->m_buffer->plainLine(cursor.line());
1100  if (!tl)
1101  {
1102  return;
1103  }
1104 
1105  // Make sure to handle surrogate pairs correctly
1106  int offset = 0;
1107  int col = cursor.col();
1108  if (bias == Bias::left_b)
1109  {
1110  offset = -1;
1111  if (tl->getChar(col - 1).isLowSurrogate() && tl->getChar(col - 2).isHighSurrogate())
1112  {
1113  offset = -2;
1114  }
1115  }
1116  else
1117  {
1118  offset = 1;
1119  if (tl->getChar(col).isHighSurrogate() && tl->getChar(col + 1).isLowSurrogate())
1120  {
1121  offset = 2;
1122  }
1123  }
1124 
1125  KateTextCursor c;
1126  if (m_view->wrapCursor())
1127  {
1128  c = WrappingCursor( this, cursor ) += offset;
1129  } else
1130  {
1131  c = BoundedCursor( this, cursor ) += offset;
1132  }
1133 
1134  updateSelection( c, sel );
1135  updateCursor( c );
1136 }
1137 
1138 void KateViewInternal::cursorLeft( bool sel )
1139 {
1140  if ( ! m_view->wrapCursor() && cursor.col() == 0 )
1141  return;
1142 
1143  moveChar( left_b, sel );
1144  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1145  m_view->m_codeCompletion->updateBox();
1146  }
1147 }
1148 
1149 void KateViewInternal::cursorRight( bool sel )
1150 {
1151  moveChar( right_b, sel );
1152  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1153  m_view->m_codeCompletion->updateBox();
1154  }
1155 }
1156 
1157 void KateViewInternal::wordLeft ( bool sel )
1158 {
1159  WrappingCursor c( this, cursor );
1160 
1161  // First we skip backwards all space.
1162  // Then we look up into which category the current position falls:
1163  // 1. a "word" character
1164  // 2. a "non-word" character (except space)
1165  // 3. the beginning of the line
1166  // and skip all preceding characters that fall into this class.
1167  // The code assumes that space is never part of the word character class.
1168 
1169  KateHighlighting* h = m_doc->highlight();
1170  if( !c.atEdge( left_b ) ) {
1171 
1172  while( !c.atEdge( left_b ) && m_doc->textLine( c.line() )[ c.col() - 1 ].isSpace() )
1173  --c;
1174  }
1175  if( c.atEdge( left_b ) )
1176  {
1177  --c;
1178  }
1179  else if( h->isInWord( m_doc->textLine( c.line() )[ c.col() - 1 ] ) )
1180  {
1181  while( !c.atEdge( left_b ) && h->isInWord( m_doc->textLine( c.line() )[ c.col() - 1 ] ) )
1182  --c;
1183  }
1184  else
1185  {
1186  while( !c.atEdge( left_b )
1187  && !h->isInWord( m_doc->textLine( c.line() )[ c.col() - 1 ] )
1188  // in order to stay symmetric to wordLeft()
1189  // we must not skip space preceding a non-word sequence
1190  && !m_doc->textLine( c.line() )[ c.col() - 1 ].isSpace() )
1191  {
1192  --c;
1193  }
1194  }
1195 
1196  updateSelection( c, sel );
1197  updateCursor( c );
1198 }
1199 
1200 void KateViewInternal::wordRight( bool sel )
1201 {
1202  WrappingCursor c( this, cursor );
1203 
1204  // We look up into which category the current position falls:
1205  // 1. a "word" character
1206  // 2. a "non-word" character (except space)
1207  // 3. the end of the line
1208  // and skip all following characters that fall into this class.
1209  // If the skipped characters are followed by space, we skip that too.
1210  // The code assumes that space is never part of the word character class.
1211 
1212  KateHighlighting* h = m_doc->highlight();
1213  if( c.atEdge( right_b ) )
1214  {
1215  ++c;
1216  }
1217  else if( h->isInWord( m_doc->textLine( c.line() )[ c.col() ] ) )
1218  {
1219  while( !c.atEdge( right_b ) && h->isInWord( m_doc->textLine( c.line() )[ c.col() ] ) )
1220  ++c;
1221  }
1222  else
1223  {
1224  while( !c.atEdge( right_b )
1225  && !h->isInWord( m_doc->textLine( c.line() )[ c.col() ] )
1226  // we must not skip space, because if that space is followed
1227  // by more non-word characters, we would skip them, too
1228  && !m_doc->textLine( c.line() )[ c.col() ].isSpace() )
1229  {
1230  ++c;
1231  }
1232  }
1233 
1234  while( !c.atEdge( right_b ) && m_doc->textLine( c.line() )[ c.col() ].isSpace() )
1235  ++c;
1236 
1237  updateSelection( c, sel );
1238  updateCursor( c );
1239 }
1240 
1241 void KateViewInternal::moveEdge( Bias bias, bool sel )
1242 {
1243  BoundedCursor c( this, cursor );
1244  c.toEdge( bias );
1245  updateSelection( c, sel );
1246  updateCursor( c );
1247 }
1248 
1249 void KateViewInternal::home( bool sel )
1250 {
1251  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1252  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Home, 0, 0);
1253  m_view->m_codeCompletion->handleKey(&e);
1254  return;
1255  }
1256 
1257  if (m_view->dynWordWrap() && currentRange().startCol) {
1258  // Allow us to go to the real start if we're already at the start of the view line
1259  if (cursor.col() != currentRange().startCol) {
1260  KateTextCursor c(cursor.line(), currentRange().startCol);
1261  updateSelection( c, sel );
1262  updateCursor( c );
1263  return;
1264  }
1265  }
1266 
1267  if( !(m_doc->configFlags() & KateDocument::cfSmartHome) ) {
1268  moveEdge( left_b, sel );
1269  return;
1270  }
1271 
1272  KateTextLine::Ptr l = textLine( cursor.line() );
1273 
1274  if (!l)
1275  return;
1276 
1277  KateTextCursor c = cursor;
1278  int lc = l->firstChar();
1279 
1280  if( lc < 0 || c.col() == lc ) {
1281  c.setCol(0);
1282  } else {
1283  c.setCol(lc);
1284  }
1285 
1286  updateSelection( c, sel );
1287  updateCursor( c, true );
1288 }
1289 
1290 void KateViewInternal::end( bool sel )
1291 {
1292  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1293  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_End, 0, 0);
1294  m_view->m_codeCompletion->handleKey(&e);
1295  return;
1296  }
1297 
1298  KateLineRange range = currentRange();
1299 
1300  if (m_view->dynWordWrap() && range.wrap) {
1301  // Allow us to go to the real end if we're already at the end of the view line
1302  if (cursor.col() < range.endCol - 1) {
1303  KateTextCursor c(cursor.line(), range.endCol - 1);
1304  updateSelection( c, sel );
1305  updateCursor( c );
1306  return;
1307  }
1308  }
1309 
1310  if( !(m_doc->configFlags() & KateDocument::cfSmartHome) ) {
1311  moveEdge( right_b, sel );
1312  return;
1313  }
1314 
1315  KateTextLine::Ptr l = textLine( cursor.line() );
1316 
1317  if (!l)
1318  return;
1319 
1320  // "Smart End", as requested in bugs #78258 and #106970
1321  KateTextCursor c = cursor;
1322 
1323  // If the cursor is already the real end, jump to last non-space character.
1324  // Otherwise, go to the real end ... obviously.
1325  if (c.col() == m_doc->lineLength(c.line())) {
1326  c.setCol(l->lastChar() + 1);
1327  updateSelection(c, sel);
1328  updateCursor(c, true);
1329  } else {
1330  moveEdge(right_b, sel);
1331  }
1332 }
1333 
1334 KateLineRange KateViewInternal::range(int realLine, const KateLineRange* previous)
1335 {
1336  // look at the cache first
1337  if (!m_updatingView && realLine >= lineRanges[0].line && realLine <= lineRanges[lineRanges.count() - 1].line)
1338  for (uint i = 0; i < lineRanges.count(); i++)
1339  if (realLine == lineRanges[i].line)
1340  if (!m_view->dynWordWrap() || (!previous && lineRanges[i].startCol == 0) || (previous && lineRanges[i].startCol == previous->endCol))
1341  return lineRanges[i];
1342 
1343  // Not in the cache, we have to create it
1344  KateLineRange ret;
1345 
1346  KateTextLine::Ptr text = textLine(realLine);
1347  if (!text) {
1348  return KateLineRange();
1349  }
1350 
1351  if (!m_view->dynWordWrap()) {
1352  Q_ASSERT(!previous);
1353  ret.line = realLine;
1354  ret.virtualLine = m_doc->getVirtualLine(realLine);
1355  ret.startCol = 0;
1356  ret.endCol = m_doc->lineLength(realLine);
1357  ret.startX = 0;
1358  ret.endX = m_view->renderer()->textWidth(text, -1);
1359  ret.viewLine = 0;
1360  ret.wrap = false;
1361  return ret;
1362  }
1363 
1364  ret.endCol = (int)m_view->renderer()->textWidth(text, previous ? previous->endCol : 0, width() - (previous ? previous->shiftX : 0), &ret.wrap, &ret.endX);
1365 
1366  Q_ASSERT(ret.endCol > ret.startCol);
1367 
1368  ret.line = realLine;
1369 
1370  if (previous) {
1371  ret.virtualLine = previous->virtualLine;
1372  ret.startCol = previous->endCol;
1373  ret.startX = previous->endX;
1374  ret.endX += previous->endX;
1375  ret.shiftX = previous->shiftX;
1376  ret.viewLine = previous->viewLine + 1;
1377 
1378  } else {
1379  // TODO worthwhile optimising this to get the data out of the initial textWidth call?
1380  if (m_view->config()->dynWordWrapAlignIndent() > 0) {
1381  int pos = text->nextNonSpaceChar(0);
1382 
1383  if (pos > 0)
1384  ret.shiftX = m_view->renderer()->textWidth(text, pos);
1385 
1386  if (ret.shiftX > ((double)width() / 100 * m_view->config()->dynWordWrapAlignIndent()))
1387  ret.shiftX = 0;
1388  }
1389 
1390  ret.virtualLine = m_doc->getVirtualLine(realLine);
1391  ret.startCol = 0;
1392  ret.startX = 0;
1393  ret.viewLine = 0;
1394  }
1395 
1396  return ret;
1397 }
1398 
1399 KateLineRange KateViewInternal::currentRange()
1400 {
1401 // Q_ASSERT(m_view->dynWordWrap());
1402 
1403  return range(cursor);
1404 }
1405 
1406 KateLineRange KateViewInternal::previousRange()
1407 {
1408  uint currentViewLine = viewLine(cursor);
1409 
1410  if (currentViewLine)
1411  return range(cursor.line(), currentViewLine - 1);
1412  else
1413  return range(m_doc->getRealLine(displayCursor.line() - 1), -1);
1414 }
1415 
1416 KateLineRange KateViewInternal::nextRange()
1417 {
1418  uint currentViewLine = viewLine(cursor) + 1;
1419 
1420  if (currentViewLine >= viewLineCount(cursor.line())) {
1421  currentViewLine = 0;
1422  return range(cursor.line() + 1, currentViewLine);
1423  } else {
1424  return range(cursor.line(), currentViewLine);
1425  }
1426 }
1427 
1428 KateLineRange KateViewInternal::range(const KateTextCursor& realCursor)
1429 {
1430 // Q_ASSERT(m_view->dynWordWrap());
1431 
1432  KateLineRange thisRange;
1433  bool first = true;
1434 
1435  do {
1436  thisRange = range(realCursor.line(), first ? 0L : &thisRange);
1437  first = false;
1438  } while (thisRange.wrap && !(realCursor.col() >= thisRange.startCol && realCursor.col() < thisRange.endCol) && thisRange.startCol != thisRange.endCol);
1439 
1440  return thisRange;
1441 }
1442 
1443 KateLineRange KateViewInternal::range(uint realLine, int viewLine)
1444 {
1445 // Q_ASSERT(m_view->dynWordWrap());
1446 
1447  KateLineRange thisRange;
1448  bool first = true;
1449 
1450  do {
1451  thisRange = range(realLine, first ? 0L : &thisRange);
1452  first = false;
1453  } while (thisRange.wrap && viewLine != thisRange.viewLine && thisRange.startCol != thisRange.endCol);
1454 
1455  if (viewLine != -1 && viewLine != thisRange.viewLine)
1456  kdDebug(13030) << "WARNING: viewLine " << viewLine << " of line " << realLine << " does not exist." << endl;
1457 
1458  return thisRange;
1459 }
1460 
1466 uint KateViewInternal::viewLine(const KateTextCursor& realCursor)
1467 {
1468  if (!m_view->dynWordWrap()) return 0;
1469 
1470  if (realCursor.col() == 0) return 0;
1471 
1472  KateLineRange thisRange;
1473  bool first = true;
1474 
1475  do {
1476  thisRange = range(realCursor.line(), first ? 0L : &thisRange);
1477  first = false;
1478  } while (thisRange.wrap && !(realCursor.col() >= thisRange.startCol && realCursor.col() < thisRange.endCol) && thisRange.startCol != thisRange.endCol);
1479 
1480  return thisRange.viewLine;
1481 }
1482 
1483 int KateViewInternal::displayViewLine(const KateTextCursor& virtualCursor, bool limitToVisible)
1484 {
1485  KateTextCursor work = startPos();
1486 
1487  int limit = linesDisplayed();
1488 
1489  // Efficient non-word-wrapped path
1490  if (!m_view->dynWordWrap()) {
1491  int ret = virtualCursor.line() - startLine();
1492  if (limitToVisible && (ret < 0 || ret > limit))
1493  return -1;
1494  else
1495  return ret;
1496  }
1497 
1498  if (work == virtualCursor) {
1499  return 0;
1500  }
1501 
1502  int ret = -(int)viewLine(work);
1503  bool forwards = (work < virtualCursor) ? true : false;
1504 
1505  // FIXME switch to using ranges? faster?
1506  if (forwards) {
1507  while (work.line() != virtualCursor.line()) {
1508  ret += viewLineCount(m_doc->getRealLine(work.line()));
1509  work.setLine(work.line() + 1);
1510  if (limitToVisible && ret > limit)
1511  return -1;
1512  }
1513  } else {
1514  while (work.line() != virtualCursor.line()) {
1515  work.setLine(work.line() - 1);
1516  ret -= viewLineCount(m_doc->getRealLine(work.line()));
1517  if (limitToVisible && ret < 0)
1518  return -1;
1519  }
1520  }
1521 
1522  // final difference
1523  KateTextCursor realCursor = virtualCursor;
1524  realCursor.setLine(m_doc->getRealLine(realCursor.line()));
1525  if (realCursor.col() == -1) realCursor.setCol(m_doc->lineLength(realCursor.line()));
1526  ret += viewLine(realCursor);
1527 
1528  if (limitToVisible && (ret < 0 || ret > limit))
1529  return -1;
1530 
1531  return ret;
1532 }
1533 
1534 uint KateViewInternal::lastViewLine(uint realLine)
1535 {
1536  if (!m_view->dynWordWrap()) return 0;
1537 
1538  KateLineRange thisRange;
1539  bool first = true;
1540 
1541  do {
1542  thisRange = range(realLine, first ? 0L : &thisRange);
1543  first = false;
1544  } while (thisRange.wrap && thisRange.startCol != thisRange.endCol);
1545 
1546  return thisRange.viewLine;
1547 }
1548 
1549 uint KateViewInternal::viewLineCount(uint realLine)
1550 {
1551  return lastViewLine(realLine) + 1;
1552 }
1553 
1554 /*
1555  * This returns the cursor which is offset by (offset) view lines.
1556  * This is the main function which is called by code not specifically dealing with word-wrap.
1557  * The opposite conversion (cursor to offset) can be done with displayViewLine.
1558  *
1559  * The cursors involved are virtual cursors (ie. equivalent to displayCursor)
1560  */
1561 KateTextCursor KateViewInternal::viewLineOffset(const KateTextCursor& virtualCursor, int offset, bool keepX)
1562 {
1563  if (!m_view->dynWordWrap()) {
1564  KateTextCursor ret(kMin((int)m_doc->visibleLines() - 1, virtualCursor.line() + offset), 0);
1565 
1566  if (ret.line() < 0)
1567  ret.setLine(0);
1568 
1569  if (keepX) {
1570  int realLine = m_doc->getRealLine(ret.line());
1571  ret.setCol(m_doc->lineLength(realLine) - 1);
1572 
1573  if (m_currentMaxX > cXPos)
1574  cXPos = m_currentMaxX;
1575 
1576  if (m_view->wrapCursor())
1577  cXPos = kMin(cXPos, (int)m_view->renderer()->textWidth(textLine(realLine), m_doc->lineLength(realLine)));
1578 
1579  m_view->renderer()->textWidth(ret, cXPos);
1580  }
1581 
1582  return ret;
1583  }
1584 
1585  KateTextCursor realCursor = virtualCursor;
1586  realCursor.setLine(m_doc->getRealLine(virtualCursor.line()));
1587 
1588  uint cursorViewLine = viewLine(realCursor);
1589 
1590  int currentOffset = 0;
1591  int virtualLine = 0;
1592 
1593  bool forwards = (offset > 0) ? true : false;
1594 
1595  if (forwards) {
1596  currentOffset = lastViewLine(realCursor.line()) - cursorViewLine;
1597  if (offset <= currentOffset) {
1598  // the answer is on the same line
1599  KateLineRange thisRange = range(realCursor.line(), cursorViewLine + offset);
1600  Q_ASSERT(thisRange.virtualLine == virtualCursor.line());
1601  return KateTextCursor(virtualCursor.line(), thisRange.startCol);
1602  }
1603 
1604  virtualLine = virtualCursor.line() + 1;
1605 
1606  } else {
1607  offset = -offset;
1608  currentOffset = cursorViewLine;
1609  if (offset <= currentOffset) {
1610  // the answer is on the same line
1611  KateLineRange thisRange = range(realCursor.line(), cursorViewLine - offset);
1612  Q_ASSERT(thisRange.virtualLine == virtualCursor.line());
1613  return KateTextCursor(virtualCursor.line(), thisRange.startCol);
1614  }
1615 
1616  virtualLine = virtualCursor.line() - 1;
1617  }
1618 
1619  currentOffset++;
1620 
1621  while (virtualLine >= 0 && virtualLine < (int)m_doc->visibleLines())
1622  {
1623  KateLineRange thisRange;
1624  bool first = true;
1625  int realLine = m_doc->getRealLine(virtualLine);
1626 
1627  do {
1628  thisRange = range(realLine, first ? 0L : &thisRange);
1629  first = false;
1630 
1631  if (offset == currentOffset) {
1632  if (!forwards) {
1633  // We actually want it the other way around
1634  int requiredViewLine = lastViewLine(realLine) - thisRange.viewLine;
1635  if (requiredViewLine != thisRange.viewLine) {
1636  thisRange = range(realLine, requiredViewLine);
1637  }
1638  }
1639 
1640  KateTextCursor ret(virtualLine, thisRange.startCol);
1641 
1642  // keep column position
1643  if (keepX) {
1644  ret.setCol(thisRange.endCol - 1);
1645  KateTextCursor realCursorTemp(m_doc->getRealLine(virtualCursor.line()), virtualCursor.col());
1646  int visibleX = m_view->renderer()->textWidth(realCursorTemp) - range(realCursorTemp).startX;
1647  int xOffset = thisRange.startX;
1648 
1649  if (m_currentMaxX > visibleX)
1650  visibleX = m_currentMaxX;
1651 
1652  cXPos = xOffset + visibleX;
1653 
1654  cXPos = kMin(cXPos, lineMaxCursorX(thisRange));
1655 
1656  m_view->renderer()->textWidth(ret, cXPos);
1657  }
1658 
1659  return ret;
1660  }
1661 
1662  currentOffset++;
1663 
1664  } while (thisRange.wrap);
1665 
1666  if (forwards)
1667  virtualLine++;
1668  else
1669  virtualLine--;
1670  }
1671 
1672  // Looks like we were asked for something a bit exotic.
1673  // Return the max/min valid position.
1674  if (forwards)
1675  return KateTextCursor(m_doc->visibleLines() - 1, m_doc->lineLength(m_doc->visibleLines() - 1));
1676  else
1677  return KateTextCursor(0, 0);
1678 }
1679 
1680 int KateViewInternal::lineMaxCursorX(const KateLineRange& range)
1681 {
1682  if (!m_view->wrapCursor() && !range.wrap)
1683  return INT_MAX;
1684 
1685  int maxX = range.endX;
1686 
1687  if (maxX && range.wrap) {
1688  TQChar lastCharInLine = textLine(range.line)->getChar(range.endCol - 1);
1689 
1690  if (lastCharInLine == TQChar('\t')) {
1691  int lineSize = 0;
1692  int lastTabSize = 0;
1693  for(int i = range.startCol; i < range.endCol; i++) {
1694  if (textLine(range.line)->getChar(i) == TQChar('\t')) {
1695  lastTabSize = m_view->tabWidth() - (lineSize % m_view->tabWidth());
1696  lineSize += lastTabSize;
1697  } else {
1698  lineSize++;
1699  }
1700  }
1701  maxX -= lastTabSize * m_view->renderer()->spaceWidth();
1702  } else {
1703  maxX -= m_view->renderer()->config()->fontMetrics()->width(lastCharInLine);
1704  }
1705  }
1706 
1707  return maxX;
1708 }
1709 
1710 int KateViewInternal::lineMaxCol(const KateLineRange& range)
1711 {
1712  int maxCol = range.endCol;
1713 
1714  if (maxCol && range.wrap)
1715  maxCol--;
1716 
1717  return maxCol;
1718 }
1719 
1720 void KateViewInternal::cursorUp(bool sel)
1721 {
1722  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1723  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Up, 0, 0);
1724  m_view->m_codeCompletion->handleKey(&e);
1725  return;
1726  }
1727 
1728  if (displayCursor.line() == 0 && (!m_view->dynWordWrap() || viewLine(cursor) == 0))
1729  return;
1730 
1731  int newLine = cursor.line(), newCol = 0, xOffset = 0, startCol = 0;
1732  m_preserveMaxX = true;
1733 
1734  if (m_view->dynWordWrap()) {
1735  // Dynamic word wrapping - navigate on visual lines rather than real lines
1736  KateLineRange thisRange = currentRange();
1737  // This is not the first line because that is already simplified out above
1738  KateLineRange pRange = previousRange();
1739 
1740  // Ensure we're in the right spot
1741  Q_ASSERT((cursor.line() == thisRange.line) &&
1742  (cursor.col() >= thisRange.startCol) &&
1743  (!thisRange.wrap || cursor.col() < thisRange.endCol));
1744 
1745  // VisibleX is the distance from the start of the text to the cursor on the current line.
1746  int visibleX = m_view->renderer()->textWidth(cursor) - thisRange.startX;
1747  int currentLineVisibleX = visibleX;
1748 
1749  // Translate to new line
1750  visibleX += thisRange.xOffset();
1751  visibleX -= pRange.xOffset();
1752 
1753  // Limit to >= 0
1754  visibleX = kMax(0, visibleX);
1755 
1756  startCol = pRange.startCol;
1757  xOffset = pRange.startX;
1758  newLine = pRange.line;
1759 
1760  // Take into account current max X (ie. if the current line was smaller
1761  // than the last definitely specified width)
1762  if (thisRange.xOffset() && !pRange.xOffset() && currentLineVisibleX == 0) // Special case for where xOffset may be > m_currentMaxX
1763  visibleX = m_currentMaxX;
1764  else if (visibleX < m_currentMaxX - pRange.xOffset())
1765  visibleX = m_currentMaxX - pRange.xOffset();
1766 
1767  cXPos = xOffset + visibleX;
1768 
1769  cXPos = kMin(cXPos, lineMaxCursorX(pRange));
1770 
1771  newCol = kMin((int)m_view->renderer()->textPos(newLine, visibleX, startCol), lineMaxCol(pRange));
1772 
1773  } else {
1774  newLine = m_doc->getRealLine(displayCursor.line() - 1);
1775 
1776  if ((m_view->wrapCursor()) && m_currentMaxX > cXPos)
1777  cXPos = m_currentMaxX;
1778  }
1779 
1780  KateTextCursor c(newLine, newCol);
1781  m_view->renderer()->textWidth(c, cXPos);
1782 
1783  updateSelection( c, sel );
1784  updateCursor( c );
1785 }
1786 
1787 void KateViewInternal::cursorDown(bool sel)
1788 {
1789  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1790  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Down, 0, 0);
1791  m_view->m_codeCompletion->handleKey(&e);
1792  return;
1793  }
1794 
1795  if ((displayCursor.line() >= (int)m_doc->numVisLines() - 1) && (!m_view->dynWordWrap() || viewLine(cursor) == lastViewLine(cursor.line())))
1796  return;
1797 
1798  int newLine = cursor.line(), newCol = 0, xOffset = 0, startCol = 0;
1799  m_preserveMaxX = true;
1800 
1801  if (m_view->dynWordWrap()) {
1802  // Dynamic word wrapping - navigate on visual lines rather than real lines
1803  KateLineRange thisRange = currentRange();
1804  // This is not the last line because that is already simplified out above
1805  KateLineRange nRange = nextRange();
1806 
1807  // Ensure we're in the right spot
1808  Q_ASSERT((cursor.line() == thisRange.line) &&
1809  (cursor.col() >= thisRange.startCol) &&
1810  (!thisRange.wrap || cursor.col() < thisRange.endCol));
1811 
1812  // VisibleX is the distance from the start of the text to the cursor on the current line.
1813  int visibleX = m_view->renderer()->textWidth(cursor) - thisRange.startX;
1814  int currentLineVisibleX = visibleX;
1815 
1816  // Translate to new line
1817  visibleX += thisRange.xOffset();
1818  visibleX -= nRange.xOffset();
1819 
1820  // Limit to >= 0
1821  visibleX = kMax(0, visibleX);
1822 
1823  if (!thisRange.wrap) {
1824  newLine = m_doc->getRealLine(displayCursor.line() + 1);
1825  } else {
1826  startCol = thisRange.endCol;
1827  xOffset = thisRange.endX;
1828  }
1829 
1830  // Take into account current max X (ie. if the current line was smaller
1831  // than the last definitely specified width)
1832  if (thisRange.xOffset() && !nRange.xOffset() && currentLineVisibleX == 0) // Special case for where xOffset may be > m_currentMaxX
1833  visibleX = m_currentMaxX;
1834  else if (visibleX < m_currentMaxX - nRange.xOffset())
1835  visibleX = m_currentMaxX - nRange.xOffset();
1836 
1837  cXPos = xOffset + visibleX;
1838 
1839  cXPos = kMin(cXPos, lineMaxCursorX(nRange));
1840 
1841  newCol = kMin((int)m_view->renderer()->textPos(newLine, visibleX, startCol), lineMaxCol(nRange));
1842 
1843  } else {
1844  newLine = m_doc->getRealLine(displayCursor.line() + 1);
1845 
1846  if ((m_view->wrapCursor()) && m_currentMaxX > cXPos)
1847  cXPos = m_currentMaxX;
1848  }
1849 
1850  KateTextCursor c(newLine, newCol);
1851  m_view->renderer()->textWidth(c, cXPos);
1852 
1853  updateSelection(c, sel);
1854  updateCursor(c);
1855 }
1856 
1857 void KateViewInternal::cursorToMatchingBracket( bool sel )
1858 {
1859  KateTextCursor start( cursor ), end;
1860 
1861  if( !m_doc->findMatchingBracket( start, end ) )
1862  return;
1863 
1864  // The cursor is now placed just to the left of the matching bracket.
1865  // If it's an ending bracket, put it to the right (so we can easily
1866  // get back to the original bracket).
1867  if( end > start )
1868  end.setCol(end.col() + 1);
1869 
1870  updateSelection( end, sel );
1871  updateCursor( end );
1872 }
1873 
1874 void KateViewInternal::topOfView( bool sel )
1875 {
1876  KateTextCursor c = viewLineOffset(startPos(), m_minLinesVisible);
1877  updateSelection( c, sel );
1878  updateCursor( c );
1879 }
1880 
1881 void KateViewInternal::bottomOfView( bool sel )
1882 {
1883  // FIXME account for wordwrap
1884  KateTextCursor c = viewLineOffset(endPos(), -m_minLinesVisible);
1885  updateSelection( c, sel );
1886  updateCursor( c );
1887 }
1888 
1889 // lines is the offset to scroll by
1890 void KateViewInternal::scrollLines( int lines, bool sel )
1891 {
1892  KateTextCursor c = viewLineOffset(displayCursor, lines, true);
1893 
1894  // Fix the virtual cursor -> real cursor
1895  c.setLine(m_doc->getRealLine(c.line()));
1896 
1897  updateSelection( c, sel );
1898  updateCursor( c );
1899 }
1900 
1901 // This is a bit misleading... it's asking for the view to be scrolled, not the cursor
1902 void KateViewInternal::scrollUp()
1903 {
1904  KateTextCursor newPos = viewLineOffset(m_startPos, -1);
1905  scrollPos(newPos);
1906 }
1907 
1908 void KateViewInternal::scrollDown()
1909 {
1910  KateTextCursor newPos = viewLineOffset(m_startPos, 1);
1911  scrollPos(newPos);
1912 }
1913 
1914 void KateViewInternal::setAutoCenterLines(int viewLines, bool updateView)
1915 {
1916  m_autoCenterLines = viewLines;
1917  m_minLinesVisible = kMin(int((linesDisplayed() - 1)/2), m_autoCenterLines);
1918  if (updateView)
1919  KateViewInternal::updateView();
1920 }
1921 
1922 void KateViewInternal::pageUp( bool sel )
1923 {
1924  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1925  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_PageUp, 0, 0);
1926  m_view->m_codeCompletion->handleKey(&e);
1927  return;
1928  }
1929 
1930  // remember the view line and x pos
1931  int viewLine = displayViewLine(displayCursor);
1932  bool atTop = (startPos().line() == 0 && startPos().col() == 0);
1933 
1934  // Adjust for an auto-centering cursor
1935  int lineadj = 2 * m_minLinesVisible;
1936  int cursorStart = (linesDisplayed() - 1) - viewLine;
1937  if (cursorStart < m_minLinesVisible)
1938  lineadj -= m_minLinesVisible - cursorStart;
1939 
1940  int linesToScroll = -kMax( ((int)linesDisplayed() - 1) - lineadj, 0 );
1941  m_preserveMaxX = true;
1942 
1943  if (!m_doc->pageUpDownMovesCursor () && !atTop) {
1944  int xPos = m_view->renderer()->textWidth(cursor) - currentRange().startX;
1945 
1946  KateTextCursor newStartPos = viewLineOffset(startPos(), linesToScroll - 1);
1947  scrollPos(newStartPos);
1948 
1949  // put the cursor back approximately where it was
1950  KateTextCursor newPos = viewLineOffset(newStartPos, viewLine, true);
1951  newPos.setLine(m_doc->getRealLine(newPos.line()));
1952 
1953  KateLineRange newLine = range(newPos);
1954 
1955  if (m_currentMaxX - newLine.xOffset() > xPos)
1956  xPos = m_currentMaxX - newLine.xOffset();
1957 
1958  cXPos = kMin(newLine.startX + xPos, lineMaxCursorX(newLine));
1959 
1960  m_view->renderer()->textWidth( newPos, cXPos );
1961 
1962  m_preserveMaxX = true;
1963  updateSelection( newPos, sel );
1964  updateCursor(newPos);
1965 
1966  } else {
1967  scrollLines( linesToScroll, sel );
1968  }
1969 }
1970 
1971 void KateViewInternal::pageDown( bool sel )
1972 {
1973  if (m_view->m_codeCompletion->codeCompletionVisible()) {
1974  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_PageDown, 0, 0);
1975  m_view->m_codeCompletion->handleKey(&e);
1976  return;
1977  }
1978 
1979  // remember the view line
1980  int viewLine = displayViewLine(displayCursor);
1981  bool atEnd = startPos() >= m_cachedMaxStartPos;
1982 
1983  // Adjust for an auto-centering cursor
1984  int lineadj = 2 * m_minLinesVisible;
1985  int cursorStart = m_minLinesVisible - viewLine;
1986  if (cursorStart > 0)
1987  lineadj -= cursorStart;
1988 
1989  int linesToScroll = kMax( ((int)linesDisplayed() - 1) - lineadj, 0 );
1990  m_preserveMaxX = true;
1991 
1992  if (!m_doc->pageUpDownMovesCursor () && !atEnd) {
1993  int xPos = m_view->renderer()->textWidth(cursor) - currentRange().startX;
1994 
1995  KateTextCursor newStartPos = viewLineOffset(startPos(), linesToScroll + 1);
1996  scrollPos(newStartPos);
1997 
1998  // put the cursor back approximately where it was
1999  KateTextCursor newPos = viewLineOffset(newStartPos, viewLine, true);
2000  newPos.setLine(m_doc->getRealLine(newPos.line()));
2001 
2002  KateLineRange newLine = range(newPos);
2003 
2004  if (m_currentMaxX - newLine.xOffset() > xPos)
2005  xPos = m_currentMaxX - newLine.xOffset();
2006 
2007  cXPos = kMin(newLine.startX + xPos, lineMaxCursorX(newLine));
2008 
2009  m_view->renderer()->textWidth( newPos, cXPos );
2010 
2011  m_preserveMaxX = true;
2012  updateSelection( newPos, sel );
2013  updateCursor(newPos);
2014 
2015  } else {
2016  scrollLines( linesToScroll, sel );
2017  }
2018 }
2019 
2020 int KateViewInternal::maxLen(uint startLine)
2021 {
2022 // Q_ASSERT(!m_view->dynWordWrap());
2023 
2024  int displayLines = (m_view->height() / m_view->renderer()->fontHeight()) + 1;
2025 
2026  int maxLen = 0;
2027 
2028  for (int z = 0; z < displayLines; z++) {
2029  int virtualLine = startLine + z;
2030 
2031  if (virtualLine < 0 || virtualLine >= (int)m_doc->visibleLines())
2032  break;
2033 
2034  KateLineRange thisRange = range((int)m_doc->getRealLine(virtualLine));
2035 
2036  maxLen = kMax(maxLen, thisRange.endX);
2037  }
2038 
2039  return maxLen;
2040 }
2041 
2042 void KateViewInternal::top( bool sel )
2043 {
2044  KateTextCursor c( 0, cursor.col() );
2045  m_view->renderer()->textWidth( c, cXPos );
2046  updateSelection( c, sel );
2047  updateCursor( c );
2048 }
2049 
2050 void KateViewInternal::bottom( bool sel )
2051 {
2052  KateTextCursor c( m_doc->lastLine(), cursor.col() );
2053  m_view->renderer()->textWidth( c, cXPos );
2054  updateSelection( c, sel );
2055  updateCursor( c );
2056 }
2057 
2058 void KateViewInternal::top_home( bool sel )
2059 {
2060  if (m_view->m_codeCompletion->codeCompletionVisible()) {
2061  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_Home, 0, 0);
2062  m_view->m_codeCompletion->handleKey(&e);
2063  return;
2064  }
2065  KateTextCursor c( 0, 0 );
2066  updateSelection( c, sel );
2067  updateCursor( c );
2068 }
2069 
2070 void KateViewInternal::bottom_end( bool sel )
2071 {
2072  if (m_view->m_codeCompletion->codeCompletionVisible()) {
2073  TQKeyEvent e(TQEvent::KeyPress, TQt::Key_End, 0, 0);
2074  m_view->m_codeCompletion->handleKey(&e);
2075  return;
2076  }
2077  KateTextCursor c( m_doc->lastLine(), m_doc->lineLength( m_doc->lastLine() ) );
2078  updateSelection( c, sel );
2079  updateCursor( c );
2080 }
2081 
2082 void KateViewInternal::updateSelection( const KateTextCursor& _newCursor, bool keepSel )
2083 {
2084  KateTextCursor newCursor = _newCursor;
2085  if( keepSel )
2086  {
2087  if ( !m_view->hasSelection() || (selectAnchor.line() == -1)
2088  || (m_view->config()->persistentSelection()
2089  && ((cursor < m_view->selectStart) || (cursor > m_view->selectEnd))) )
2090  {
2091  selectAnchor = cursor;
2092  m_view->setSelection( cursor, newCursor );
2093  }
2094  else
2095  {
2096  bool doSelect = true;
2097  switch (m_selectionMode)
2098  {
2099  case Word:
2100  {
2101  // Restore selStartCached if needed. It gets nuked by
2102  // viewSelectionChanged if we drag the selection into non-existence,
2103  // which can legitimately happen if a shift+DC selection is unable to
2104  // set a "proper" (i.e. non-empty) cached selection, e.g. because the
2105  // start was on something that isn't a word. Word select mode relies
2106  // on the cached selection being set properly, even if it is empty
2107  // (i.e. selStartCached == selEndCached).
2108  if ( selStartCached.line() == -1 )
2109  selStartCached = selEndCached;
2110 
2111  int c;
2112  if ( newCursor > selEndCached )
2113  {
2114  selectAnchor = selStartCached;
2115 
2116  KateTextLine::Ptr l = m_doc->kateTextLine( newCursor.line() );
2117 
2118  c = newCursor.col();
2119  if ( c > 0 && m_doc->highlight()->isInWord( l->getChar( c-1 ) ) ) {
2120  for (; c < l->length(); c++ )
2121  if ( !m_doc->highlight()->isInWord( l->getChar( c ) ) )
2122  break;
2123  }
2124 
2125  newCursor.setCol( c );
2126  }
2127  else if ( newCursor < selStartCached )
2128  {
2129  selectAnchor = selEndCached;
2130 
2131  KateTextLine::Ptr l = m_doc->kateTextLine( newCursor.line() );
2132 
2133  c = newCursor.col();
2134  if ( c > 0 && c < m_doc->textLine( newCursor.line() ).length()
2135  && m_doc->highlight()->isInWord( l->getChar( c ) )
2136  && m_doc->highlight()->isInWord( l->getChar( c-1 ) ) ) {
2137  for ( c -= 2; c >= 0; c-- )
2138  if ( !m_doc->highlight()->isInWord( l->getChar( c ) ) )
2139  break;
2140  newCursor.setCol( c+1 );
2141  }
2142 
2143  }
2144  else
2145  doSelect = false;
2146 
2147  }
2148  break;
2149  case Line:
2150  if ( newCursor.line() > selStartCached.line() )
2151  {
2152  if ( newCursor.line()+1 >= m_doc->numLines() )
2153  newCursor.setCol( m_doc->textLine( newCursor.line() ).length() );
2154  else
2155  newCursor.setPos( newCursor.line() + 1, 0 );
2156  // Grow to include entire line
2157  selectAnchor = selStartCached;
2158  selectAnchor.setCol( 0 );
2159  }
2160  else if ( newCursor.line() < selStartCached.line() )
2161  {
2162  newCursor.setCol( 0 );
2163  // Grow to include entire line
2164  selectAnchor = selEndCached;
2165  if ( selectAnchor.col() > 0 )
2166  {
2167  if ( selectAnchor.line()+1 >= m_doc->numLines() )
2168  selectAnchor.setCol( m_doc->textLine( selectAnchor.line() ).length() );
2169  else
2170  selectAnchor.setPos( selectAnchor.line() + 1, 0 );
2171  }
2172  }
2173  else // same line, ignore
2174  doSelect = false;
2175  break;
2176  case Mouse:
2177  {
2178  if ( selStartCached.line() < 0 ) // invalid
2179  break;
2180 
2181  if ( newCursor > selEndCached )
2182  selectAnchor = selStartCached;
2183  else if ( newCursor < selStartCached )
2184  selectAnchor = selEndCached;
2185  else
2186  doSelect = false;
2187  }
2188  break;
2189  default:
2190  {
2191  if ( selectAnchor.line() < 0 ) // invalid
2192  break;
2193  }
2194  }
2195 
2196  if ( doSelect )
2197  m_view->setSelection( selectAnchor, newCursor);
2198  else if ( selStartCached.line() >= 0 ) // we have a cached selection, so we restore that
2199  m_view->setSelection( selStartCached, selEndCached );
2200  }
2201 
2202  m_selChangedByUser = true;
2203  }
2204  else if ( !m_view->config()->persistentSelection() )
2205  {
2206  m_view->clearSelection();
2207  selStartCached.setLine( -1 );
2208  selectAnchor.setLine( -1 );
2209  }
2210 }
2211 
2212 void KateViewInternal::updateCursor( const KateTextCursor& newCursor, bool force, bool center, bool calledExternally )
2213 {
2214  if ( !force && (cursor == newCursor) )
2215  {
2216  if ( !m_madeVisible && m_view == m_doc->activeView() )
2217  {
2218  // unfold if required
2219  m_doc->foldingTree()->ensureVisible( newCursor.line() );
2220 
2221  makeVisible ( displayCursor, displayCursor.col(), false, center, calledExternally );
2222  }
2223 
2224  return;
2225  }
2226 
2227  // unfold if required
2228  m_doc->foldingTree()->ensureVisible( newCursor.line() );
2229 
2230  KateTextCursor oldDisplayCursor = displayCursor;
2231 
2232  cursor.setPos (newCursor);
2233  displayCursor.setPos (m_doc->getVirtualLine(cursor.line()), cursor.col());
2234 
2235  cXPos = m_view->renderer()->textWidth( cursor );
2236  if (m_view == m_doc->activeView())
2237  makeVisible ( displayCursor, displayCursor.col(), false, center, calledExternally );
2238 
2239  updateBracketMarks();
2240 
2241  // It's efficient enough to just tag them both without checking to see if they're on the same view line
2242  tagLine(oldDisplayCursor);
2243  tagLine(displayCursor);
2244 
2245  updateMicroFocusHint();
2246 
2247  if (m_cursorTimer.isActive ())
2248  {
2249  if ( TDEApplication::cursorFlashTime() > 0 )
2250  m_cursorTimer.start( TDEApplication::cursorFlashTime() / 2 );
2251  m_view->renderer()->setDrawCaret(true);
2252  }
2253 
2254  // Remember the maximum X position if requested
2255  if (m_preserveMaxX)
2256  m_preserveMaxX = false;
2257  else
2258  if (m_view->dynWordWrap())
2259  m_currentMaxX = m_view->renderer()->textWidth(displayCursor) - currentRange().startX + currentRange().xOffset();
2260  else
2261  m_currentMaxX = cXPos;
2262 
2263  //kdDebug() << "m_currentMaxX: " << m_currentMaxX << " (was "<< oldmaxx << "), cXPos: " << cXPos << endl;
2264  //kdDebug(13030) << "Cursor now located at real " << cursor.line << "," << cursor.col << ", virtual " << displayCursor.line << ", " << displayCursor.col << "; Top is " << startLine() << ", " << startPos().col << endl;
2265 
2266  paintText(0, 0, width(), height(), true);
2267 
2268  emit m_view->cursorPositionChanged();
2269 }
2270 
2271 void KateViewInternal::updateBracketMarks()
2272 {
2273  if ( bm.isValid() ) {
2274  KateTextCursor bmStart(m_doc->getVirtualLine(bm.start().line()), bm.start().col());
2275  KateTextCursor bmEnd(m_doc->getVirtualLine(bm.end().line()), bm.end().col());
2276 
2277  if( bm.getMinIndent() != 0 )
2278  {
2279  // @@ Do this only when cursor near start/end.
2280  if( bmStart > bmEnd )
2281  {
2282  tagLines(bmEnd, bmStart);
2283  }
2284  else
2285  {
2286  tagLines(bmStart, bmEnd);
2287  }
2288  }
2289  else
2290  {
2291  tagLine(bmStart);
2292  tagLine(bmEnd);
2293  }
2294  }
2295 
2296  // add some limit to this, this is really endless on big files without limit
2297  int maxLines = linesDisplayed () * 3;
2298  m_doc->newBracketMark( cursor, bm, maxLines );
2299 
2300  if ( bm.isValid() ) {
2301  KateTextCursor bmStart(m_doc->getVirtualLine(bm.start().line()), bm.start().col());
2302  KateTextCursor bmEnd(m_doc->getVirtualLine(bm.end().line()), bm.end().col());
2303 
2304  if( bm.getMinIndent() != 0 )
2305  {
2306  // @@ Do this only when cursor near start/end.
2307  if( bmStart > bmEnd )
2308  {
2309  tagLines(bmEnd, bmStart);
2310  }
2311  else
2312  {
2313  tagLines(bmStart, bmEnd);
2314  }
2315  }
2316  else
2317  {
2318  tagLine(bmStart);
2319  tagLine(bmEnd);
2320  }
2321  }
2322 }
2323 
2324 bool KateViewInternal::tagLine(const KateTextCursor& virtualCursor)
2325 {
2326  int viewLine = displayViewLine(virtualCursor, true);
2327  if (viewLine >= 0 && viewLine < (int)lineRanges.count()) {
2328  lineRanges[viewLine].dirty = true;
2329  leftBorder->update (0, lineToY(viewLine), leftBorder->width(), m_view->renderer()->fontHeight());
2330  return true;
2331  }
2332  return false;
2333 }
2334 
2335 bool KateViewInternal::tagLines( int start, int end, bool realLines )
2336 {
2337  return tagLines(KateTextCursor(start, 0), KateTextCursor(end, -1), realLines);
2338 }
2339 
2340 bool KateViewInternal::tagLines(KateTextCursor start, KateTextCursor end, bool realCursors)
2341 {
2342  if (realCursors)
2343  {
2344  //kdDebug()<<"realLines is true"<<endl;
2345  start.setLine(m_doc->getVirtualLine( start.line() ));
2346  end.setLine(m_doc->getVirtualLine( end.line() ));
2347  }
2348 
2349  if (end.line() < (int)startLine())
2350  {
2351  //kdDebug()<<"end<startLine"<<endl;
2352  return false;
2353  }
2354  if (start.line() > (int)endLine())
2355  {
2356  //kdDebug()<<"start> endLine"<<start<<" "<<((int)endLine())<<endl;
2357  return false;
2358  }
2359 
2360  //kdDebug(13030) << "tagLines( [" << start.line << "," << start.col << "], [" << end.line << "," << end.col << "] )\n";
2361 
2362  bool ret = false;
2363 
2364  for (uint z = 0; z < lineRanges.size(); z++)
2365  {
2366  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)))) {
2367  ret = lineRanges[z].dirty = true;
2368  //kdDebug() << "Tagged line " << lineRanges[z].line << endl;
2369  }
2370  }
2371 
2372  if (!m_view->dynWordWrap())
2373  {
2374  int y = lineToY( start.line() );
2375  // FIXME is this enough for when multiple lines are deleted
2376  int h = (end.line() - start.line() + 2) * m_view->renderer()->fontHeight();
2377  if (end.line() == (int)m_doc->numVisLines() - 1)
2378  h = height();
2379 
2380  leftBorder->update (0, y, leftBorder->width(), h);
2381  }
2382  else
2383  {
2384  // FIXME Do we get enough good info in editRemoveText to optimise this more?
2385  //bool justTagged = false;
2386  for (uint z = 0; z < lineRanges.size(); z++)
2387  {
2388  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))))
2389  {
2390  //justTagged = true;
2391  leftBorder->update (0, z * m_view->renderer()->fontHeight(), leftBorder->width(), leftBorder->height());
2392  break;
2393  }
2394  /*else if (justTagged)
2395  {
2396  justTagged = false;
2397  leftBorder->update (0, z * m_doc->viewFont.fontHeight, leftBorder->width(), m_doc->viewFont.fontHeight);
2398  break;
2399  }*/
2400  }
2401  }
2402 
2403  return ret;
2404 }
2405 
2406 void KateViewInternal::tagAll()
2407 {
2408  //kdDebug(13030) << "tagAll()" << endl;
2409  for (uint z = 0; z < lineRanges.size(); z++)
2410  {
2411  lineRanges[z].dirty = true;
2412  }
2413 
2414  leftBorder->updateFont();
2415  leftBorder->update ();
2416 }
2417 
2418 void KateViewInternal::paintCursor()
2419 {
2420  if (tagLine(displayCursor))
2421  paintText (0,0,width(), height(), true);
2422 }
2423 
2424 // Point in content coordinates
2425 void KateViewInternal::placeCursor( const TQPoint& p, bool keepSelection, bool updateSelection )
2426 {
2427  KateLineRange thisRange = yToKateLineRange(p.y());
2428 
2429  if (thisRange.line == -1) {
2430  for (int i = (p.y() / m_view->renderer()->fontHeight()); i >= 0; i--) {
2431  thisRange = lineRanges[i];
2432  if (thisRange.line != -1)
2433  break;
2434  }
2435  Q_ASSERT(thisRange.line != -1);
2436  }
2437 
2438  int realLine = thisRange.line;
2439  int visibleLine = thisRange.virtualLine;
2440  uint startCol = thisRange.startCol;
2441 
2442  visibleLine = kMax( 0, kMin( visibleLine, int(m_doc->numVisLines()) - 1 ) );
2443 
2444  KateTextCursor c(realLine, 0);
2445 
2446  int x = kMin(kMax(-m_startX, p.x() - thisRange.xOffset()), lineMaxCursorX(thisRange) - thisRange.startX);
2447 
2448  m_view->renderer()->textWidth( c, startX() + x, startCol);
2449 
2450  if (updateSelection)
2451  KateViewInternal::updateSelection( c, keepSelection );
2452 
2453  updateCursor( c );
2454 }
2455 
2456 // Point in content coordinates
2457 bool KateViewInternal::isTargetSelected( const TQPoint& p )
2458 {
2459  KateLineRange thisRange = yToKateLineRange(p.y());
2460 
2461  KateTextLine::Ptr l = textLine( thisRange.line );
2462  if( !l )
2463  return false;
2464 
2465  int col = m_view->renderer()->textPos( l, startX() + p.x() - thisRange.xOffset(), thisRange.startCol, false );
2466 
2467  return m_view->lineColSelected( thisRange.line, col );
2468 }
2469 
2470 //BEGIN EVENT HANDLING STUFF
2471 
2472 bool KateViewInternal::eventFilter( TQObject *obj, TQEvent *e )
2473 {
2474  if (obj == m_lineScroll)
2475  {
2476  // the second condition is to make sure a scroll on the vertical bar doesn't cause a horizontal scroll ;)
2477  if (e->type() == TQEvent::Wheel && m_lineScroll->minValue() != m_lineScroll->maxValue())
2478  {
2479  wheelEvent((TQWheelEvent*)e);
2480  return true;
2481  }
2482 
2483  // continue processing
2484  return TQWidget::eventFilter( obj, e );
2485  }
2486 
2487  switch( e->type() )
2488  {
2489  case TQEvent::KeyPress:
2490  {
2491  TQKeyEvent *k = (TQKeyEvent *)e;
2492 
2493  if (m_view->m_codeCompletion->codeCompletionVisible ())
2494  {
2495  kdDebug (13030) << "hint around" << endl;
2496 
2497  if( k->key() == Key_Escape )
2498  m_view->m_codeCompletion->abortCompletion();
2499  }
2500 
2501  if ((k->key() == TQt::Key_Escape) && !m_view->config()->persistentSelection() )
2502  {
2503  m_view->clearSelection();
2504  return true;
2505  }
2506  else if ( !((k->state() & ControlButton) || (k->state() & AltButton)) )
2507  {
2508  keyPressEvent( k );
2509  return k->isAccepted();
2510  }
2511 
2512  } break;
2513 
2514  case TQEvent::DragMove:
2515  {
2516  TQPoint currentPoint = ((TQDragMoveEvent*) e)->pos();
2517 
2518  TQRect doNotScrollRegion( scrollMargin, scrollMargin,
2519  width() - scrollMargin * 2,
2520  height() - scrollMargin * 2 );
2521 
2522  if ( !doNotScrollRegion.contains( currentPoint ) )
2523  {
2524  startDragScroll();
2525  // Keep sending move events
2526  ( (TQDragMoveEvent*)e )->accept( TQRect(0,0,0,0) );
2527  }
2528 
2529  dragMoveEvent((TQDragMoveEvent*)e);
2530  } break;
2531 
2532  case TQEvent::DragLeave:
2533  // happens only when pressing ESC while dragging
2534  stopDragScroll();
2535  break;
2536 
2537  case TQEvent::WindowBlocked:
2538  // next focus originates from an internal dialog:
2539  // don't show the modonhd prompt
2540  m_doc->m_isasking = -1;
2541  break;
2542 
2543  default:
2544  break;
2545  }
2546 
2547  return TQWidget::eventFilter( obj, e );
2548 }
2549 
2550 void KateViewInternal::keyPressEvent( TQKeyEvent* e )
2551 {
2552  KKey key(e);
2553 
2554  bool codeComp = m_view->m_codeCompletion->codeCompletionVisible ();
2555 
2556  if (codeComp)
2557  {
2558  kdDebug (13030) << "hint around" << endl;
2559 
2560  if( e->key() == Key_Enter || e->key() == Key_Return ||
2561  (key == SHIFT + TQt::Key_Return) || (key == SHIFT + TQt::Key_Enter)) {
2562  m_view->m_codeCompletion->doComplete();
2563  e->accept();
2564  return;
2565  }
2566  }
2567 
2568  if( !m_doc->isReadWrite() )
2569  {
2570  e->ignore();
2571  return;
2572  }
2573 
2574  if ((key == TQt::Key_Return) || (key == TQt::Key_Enter))
2575  {
2576  m_view->keyReturn();
2577  e->accept();
2578  return;
2579  }
2580 
2581  if ((key == SHIFT + TQt::Key_Return) || (key == SHIFT + TQt::Key_Enter))
2582  {
2583  uint ln = cursor.line();
2584  int col = cursor.col();
2585  KateTextLine::Ptr line = m_doc->kateTextLine( ln );
2586  int pos = line->firstChar();
2587  if (pos > cursor.col()) pos = cursor.col();
2588  if (pos != -1) {
2589  while ((int)line->length() > pos &&
2590  !line->getChar(pos).isLetterOrNumber() &&
2591  pos < cursor.col()) ++pos;
2592  } else {
2593  pos = line->length(); // stay indented
2594  }
2595  m_doc->editStart();
2596  m_doc->insertText( cursor.line(), line->length(), "\n" + line->string(0, pos)
2597  + line->string().right( line->length() - cursor.col() ) );
2598  cursor.setPos(ln + 1, pos);
2599  if (col < int(line->length()))
2600  m_doc->editRemoveText(ln, col, line->length() - col);
2601  m_doc->editEnd();
2602  updateCursor(cursor, true);
2603  updateView();
2604  e->accept();
2605 
2606  return;
2607  }
2608 
2609  if (key == TQt::Key_Backspace || key == SHIFT + TQt::Key_Backspace)
2610  {
2611  m_view->backspace();
2612  e->accept();
2613 
2614  if (codeComp)
2615  m_view->m_codeCompletion->updateBox ();
2616 
2617  return;
2618  }
2619 
2620  if (key == TQt::Key_Tab || key == SHIFT+TQt::Key_Backtab || key == TQt::Key_Backtab)
2621  {
2622  if (m_doc->invokeTabInterceptor(key)) {
2623  e->accept();
2624  return;
2625  } else
2626  if (m_doc->configFlags() & KateDocumentConfig::cfTabIndents)
2627  {
2628  if( key == TQt::Key_Tab )
2629  {
2630  if (m_view->hasSelection() || (m_doc->configFlags() & KateDocumentConfig::cfTabIndentsMode))
2631  m_doc->indent( m_view, cursor.line(), 1 );
2632  else if (m_doc->configFlags() & KateDocumentConfig::cfTabInsertsTab)
2633  m_doc->typeChars ( m_view, TQString ("\t") );
2634  else
2635  m_doc->insertIndentChars ( m_view );
2636 
2637  e->accept();
2638 
2639  if (codeComp)
2640  m_view->m_codeCompletion->updateBox ();
2641 
2642  return;
2643  }
2644 
2645  if (key == SHIFT+TQt::Key_Backtab || key == TQt::Key_Backtab)
2646  {
2647  m_doc->indent( m_view, cursor.line(), -1 );
2648  e->accept();
2649 
2650  if (codeComp)
2651  m_view->m_codeCompletion->updateBox ();
2652 
2653  return;
2654  }
2655  }
2656 }
2657  if ( !(e->state() & ControlButton) && !(e->state() & AltButton)
2658  && m_doc->typeChars ( m_view, e->text() ) )
2659  {
2660  e->accept();
2661 
2662  if (codeComp)
2663  m_view->m_codeCompletion->updateBox ();
2664 
2665  return;
2666  }
2667 
2668  e->ignore();
2669 }
2670 
2671 void KateViewInternal::keyReleaseEvent( TQKeyEvent* e )
2672 {
2673  KKey key(e);
2674 
2675  if (key == SHIFT)
2676  m_shiftKeyPressed = true;
2677  else
2678  {
2679  if (m_shiftKeyPressed)
2680  {
2681  m_shiftKeyPressed = false;
2682 
2683  if (m_selChangedByUser)
2684  {
2685  TQApplication::clipboard()->setSelectionMode( true );
2686  m_view->copy();
2687  TQApplication::clipboard()->setSelectionMode( false );
2688 
2689  m_selChangedByUser = false;
2690  }
2691  }
2692  }
2693 
2694  e->ignore();
2695  return;
2696 }
2697 
2698 void KateViewInternal::contextMenuEvent ( TQContextMenuEvent * e )
2699 {
2700  // try to show popup menu
2701 
2702  TQPoint p = e->pos();
2703 
2704  if ( m_view->m_doc->browserView() )
2705  {
2706  m_view->contextMenuEvent( e );
2707  return;
2708  }
2709 
2710  if ( e->reason() == TQContextMenuEvent::Keyboard )
2711  {
2712  makeVisible( cursor, 0 );
2713  p = cursorCoordinates();
2714  }
2715  else if ( ! m_view->hasSelection() || m_view->config()->persistentSelection() )
2716  placeCursor( e->pos() );
2717 
2718  // popup is a qguardedptr now
2719  if (m_view->popup()) {
2720  m_view->popup()->popup( mapToGlobal( p ) );
2721  e->accept ();
2722  }
2723 }
2724 
2725 void KateViewInternal::mousePressEvent( TQMouseEvent* e )
2726 {
2727  switch (e->button())
2728  {
2729  case TQt::LeftButton:
2730  m_selChangedByUser = false;
2731 
2732  if (possibleTripleClick)
2733  {
2734  possibleTripleClick = false;
2735 
2736  m_selectionMode = Line;
2737 
2738  if ( e->state() & TQt::ShiftButton )
2739  {
2740  updateSelection( cursor, true );
2741  }
2742  else
2743  {
2744  m_view->selectLine( cursor );
2745  }
2746 
2747  TQApplication::clipboard()->setSelectionMode( true );
2748  m_view->copy();
2749  TQApplication::clipboard()->setSelectionMode( false );
2750 
2751  // Keep the line at the select anchor selected during further
2752  // mouse selection
2753  if ( selectAnchor.line() > m_view->selectStart.line() )
2754  {
2755  // Preserve the last selected line
2756  if ( selectAnchor == m_view->selectEnd && selectAnchor.col() == 0 )
2757  selStartCached = KateTextCursor( selectAnchor.line()-1, 0 );
2758  else
2759  selStartCached = KateTextCursor( selectAnchor.line(), 0 );
2760  selEndCached = m_view->selectEnd;
2761  }
2762  else
2763  {
2764  // Preserve the first selected line
2765  selStartCached = m_view->selectStart;
2766  if ( m_view->selectEnd.line() > m_view->selectStart.line() )
2767  selEndCached = KateTextCursor( m_view->selectStart.line()+1, 0 );
2768  else
2769  selEndCached = m_view->selectEnd;
2770  }
2771 
2772  // Set cursor to edge of selection... which edge depends on what
2773  // "direction" the selection was made in
2774  if ( m_view->selectStart < selectAnchor
2775  && selectAnchor.line() != m_view->selectStart.line() )
2776  updateCursor( m_view->selectStart );
2777  else
2778  updateCursor( m_view->selectEnd );
2779 
2780  e->accept ();
2781  return;
2782  }
2783  else if (m_selectionMode == Default)
2784  {
2785  m_selectionMode = Mouse;
2786  }
2787 
2788  if ( e->state() & TQt::ShiftButton )
2789  {
2790  if (selectAnchor.line() < 0)
2791  selectAnchor = cursor;
2792  }
2793  else
2794  {
2795  selStartCached.setLine( -1 ); // invalidate
2796  }
2797 
2798  if( !( e->state() & TQt::ShiftButton ) && isTargetSelected( e->pos() ) )
2799  {
2800  dragInfo.state = diPending;
2801  dragInfo.start = e->pos();
2802  }
2803  else
2804  {
2805  dragInfo.state = diNone;
2806 
2807  if ( e->state() & TQt::ShiftButton )
2808  {
2809  placeCursor( e->pos(), true, false );
2810  if ( selStartCached.line() >= 0 )
2811  {
2812  if ( cursor > selEndCached )
2813  {
2814  m_view->setSelection( selStartCached, cursor );
2815  selectAnchor = selStartCached;
2816  }
2817  else if ( cursor < selStartCached )
2818  {
2819  m_view->setSelection( cursor, selEndCached );
2820  selectAnchor = selEndCached;
2821  }
2822  else
2823  {
2824  m_view->setSelection( selStartCached, cursor );
2825  }
2826  }
2827  else
2828  {
2829  m_view->setSelection( selectAnchor, cursor );
2830  }
2831  }
2832  else
2833  {
2834  placeCursor( e->pos() );
2835  }
2836 
2837  scrollX = 0;
2838  scrollY = 0;
2839 
2840  m_scrollTimer.start (50);
2841  }
2842 
2843  e->accept ();
2844  break;
2845 
2846  default:
2847  e->ignore ();
2848  break;
2849  }
2850 }
2851 
2852 void KateViewInternal::mouseDoubleClickEvent(TQMouseEvent *e)
2853 {
2854  switch (e->button())
2855  {
2856  case TQt::LeftButton:
2857  m_selectionMode = Word;
2858 
2859  if ( e->state() & TQt::ShiftButton )
2860  {
2861  KateTextCursor oldSelectStart = m_view->selectStart;
2862  KateTextCursor oldSelectEnd = m_view->selectEnd;
2863 
2864  // Now select the word under the select anchor
2865  int cs, ce;
2866  KateTextLine::Ptr l = m_doc->kateTextLine( selectAnchor.line() );
2867 
2868  ce = selectAnchor.col();
2869  if ( ce > 0 && m_doc->highlight()->isInWord( l->getChar( ce ) ) ) {
2870  for (; ce < l->length(); ce++ )
2871  if ( !m_doc->highlight()->isInWord( l->getChar( ce ) ) )
2872  break;
2873  }
2874 
2875  cs = selectAnchor.col() - 1;
2876  if ( cs < m_doc->textLine( selectAnchor.line() ).length()
2877  && m_doc->highlight()->isInWord( l->getChar( cs ) ) ) {
2878  for ( cs--; cs >= 0; cs-- )
2879  if ( !m_doc->highlight()->isInWord( l->getChar( cs ) ) )
2880  break;
2881  }
2882 
2883  // ...and keep it selected
2884  if (cs+1 < ce)
2885  {
2886  selStartCached = KateTextCursor( selectAnchor.line(), cs+1 );
2887  selEndCached = KateTextCursor( selectAnchor.line(), ce );
2888  }
2889  else
2890  {
2891  selStartCached = selectAnchor;
2892  selEndCached = selectAnchor;
2893  }
2894  // Now word select to the mouse cursor
2895  placeCursor( e->pos(), true );
2896  }
2897  else
2898  {
2899  // first clear the selection, otherwise we run into bug #106402
2900  // ...and set the cursor position, for the same reason (otherwise there
2901  // are *other* idiosyncrasies we can't fix without reintroducing said
2902  // bug)
2903  // Parameters: 1st false: don't redraw
2904  // 2nd false: don't emit selectionChanged signals, as
2905  // selectWord() emits this already
2906  m_view->clearSelection( false, false );
2907  placeCursor( e->pos() );
2908  m_view->selectWord( cursor );
2909  if (m_view->hasSelection())
2910  {
2911  selectAnchor = selStartCached = m_view->selectStart;
2912  selEndCached = m_view->selectEnd;
2913  }
2914  else
2915  {
2916  // if we didn't actually select anything, restore the selection mode
2917  // -- see bug #131369 (kling)
2918  m_selectionMode = Default;
2919  }
2920  }
2921 
2922  // Move cursor to end (or beginning) of selected word
2923  if (m_view->hasSelection())
2924  {
2925  TQApplication::clipboard()->setSelectionMode( true );
2926  m_view->copy();
2927  TQApplication::clipboard()->setSelectionMode( false );
2928 
2929  // Shift+DC before the "cached" word should move the cursor to the
2930  // beginning of the selection, not the end
2931  if (m_view->selectStart < selStartCached)
2932  updateCursor( m_view->selectStart );
2933  else
2934  updateCursor( m_view->selectEnd );
2935  }
2936 
2937  possibleTripleClick = true;
2938  TQTimer::singleShot ( TQApplication::doubleClickInterval(), this, TQ_SLOT(tripleClickTimeout()) );
2939 
2940  scrollX = 0;
2941  scrollY = 0;
2942 
2943  m_scrollTimer.start (50);
2944 
2945  e->accept ();
2946  break;
2947 
2948  default:
2949  e->ignore ();
2950  break;
2951  }
2952 }
2953 
2954 void KateViewInternal::tripleClickTimeout()
2955 {
2956  possibleTripleClick = false;
2957 }
2958 
2959 void KateViewInternal::mouseReleaseEvent( TQMouseEvent* e )
2960 {
2961  switch (e->button())
2962  {
2963  case TQt::LeftButton:
2964  m_selectionMode = Default;
2965 // selStartCached.setLine( -1 );
2966 
2967  if (m_selChangedByUser)
2968  {
2969  TQApplication::clipboard()->setSelectionMode( true );
2970  m_view->copy();
2971  TQApplication::clipboard()->setSelectionMode( false );
2972  // Set cursor to edge of selection... which edge depends on what
2973  // "direction" the selection was made in
2974  if ( m_view->selectStart < selectAnchor )
2975  updateCursor( m_view->selectStart );
2976  else
2977  updateCursor( m_view->selectEnd );
2978 
2979  m_selChangedByUser = false;
2980  }
2981 
2982  if (dragInfo.state == diPending)
2983  placeCursor( e->pos(), e->state() & ShiftButton );
2984  else if (dragInfo.state == diNone)
2985  m_scrollTimer.stop ();
2986 
2987  dragInfo.state = diNone;
2988 
2989  e->accept ();
2990  break;
2991 
2992  case TQt::MidButton:
2993  placeCursor( e->pos() );
2994 
2995  if( m_doc->isReadWrite() )
2996  {
2997  TQApplication::clipboard()->setSelectionMode( true );
2998  m_view->paste ();
2999  TQApplication::clipboard()->setSelectionMode( false );
3000  }
3001 
3002  e->accept ();
3003  break;
3004 
3005  default:
3006  e->ignore ();
3007  break;
3008  }
3009 }
3010 
3011 void KateViewInternal::mouseMoveEvent( TQMouseEvent* e )
3012 {
3013  if( e->state() & TQt::LeftButton )
3014  {
3015  if (dragInfo.state == diPending)
3016  {
3017  // we had a mouse down, but haven't confirmed a drag yet
3018  // if the mouse has moved sufficiently, we will confirm
3019  TQPoint p( e->pos() - dragInfo.start );
3020 
3021  // we've left the drag square, we can start a real drag operation now
3022  if( p.manhattanLength() > TDEGlobalSettings::dndEventDelay() )
3023  doDrag();
3024 
3025  return;
3026  }
3027  else if (dragInfo.state == diDragging)
3028  {
3029  // Don't do anything after a canceled drag until the user lets go of
3030  // the mouse button!
3031  return;
3032  }
3033 
3034  mouseX = e->x();
3035  mouseY = e->y();
3036 
3037  scrollX = 0;
3038  scrollY = 0;
3039  int d = m_view->renderer()->fontHeight();
3040 
3041  if (mouseX < 0)
3042  scrollX = -d;
3043 
3044  if (mouseX > width())
3045  scrollX = d;
3046 
3047  if (mouseY < 0)
3048  {
3049  mouseY = 0;
3050  scrollY = -d;
3051  }
3052 
3053  if (mouseY > height())
3054  {
3055  mouseY = height();
3056  scrollY = d;
3057  }
3058 
3059  placeCursor( TQPoint( mouseX, mouseY ), true );
3060 
3061  }
3062  else
3063  {
3064  if (isTargetSelected( e->pos() ) ) {
3065  // mouse is over selected text. indicate that the text is draggable by setting
3066  // the arrow cursor as other Qt text editing widgets do
3067  if (m_mouseCursor != ArrowCursor) {
3068  setCursor( KCursor::arrowCursor() );
3069  m_mouseCursor = TQt::ArrowCursor;
3070  }
3071  } else {
3072  // normal text cursor
3073  if (m_mouseCursor != IbeamCursor) {
3074  setCursor( KCursor::ibeamCursor() );
3075  m_mouseCursor = TQt::IbeamCursor;
3076  }
3077  }
3078 
3079  if (m_textHintEnabled)
3080  {
3081  m_textHintTimer.start(m_textHintTimeout);
3082  m_textHintMouseX=e->x();
3083  m_textHintMouseY=e->y();
3084  }
3085  }
3086 }
3087 
3088 void KateViewInternal::paintEvent(TQPaintEvent *e)
3089 {
3090  paintText(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
3091 }
3092 
3093 void KateViewInternal::resizeEvent(TQResizeEvent* e)
3094 {
3095  bool expandedHorizontally = width() > e->oldSize().width();
3096  bool expandedVertically = height() > e->oldSize().height();
3097  bool heightChanged = height() != e->oldSize().height();
3098 
3099  m_madeVisible = false;
3100 
3101  if (heightChanged) {
3102  setAutoCenterLines(m_autoCenterLines, false);
3103  m_cachedMaxStartPos.setPos(-1, -1);
3104  }
3105 
3106  if (m_view->dynWordWrap()) {
3107  bool dirtied = false;
3108 
3109  for (uint i = 0; i < lineRanges.count(); i++) {
3110  // find the first dirty line
3111  // the word wrap updateView algorithm is forced to check all lines after a dirty one
3112  if (lineRanges[i].wrap ||
3113  (!expandedHorizontally && (lineRanges[i].endX - lineRanges[i].startX) > width())) {
3114  dirtied = lineRanges[i].dirty = true;
3115  break;
3116  }
3117  }
3118 
3119  if (dirtied || heightChanged) {
3120  updateView(true);
3121  leftBorder->update();
3122  }
3123 
3124  if (width() < e->oldSize().width()) {
3125  if (!m_view->wrapCursor()) {
3126  // May have to restrain cursor to new smaller width...
3127  if (cursor.col() > m_doc->lineLength(cursor.line())) {
3128  KateLineRange thisRange = currentRange();
3129 
3130  KateTextCursor newCursor(cursor.line(), thisRange.endCol + ((width() - thisRange.xOffset() - (thisRange.endX - thisRange.startX)) / m_view->renderer()->spaceWidth()) - 1);
3131  updateCursor(newCursor);
3132  }
3133  }
3134  }
3135 
3136  } else {
3137  updateView();
3138 
3139  if (expandedHorizontally && startX() > 0)
3140  scrollColumns(startX() - (width() - e->oldSize().width()));
3141  }
3142 
3143  if (expandedVertically) {
3144  KateTextCursor max = maxStartPos();
3145  if (startPos() > max)
3146  scrollPos(max);
3147  }
3148 }
3149 
3150 void KateViewInternal::scrollTimeout ()
3151 {
3152  if (scrollX || scrollY)
3153  {
3154  scrollLines (startPos().line() + (scrollY / (int)m_view->renderer()->fontHeight()));
3155  placeCursor( TQPoint( mouseX, mouseY ), true );
3156  }
3157 }
3158 
3159 void KateViewInternal::cursorTimeout ()
3160 {
3161  m_view->renderer()->setDrawCaret(!m_view->renderer()->drawCaret());
3162  paintCursor();
3163 }
3164 
3165 void KateViewInternal::textHintTimeout ()
3166 {
3167  m_textHintTimer.stop ();
3168 
3169  KateLineRange thisRange = yToKateLineRange(m_textHintMouseY);
3170 
3171  if (thisRange.line == -1) return;
3172 
3173  if (m_textHintMouseX> (lineMaxCursorX(thisRange) - thisRange.startX)) return;
3174 
3175  int realLine = thisRange.line;
3176  int startCol = thisRange.startCol;
3177 
3178  KateTextCursor c(realLine, 0);
3179  m_view->renderer()->textWidth( c, startX() + m_textHintMouseX, startCol);
3180 
3181  TQString tmp;
3182 
3183  emit m_view->needTextHint(c.line(), c.col(), tmp);
3184 
3185  if (!tmp.isEmpty()) kdDebug(13030)<<"Hint text: "<<tmp<<endl;
3186 }
3187 
3188 void KateViewInternal::focusInEvent (TQFocusEvent *)
3189 {
3190  if (TDEApplication::cursorFlashTime() > 0)
3191  m_cursorTimer.start ( TDEApplication::cursorFlashTime() / 2 );
3192 
3193  if (m_textHintEnabled)
3194  m_textHintTimer.start( m_textHintTimeout );
3195 
3196  paintCursor();
3197 
3198  m_doc->setActiveView( m_view );
3199 
3200  emit m_view->gotFocus( m_view );
3201 }
3202 
3203 void KateViewInternal::focusOutEvent (TQFocusEvent *)
3204 {
3205  if( m_view->renderer() && ! m_view->m_codeCompletion->codeCompletionVisible() )
3206  {
3207  m_cursorTimer.stop();
3208 
3209  m_view->renderer()->setDrawCaret(true);
3210  paintCursor();
3211  emit m_view->lostFocus( m_view );
3212  }
3213 
3214  m_textHintTimer.stop();
3215 }
3216 
3217 void KateViewInternal::doDrag()
3218 {
3219  dragInfo.state = diDragging;
3220  dragInfo.dragObject = new TQTextDrag(m_view->selection(), this);
3221  dragInfo.dragObject->drag();
3222 }
3223 
3224 void KateViewInternal::dragEnterEvent( TQDragEnterEvent* event )
3225 {
3226  event->accept( (TQTextDrag::canDecode(event) && m_doc->isReadWrite()) ||
3227  KURLDrag::canDecode(event) );
3228 }
3229 
3230 void KateViewInternal::dragMoveEvent( TQDragMoveEvent* event )
3231 {
3232  // track the cursor to the current drop location
3233  placeCursor( event->pos(), true, false );
3234 
3235  // important: accept action to switch between copy and move mode
3236  // without this, the text will always be copied.
3237  event->acceptAction();
3238 }
3239 
3240 void KateViewInternal::dropEvent( TQDropEvent* event )
3241 {
3242  if ( KURLDrag::canDecode(event) ) {
3243 
3244  emit dropEventPass(event);
3245 
3246  } else if ( TQTextDrag::canDecode(event) && m_doc->isReadWrite() ) {
3247 
3248  TQString text;
3249 
3250  if (!TQTextDrag::decode(event, text))
3251  return;
3252 
3253  // is the source our own document?
3254  bool priv = false;
3255  if (event->source() && event->source()->inherits("KateViewInternal"))
3256  priv = m_doc->ownedView( ((KateViewInternal*)(event->source()))->m_view );
3257 
3258  // dropped on a text selection area?
3259  bool selected = isTargetSelected( event->pos() );
3260 
3261  if( priv && selected ) {
3262  // this is a drag that we started and dropped on our selection
3263  // ignore this case
3264  return;
3265  }
3266 
3267  // use one transaction
3268  m_doc->editStart ();
3269 
3270  // on move: remove selected text; on copy: duplicate text
3271  if ( event->action() != TQDropEvent::Copy )
3272  m_view->removeSelectedText();
3273 
3274  m_doc->insertText( cursor.line(), cursor.col(), text );
3275 
3276  m_doc->editEnd ();
3277 
3278  placeCursor( event->pos() );
3279 
3280  event->acceptAction();
3281  updateView();
3282  }
3283 
3284  // finally finish drag and drop mode
3285  dragInfo.state = diNone;
3286  // important, because the eventFilter`s DragLeave does not occur
3287  stopDragScroll();
3288 }
3289 //END EVENT HANDLING STUFF
3290 
3291 void KateViewInternal::clear()
3292 {
3293  cursor.setPos(0, 0);
3294  displayCursor.setPos(0, 0);
3295 }
3296 
3297 void KateViewInternal::wheelEvent(TQWheelEvent* e)
3298 {
3299  if (e->state() & ControlButton)
3300  {
3301  if (e->delta() > 0)
3302  {
3303  slotIncFontSizes();
3304  }
3305  else
3306  {
3307  slotDecFontSizes();
3308  }
3309  }
3310  else
3311  {
3312  if (m_lineScroll->minValue() != m_lineScroll->maxValue() && e->orientation() != TQt::Horizontal)
3313  {
3314  // React to this as a vertical event
3315  if ( e->state() & ShiftButton )
3316  {
3317  if (e->delta() > 0)
3318  scrollPrevPage();
3319  else
3320  scrollNextPage();
3321  }
3322  else
3323  {
3324  scrollViewLines(-((e->delta() / 120) * TQApplication::wheelScrollLines()));
3325  // maybe a menu was opened or a bubbled window title is on us -> we shall erase it
3326  update();
3327  leftBorder->update();
3328  }
3329  } else if (columnScrollingPossible()) {
3330  TQWheelEvent copy = *e;
3331  TQApplication::sendEvent(m_columnScroll, &copy);
3332 
3333  } else {
3334  e->ignore();
3335  }
3336  }
3337 }
3338 
3339 void KateViewInternal::startDragScroll()
3340 {
3341  if ( !m_dragScrollTimer.isActive() ) {
3342  m_dragScrollTimer.start( scrollTime );
3343  }
3344 }
3345 
3346 void KateViewInternal::stopDragScroll()
3347 {
3348  m_dragScrollTimer.stop();
3349  updateView();
3350 }
3351 
3352 void KateViewInternal::doDragScroll()
3353 {
3354  TQPoint p = this->mapFromGlobal( TQCursor::pos() );
3355 
3356  int dx = 0, dy = 0;
3357  if ( p.y() < scrollMargin ) {
3358  dy = p.y() - scrollMargin;
3359  } else if ( p.y() > height() - scrollMargin ) {
3360  dy = scrollMargin - (height() - p.y());
3361  }
3362 
3363  if ( p.x() < scrollMargin ) {
3364  dx = p.x() - scrollMargin;
3365  } else if ( p.x() > width() - scrollMargin ) {
3366  dx = scrollMargin - (width() - p.x());
3367  }
3368 
3369  dy /= 4;
3370 
3371  if (dy)
3372  scrollLines(startPos().line() + dy);
3373 
3374  if (columnScrollingPossible () && dx)
3375  scrollColumns(kMin (m_startX + dx, m_columnScroll->maxValue()));
3376 
3377  if (!dy && !dx)
3378  stopDragScroll();
3379 }
3380 
3381 void KateViewInternal::enableTextHints(int timeout)
3382 {
3383  m_textHintTimeout=timeout;
3384  m_textHintEnabled=true;
3385  m_textHintTimer.start(timeout);
3386 }
3387 
3388 void KateViewInternal::disableTextHints()
3389 {
3390  m_textHintEnabled=false;
3391  m_textHintTimer.stop ();
3392 }
3393 
3394 bool KateViewInternal::columnScrollingPossible ()
3395 {
3396  return !m_view->dynWordWrap() && m_columnScroll->isEnabled() && (m_columnScroll->maxValue() > 0);
3397 }
3398 
3399 //BEGIN EDIT STUFF
3400 void KateViewInternal::editStart()
3401 {
3402  editSessionNumber++;
3403 
3404  if (editSessionNumber > 1)
3405  return;
3406 
3407  editIsRunning = true;
3408  editOldCursor = cursor;
3409 }
3410 
3411 void KateViewInternal::editEnd(int editTagLineStart, int editTagLineEnd, bool tagFrom)
3412 {
3413  if (editSessionNumber == 0)
3414  return;
3415 
3416  editSessionNumber--;
3417 
3418  if (editSessionNumber > 0)
3419  return;
3420 
3421  if (tagFrom && (editTagLineStart <= int(m_doc->getRealLine(startLine()))))
3422  tagAll();
3423  else
3424  tagLines (editTagLineStart, tagFrom ? m_doc->lastLine() : editTagLineEnd, true);
3425 
3426  if (editOldCursor == cursor)
3427  updateBracketMarks();
3428 
3429  if (m_imPreeditLength <= 0)
3430  updateView(true);
3431 
3432  if ((editOldCursor != cursor) && (m_imPreeditLength <= 0))
3433  {
3434  m_madeVisible = false;
3435  updateCursor ( cursor, true );
3436  }
3437  else if ( m_view == m_doc->activeView() )
3438  {
3439  makeVisible(displayCursor, displayCursor.col());
3440  }
3441 
3442  editIsRunning = false;
3443 }
3444 
3445 void KateViewInternal::editSetCursor (const KateTextCursor &cursor)
3446 {
3447  if (this->cursor != cursor)
3448  {
3449  this->cursor.setPos (cursor);
3450  }
3451 }
3452 //END
3453 
3454 void KateViewInternal::viewSelectionChanged ()
3455 {
3456  if (!m_view->hasSelection())
3457  {
3458  selectAnchor.setPos (-1, -1);
3459  selStartCached.setPos (-1, -1);
3460  }
3461 }
3462 
3463 //BEGIN IM INPUT STUFF
3464 void KateViewInternal::imStartEvent( TQIMEvent *e )
3465 {
3466  if ( m_doc->m_bReadOnly ) {
3467  e->ignore();
3468  return;
3469  }
3470 
3471  if ( m_view->hasSelection() )
3472  m_view->removeSelectedText();
3473 
3474  m_imPreeditStartLine = cursor.line();
3475  m_imPreeditStart = cursor.col();
3476  m_imPreeditLength = 0;
3477  m_imPreeditSelStart = m_imPreeditStart;
3478 
3479  m_view->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, 0, 0, 0, true );
3480 }
3481 
3482 void KateViewInternal::imComposeEvent( TQIMEvent *e )
3483 {
3484  if ( m_doc->m_bReadOnly ) {
3485  e->ignore();
3486  return;
3487  }
3488 
3489  // remove old preedit
3490  if ( m_imPreeditLength > 0 ) {
3491  cursor.setPos( m_imPreeditStartLine, m_imPreeditStart );
3492  m_doc->removeText( m_imPreeditStartLine, m_imPreeditStart,
3493  m_imPreeditStartLine, m_imPreeditStart + m_imPreeditLength );
3494  }
3495 
3496  m_imPreeditLength = e->text().length();
3497  m_imPreeditSelStart = m_imPreeditStart + e->cursorPos();
3498 
3499  // update selection
3500  m_view->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, m_imPreeditStart + m_imPreeditLength,
3501  m_imPreeditSelStart, m_imPreeditSelStart + e->selectionLength(),
3502  true );
3503 
3504  // insert new preedit
3505  m_doc->insertText( m_imPreeditStartLine, m_imPreeditStart, e->text() );
3506 
3507 
3508  // update cursor
3509  cursor.setPos( m_imPreeditStartLine, m_imPreeditSelStart );
3510  updateCursor( cursor, true );
3511 
3512  updateView( true );
3513 }
3514 
3515 void KateViewInternal::imEndEvent( TQIMEvent *e )
3516 {
3517  if ( m_doc->m_bReadOnly ) {
3518  e->ignore();
3519  return;
3520  }
3521 
3522  if ( m_imPreeditLength > 0 ) {
3523  cursor.setPos( m_imPreeditStartLine, m_imPreeditStart );
3524  m_doc->removeText( m_imPreeditStartLine, m_imPreeditStart,
3525  m_imPreeditStartLine, m_imPreeditStart + m_imPreeditLength );
3526  }
3527 
3528  m_view->setIMSelectionValue( m_imPreeditStartLine, m_imPreeditStart, 0, 0, 0, false );
3529 
3530  if ( e->text().length() > 0 ) {
3531  m_doc->insertText( cursor.line(), cursor.col(), e->text() );
3532 
3533  if ( !m_cursorTimer.isActive() && TDEApplication::cursorFlashTime() > 0 )
3534  m_cursorTimer.start ( TDEApplication::cursorFlashTime() / 2 );
3535 
3536  updateView( true );
3537  updateCursor( cursor, true );
3538  }
3539 
3540  m_imPreeditStart = 0;
3541  m_imPreeditLength = 0;
3542  m_imPreeditSelStart = 0;
3543 }
3544 //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.