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

kate

  • kate
  • part
katecodecompletion.cpp
1/* This file is part of the KDE libraries
2 Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
3 Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
4 Copyright (C) 2001 by Victor Röder <Victor_Roeder@GMX.de>
5 Copyright (C) 2002 by Roberto Raggi <roberto@kdevelop.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License version 2 as published by the Free Software Foundation.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22/******** Partly based on the ArgHintWidget of Qt3 by Trolltech AS *********/
23/* Trolltech doesn't mind, if we license that piece of code as LGPL, because there isn't much
24 * left from the desigener code */
25
26#include "katecodecompletion.h"
27#include "katecodecompletion.moc"
28
29#include "katedocument.h"
30#include "kateview.h"
31#include "katerenderer.h"
32#include "kateconfig.h"
33#include "katefont.h"
34
35#include <kdebug.h>
36
37#include <tqwhatsthis.h>
38#include <tqvbox.h>
39#include <tqlistbox.h>
40#include <tqtimer.h>
41#include <tqtooltip.h>
42#include <tqapplication.h>
43#include <tqsizegrip.h>
44#include <tqfontmetrics.h>
45#include <tqlayout.h>
46#include <tqregexp.h>
47
54class KateCCListBox : public TQListBox
55{
56 public:
60 KateCCListBox (TQWidget* parent = 0, const char* name = 0, WFlags f = 0):TQListBox(parent, name, f)
61 {
62 }
63
64 TQSize sizeHint() const
65 {
66 int count = this->count();
67 int height = 20;
68 int tmpwidth = 8;
69 //FIXME the height is for some reasons at least 3 items heigh, even if there is only one item in the list
70 if (count > 0)
71 if(count < 11)
72 height = count * itemHeight(0);
73 else {
74 height = 10 * itemHeight(0);
75 tmpwidth += verticalScrollBar()->width();
76 }
77
78 int maxcount = 0, tmpcount = 0;
79 for (int i = 0; i < count; ++i)
80 if ( (tmpcount = fontMetrics().width(text(i)) ) > maxcount)
81 maxcount = tmpcount;
82
83 if (maxcount > TQApplication::desktop()->width()){
84 tmpwidth = TQApplication::desktop()->width() - 5;
85 height += horizontalScrollBar()->height();
86 } else
87 tmpwidth += maxcount;
88 return TQSize(tmpwidth,height);
89
90 }
91};
92
93class KateCompletionItem : public TQListBoxText
94{
95 public:
96 KateCompletionItem( TQListBox* lb, KTextEditor::CompletionEntry entry )
97 : TQListBoxText( lb )
98 , m_entry( entry )
99 {
100 if( entry.postfix == "()" ) { // should be configurable
101 setText( entry.prefix + " " + entry.text + entry.postfix );
102 } else {
103 setText( entry.prefix + " " + entry.text + " " + entry.postfix);
104 }
105 }
106
107 KTextEditor::CompletionEntry m_entry;
108};
109
110
111KateCodeCompletion::KateCodeCompletion( KateView* view )
112 : TQObject( view, "Kate Code Completion" )
113 , m_view( view )
114 , m_commentLabel( 0 )
115{
116 m_completionPopup = new TQVBox( 0, 0, (WFlags)WType_Popup );
117 m_completionPopup->setFrameStyle( TQFrame::Box | TQFrame::Plain );
118 m_completionPopup->setLineWidth( 1 );
119
120 m_completionListBox = new KateCCListBox( m_completionPopup );
121 m_completionListBox->setFrameStyle( TQFrame::NoFrame );
122 //m_completionListBox->setCornerWidget( new TQSizeGrip( m_completionListBox) );
123 m_completionListBox->setFocusProxy( m_view->m_viewInternal );
124
125 m_completionListBox->installEventFilter( this );
126
127 m_completionPopup->resize(m_completionListBox->sizeHint() + TQSize(2,2));
128 m_completionPopup->installEventFilter( this );
129 m_completionPopup->setFocusProxy( m_view->m_viewInternal );
130
131 m_pArgHint = new KateArgHint( m_view );
132 connect( m_pArgHint, TQ_SIGNAL(argHintHidden()),
133 this, TQ_SIGNAL(argHintHidden()) );
134
135 connect( m_view, TQ_SIGNAL(cursorPositionChanged()),
136 this, TQ_SLOT(slotCursorPosChanged()) );
137}
138
139KateCodeCompletion::~KateCodeCompletion()
140{
141 delete m_completionPopup;
142}
143
144bool KateCodeCompletion::codeCompletionVisible () {
145 return m_completionPopup->isVisible();
146}
147
148void KateCodeCompletion::showCompletionBox(
149 TQValueList<KTextEditor::CompletionEntry> complList, int offset, bool casesensitive )
150{
151 kdDebug(13035) << "showCompletionBox " << endl;
152
153 if ( codeCompletionVisible() ) return;
154
155 m_caseSensitive = casesensitive;
156 m_complList = complList;
157 m_offset = offset;
158 m_view->cursorPositionReal( &m_lineCursor, &m_colCursor );
159 m_colCursor -= offset;
160
161 updateBox( true );
162}
163
164bool KateCodeCompletion::eventFilter( TQObject *o, TQEvent *e )
165{
166 if ( o != m_completionPopup &&
167 o != m_completionListBox &&
168 o != m_completionListBox->viewport() )
169 return false;
170
171 if( e->type() == TQEvent::Hide )
172 {
173 //don't use abortCompletion() as aborting here again will send abort signal
174 //even on successfull completion we will emit completionAborted() twice...
175 m_completionPopup->hide();
176 delete m_commentLabel;
177 m_commentLabel = 0;
178 return false;
179 }
180
181
182 if ( e->type() == TQEvent::MouseButtonDblClick ) {
183 doComplete();
184 return false;
185 }
186
187 if ( e->type() == TQEvent::MouseButtonPress ) {
188 TQTimer::singleShot(0, this, TQ_SLOT(showComment()));
189 return false;
190 }
191
192 return false;
193}
194
195void KateCodeCompletion::handleKey (TQKeyEvent *e)
196{
197 // close completion if you move out of range
198 if ((e->key() == Key_Up) && (m_completionListBox->currentItem() == 0))
199 {
200 abortCompletion();
201 m_view->setFocus();
202 return;
203 }
204
205 // keyboard movement
206 if( (e->key() == Key_Up) || (e->key() == Key_Down ) ||
207 (e->key() == Key_Home ) || (e->key() == Key_End) ||
208 (e->key() == Key_Prior) || (e->key() == Key_Next ))
209 {
210 TQTimer::singleShot(0,this,TQ_SLOT(showComment()));
211 TQApplication::sendEvent( m_completionListBox, (TQEvent*)e );
212 return;
213 }
214
215 // update the box
216 updateBox();
217}
218
219void KateCodeCompletion::doComplete()
220{
221 KateCompletionItem* item = static_cast<KateCompletionItem*>(
222 m_completionListBox->item(m_completionListBox->currentItem()));
223
224 if( item == 0 )
225 return;
226
227 TQString text = item->m_entry.text;
228 TQString currentLine = m_view->currentTextLine();
229 int len = m_view->cursorColumnReal() - m_colCursor;
230 TQString currentComplText = currentLine.mid(m_colCursor,len);
231 TQString add = text.mid(currentComplText.length());
232 if( item->m_entry.postfix == "()" )
233 add += "(";
234
235 emit filterInsertString(&(item->m_entry),&add);
236 m_view->insertText(add);
237
238 complete( item->m_entry );
239 m_view->setFocus();
240}
241
242void KateCodeCompletion::abortCompletion()
243{
244 m_completionPopup->hide();
245 delete m_commentLabel;
246 m_commentLabel = 0;
247 emit completionAborted();
248}
249
250void KateCodeCompletion::complete( KTextEditor::CompletionEntry entry )
251{
252 m_completionPopup->hide();
253 delete m_commentLabel;
254 m_commentLabel = 0;
255 emit completionDone( entry );
256 emit completionDone();
257}
258
259void KateCodeCompletion::updateBox( bool )
260{
261 if( m_colCursor > m_view->cursorColumnReal() ) {
262 // the cursor is too far left
263 kdDebug(13035) << "Aborting Codecompletion after sendEvent" << endl;
264 kdDebug(13035) << m_view->cursorColumnReal() << endl;
265 abortCompletion();
266 m_view->setFocus();
267 return;
268 }
269
270 m_completionListBox->clear();
271
272 TQString currentLine = m_view->currentTextLine();
273 int len = m_view->cursorColumnReal() - m_colCursor;
274 TQString currentComplText = currentLine.mid(m_colCursor,len);
275/* No-one really badly wants those, or?
276 kdDebug(13035) << "Column: " << m_colCursor << endl;
277 kdDebug(13035) << "Line: " << currentLine << endl;
278 kdDebug(13035) << "CurrentColumn: " << m_view->cursorColumnReal() << endl;
279 kdDebug(13035) << "Len: " << len << endl;
280 kdDebug(13035) << "Text: '" << currentComplText << "'" << endl;
281 kdDebug(13035) << "Count: " << m_complList.count() << endl;
282*/
283 TQValueList<KTextEditor::CompletionEntry>::Iterator it;
284 if( m_caseSensitive ) {
285 for( it = m_complList.begin(); it != m_complList.end(); ++it ) {
286 if( (*it).text.startsWith(currentComplText) ) {
287 new KateCompletionItem(m_completionListBox,*it);
288 }
289 }
290 } else {
291 currentComplText = currentComplText.upper();
292 for( it = m_complList.begin(); it != m_complList.end(); ++it ) {
293 if( (*it).text.upper().startsWith(currentComplText) ) {
294 new KateCompletionItem(m_completionListBox,*it);
295 }
296 }
297 }
298
299 if( m_completionListBox->count() == 0 ||
300 ( m_completionListBox->count() == 1 && // abort if we equaled the last item
301 currentComplText == m_completionListBox->text(0).stripWhiteSpace() ) ) {
302 abortCompletion();
303 m_view->setFocus();
304 return;
305 }
306
307 kdDebug(13035)<<"KateCodeCompletion::updateBox: Resizing widget"<<endl;
308 m_completionPopup->resize(m_completionListBox->sizeHint() + TQSize(2,2));
309 TQPoint p = m_view->mapToGlobal( m_view->cursorCoordinates() );
310 int x = p.x();
311 int y = p.y() ;
312 if ( y + m_completionPopup->height() + m_view->renderer()->config()->fontMetrics( )->height() > TQApplication::desktop()->height() )
313 y -= (m_completionPopup->height() );
314 else
315 y += m_view->renderer()->config()->fontMetrics( )->height();
316
317 if (x + m_completionPopup->width() > TQApplication::desktop()->width())
318 x = TQApplication::desktop()->width() - m_completionPopup->width();
319
320 m_completionPopup->move( TQPoint(x,y) );
321
322 m_completionListBox->setCurrentItem( 0 );
323 m_completionListBox->setSelected( 0, true );
324 m_completionListBox->setFocus();
325 m_completionPopup->show();
326
327 TQTimer::singleShot(0,this,TQ_SLOT(showComment()));
328}
329
330void KateCodeCompletion::showArgHint ( TQStringList functionList, const TQString& strWrapping, const TQString& strDelimiter )
331{
332 unsigned int line, col;
333 m_view->cursorPositionReal( &line, &col );
334 m_pArgHint->reset( line, col );
335 m_pArgHint->setArgMarkInfos( strWrapping, strDelimiter );
336
337 int nNum = 0;
338 TQStringList::Iterator end(functionList.end());
339 for( TQStringList::Iterator it = functionList.begin(); it != end; ++it )
340 {
341 kdDebug(13035) << "Insert function text: " << *it << endl;
342
343 m_pArgHint->addFunction( nNum, ( *it ) );
344
345 nNum++;
346 }
347
348 m_pArgHint->move(m_view->mapToGlobal(m_view->cursorCoordinates() + TQPoint(0,m_view->renderer()->config()->fontMetrics( )->height())) );
349 m_pArgHint->show();
350}
351
352void KateCodeCompletion::slotCursorPosChanged()
353{
354 m_pArgHint->cursorPositionChanged ( m_view, m_view->cursorLine(), m_view->cursorColumnReal() );
355}
356
357void KateCodeCompletion::showComment()
358{
359 if (!m_completionPopup->isVisible())
360 return;
361
362 KateCompletionItem* item = static_cast<KateCompletionItem*>(m_completionListBox->item(m_completionListBox->currentItem()));
363
364 if( !item )
365 return;
366
367 if( item->m_entry.comment.isEmpty() )
368 return;
369
370 delete m_commentLabel;
371 m_commentLabel = new KateCodeCompletionCommentLabel( 0, item->m_entry.comment );
372 m_commentLabel->setFont(TQToolTip::font());
373 m_commentLabel->setPalette(TQToolTip::palette());
374
375 TQPoint rightPoint = m_completionPopup->mapToGlobal(TQPoint(m_completionPopup->width(),0));
376 TQPoint leftPoint = m_completionPopup->mapToGlobal(TQPoint(0,0));
377 TQRect screen = TQApplication::desktop()->screenGeometry ( m_commentLabel );
378 TQPoint finalPoint;
379 if (rightPoint.x()+m_commentLabel->width() > screen.x() + screen.width())
380 finalPoint.setX(leftPoint.x()-m_commentLabel->width());
381 else
382 finalPoint.setX(rightPoint.x());
383
384 m_completionListBox->ensureCurrentVisible();
385
386 finalPoint.setY(
387 m_completionListBox->viewport()->mapToGlobal(m_completionListBox->itemRect(
388 m_completionListBox->item(m_completionListBox->currentItem())).topLeft()).y());
389
390 m_commentLabel->move(finalPoint);
391 m_commentLabel->show();
392}
393
394KateArgHint::KateArgHint( KateView* parent, const char* name )
395 : TQFrame( parent, name, (WFlags)WType_Popup )
396{
397 setBackgroundColor( black );
398 setPaletteForegroundColor( TQt::black );
399
400 labelDict.setAutoDelete( true );
401 layout = new TQVBoxLayout( this, 1, 2 );
402 layout->setAutoAdd( true );
403 editorView = parent;
404
405 m_markCurrentFunction = true;
406
407 setFocusPolicy( TQWidget::StrongFocus );
408 setFocusProxy( parent );
409
410 reset( -1, -1 );
411}
412
413KateArgHint::~KateArgHint()
414{
415}
416
417void KateArgHint::setArgMarkInfos( const TQString& wrapping, const TQString& delimiter )
418{
419 m_wrapping = wrapping;
420 m_delimiter = delimiter;
421 m_markCurrentFunction = true;
422}
423
424void KateArgHint::reset( int line, int col )
425{
426 m_functionMap.clear();
427 m_currentFunction = -1;
428 labelDict.clear();
429
430 m_currentLine = line;
431 m_currentCol = col - 1;
432}
433
434void KateArgHint::slotDone(bool completed)
435{
436 hide();
437
438 m_currentLine = m_currentCol = -1;
439
440 emit argHintHidden();
441 if (completed)
442 emit argHintCompleted();
443 else
444 emit argHintAborted();
445}
446
447void KateArgHint::cursorPositionChanged( KateView* view, int line, int col )
448{
449 if( m_currentCol == -1 || m_currentLine == -1 ){
450 slotDone(false);
451 return;
452 }
453
454 int nCountDelimiter = 0;
455 int count = 0;
456
457 TQString currentTextLine = view->doc()->textLine( line );
458 TQString text = currentTextLine.mid( m_currentCol, col - m_currentCol );
459 TQRegExp strconst_rx( "\"[^\"]*\"" );
460 TQRegExp chrconst_rx( "'[^']*'" );
461
462 text = text
463 .replace( strconst_rx, "\"\"" )
464 .replace( chrconst_rx, "''" );
465
466 int index = 0;
467 while( index < (int)text.length() ){
468 if( text[index] == m_wrapping[0] ){
469 ++count;
470 } else if( text[index] == m_wrapping[1] ){
471 --count;
472 } else if( count > 0 && text[index] == m_delimiter[0] ){
473 ++nCountDelimiter;
474 }
475 ++index;
476 }
477
478 if( (m_currentLine > 0 && m_currentLine != line) || (m_currentLine < col) || (count == 0) ){
479 slotDone(count == 0);
480 return;
481 }
482
483 // setCurArg ( nCountDelimiter + 1 );
484
485}
486
487void KateArgHint::addFunction( int id, const TQString& prot )
488{
489 m_functionMap[ id ] = prot;
490 TQLabel* label = new TQLabel( prot.stripWhiteSpace().simplifyWhiteSpace(), this );
491 label->setBackgroundColor( TQColor(255, 255, 238) );
492 label->show();
493 labelDict.insert( id, label );
494
495 if( m_currentFunction < 0 )
496 setCurrentFunction( id );
497}
498
499void KateArgHint::setCurrentFunction( int currentFunction )
500{
501 if( m_currentFunction != currentFunction ){
502
503 if( currentFunction < 0 )
504 currentFunction = (int)m_functionMap.size() - 1;
505
506 if( currentFunction > (int)m_functionMap.size()-1 )
507 currentFunction = 0;
508
509 if( m_markCurrentFunction && m_currentFunction >= 0 ){
510 TQLabel* label = labelDict[ m_currentFunction ];
511 label->setFont( font() );
512 }
513
514 m_currentFunction = currentFunction;
515
516 if( m_markCurrentFunction ){
517 TQLabel* label = labelDict[ currentFunction ];
518 TQFont fnt( font() );
519 fnt.setBold( true );
520 label->setFont( fnt );
521 }
522
523 adjustSize();
524 }
525}
526
527void KateArgHint::show()
528{
529 TQFrame::show();
530 adjustSize();
531}
532
533bool KateArgHint::eventFilter( TQObject*, TQEvent* e )
534{
535 if( isVisible() && e->type() == TQEvent::KeyPress ){
536 TQKeyEvent* ke = static_cast<TQKeyEvent*>( e );
537 if( (ke->state() & ControlButton) && ke->key() == Key_Left ){
538 setCurrentFunction( currentFunction() - 1 );
539 ke->accept();
540 return true;
541 } else if( ke->key() == Key_Escape ){
542 slotDone(false);
543 return false;
544 } else if( (ke->state() & ControlButton) && ke->key() == Key_Right ){
545 setCurrentFunction( currentFunction() + 1 );
546 ke->accept();
547 return true;
548 }
549 }
550
551 return false;
552}
553
554void KateArgHint::adjustSize( )
555{
556 TQRect screen = TQApplication::desktop()->screenGeometry( pos() );
557
558 TQFrame::adjustSize();
559 if( width() > screen.width() )
560 resize( screen.width(), height() );
561
562 if( x() + width() > screen.x() + screen.width() )
563 move( screen.x() + screen.width() - width(), y() );
564}
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
TDEStdAccel::name
TQString name(StdAccel id)
TDEStdAccel::end
const TDEShortcut & end()
TDEStdAccel::label
TQString label(StdAccel id)

kate

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

kate

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