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