• 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
54KateViewInternal::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
220KateViewInternal::~KateViewInternal ()
221{
222}
223
224void KateViewInternal::prepareForDynWrapChange()
225{
226 // Which is the current view line?
227 m_wrapChangeViewLine = displayViewLine(displayCursor, true);
228}
229
230void 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
258KateTextCursor 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
291uint KateViewInternal::endLine() const
292{
293 return endPos().line();
294}
295
296KateLineRange 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
307int KateViewInternal::lineToY(uint viewLine) const
308{
309 return (viewLine-startLine()) * m_view->renderer()->fontHeight();
310}
311
312void KateViewInternal::slotIncFontSizes()
313{
314 m_view->renderer()->increaseFontSizes();
315}
316
317void KateViewInternal::slotDecFontSizes()
318{
319 m_view->renderer()->decreaseFontSizes();
320}
321
325void KateViewInternal::scrollLines ( int line )
326{
327 KateTextCursor newPos(line, 0);
328 scrollPos(newPos);
329}
330
331// This can scroll less than one true line
332void 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
342void KateViewInternal::scrollNextPage()
343{
344 scrollViewLines(kMax( (int)linesDisplayed() - 1, 0 ));
345}
346
347void KateViewInternal::scrollPrevPage()
348{
349 scrollViewLines(-kMax( (int)linesDisplayed() - 1, 0 ));
350}
351
352void KateViewInternal::scrollPrevLine()
353{
354 scrollViewLines(-1);
355}
356
357void KateViewInternal::scrollNextLine()
358{
359 scrollViewLines(1);
360}
361
362KateTextCursor 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
379void 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
448void 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.
470void 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
715void 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
764void 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
817void 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
830void KateViewInternal::slotCodeFoldingChanged()
831{
832 leftBorder->update();
833}
834
835void KateViewInternal::slotRegionBeginEndAddedRemoved(unsigned int)
836{
837 kdDebug(13030) << "slotRegionBeginEndAddedRemoved()" << endl;
838 // FIXME: performance problem
839 leftBorder->update();
840}
841
842void KateViewInternal::showEvent ( TQShowEvent *e )
843{
844 updateView ();
845
846 TQWidget::showEvent (e);
847}
848
849uint KateViewInternal::linesDisplayed() const
850{
851 int h = height();
852 int fh = m_view->renderer()->fontHeight();
853
854 return (h - (h % fh)) / fh;
855}
856
857TQPoint 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
870void 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
893void KateViewInternal::doReturn()
894{
895 KateTextCursor c = cursor;
896 m_doc->newLine( c, this );
897 updateCursor( c );
898 updateView();
899}
900
901void 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
909void 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
917void KateViewInternal::doTranspose()
918{
919 m_doc->transpose( cursor );
920}
921
922void KateViewInternal::doDeleteWordLeft()
923{
924 wordLeft( true );
925 m_view->removeSelectedText();
926 update();
927}
928
929void KateViewInternal::doDeleteWordRight()
930{
931 wordRight( true );
932 m_view->removeSelectedText();
933 update();
934}
935
936class CalculatingCursor : public KateTextCursor {
937public:
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
994protected:
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
1004class BoundedCursor : public CalculatingCursor {
1005public:
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
1050class WrappingCursor : public CalculatingCursor {
1051public:
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
1092void 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
1138void 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
1149void 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
1157void 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
1200void 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
1241void 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
1249void 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
1290void 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
1334KateLineRange 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
1399KateLineRange KateViewInternal::currentRange()
1400{
1401// Q_ASSERT(m_view->dynWordWrap());
1402
1403 return range(cursor);
1404}
1405
1406KateLineRange 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
1416KateLineRange 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
1428KateLineRange 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
1443KateLineRange 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
1466uint 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
1483int 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
1534uint 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
1549uint 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 */
1561KateTextCursor 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
1680int 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
1710int 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
1720void 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
1787void 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
1857void 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
1874void KateViewInternal::topOfView( bool sel )
1875{
1876 KateTextCursor c = viewLineOffset(startPos(), m_minLinesVisible);
1877 updateSelection( c, sel );
1878 updateCursor( c );
1879}
1880
1881void 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
1890void 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
1902void KateViewInternal::scrollUp()
1903{
1904 KateTextCursor newPos = viewLineOffset(m_startPos, -1);
1905 scrollPos(newPos);
1906}
1907
1908void KateViewInternal::scrollDown()
1909{
1910 KateTextCursor newPos = viewLineOffset(m_startPos, 1);
1911 scrollPos(newPos);
1912}
1913
1914void 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
1922void 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
1971void 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
2020int 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
2042void 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
2050void 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
2058void 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
2070void 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
2082void 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
2212void 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
2271void 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
2324bool 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
2335bool KateViewInternal::tagLines( int start, int end, bool realLines )
2336{
2337 return tagLines(KateTextCursor(start, 0), KateTextCursor(end, -1), realLines);
2338}
2339
2340bool 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
2406void 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
2418void KateViewInternal::paintCursor()
2419{
2420 if (tagLine(displayCursor))
2421 paintText (0,0,width(), height(), true);
2422}
2423
2424// Point in content coordinates
2425void 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
2457bool 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
2472bool 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
2550void 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
2671void 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
2698void 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
2725void 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
2852void 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
2954void KateViewInternal::tripleClickTimeout()
2955{
2956 possibleTripleClick = false;
2957}
2958
2959void 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
3011void 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
3088void KateViewInternal::paintEvent(TQPaintEvent *e)
3089{
3090 paintText(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
3091}
3092
3093void 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
3150void 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
3159void KateViewInternal::cursorTimeout ()
3160{
3161 m_view->renderer()->setDrawCaret(!m_view->renderer()->drawCaret());
3162 paintCursor();
3163}
3164
3165void 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
3188void 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
3203void 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
3217void KateViewInternal::doDrag()
3218{
3219 dragInfo.state = diDragging;
3220 dragInfo.dragObject = new TQTextDrag(m_view->selection(), this);
3221 dragInfo.dragObject->drag();
3222}
3223
3224void KateViewInternal::dragEnterEvent( TQDragEnterEvent* event )
3225{
3226 event->accept( (TQTextDrag::canDecode(event) && m_doc->isReadWrite()) ||
3227 KURLDrag::canDecode(event) );
3228}
3229
3230void 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
3240void 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
3291void KateViewInternal::clear()
3292{
3293 cursor.setPos(0, 0);
3294 displayCursor.setPos(0, 0);
3295}
3296
3297void 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
3339void KateViewInternal::startDragScroll()
3340{
3341 if ( !m_dragScrollTimer.isActive() ) {
3342 m_dragScrollTimer.start( scrollTime );
3343 }
3344}
3345
3346void KateViewInternal::stopDragScroll()
3347{
3348 m_dragScrollTimer.stop();
3349 updateView();
3350}
3351
3352void 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
3381void KateViewInternal::enableTextHints(int timeout)
3382{
3383 m_textHintTimeout=timeout;
3384 m_textHintEnabled=true;
3385 m_textHintTimer.start(timeout);
3386}
3387
3388void KateViewInternal::disableTextHints()
3389{
3390 m_textHintEnabled=false;
3391 m_textHintTimer.stop ();
3392}
3393
3394bool KateViewInternal::columnScrollingPossible ()
3395{
3396 return !m_view->dynWordWrap() && m_columnScroll->isEnabled() && (m_columnScroll->maxValue() > 0);
3397}
3398
3399//BEGIN EDIT STUFF
3400void KateViewInternal::editStart()
3401{
3402 editSessionNumber++;
3403
3404 if (editSessionNumber > 1)
3405 return;
3406
3407 editIsRunning = true;
3408 editOldCursor = cursor;
3409}
3410
3411void 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
3445void KateViewInternal::editSetCursor (const KateTextCursor &cursor)
3446{
3447 if (this->cursor != cursor)
3448 {
3449 this->cursor.setPos (cursor);
3450 }
3451}
3452//END
3453
3454void 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
3464void 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
3482void 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
3515void 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.4
This website is maintained by Timothy Pearson.