Browse Source

ctkConsole/ctkPythonConsole - Handle standardinput from ctkConsole

PythonQt allows to set a callback function each time the file 'sys.stdin'
is read from.
See PythonQt::self()->setRedirectStdInCallBack(...)

Within ctkConsole, the function readInputLine() ends up being called.

Relying on a custom InputEventLoop, we managed to keep the main thread
event loop running. De facto, input can be obtained from ctkConsole itself.

When reading such input from the console, the color of the text can be
customized using the property "StdinTextColor".

Note also that the callback can be enabled/disabled using
PythonQt::self()->setRedirectStdInCallBackEnabled(true/false)

When disabled, the original stdin file will be restored. Note that the
callback can be re-enabled calling setRedirectStdInCallBackEnabled(true)
Jean-Christophe Fillion-Robin 14 years ago
parent
commit
3492e3e773

+ 3 - 0
Libs/Scripting/Python/Widgets/ctkPythonConsole.cpp

@@ -350,6 +350,9 @@ void ctkPythonConsole::initialize(ctkAbstractPythonManager* newPythonManager)
   this->connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)),
                 d, SLOT(printErrorMessage(const QString&)));
 
+  PythonQt::self()->setRedirectStdInCallBack(
+        ctkConsole::stdInRedirectCallBack, reinterpret_cast<void*>(this));
+
   // Set primary and secondary prompt
   this->setPs1(">>> ");
   this->setPs2("... ");

+ 88 - 3
Libs/Widgets/ctkConsole.cpp

@@ -108,6 +108,7 @@ void ctkConsolePrivate::init()
   this->PromptColor = QColor(0, 0, 0);    // Black
   this->OutputTextColor = QColor(0, 150, 0);  // Green
   this->ErrorTextColor = QColor(255, 0, 0);   // Red
+  this->StdinTextColor = QColor(Qt::darkGray);
   this->CommandTextColor = QColor(0, 0, 150); // Blue
   this->WelcomeTextColor = QColor(0, 0, 255); // Dark Blue
 
@@ -226,6 +227,7 @@ void ctkConsolePrivate::keyPressEvent(QKeyEvent* e)
       {
       text_cursor.setPosition(this->documentEnd());
       this->setTextCursor(text_cursor);
+
       }
 
     switch(e->key())
@@ -298,7 +300,15 @@ void ctkConsolePrivate::keyPressEvent(QKeyEvent* e)
 
         text_cursor.setPosition(this->documentEnd());
         this->setTextCursor(text_cursor);
-        this->internalExecuteCommand();
+
+        if (this->InputEventLoop.isNull())
+          {
+          this->internalExecuteCommand();
+          }
+        else
+          {
+          this->processInput();
+          }
         break;
 
       default:
@@ -315,14 +325,19 @@ void ctkConsolePrivate::keyPressEvent(QKeyEvent* e)
 //-----------------------------------------------------------------------------
 void ctkConsolePrivate::switchToUserInputTextColor(QTextCursor* textCursorToUpdate)
 {
+  QColor color = this->CommandTextColor;
+  if (!this->InputEventLoop.isNull())
+    {
+    color = this->StdinTextColor;
+    }
   QTextCharFormat currentFormat = this->currentCharFormat();
-  currentFormat.setForeground(this->CommandTextColor);
+  currentFormat.setForeground(color);
   this->setCurrentCharFormat(currentFormat);
 
   if (textCursorToUpdate)
     {
     QTextCharFormat textCursorFormat = textCursorToUpdate->charFormat();
-    textCursorFormat.setForeground(this->CommandTextColor);
+    textCursorFormat.setForeground(color);
     textCursorToUpdate->setCharFormat(textCursorFormat);
     }
 }
@@ -363,6 +378,7 @@ void ctkConsolePrivate::scrollToBottom()
   this->verticalScrollBar()->setValue(this->verticalScrollBar()->maximum());
 }
 
+//-----------------------------------------------------------------------------
 void ctkConsolePrivate::updateCompleterIfVisible()
 {
   if (this->Completer && this->Completer->popup()->isVisible())
@@ -505,6 +521,26 @@ void ctkConsolePrivate::internalExecuteCommand()
 }
 
 //-----------------------------------------------------------------------------
