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