Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/scriptconsole.h"
Toshihiro Shimizu 890ddd
#include "toonz/scriptengine.h"
Toshihiro Shimizu 890ddd
#include <qkeyevent></qkeyevent>
Toshihiro Shimizu 890ddd
#include <qtextblock></qtextblock>
Toshihiro Shimizu 890ddd
#include <qurl></qurl>
Toshihiro Shimizu 890ddd
#include <qmimedata></qmimedata>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ScriptConsole::ScriptConsole(QWidget *parent)
Shinya Kitaoka 120a6e
    : QTextEdit(parent), m_commandIndex(0) {
shun-iwasawa eec841
  setObjectName("ScriptConsole");
shun-iwasawa eec841
Shinya Kitaoka 120a6e
  m_prompt = ">> ";
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  append(m_prompt);
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::EndOfLine);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  m_engine = new ScriptEngine();
Shinya Kitaoka 120a6e
  connect(m_engine, SIGNAL(evaluationDone()), this, SLOT(onEvaluationDone()));
Shinya Kitaoka 120a6e
  connect(m_engine, SIGNAL(output(int, const QString &)), this,
Shinya Kitaoka 120a6e
          SLOT(output(int, const QString &)));
Shinya Kitaoka 120a6e
  connect(this, SIGNAL(cursorPositionChanged()), this,
Shinya Kitaoka 120a6e
          SLOT(onCursorPositionChanged()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
ScriptConsole::~ScriptConsole() { delete m_engine; }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
void ScriptConsole::keyPressEvent(QKeyEvent *e) {
Shinya Kitaoka 120a6e
  if (e->modifiers() == Qt::ControlModifier && e->key() == Qt::Key_Y) {
Shinya Kitaoka 120a6e
    if (m_engine->isEvaluating()) {
Shinya Kitaoka 120a6e
      m_engine->interrupt();
Shinya Kitaoka 120a6e
      setTextColor(QColor(255, 127, 0));
Shinya Kitaoka 120a6e
      append("Interrupt");
Shinya Kitaoka 120a6e
      moveCursor(QTextCursor::EndOfLine);
Shinya Kitaoka 120a6e
      setTextColor(Qt::black);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  switch (e->key()) {
Shinya Kitaoka 120a6e
  case Qt::Key_Return:
Shinya Kitaoka 120a6e
    onReturnKeyPress();
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case Qt::Key_Up:
Shinya Kitaoka 120a6e
    if (m_commandIndex > 0) {
Shinya Kitaoka 120a6e
      moveCursor(QTextCursor::End);
Shinya Kitaoka 120a6e
      moveCursor(QTextCursor::StartOfBlock);
Shinya Kitaoka 120a6e
      moveCursor(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
Shinya Kitaoka 120a6e
      // the first KeyUp save the current command, possibly not completed yet
Shinya Kitaoka 120a6e
      // note: m_currentCommand is the whole line, containing the prompt
Shinya Kitaoka 120a6e
      if (m_commandIndex == m_commands.count())
Shinya Kitaoka 120a6e
        m_currentCommand = textCursor().selectedText();
Shinya Kitaoka 120a6e
      textCursor().insertText(m_prompt + m_commands[--m_commandIndex]);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case Qt::Key_Down:
Shinya Kitaoka 120a6e
    if (m_commandIndex < m_commands.count()) {
Shinya Kitaoka 120a6e
      moveCursor(QTextCursor::End);
Shinya Kitaoka 120a6e
      moveCursor(QTextCursor::StartOfBlock);
Shinya Kitaoka 120a6e
      moveCursor(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
Shinya Kitaoka 120a6e
      if (m_commandIndex == m_commands.count() - 1) {
Shinya Kitaoka 120a6e
        // the last KeyDown insert back the current command, possibly not
Shinya Kitaoka 120a6e
        // completed yet
Shinya Kitaoka 120a6e
        textCursor().insertText(m_currentCommand);
Shinya Kitaoka 120a6e
        ++m_commandIndex;
Shinya Kitaoka 120a6e
      } else
Shinya Kitaoka 120a6e
        textCursor().insertText(m_prompt + m_commands[++m_commandIndex]);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  case Qt::Key_Backspace:
Shinya Kitaoka 120a6e
  case Qt::Key_Left:
Shinya Kitaoka 120a6e
    if (textCursor().positionInBlock() > 3)
Shinya Kitaoka 120a6e
      QTextEdit::keyPressEvent(e);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      e->ignore();
Shinya Kitaoka 120a6e
    break;
Shinya Kitaoka 120a6e
  default:
Shinya Kitaoka 120a6e
    QTextEdit::keyPressEvent(e);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ScriptConsole::onCursorPositionChanged() {
Shinya Kitaoka 120a6e
  // only the last block (i.e. the current command) is editable
Shinya Kitaoka 120a6e
  setReadOnly(textCursor().block().next().isValid());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
bool ScriptConsole::canInsertFromMimeData(const QMimeData *source) const {
Shinya Kitaoka 120a6e
  if (source->hasText()) {
Shinya Kitaoka 120a6e
    QString text = source->text();
Shinya Kitaoka 120a6e
    if (text.contains("\n"))
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return true;
Shinya Kitaoka 120a6e
  } else if (source->hasUrls() && source->urls().length() == 1) {
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ScriptConsole::insertFromMimeData(const QMimeData *source) {
Shinya Kitaoka 120a6e
  if (canInsertFromMimeData(source)) {
Shinya Kitaoka 120a6e
    if (source->hasText())
Shinya Kitaoka 120a6e
      QTextEdit::insertFromMimeData(source);
Shinya Kitaoka 120a6e
    else if (source->hasUrls() && source->urls().length() == 1) {
Shinya Kitaoka 120a6e
      QUrl url                    = source->urls()[0];
Shinya Kitaoka 120a6e
      QString text                = url.toString();
Shinya Kitaoka 120a6e
      if (url.isLocalFile()) text = url.toLocalFile();
Shinya Kitaoka 120a6e
      text = "\"" + text.replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
Shinya Kitaoka 120a6e
      textCursor().insertText(text);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ScriptConsole::onReturnKeyPress() {
Shinya Kitaoka 120a6e
  int promptLength   = m_prompt.length();
Shinya Kitaoka 120a6e
  QTextCursor cursor = textCursor();
Shinya Kitaoka 120a6e
  cursor.movePosition(QTextCursor::StartOfLine);
Shinya Kitaoka 120a6e
  cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor,
Shinya Kitaoka 120a6e
                      promptLength);
Shinya Kitaoka 120a6e
  cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor);
Shinya Kitaoka 120a6e
  QString command = cursor.selectedText();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QTextCharFormat fmt;
Shinya Kitaoka 120a6e
  fmt.setForeground(QColor(120, 120, 120));
Shinya Kitaoka 120a6e
  cursor.mergeCharFormat(fmt);
Shinya Kitaoka 120a6e
  cursor.clearSelection();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (command.trimmed() != "") {
Shinya Kitaoka 120a6e
    int k = m_commands.indexOf(command);
Shinya Kitaoka 120a6e
    if (k < 0)
Shinya Kitaoka 120a6e
      m_commands.append(command);
Shinya Kitaoka 120a6e
    else if (k <= m_commands.length() - 1) {
Shinya Kitaoka 120a6e
      m_commands.takeAt(k);
Shinya Kitaoka 120a6e
      m_commands.append(command);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
    m_commandIndex = m_commands.count();
Shinya Kitaoka 120a6e
    // m_currentCommand = m_prompt;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::EndOfLine);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (command.trimmed() != "") {
Shinya Kitaoka 120a6e
    append("");
Shinya Kitaoka 120a6e
    cursor.movePosition(QTextCursor::StartOfBlock);
Shinya Kitaoka 120a6e
    m_engine->evaluate(command);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    append("");
Shinya Kitaoka 120a6e
    onEvaluationDone();
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ScriptConsole::onEvaluationDone() {
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::End);
Shinya Kitaoka 120a6e
  setTextColor(Qt::black);
Shinya Kitaoka 120a6e
  textCursor().insertText(m_prompt);
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::EndOfLine);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ScriptConsole::output(int type, const QString &value) {
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::End);
Shinya Kitaoka 120a6e
  if (type == ScriptEngine::ExecutionError ||
Shinya Kitaoka 120a6e
      type == ScriptEngine::SyntaxError) {
Shinya Kitaoka 120a6e
    setTextColor(Qt::red);
Shinya Kitaoka 120a6e
  } else if (type == ScriptEngine::UndefinedEvaluationResult ||
Shinya Kitaoka 120a6e
             type == ScriptEngine::Warning) {
Shinya Kitaoka 120a6e
    setTextColor(QColor(250, 120, 40));
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    setTextColor(QColor(10, 150, 240));
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  textCursor().insertText(value + "\n");
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::EndOfLine);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void ScriptConsole::executeCommand(const QString &cmd) {
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::End);
Shinya Kitaoka 120a6e
  setTextColor(Qt::black);
Shinya Kitaoka 120a6e
  append(m_prompt);
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::EndOfLine);
Shinya Kitaoka 120a6e
  textCursor().insertText(cmd);
Shinya Kitaoka 120a6e
  moveCursor(QTextCursor::EndOfLine);
Shinya Kitaoka 120a6e
  onReturnKeyPress();
Toshihiro Shimizu 890ddd
}