+void ctkConsolePrivate::processInput()
+{
+  QString command = this->commandBuffer();
+
+  if (this->EditorHints & ctkConsole::RemoveTrailingSpaces)
+    {
+    command.replace(QRegExp("\\s*$"), ""); // Remove trailing spaces
+    this->commandBuffer() = command; // Update buffer
+    }
+
+  QTextCursor c(this->document());
+  c.movePosition(QTextCursor::End);
+  c.insertText("\n");
+
+  this->InteractivePosition = this->documentEnd();
+
+  this->InputEventLoop->exit();
+}
+
+//-----------------------------------------------------------------------------
 void ctkConsolePrivate::printString(const QString& text)
 {
   this->textCursor().movePosition(QTextCursor::End);
@@ -679,6 +715,10 @@ CTK_GET_CPP(ctkConsole, QColor, errorTextColor, ErrorTextColor);
 CTK_SET_CPP(ctkConsole, const QColor&, setErrorTextColor, ErrorTextColor);
 
 //-----------------------------------------------------------------------------
+CTK_GET_CPP(ctkConsole, QColor, stdinTextColor, StdinTextColor);
+CTK_SET_CPP(ctkConsole, const QColor&, setStdinTextColor, StdinTextColor);
+
+//-----------------------------------------------------------------------------
 CTK_GET_CPP(ctkConsole, QColor, commandTextColor, CommandTextColor);
 CTK_SET_CPP(ctkConsole, const QColor&, setCommandTextColor, CommandTextColor);
 
@@ -780,3 +820,48 @@ void ctkConsole::reset()
   d->promptForInput();
 }
 
+//-----------------------------------------------------------------------------
+QString ctkConsole::stdInRedirectCallBack(void * callData)
+{
+  ctkConsole * self = reinterpret_cast<ctkConsole*>(callData);
+  Q_ASSERT(self);
+  if (!self)
+    {
+    return QLatin1String("");
+    }
+
+  return self->readInputLine();
+}
+
+namespace
+{
+class InputEventLoop : public QEventLoop
+{
+public:
+  InputEventLoop(QApplication * app, QObject * parentObject = 0) :
+    QEventLoop(parentObject), App(app){}
+  virtual bool processEvents(ProcessEventsFlags flags = AllEvents)
+    {
+    this->App->processEvents(flags);
+    return true;
+    }
+  QApplication * App;
+};
+
+}
+
+//-----------------------------------------------------------------------------
+QString ctkConsole::readInputLine()
+{
+  Q_D(ctkConsole);
+
+  d->moveCursor(QTextCursor::End);
+
+  QScopedPointer<InputEventLoop> eventLoop(new InputEventLoop(qApp));
+  d->InputEventLoop = QPointer<QEventLoop>(eventLoop.data());
+
+  eventLoop->exec();
+
+  return d->commandBuffer();
+}
+

+ 11 - 0
Libs/Widgets/ctkConsole.h

@@ -70,6 +70,7 @@ class CTK_WIDGETS_EXPORT ctkConsole : public QWidget
   Q_PROPERTY(QColor promptColor READ promptColor WRITE setPromptColor)
   Q_PROPERTY(QColor outputTextColor READ outputTextColor WRITE setOutputTextColor)
   Q_PROPERTY(QColor errorTextColor READ errorTextColor WRITE setErrorTextColor)
+  Q_PROPERTY(QColor stdinTextColor READ stdinTextColor WRITE setStdinTextColor)
   Q_PROPERTY(QColor commandTextColor READ commandTextColor WRITE setCommandTextColor)
   Q_PROPERTY(QColor welcomeTextColor READ welcomeTextColor WRITE setWelcomeTextColor)
   Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor)
@@ -122,6 +123,11 @@ public:
   /// \sa errorTextColor()
   void setErrorTextColor(const QColor& newColor);
 
+  QColor stdinTextColor()const;
+
+  /// \sa stdinTextColor()
+  void setStdinTextColor(const QColor& newColor);
+
   QColor commandTextColor()const;
 
   /// \sa commandTextColor()
@@ -161,6 +167,8 @@ public:
   /// Set the string used as secondary prompt
   virtual void setPs2(const QString& newPs2);
 
+  static QString stdInRedirectCallBack(void * callData);
+
 signals:
 
   /// This signal emitted before and after a command is executed
@@ -176,6 +184,9 @@ public slots:
 
 protected:
 
+  /// Prompt the user for input
+  QString readInputLine();
+
   /// Called whenever the user enters a command
   virtual void executeCommand(const QString& Command);
 

+ 7 - 0
Libs/Widgets/ctkConsole_p.h

@@ -24,6 +24,7 @@
 // Qt includes
 #include <QTextEdit>
 #include <QPointer>
+#include <QEventLoop>
 
 // CTK includes
 #include "ctkConsole.h"
@@ -78,6 +79,8 @@ public:
   /// Implements command-execution
   void internalExecuteCommand();
 
+  void processInput();
+
   /// Writes the supplied text to the console
   void printString(const QString& text);
 
@@ -144,6 +147,9 @@ public:
   /// Error text color
   QColor ErrorTextColor;
 
+  /// Standard input text color.
+  QColor StdinTextColor;
+
   /// Command text color
   QColor CommandTextColor;
 
@@ -160,6 +166,7 @@ public:
 
   bool ScrollbarAtBottom;
 
+  QPointer<QEventLoop> InputEventLoop;
 };