KDevelop API Documentation

editors/qeditor/qeditorcodecompletion.cpp

Go to the documentation of this file.
00001 /*************************************************************************** 00002 qeditorcodecompletion.cpp - description 00003 ------------------- 00004 00005 00006 begin : Sun Nov 18 20:00 CET 2001 00007 copyright : (C) 2001 Joseph Wenninger <jowenn@kde.org> 00008 (C) 2002 John Firebaugh <jfirebaugh@kde.org> 00009 (C) 2002 Roberto Raggi <roberto@kdevelop.org> 00010 00011 taken from KDEVELOP: 00012 begin : Sam Jul 14 18:20:00 CEST 2001 00013 copyright : (C) 2001 by Victor Röder <Victor_Roeder@GMX.de> 00014 ***************************************************************************/ 00015 00016 /******** Partly based on the ArgHintWidget of Qt3 by Trolltech AS *********/ 00017 00018 /*************************************************************************** 00019 * * 00020 * This program is free software; you can redistribute it and/or modify * 00021 * it under the terms of the GNU General Public License as published by * 00022 * the Free Software Foundation; either version 2 of the License, or * 00023 * (at your option) any later version. * 00024 * * 00025 ***************************************************************************/ 00026 00027 #include "qeditorcodecompletion.h" 00028 #include "qeditor_settings.h" 00029 #include "qeditorcodecompletion.moc" 00030 00031 // #include "qeditorcodecompletion_arghint.h" 00032 #include "qeditor_arghint.h" 00033 #include "qeditor_part.h" 00034 #include "qeditor_view.h" 00035 #include "qeditor.h" 00036 00037 #include <qwhatsthis.h> 00038 #include <qtimer.h> 00039 #include <qtooltip.h> 00040 #include <qsizegrip.h> 00041 #include <qapplication.h> 00042 #include <private/qrichtext_p.h> 00043 00044 #include <kdebug.h> 00045 //default size for codecompletionlistbox, value may not be ideal, change later 00046 QSize CCListBox::m_size = QSize(300,200); 00047 00048 static QColor getColor( const QString &type ) 00049 { 00050 // #### should be configurable 00051 if ( type == "function" || type == "slot" ) 00052 return Qt::blue; 00053 if ( type == "variable" ) 00054 return Qt::darkRed; 00055 if ( type == "property" ) 00056 return Qt::darkGreen; 00057 if ( type == "type" ) 00058 return Qt::darkBlue; 00059 return Qt::black; 00060 } 00061 00062 class CompletionItem : public QListBoxItem 00063 { 00064 public: 00065 CompletionItem( QListBox *lb, const KTextEditor::CompletionEntry& entry ) 00066 : QListBoxItem( lb ), parag( 0 ), lastState( FALSE ), m_entry( entry ) 00067 { 00068 m_entry.type = ""; // #### at the moment cppcodecompletion don't fill type in the right way (robe) 00069 setText( m_entry.text ); 00070 } 00071 00072 ~CompletionItem() { delete parag; } 00073 00074 void paint( QPainter *painter ) { 00075 if ( lastState != isSelected() ) { 00076 delete parag; 00077 parag = 0; 00078 } 00079 lastState = isSelected(); 00080 if ( !parag ) 00081 setupParag(); 00082 parag->paint( *painter, listBox()->colorGroup() ); 00083 } 00084 00085 int height( const QListBox * ) const { 00086 if ( !parag ) 00087 ( (CompletionItem*)this )->setupParag(); 00088 return parag->rect().height(); 00089 } 00090 00091 int width( const QListBox * ) const { 00092 if ( !parag ) 00093 ( (CompletionItem*)this )->setupParag(); 00094 return parag->rect().width() - 2; 00095 } 00096 00097 QString text() const { return QListBoxItem::text() + m_entry.postfix; } 00098 00099 private: 00100 void setupParag() { 00101 if ( !parag ) { 00102 QTextFormatter *formatter; 00103 formatter = new QTextFormatterBreakWords; 00104 formatter->setWrapEnabled( FALSE ); 00105 parag = new QTextParagraph( 0 ); 00106 parag->pseudoDocument()->pFormatter = formatter; 00107 parag->insert( 0, " " + m_entry.type + ( m_entry.type.isEmpty() ? " " : "\t" ) + m_entry.prefix + " "+ 00108 QListBoxItem::text() + m_entry.postfix ); 00109 bool selCol = isSelected() && listBox()->colorGroup().highlightedText() != listBox()->colorGroup().text(); 00110 QColor sc = listBox()->colorGroup().highlightedText(); 00111 QTextFormat *f1 = parag->formatCollection()->format( listBox()->font(), selCol ? sc : getColor( m_entry.type ) ); 00112 QTextFormat *f3 = parag->formatCollection()->format( listBox()->font(), isSelected() ? 00113 listBox()->colorGroup().highlightedText() : 00114 listBox()->colorGroup().text() ); 00115 QFont f( listBox()->font() ); 00116 f.setBold( TRUE ); 00117 QTextFormat *f2 = 00118 parag->formatCollection()->format( f, isSelected() ? listBox()->colorGroup().highlightedText() : 00119 listBox()->colorGroup().text() ); 00120 00121 parag->setFormat( 1, m_entry.type.length() + 1, f1 ); 00122 if( m_entry.text.endsWith("(") ){ 00123 parag->setFormat( m_entry.type.length() + 2, 00124 m_entry.prefix.length() + 1 + QListBoxItem::text().length() - 1, 00125 f2 ); 00126 } else { 00127 parag->setFormat( m_entry.type.length() + 2, 00128 m_entry.prefix.length() + 1 + QListBoxItem::text().length(), 00129 f2 ); 00130 } 00131 00132 if ( !m_entry.postfix.isEmpty() ) 00133 parag->setFormat( m_entry.type.length() + 2 + m_entry.prefix.length() + 1 + QListBoxItem::text().length(), 00134 m_entry.postfix.length(), f3 ); 00135 00136 f1->removeRef(); 00137 f2->removeRef(); 00138 f3->removeRef(); 00139 parag->format(); 00140 } 00141 } 00142 00143 public: 00144 QTextParagraph *parag; 00145 bool lastState; 00146 KTextEditor::CompletionEntry m_entry; 00147 }; 00148 00149 00150 QEditorCodeCompletion::QEditorCodeCompletion( QEditorView* view ) 00151 : QObject( view, "QEditor Code Completion" ) 00152 , m_view( view ) 00153 , m_commentLabel( 0 ) 00154 { 00155 m_completionPopup = new QVBox( 0, 0, WType_Popup ); 00156 m_completionPopup->setFrameStyle( QFrame::Box | QFrame::Plain ); 00157 m_completionPopup->setLineWidth( 1 ); 00158 00159 m_completionListBox = new CCListBox( m_completionPopup ); 00160 m_completionListBox->setFrameStyle( QFrame::NoFrame ); 00161 m_completionListBox->installEventFilter( this ); 00162 m_completionListBox->setHScrollBarMode( QScrollView::AlwaysOn ); 00163 m_completionListBox->setVScrollBarMode( QScrollView::AlwaysOn ); 00164 m_completionListBox->setCornerWidget( new QSizeGrip(m_completionListBox) ); 00165 00166 m_completionPopup->installEventFilter( this ); 00167 m_completionPopup->setFocusProxy( m_completionListBox ); 00168 00169 m_pArgHint = new QEditorArgHint( m_view ); 00170 m_view->editor()->installEventFilter( m_pArgHint ); 00171 connect( m_pArgHint, SIGNAL(argHintHidden()), 00172 this, SIGNAL(argHintHidden()) ); 00173 00174 connect( m_view, SIGNAL(cursorPositionChanged()), 00175 this, SLOT(slotCursorPosChanged()) ); 00176 } 00177 00178 void QEditorCodeCompletion::showCompletionBox( 00179 QValueList<KTextEditor::CompletionEntry> complList, int offset, bool casesensitive ) 00180 { 00181 kdDebug(9032) << "showCompletionBox " << endl; 00182 00183 m_caseSensitive = casesensitive; 00184 m_complList = complList; 00185 m_offset = offset; 00186 m_view->cursorPositionReal( &m_lineCursor, &m_colCursor ); 00187 m_colCursor -= offset; 00188 00189 updateBox( true ); 00190 } 00191 00192 bool QEditorCodeCompletion::eventFilter( QObject *o, QEvent *e ) 00193 { 00194 if ( o != m_completionPopup && 00195 o != m_completionListBox && 00196 o != m_completionListBox->viewport() ) 00197 return false; 00198 00199 if ( e->type() == QEvent::KeyPress ) { 00200 QKeyEvent *ke = (QKeyEvent*)e; 00201 if( (ke->key() == Key_Left) || (ke->key() == Key_Right) || 00202 (ke->key() == Key_Up) || (ke->key() == Key_Down ) || 00203 (ke->key() == Key_Home ) || (ke->key() == Key_End) || 00204 (ke->key() == Key_Prior) || (ke->key() == Key_Next )) { 00205 QTimer::singleShot(0,this,SLOT(showComment())); 00206 return false; 00207 } 00208 if( ke->key() == Key_Enter || ke->key() == Key_Return || 00209 (QEditorSettings::self()->completeWordWithSpace() && (ke->key() == Key_Space || ke->key() == Key_Tab)) ) { 00210 CompletionItem* item = static_cast<CompletionItem*>( 00211 m_completionListBox->item(m_completionListBox->currentItem())); 00212 00213 if( item == 0 ) 00214 return false; 00215 00216 QString text = item->m_entry.text; 00217 QString currentLine = m_view->currentTextLine(); 00218 int len = m_view->cursorColumnReal() - m_colCursor; 00219 QString currentComplText = currentLine.mid(m_colCursor,len); 00220 QString add = text.mid(currentComplText.length()); 00221 if( item->m_entry.postfix == "()" ) 00222 add += "("; 00223 00224 emit filterInsertString(&(item->m_entry),&add); 00225 m_view->insertText(add); 00226 00227 if( QEditorSettings::self()->completeWordWithSpace() ){ 00228 if( ke->key() == Key_Space ) 00229 m_view->insertText( " " ); 00230 else if( ke->key() == Key_Tab ) 00231 m_view->insertText( "\t" ); 00232 } 00233 00234 // HACK: move cursor. This needs to be handled in a clean way 00235 // by the doc/view. 00236 //m_view->setCursorPositionReal( m_lineCursor, m_view->cursorColumnReal() + add.length() ); 00237 00238 complete( item->m_entry ); 00239 m_view->setFocus(); 00240 return false; 00241 } 00242 00243 if( ke->key() == Key_Escape ) { 00244 abortCompletion(); 00245 m_view->setFocus(); 00246 return false; 00247 } 00248 00249 // redirect the event to the editor 00250 QApplication::sendEvent( m_view->editor(), e ); 00251 00252 QString currentLine = m_view->currentTextLine(); 00253 int len = m_view->cursorColumnReal() - m_colCursor; 00254 QString currentComplText = currentLine.mid( m_colCursor, len ); 00255 00256 if( m_colCursor + m_offset > m_view->cursorColumnReal() || 00257 (m_completionListBox->count() == 1 && m_completionListBox->currentText() == currentComplText) ) { 00258 // the cursor is too far left 00259 kdDebug(9032) << "Aborting Codecompletion after sendEvent" << endl; 00260 kdDebug(9032) << m_view->cursorColumnReal() << endl; 00261 abortCompletion(); 00262 m_view->setFocus(); 00263 return true; 00264 } 00265 updateBox(); 00266 return true; 00267 } 00268 00269 if( e->type() == QEvent::FocusOut ) 00270 abortCompletion(); 00271 return false; 00272 } 00273 00274 void QEditorCodeCompletion::abortCompletion() 00275 { 00276 m_completionPopup->hide(); 00277 delete m_commentLabel; 00278 m_commentLabel = 0; 00279 emit completionAborted(); 00280 } 00281 00282 void QEditorCodeCompletion::complete( KTextEditor::CompletionEntry entry ) 00283 { 00284 m_completionPopup->hide(); 00285 delete m_commentLabel; 00286 m_commentLabel = 0; 00287 emit completionDone( entry ); 00288 emit completionDone(); 00289 } 00290 00291 void QEditorCodeCompletion::updateBox( bool newCoordinate ) 00292 { 00293 m_completionListBox->clear(); 00294 00295 QString currentLine = m_view->currentTextLine(); 00296 int len = m_view->cursorColumnReal() - m_colCursor; 00297 QString currentComplText = currentLine.mid(m_colCursor,len); 00298 00299 kdDebug(9032) << "Column: " << m_colCursor << endl; 00300 kdDebug(9032) << "Line: " << currentLine << endl; 00301 kdDebug(9032) << "CurrentColumn: " << m_view->cursorColumnReal() << endl; 00302 kdDebug(9032) << "Len: " << len << endl; 00303 kdDebug(9032) << "Text: " << currentComplText << endl; 00304 kdDebug(9032) << "Count: " << m_complList.count() << endl; 00305 00306 QValueList<KTextEditor::CompletionEntry>::Iterator it; 00307 if( m_caseSensitive ) { 00308 for( it = m_complList.begin(); it != m_complList.end(); ++it ) { 00309 if( (*it).text.startsWith(currentComplText) ) { 00310 new CompletionItem(m_completionListBox,*it); 00311 } 00312 } 00313 } else { 00314 currentComplText = currentComplText.upper(); 00315 for( it = m_complList.begin(); it != m_complList.end(); ++it ) { 00316 if( (*it).text.upper().startsWith(currentComplText) ) { 00317 new CompletionItem(m_completionListBox,*it); 00318 } 00319 } 00320 } 00321 00322 if( m_completionListBox->count() == 0 ) { 00323 abortCompletion(); 00324 m_view->setFocus(); 00325 return; 00326 } 00327 00328 if( newCoordinate ) { 00329 QEditor* curEditor = m_view->editor(); 00330 QTextCursor* cursor = curEditor->textCursor(); 00331 QTextStringChar *chr = cursor->paragraph()->at( cursor->index() ); 00332 int x = cursor->paragraph()->rect().x() + chr->x; 00333 int y, dummy; 00334 int h = cursor->paragraph()->lineHeightOfChar( cursor->index(), &dummy, &y ); 00335 y += cursor->paragraph()->rect().y(); 00336 00337 m_completionPopup->resize( m_completionListBox->sizeHint()+ QSize(2,2)); 00338 00339 QPoint pt = curEditor->contentsToViewport( QPoint(x, y) ); 00340 int yy = curEditor->mapToGlobal( pt ).y() + h + m_completionListBox->height(); 00341 if ( yy < QApplication::desktop()->height() ) 00342 m_completionPopup->move( curEditor->mapToGlobal( curEditor-> 00343 contentsToViewport( QPoint( x, y + h ) ) ) ); 00344 else 00345 m_completionPopup->move( curEditor->mapToGlobal( curEditor-> 00346 contentsToViewport( QPoint( x, y - m_completionPopup->height() ) ) ) ); 00347 } 00348 00349 m_completionListBox->setCurrentItem( 0 ); 00350 m_completionListBox->setSelected( 0, true ); 00351 m_completionListBox->setFocus(); 00352 m_completionPopup->show(); 00353 QTimer::singleShot( 0, this, SLOT(showComment()) ); 00354 } 00355 00356 void QEditorCodeCompletion::showArgHint ( QStringList functionList, 00357 const QString& strWrapping, 00358 const QString& strDelimiter ) 00359 { 00360 unsigned int line, col; 00361 m_view->cursorPositionReal( &line, &col ); 00362 m_pArgHint->reset( line, col ); 00363 00364 m_pArgHint->setArgMarkInfos( "()", "," ); 00365 00366 int nNum = 0; 00367 for( QStringList::Iterator it = functionList.begin(); it != functionList.end(); it++ ) 00368 { 00369 kdDebug(9032) << "Insert function text: " << *it << endl; 00370 00371 m_pArgHint->addFunction ( nNum, ( *it ) ); 00372 00373 nNum++; 00374 } 00375 00376 m_pArgHint->move(m_view->mapToGlobal(m_view->cursorCoordinates())); 00377 m_pArgHint->show(); 00378 } 00379 00380 void QEditorCodeCompletion::slotCursorPosChanged() 00381 { 00382 unsigned int line, col; 00383 m_view->cursorPositionReal( &line, &col ); 00384 m_pArgHint->cursorPositionChanged( m_view, line, col ); 00385 } 00386 00387 void QEditorCodeCompletion::showComment() 00388 { 00389 CompletionItem* item = static_cast<CompletionItem*>(m_completionListBox->item(m_completionListBox->currentItem())); 00390 00391 if( !item ) 00392 return; 00393 if( item->m_entry.comment.isEmpty() ) 00394 return; 00395 00396 delete m_commentLabel; 00397 m_commentLabel = new QEditorCodeCompletionCommentLabel( 0, item->m_entry.comment ); 00398 m_commentLabel->setFont(QToolTip::font()); 00399 m_commentLabel->setPalette(QToolTip::palette()); 00400 00401 QPoint rightPoint = m_completionPopup->mapToGlobal(QPoint(m_completionPopup->width(),0)); 00402 QPoint leftPoint = m_completionPopup->mapToGlobal(QPoint(0,0)); 00403 QDesktopWidget *desktop = QApplication::desktop(); 00404 QRect screen = desktop->screenGeometry( desktop->screenNumber(m_commentLabel) ); 00405 QPoint finalPoint; 00406 if (rightPoint.x()+m_commentLabel->width() > screen.x() + screen.width()) 00407 finalPoint.setX(leftPoint.x()-m_commentLabel->width()); 00408 else 00409 finalPoint.setX(rightPoint.x()); 00410 00411 m_completionListBox->ensureCurrentVisible(); 00412 00413 finalPoint.setY( 00414 m_completionListBox->viewport()->mapToGlobal(m_completionListBox->itemRect( 00415 m_completionListBox->item(m_completionListBox->currentItem())).topLeft()).y()); 00416 00417 m_commentLabel->move(finalPoint); 00418 m_commentLabel->show(); 00419 } 00420 00421 #undef kdDebug 00422
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Oct 6 17:38:56 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003