ctkConsoleWidget.cpp
Go to the documentation of this file.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
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 #include <QAbstractItemView>
00054 #include <QApplication>
00055 #include <QClipboard>
00056 #include <QCompleter>
00057 #include <QKeyEvent>
00058 #include <QPointer>
00059 #include <QTextCursor>
00060 #include <QTextEdit>
00061 #include <QVBoxLayout>
00062 #include <QScrollBar>
00063
00064
00065 #include "ctkConsoleWidget.h"
00066
00068
00069
00070 class ctkConsoleWidget::pqImplementation :
00071 public QTextEdit
00072 {
00073 public:
00074 pqImplementation(ctkConsoleWidget& p) :
00075 QTextEdit(&p),
00076 Parent(p),
00077 InteractivePosition(documentEnd())
00078 {
00079 this->setTabChangesFocus(false);
00080 this->setAcceptDrops(false);
00081 this->setAcceptRichText(false);
00082 this->setUndoRedoEnabled(false);
00083
00084 QFont f;
00085 f.setFamily("Courier");
00086 f.setStyleHint(QFont::TypeWriter);
00087 f.setFixedPitch(true);
00088
00089 QTextCharFormat format;
00090 format.setFont(f);
00091 format.setForeground(QColor(0, 0, 0));
00092 this->setCurrentCharFormat(format);
00093
00094 this->CommandHistory.append("");
00095 this->CommandPosition = 0;
00096 }
00097
00098 void keyPressEvent(QKeyEvent* e)
00099 {
00100
00101 if (this->Completer && this->Completer->popup()->isVisible())
00102 {
00103
00104 switch (e->key())
00105 {
00106 case Qt::Key_Enter:
00107 case Qt::Key_Return:
00108 case Qt::Key_Escape:
00109 case Qt::Key_Tab:
00110 case Qt::Key_Backtab:
00111 e->ignore();
00112 return;
00113 default:
00114 break;
00115 }
00116 }
00117
00118 QTextCursor text_cursor = this->textCursor();
00119
00120
00121 const bool selection = text_cursor.anchor() != text_cursor.position();
00122
00123 const bool history_area =
00124 text_cursor.anchor() < this->InteractivePosition
00125 || text_cursor.position() < this->InteractivePosition;
00126
00127
00128 if(e->key() == Qt::Key_C && e->modifiers() == Qt::ControlModifier)
00129 {
00130 if(selection)
00131 {
00132 this->copy();
00133 }
00134
00135 e->accept();
00136 return;
00137 }
00138
00139
00140 if(e->key() == Qt::Key_X && e->modifiers() == Qt::ControlModifier)
00141 {
00142 if(selection && !history_area)
00143 {
00144 this->cut();
00145 }
00146
00147 e->accept();
00148 return;
00149 }
00150
00151
00152 if(e->key() == Qt::Key_V && e->modifiers() == Qt::ControlModifier)
00153 {
00154 if(!history_area)
00155 {
00156 const QMimeData* const clipboard = QApplication::clipboard()->mimeData();
00157 const QString text = clipboard->text();
00158 if(!text.isNull())
00159 {
00160 text_cursor.insertText(text);
00161 this->updateCommandBuffer();
00162 }
00163 }
00164
00165 e->accept();
00166 return;
00167 }
00168
00169
00170 if(history_area && e->key() != Qt::Key_Control)
00171 {
00172 text_cursor.setPosition(this->documentEnd());
00173 this->setTextCursor(text_cursor);
00174 }
00175
00176 switch(e->key())
00177 {
00178 case Qt::Key_Up:
00179 e->accept();
00180 if (this->CommandPosition > 0)
00181 {
00182 this->replaceCommandBuffer(this->CommandHistory[--this->CommandPosition]);
00183 }
00184 break;
00185
00186 case Qt::Key_Down:
00187 e->accept();
00188 if (this->CommandPosition < this->CommandHistory.size() - 2)
00189 {
00190 this->replaceCommandBuffer(this->CommandHistory[++this->CommandPosition]);
00191 }
00192 else
00193 {
00194 this->CommandPosition = this->CommandHistory.size()-1;
00195 this->replaceCommandBuffer("");
00196 }
00197 break;
00198
00199 case Qt::Key_Left:
00200 if (text_cursor.position() > this->InteractivePosition)
00201 {
00202 QTextEdit::keyPressEvent(e);
00203 }
00204 else
00205 {
00206 e->accept();
00207 }
00208 break;
00209
00210
00211 case Qt::Key_Delete:
00212 e->accept();
00213 QTextEdit::keyPressEvent(e);
00214 this->updateCommandBuffer();
00215 break;
00216
00217 case Qt::Key_Backspace:
00218 e->accept();
00219 if(text_cursor.position() > this->InteractivePosition)
00220 {
00221 QTextEdit::keyPressEvent(e);
00222 this->updateCommandBuffer();
00223 this->updateCompleterIfVisible();
00224 }
00225 break;
00226
00227 case Qt::Key_Tab:
00228 e->accept();
00229 this->updateCompleter();
00230 this->selectCompletion();
00231 break;
00232
00233
00234 case Qt::Key_Home:
00235 e->accept();
00236 text_cursor.setPosition(this->InteractivePosition);
00237 this->setTextCursor(text_cursor);
00238 break;
00239
00240 case Qt::Key_Return:
00241 case Qt::Key_Enter:
00242 e->accept();
00243
00244 text_cursor.setPosition(this->documentEnd());
00245 this->setTextCursor(text_cursor);
00246
00247 this->internalExecuteCommand();
00248 break;
00249
00250 default:
00251 e->accept();
00252 QTextEdit::keyPressEvent(e);
00253 this->updateCommandBuffer();
00254 this->updateCompleterIfVisible();
00255 break;
00256 }
00257 }
00258
00260 int documentEnd()
00261 {
00262 QTextCursor c(this->document());
00263 c.movePosition(QTextCursor::End);
00264 return c.position();
00265 }
00266
00267 void focusOutEvent(QFocusEvent *e)
00268 {
00269 QTextEdit::focusOutEvent(e);
00270
00271
00272
00273 this->setFocusPolicy(Qt::WheelFocus);
00274 }
00275
00276 void updateCompleterIfVisible()
00277 {
00278 if (this->Completer && this->Completer->popup()->isVisible())
00279 {
00280 this->updateCompleter();
00281 }
00282 }
00283
00286 void selectCompletion()
00287 {
00288 if (this->Completer && this->Completer->completionCount() == 1)
00289 {
00290 this->Parent.insertCompletion(this->Completer->currentCompletion());
00291 this->Completer->popup()->hide();
00292 }
00293 }
00294
00295 void updateCompleter()
00296 {
00297 if (this->Completer)
00298 {
00299
00300
00301 QTextCursor text_cursor = this->textCursor();
00302 text_cursor.setPosition(this->InteractivePosition, QTextCursor::KeepAnchor);
00303 QString commandText = text_cursor.selectedText();
00304
00305
00306 this->Completer->updateCompletionModel(commandText);
00307
00308
00309 if (this->Completer->completionCount())
00310 {
00311
00312
00313 text_cursor = this->textCursor();
00314 text_cursor.movePosition(QTextCursor::StartOfWord);
00315 QRect cr = this->cursorRect(text_cursor);
00316 cr.translate(0,8);
00317 cr.setWidth(this->Completer->popup()->sizeHintForColumn(0)
00318 + this->Completer->popup()->verticalScrollBar()->sizeHint().width());
00319 this->Completer->complete(cr);
00320 }
00321 else
00322 {
00323 this->Completer->popup()->hide();
00324 }
00325 }
00326 }
00327
00329 void updateCommandBuffer()
00330 {
00331 this->commandBuffer() = this->toPlainText().mid(this->InteractivePosition);
00332 }
00333
00335 void replaceCommandBuffer(const QString& Text)
00336 {
00337 this->commandBuffer() = Text;
00338
00339 QTextCursor c(this->document());
00340 c.setPosition(this->InteractivePosition);
00341 c.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
00342 c.removeSelectedText();
00343 c.insertText(Text);
00344 }
00345
00347 QString& commandBuffer()
00348 {
00349 return this->CommandHistory.back();
00350 }
00351
00353 void internalExecuteCommand()
00354 {
00355
00356
00357
00358 QString command = this->commandBuffer();
00359 if (!command.isEmpty())
00360 {
00361 this->CommandHistory.push_back("");
00362 this->CommandPosition = this->CommandHistory.size() - 1;
00363 }
00364 QTextCursor c(this->document());
00365 c.movePosition(QTextCursor::End);
00366 c.insertText("\n");
00367
00368 this->InteractivePosition = this->documentEnd();
00369 this->Parent.internalExecuteCommand(command);
00370 }
00371
00372 void setCompleter(ctkConsoleWidgetCompleter* completer)
00373 {
00374 if (this->Completer)
00375 {
00376 this->Completer->setWidget(0);
00377 QObject::disconnect(this->Completer, SIGNAL(activated(const QString&)),
00378 &this->Parent, SLOT(insertCompletion(const QString&)));
00379
00380 }
00381 this->Completer = completer;
00382 if (this->Completer)
00383 {
00384 this->Completer->setWidget(this);
00385 QObject::connect(this->Completer, SIGNAL(activated(const QString&)),
00386 &this->Parent, SLOT(insertCompletion(const QString&)));
00387 }
00388 }
00389
00391 ctkConsoleWidget& Parent;
00392
00394 QPointer<ctkConsoleWidgetCompleter> Completer;
00395
00398 int InteractivePosition;
00400 QStringList CommandHistory;
00402 int CommandPosition;
00403 };
00404
00406
00407
00408 ctkConsoleWidget::ctkConsoleWidget(QWidget* Parent) :
00409 QWidget(Parent),
00410 Implementation(new pqImplementation(*this))
00411 {
00412 QVBoxLayout* const l = new QVBoxLayout(this);
00413 l->setMargin(0);
00414 l->addWidget(this->Implementation);
00415 }
00416
00417
00418 ctkConsoleWidget::~ctkConsoleWidget()
00419 {
00420 delete this->Implementation;
00421 }
00422
00423
00424 QTextCharFormat ctkConsoleWidget::getFormat()
00425 {
00426 return this->Implementation->currentCharFormat();
00427 }
00428
00429
00430 void ctkConsoleWidget::setFormat(const QTextCharFormat& Format)
00431 {
00432 this->Implementation->setCurrentCharFormat(Format);
00433 }
00434
00435
00436 void ctkConsoleWidget::setCompleter(ctkConsoleWidgetCompleter* completer)
00437 {
00438 this->Implementation->setCompleter(completer);
00439 }
00440
00441
00442 void ctkConsoleWidget::insertCompletion(const QString& completion)
00443 {
00444 QTextCursor tc = this->Implementation->textCursor();
00445 tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);
00446 if (tc.selectedText()==".")
00447 {
00448 tc.insertText(QString(".") + completion);
00449 }
00450 else
00451 {
00452 tc = this->Implementation->textCursor();
00453 tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);
00454 tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
00455 tc.insertText(completion);
00456 this->Implementation->setTextCursor(tc);
00457 }
00458 this->Implementation->updateCommandBuffer();
00459 }
00460
00461
00462 void ctkConsoleWidget::printString(const QString& Text)
00463 {
00464 this->Implementation->textCursor().movePosition(QTextCursor::End);
00465 this->Implementation->textCursor().insertText(Text);
00466 this->Implementation->InteractivePosition = this->Implementation->documentEnd();
00467 this->Implementation->ensureCursorVisible();
00468 }
00469
00470
00471 void ctkConsoleWidget::printCommand(const QString& cmd)
00472 {
00473 this->Implementation->textCursor().insertText(cmd);
00474 this->Implementation->updateCommandBuffer();
00475 }
00476
00477
00478 void ctkConsoleWidget::prompt(const QString& text)
00479 {
00480 QTextCursor text_cursor = this->Implementation->textCursor();
00481
00482
00483
00484 text_cursor.movePosition(QTextCursor::StartOfLine);
00485 int startpos = text_cursor.position();
00486 text_cursor.movePosition(QTextCursor::EndOfLine);
00487 int endpos = text_cursor.position();
00488 if (endpos != startpos)
00489 {
00490 this->Implementation->textCursor().insertText("\n");
00491 }
00492
00493 this->Implementation->textCursor().insertText(text);
00494 this->Implementation->InteractivePosition = this->Implementation->documentEnd();
00495 this->Implementation->ensureCursorVisible();
00496 }
00497
00498
00499 void ctkConsoleWidget::clear()
00500 {
00501 this->Implementation->clear();
00502
00503
00504
00505 this->Implementation->setFocusPolicy(Qt::WheelFocus);
00506 }
00507
00508
00509 void ctkConsoleWidget::internalExecuteCommand(const QString& Command)
00510 {
00511 emit this->executeCommand(Command);
00512 }