00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
#include "qeditorcodecompletion.h"
00028
#include "qeditor_settings.h"
00029
#include "qeditorcodecompletion.moc"
00030
00031
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
00046 QSize CCListBox::m_size =
QSize(300,200);
00047
00048 static QColor getColor(
const QString &type )
00049 {
00050
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 =
"";
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
00235
00236
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
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
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