Path: blob/devel/ElmerGUI/Application/vtkpost/ecmaconsole.cpp
3203 views
/*****************************************************************************1* *2* Elmer, A Finite Element Software for Multiphysical Problems *3* *4* Copyright 1st April 1995 - , CSC - IT Center for Science Ltd., Finland *5* *6* This program is free software; you can redistribute it and/or *7* modify it under the terms of the GNU General Public License *8* as published by the Free Software Foundation; either version 2 *9* of the License, or (at your option) any later version. *10* *11* This program is distributed in the hope that it will be useful, *12* but WITHOUT ANY WARRANTY; without even the implied warranty of *13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *14* GNU General Public License for more details. *15* *16* You should have received a copy of the GNU General Public License *17* along with this program (in file fem/GPL-2); if not, write to the *18* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, *19* Boston, MA 02110-1301, USA. *20* *21*****************************************************************************/2223/*****************************************************************************24* *25* ElmerGUI ecmaconsole *26* *27* Modified from the PythonQt console by Florian Link / MeVis Research *28* *29*****************************************************************************30* *31* Authors: Mikko Lyly, Juha Ruokolainen and Peter RÃ¥back *32* Email: [email protected] *33* Web: http://www.csc.fi/elmer *34* Address: CSC - IT Center for Science Ltd. *35* Keilaranta 14 *36* 02101 Espoo, Finland *37* *38* Original Date: 15 Mar 2008 *39* *40*****************************************************************************/4142#include "ecmaconsole.h"4344#if WITH_QT5 || WITH_QT645#include <QtWidgets>46#endif47#include <QWidget>48#include <QKeyEvent>49#include <QMouseEvent>50#include <QTextCursor>51#include <QTextBlock>52#include <QMetaObject>53#include <QMetaMethod>54#include <QCompleter>55#include <QStringListModel>56#include <QScrollBar>5758#if WITH_QT659#include <QJSEngine>60#endif6162#include <iostream>63using namespace std;6465EcmaConsole::EcmaConsole(QWidget* parent)66: QTextEdit(parent)67{68prompt = "qs> ";69this->clearHistory();70}7172EcmaConsole::~EcmaConsole()73{74}7576void EcmaConsole::mouseDoubleClickEvent(QMouseEvent* event)77{78event->ignore();79}8081void EcmaConsole::mousePressEvent(QMouseEvent* event)82{83event->ignore();84}8586void EcmaConsole::mouseReleaseEvent(QMouseEvent* event)87{88event->ignore();89}9091void EcmaConsole::keyPressEvent(QKeyEvent* event)92{93if(completer && completer->popup()->isVisible()) {94switch(event->key()) {95case Qt::Key_Return:96if(!completer->popup()->currentIndex().isValid()) {97insertCompletion(completer->currentCompletion());98completer->popup()->hide();99event->accept();100return;101}102event->ignore();103return;104case Qt::Key_Enter:105case Qt::Key_Escape:106case Qt::Key_Tab:107case Qt::Key_Backtab:108event->ignore();109return;110default:111break;112}113}114115bool eventHandled = false;116117switch(event->key()) {118case Qt::Key_Return:119execLine();120eventHandled = true;121break;122123case Qt::Key_Up:124if(historyPtr > 0) {125historyPtr--;126scanHistory();127}128eventHandled = true;129break;130131case Qt::Key_Down:132if(historyPtr < history.count()-1) {133historyPtr++;134scanHistory();135}136eventHandled = true;137break;138139case Qt::Key_Left:140case Qt::Key_Backspace:141case Qt::Key_Backtab:142if(this->textCursor().position() <= getPromptPos())143eventHandled = true;144break;145146default:147break;148}149150if(eventHandled) {151completer->popup()->hide();152event->ignore();153} else {154QTextEdit::keyPressEvent(event);155QString text = event->text();156if(!text.isEmpty()) {157handleTabCompletion();158} else {159completer->popup()->hide();160}161}162}163164int EcmaConsole::getPromptPos()165{166QTextCursor textCursor(this->textCursor());167textCursor.movePosition(QTextCursor::End);168int position = textCursor.block().position() + prompt.length();169return position;170}171172void EcmaConsole::execLine()173{174QTextCursor textCursor = this->textCursor();175textCursor.movePosition(QTextCursor::End);176textCursor.setPosition(getPromptPos());177textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);178QString line = textCursor.selectedText().trimmed();179180if(!line.isEmpty()) {181emit(cmd(line));182history << line;183historyPtr = history.count();184}185186this->append(prompt);187textCursor = this->textCursor();188textCursor.movePosition(QTextCursor::End);189setTextCursor(textCursor);190}191192void EcmaConsole::scanHistory()193{194QTextCursor textCursor = this->textCursor();195textCursor.movePosition(QTextCursor::End);196textCursor.setPosition(getPromptPos(), QTextCursor::KeepAnchor);197textCursor.insertText(history.value(historyPtr));198textCursor.movePosition(QTextCursor::End);199setTextCursor(textCursor);200}201202void EcmaConsole::clearHistory()203{204this->clear();205history.clear();206historyPtr = 0;207this->append(prompt);208}209210void EcmaConsole::addNames(QString className, const QMetaObject* metaObject)211{212QStringList publicSlots;213int methodCount = metaObject->methodCount();214for(int i = 0; i < methodCount; i++) {215QMetaMethod method = metaObject->method(i);216QMetaMethod::Access access = method.access();217QMetaMethod::MethodType methodType = method.methodType();218if((access == QMetaMethod::Public) && (methodType == QMetaMethod::Slot)) {219220#if WITH_QT5 || WITH_QT6221QString signature = method.methodSignature();222#else223QString signature = method.signature();224#endif225int j = signature.indexOf("(");226QString slotName = signature.left(j);227publicSlots << slotName;228}229}230publicSlots.sort();231names.insert(className, publicSlots);232}233234void EcmaConsole::initCompleter()235{236completer = new QCompleter(this);237completer->setWidget(this);238connect(completer, SIGNAL(activated(const QString&)), this, SLOT(insertCompletion(const QString&)));239}240241242void EcmaConsole::handleTabCompletion()243{244QTextCursor textCursor = this->textCursor();245int pos = textCursor.position();246textCursor.setPosition(getPromptPos());247textCursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);248int startPos = textCursor.selectionStart();249250int offset = pos-startPos;251QString text = textCursor.selectedText();252253QString textToComplete;254int cur = offset;255256while(cur--) {257QChar c = text.at(cur);258if(c.isLetterOrNumber() || (c == '.') || (c == '_')) {259textToComplete.prepend(c);260} else {261break;262}263}264265QString lookup;266QString compareText = textToComplete;267int dot = compareText.lastIndexOf('.');268269if(dot != -1) {270lookup = compareText.mid(0, dot);271compareText = compareText.mid(dot+1, offset);272}273274if(!lookup.isEmpty() || !compareText.isEmpty()) {275compareText = compareText.toLower();276QStringList found;277278QStringList list;279if(lookup.isEmpty()) {280// all class names281list = names.keys();282} else {283// methods for a class284list = names.value(lookup);285}286287foreach(QString name, list) {288if(name.toLower().startsWith(compareText))289found << name;290}291292if(!found.isEmpty()) {293completer->setCompletionPrefix(compareText);294completer->setCompletionMode(QCompleter::PopupCompletion);295completer->setModel(new QStringListModel(found, completer));296completer->setCaseSensitivity(Qt::CaseInsensitive);297QTextCursor c = this->textCursor();298c.movePosition(QTextCursor::StartOfWord);299QRect cr = cursorRect(c);300cr.setWidth(completer->popup()->sizeHintForColumn(0)301+ completer->popup()->verticalScrollBar()->sizeHint().width());302cr.translate(0,8);303completer->complete(cr);304} else {305completer->popup()->hide();306}307} else {308completer->popup()->hide();309}310}311312void EcmaConsole::insertCompletion(const QString& completion)313{314QTextCursor tc = textCursor();315tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor);316if (tc.selectedText() == ".") {317tc.insertText(QString(".") + completion);318} else {319tc = textCursor();320tc.movePosition(QTextCursor::StartOfWord, QTextCursor::MoveAnchor);321tc.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);322tc.insertText(completion);323setTextCursor(tc);324}325}326327#if WITH_QT6328template<class... A> QJSValue EcmaConsole::print(A... args)329{330QString result;331332for(char* s : std::initializer_list<char*>{args...}) {333result.append(" ");334result.append(s);335}336append(result.trimmed());337338return QJSValue(QJSValue::UndefinedValue);339}340#endif341342