123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- /*=========================================================================
- Library: CTK
-
- Copyright (c) 2010 Kitware Inc.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.commontk.org/LICENSE
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
-
- =========================================================================*/
- /*=========================================================================
- Program: ParaView
- Module: $RCSfile$
- Copyright (c) 2005-2008 Sandia Corporation, Kitware Inc.
- All rights reserved.
- ParaView is a free software; you can redistribute it and/or modify it
- under the terms of the ParaView license version 1.2.
- See License_v1.2.txt for the full ParaView license.
- A copy of this license can be obtained by contacting
- Kitware Inc.
- 28 Corporate Drive
- Clifton Park, NY 12065
- USA
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR
- CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- =========================================================================*/
- //#include <vtkPython.h> // python first
- // Qt includes
- #include <QCoreApplication>
- #include <QResizeEvent>
- #include <QScrollBar>
- #include <QStringListModel>
- #include <QTextCharFormat>
- #include <QVBoxLayout>
- // PythonQt includes
- #include <PythonQt.h>
- #include <PythonQtObjectPtr.h>
- // CTK includes
- #include <ctkConsoleWidget.h>
- #include <ctkAbstractPythonManager.h>
- #include "ctkPythonShell.h"
- //----------------------------------------------------------------------------
- class ctkPythonShellCompleter : public ctkConsoleWidgetCompleter
- {
- public:
- ctkPythonShellCompleter(ctkPythonShell& p) : Parent(p)
- {
- this->setParent(&p);
- }
- virtual void updateCompletionModel(const QString& completion)
- {
- // Start by clearing the model
- this->setModel(0);
- // Don't try to complete the empty string
- if (completion.isEmpty())
- {
- return;
- }
- // Search backward through the string for usable characters
- QString textToComplete;
- for (int i = completion.length()-1; i >= 0; --i)
- {
- QChar c = completion.at(i);
- if (c.isLetterOrNumber() || c == '.' || c == '_')
- {
- textToComplete.prepend(c);
- }
- else
- {
- break;
- }
- }
- // Split the string at the last dot, if one exists
- QString lookup;
- QString compareText = textToComplete;
- int dot = compareText.lastIndexOf('.');
- if (dot != -1)
- {
- lookup = compareText.mid(0, dot);
- compareText = compareText.mid(dot+1);
- }
- // Lookup python names
- QStringList attrs;
- if (!lookup.isEmpty() || !compareText.isEmpty())
- {
- attrs = Parent.getPythonAttributes(lookup);
- }
- // Initialize the completion model
- if (!attrs.isEmpty())
- {
- this->setCompletionMode(QCompleter::PopupCompletion);
- this->setModel(new QStringListModel(attrs, this));
- this->setCaseSensitivity(Qt::CaseInsensitive);
- this->setCompletionPrefix(compareText.toLower());
- this->popup()->setCurrentIndex(this->completionModel()->index(0, 0));
- }
- }
- ctkPythonShell& Parent;
- };
- /////////////////////////////////////////////////////////////////////////
- // ctkPythonShell::pqImplementation
- struct ctkPythonShell::pqImplementation
- {
- pqImplementation(QWidget* _parent, ctkAbstractPythonManager* pythonManager)
- : Console(_parent), PythonManager(pythonManager)
- {
- }
- //----------------------------------------------------------------------------
- // void initialize(int argc, char* argv[])
- // {
- // // Setup Python's interactive prompts
- // PyObject* ps1 = PySys_GetObject(const_cast<char*>("ps1"));
- // if(!ps1)
- // {
- // PySys_SetObject(const_cast<char*>("ps1"), ps1 = PyString_FromString(">>> "));
- // Py_XDECREF(ps1);
- // }
- //
- // PyObject* ps2 = PySys_GetObject(const_cast<char*>("ps2"));
- // if(!ps2)
- // {
- // PySys_SetObject(const_cast<char*>("ps2"), ps2 = PyString_FromString("... "));
- // Py_XDECREF(ps2);
- // }
- // this->MultilineStatement = false;
- // }
- //----------------------------------------------------------------------------
- ~pqImplementation()
- {
- // this->destroyInterpretor();
- }
- //----------------------------------------------------------------------------
- // void destroyInterpretor()
- // {
- // if (this->Interpreter)
- // {
- // QTextCharFormat format = this->Console.getFormat();
- // format.setForeground(QColor(255, 0, 0));
- // this->Console.setFormat(format);
- // this->Console.printString("\n... restarting ...\n");
- // format.setForeground(QColor(0, 0, 0));
- // this->Console.setFormat(format);
- //
- // this->Interpreter->MakeCurrent();
- //
- // // Restore Python's original stdout and stderr
- // PySys_SetObject(const_cast<char*>("stdout"), PySys_GetObject(const_cast<char*>("__stdout__")));
- // PySys_SetObject(const_cast<char*>("stderr"), PySys_GetObject(const_cast<char*>("__stderr__")));
- // this->Interpreter->ReleaseControl();
- // this->Interpreter->Delete();
- // }
- // this->Interpreter = 0;
- // }
- //----------------------------------------------------------------------------
- void executeCommand(const QString& command)
- {
- // this->MultilineStatement =
- // this->Interpreter->Push(Command.toAscii().data());
- if (command.length())
- {
- Q_ASSERT(this->PythonManager);
- this->PythonManager->executeString(command);
- }
- }
-
- //----------------------------------------------------------------------------
- void promptForInput(const QString& indent=QString())
- {
- QTextCharFormat format = this->Console.getFormat();
- format.setForeground(QColor(0, 0, 0));
- this->Console.setFormat(format);
- // this->Interpreter->MakeCurrent();
- if(!this->MultilineStatement)
- {
- this->Console.prompt(">>> ");
- //this->Console.prompt(
- // PyString_AsString(PySys_GetObject(const_cast<char*>("ps1"))));
- }
- else
- {
- this->Console.prompt("... ");
- //this->Console.prompt(
- // PyString_AsString(PySys_GetObject(const_cast<char*>("ps2"))));
- }
- this->Console.printCommand(indent);
- // this->Interpreter->ReleaseControl();
- }
- /// Provides a console for gathering user input and displaying
- /// Python output
- ctkConsoleWidget Console;
- ctkAbstractPythonManager* PythonManager;
- /// Indicates if the last statement processes was incomplete.
- bool MultilineStatement;
- };
- /////////////////////////////////////////////////////////////////////////
- // ctkPythonShell
- //----------------------------------------------------------------------------
- ctkPythonShell::ctkPythonShell(ctkAbstractPythonManager* pythonManager, QWidget* _parent):
- Superclass(_parent),
- Implementation(new pqImplementation(this, pythonManager))
- {
- // Layout UI
- QVBoxLayout* const boxLayout = new QVBoxLayout(this);
- boxLayout->setMargin(0);
- boxLayout->addWidget(&this->Implementation->Console);
- this->setObjectName("pythonShell");
- ctkPythonShellCompleter* completer = new ctkPythonShellCompleter(*this);
- this->Implementation->Console.setCompleter(completer);
-
- QObject::connect(
- &this->Implementation->Console, SIGNAL(executeCommand(const QString&)),
- this, SLOT(onExecuteCommand(const QString&)));
- // The call to mainContext() ensures that python has been initialized.
- Q_ASSERT(this->Implementation->PythonManager);
- this->Implementation->PythonManager->mainContext();
- QTextCharFormat format = this->Implementation->Console.getFormat();
- format.setForeground(QColor(0, 0, 255));
- this->Implementation->Console.setFormat(format);
- this->Implementation->Console.printString(
- QString("Python %1 on %2\n").arg(Py_GetVersion()).arg(Py_GetPlatform()));
- this->promptForInput();
- Q_ASSERT(PythonQt::self());
- this->connect(PythonQt::self(), SIGNAL(pythonStdOut(const QString&)),
- SLOT(printStdout(const QString&)));
- this->connect(PythonQt::self(), SIGNAL(pythonStdErr(const QString&)),
- SLOT(printStderr(const QString&)));
- }
- //----------------------------------------------------------------------------
- ctkPythonShell::~ctkPythonShell()
- {
- delete this->Implementation;
- }
- //----------------------------------------------------------------------------
- void ctkPythonShell::clear()
- {
- this->Implementation->Console.clear();
- this->Implementation->promptForInput();
- }
- // //----------------------------------------------------------------------------
- // void ctkPythonShell::makeCurrent()
- // {
- // this->Implementation->Interpreter->MakeCurrent();
- // }
- //
- // //----------------------------------------------------------------------------
- // void ctkPythonShell::releaseControl()
- // {
- // this->Implementation->Interpreter->ReleaseControl();
- // }
- //----------------------------------------------------------------------------
- void ctkPythonShell::executeScript(const QString& script)
- {
- Q_UNUSED(script);
-
- this->printStdout("\n");
- emit this->executing(true);
- // this->Implementation->Interpreter->RunSimpleString(
- // script.toAscii().data());
- emit this->executing(false);
- this->Implementation->promptForInput();
- }
- //----------------------------------------------------------------------------
- QStringList ctkPythonShell::getPythonAttributes(const QString& pythonVariableName)
- {
- // this->makeCurrent();
- Q_ASSERT(PyThreadState_GET()->interp);
- PyObject* dict = PyImport_GetModuleDict();
- PyObject* object = PyDict_GetItemString(dict, "__main__");
- Py_INCREF(object);
- if (!pythonVariableName.isEmpty())
- {
- QStringList tmpNames = pythonVariableName.split('.');
- for (int i = 0; i < tmpNames.size() && object; ++i)
- {
- QByteArray tmpName = tmpNames.at(i).toLatin1();
- PyObject* prevObj = object;
- if (PyDict_Check(object))
- {
- object = PyDict_GetItemString(object, tmpName.data());
- Py_XINCREF(object);
- }
- else
- {
- object = PyObject_GetAttrString(object, tmpName.data());
- }
- Py_DECREF(prevObj);
- }
- PyErr_Clear();
- }
- QStringList results;
- if (object)
- {
- PyObject* keys = PyObject_Dir(object);
- if (keys)
- {
- PyObject* key;
- PyObject* value;
- QString keystr;
- int nKeys = PyList_Size(keys);
- for (int i = 0; i < nKeys; ++i)
- {
- key = PyList_GetItem(keys, i);
- value = PyObject_GetAttr(object, key);
- if (!value)
- {
- continue;
- }
- results << PyString_AsString(key);
- Py_DECREF(value);
- }
- Py_DECREF(keys);
- }
- Py_DECREF(object);
- }
- // this->releaseControl();
- return results;
- }
- //----------------------------------------------------------------------------
- void ctkPythonShell::printStdout(const QString& text)
- {
- QTextCharFormat format = this->Implementation->Console.getFormat();
- format.setForeground(QColor(0, 150, 0));
- this->Implementation->Console.setFormat(format);
-
- this->Implementation->Console.printString(text);
-
- QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
- }
- //----------------------------------------------------------------------------
- void ctkPythonShell::printMessage(const QString& text)
- {
- QTextCharFormat format = this->Implementation->Console.getFormat();
- format.setForeground(QColor(0, 0, 150));
- this->Implementation->Console.setFormat(format);
-
- this->Implementation->Console.printString(text);
- }
- //----------------------------------------------------------------------------
- void ctkPythonShell::printStderr(const QString& text)
- {
- QTextCharFormat format = this->Implementation->Console.getFormat();
- format.setForeground(QColor(255, 0, 0));
- this->Implementation->Console.setFormat(format);
-
- this->Implementation->Console.printString(text);
-
- QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
- }
- //----------------------------------------------------------------------------
- void ctkPythonShell::onExecuteCommand(const QString& Command)
- {
- QString command = Command;
- command.replace(QRegExp("\\s*$"), "");
- this->internalExecuteCommand(command);
- // Find the indent for the command.
- QRegExp regExp("^(\\s+)");
- QString indent;
- if (regExp.indexIn(command) != -1)
- {
- indent = regExp.cap(1);
- }
- this->Implementation->promptForInput(indent);
- }
- //----------------------------------------------------------------------------
- void ctkPythonShell::promptForInput()
- {
- this->Implementation->promptForInput();
- }
- //----------------------------------------------------------------------------
- void ctkPythonShell::internalExecuteCommand(const QString& command)
- {
- emit this->executing(true);
- this->Implementation->executeCommand(command);
- emit this->executing(false);
- }
|