Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "toonzqt/expressionfield.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "texpression.h"
Toshihiro Shimizu 890ddd
#include "tparser.h"
Toshihiro Shimizu 890ddd
#include "tconvert.h"
Toshihiro Shimizu 890ddd
#include <qsyntaxhighlighter></qsyntaxhighlighter>
Toshihiro Shimizu 890ddd
#include <qcompleter></qcompleter>
Toshihiro Shimizu 890ddd
#include <qkeyevent></qkeyevent>
Toshihiro Shimizu 890ddd
#include <qabstractitemview></qabstractitemview>
Toshihiro Shimizu 890ddd
#include <qscrollbar></qscrollbar>
Toshihiro Shimizu 890ddd
#include <qstringlistmodel></qstringlistmodel>
Toshihiro Shimizu 890ddd
#include <qstandarditemmodel></qstandarditemmodel>
Toshihiro Shimizu 890ddd
#include <qstandarditem></qstandarditem>
Toshihiro Shimizu 890ddd
#include <qtooltip></qtooltip>
Toshihiro Shimizu 890ddd
#include <qlistview></qlistview>
Toshihiro Shimizu 890ddd
#include <qlabel></qlabel>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
using namespace DVGui;
Toshihiro Shimizu 890ddd
using namespace TSyntax;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class ExpressionField::SyntaxHighlighter : public QSyntaxHighlighter
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	const Grammar *m_grammar;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	bool m_open;
Toshihiro Shimizu 890ddd
	SyntaxHighlighter(QTextDocument *parent)
Toshihiro Shimizu 890ddd
		: QSyntaxHighlighter(parent), m_grammar(0), m_open(true)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	~SyntaxHighlighter()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void setGrammar(const Grammar *grammar) { m_grammar = grammar; }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	void highlightBlock(const QString &text)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		Parser parser(m_grammar);
Toshihiro Shimizu 890ddd
		std::vector<syntaxtoken> tokens;</syntaxtoken>
Toshihiro Shimizu 890ddd
		Parser::SyntaxStatus status = parser.checkSyntax(tokens, text.toStdString());
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		int nextPos = 0;
Toshihiro Shimizu 890ddd
		for (int i = 0; i < (int)tokens.size(); i++) {
Toshihiro Shimizu 890ddd
			QTextCharFormat fmt;
Toshihiro Shimizu 890ddd
			int pos = tokens[i].m_pos;
Toshihiro Shimizu 890ddd
			int length = tokens[i].m_length;
Toshihiro Shimizu 890ddd
			int type = tokens[i].m_type;
Toshihiro Shimizu 890ddd
			nextPos = pos + length;
Toshihiro Shimizu 890ddd
			switch (type) {
Toshihiro Shimizu 890ddd
			case TSyntax::Unknown:
Toshihiro Shimizu 890ddd
				fmt.setForeground(Qt::black);
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			case TSyntax::Number:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(0x50, 0x7d, 0x0));
Toshihiro Shimizu 890ddd
				break; // number
Toshihiro Shimizu 890ddd
			case TSyntax::Constant:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(0x50, 0x7d, 0x0));
Toshihiro Shimizu 890ddd
				break; // constant
Toshihiro Shimizu 890ddd
			case TSyntax::Variable:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(0x0, 0x88, 0xc8));
Toshihiro Shimizu 890ddd
				break; // var
Toshihiro Shimizu 890ddd
			case TSyntax::Operator:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(50, 0, 255));
Toshihiro Shimizu 890ddd
				break; // infix
Toshihiro Shimizu 890ddd
			case TSyntax::Parenthesis:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(50, 50, 255));
Toshihiro Shimizu 890ddd
				break; // braket
Toshihiro Shimizu 890ddd
			case TSyntax::Function:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(0x0, 0x50, 0x7d));
Toshihiro Shimizu 890ddd
				break; // fname
Toshihiro Shimizu 890ddd
			case TSyntax::Comma:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(50, 20, 255));
Toshihiro Shimizu 890ddd
				break; // f ;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			case TSyntax::UnexpectedToken:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(0xdc, 0x0, 0x0));
Toshihiro Shimizu 890ddd
				break; // expression not found
Toshihiro Shimizu 890ddd
			case TSyntax::Eos:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(255, 127, 0));
Toshihiro Shimizu 890ddd
				break; //  EOS
Toshihiro Shimizu 890ddd
			case TSyntax::Mismatch:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(255, 0, 0));
Toshihiro Shimizu 890ddd
				break; // token mismatch
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
			default:
Toshihiro Shimizu 890ddd
				fmt.setForeground(QColor(127, 127, 255));
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			}
Toshihiro Shimizu 890ddd
			if (type == 4)
Toshihiro Shimizu 890ddd
				fmt.setToolTip("Infix");
Toshihiro Shimizu 890ddd
			if (length == 0)
Toshihiro Shimizu 890ddd
				length = 1;
Toshihiro Shimizu 890ddd
			setFormat(pos, length, fmt);
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
class MyListView : public QListView
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QLabel *m_tooltip;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
public:
Toshihiro Shimizu 890ddd
	MyListView() : QListView()
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		setObjectName("SuggestionPopup");
Toshihiro Shimizu 890ddd
		setStyleSheet("#SuggestionPopup {background-color:#FFFFFF; border:1px solid black;}");
Toshihiro Shimizu 890ddd
		setWindowFlags(Qt::Popup);
Toshihiro Shimizu 890ddd
		setMouseTracking(true);
Toshihiro Shimizu 890ddd
		m_tooltip = new QLabel(0, Qt::ToolTip);
Toshihiro Shimizu 890ddd
		//Stesso stile del popuop che lo contiene.
Toshihiro Shimizu 890ddd
		m_tooltip->hide();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		m_tooltip->setObjectName("helpTooltip");
Toshihiro Shimizu 890ddd
		m_tooltip->setAlignment(Qt::AlignLeft);
Toshihiro Shimizu 890ddd
		m_tooltip->setIndent(1);
Toshihiro Shimizu 890ddd
		m_tooltip->setWordWrap(false);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void showEvent(QShowEvent *)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		showToolTip(currentIndex());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void hideEvent(QHideEvent *)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		m_tooltip->hide();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void currentChanged(const QModelIndex ¤t, const QModelIndex &previous)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		showToolTip(current);
Toshihiro Shimizu 890ddd
		QListView::currentChanged(current, previous);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	void showToolTip(const QModelIndex &index)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		if (!index.isValid()) {
Toshihiro Shimizu 890ddd
			m_tooltip->hide();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		QVariant data = model()->data(index, Qt::ToolTipRole);
Toshihiro Shimizu 890ddd
		if (!data.isValid()) {
Toshihiro Shimizu 890ddd
			m_tooltip->hide();
Toshihiro Shimizu 890ddd
			return;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		QRect rect = visualRect(index);
Toshihiro Shimizu 890ddd
		m_tooltip->setText(data.toString());
Toshihiro Shimizu 890ddd
		QPoint pos = viewport()->mapToGlobal(QPoint(-m_tooltip->sizeHint().width(), rect.top()));
Toshihiro Shimizu 890ddd
		m_tooltip->setGeometry(QRect(pos, m_tooltip->sizeHint()));
Toshihiro Shimizu 890ddd
		m_tooltip->show();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
protected:
Toshihiro Shimizu 890ddd
	void resizeEvent(QResizeEvent *e)
Toshihiro Shimizu 890ddd
	{
Toshihiro Shimizu 890ddd
		QListView::resizeEvent(e);
Toshihiro Shimizu 890ddd
		if (m_tooltip->isVisible())
Toshihiro Shimizu 890ddd
			showToolTip(currentIndex());
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
};
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ExpressionField::ExpressionField(QWidget *parent)
Toshihiro Shimizu 890ddd
	: QTextEdit(parent), m_editing(false), m_grammar(0), m_syntaxHighlighter(0), m_completerPopup(0), m_completerStartPos(0)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setFrameStyle(QFrame::StyledPanel);
Toshihiro Shimizu 890ddd
	setObjectName("ExpressionField");
Toshihiro Shimizu 890ddd
	setLineWrapMode(NoWrap);
Toshihiro Shimizu 890ddd
	setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Toshihiro Shimizu 890ddd
	setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
Toshihiro Shimizu 890ddd
	setTabChangesFocus(true);
Toshihiro Shimizu 890ddd
	// setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Fixed));
Toshihiro Shimizu 890ddd
	connect(this, SIGNAL(textChanged()), this, SLOT(onTextChanged()));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#ifdef MACOSX
Toshihiro Shimizu 890ddd
	setFixedHeight(23);
Toshihiro Shimizu 890ddd
#else
Toshihiro Shimizu 890ddd
	setFixedHeight(20); // +40);
Toshihiro Shimizu 890ddd
#endif
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_completerPopup = new MyListView();
Toshihiro Shimizu 890ddd
	QStandardItemModel *model = new QStandardItemModel();
Toshihiro Shimizu 890ddd
	m_completerPopup->setModel(model);
Toshihiro Shimizu 890ddd
	m_completerPopup->setFocusPolicy(Qt::NoFocus);
Toshihiro Shimizu 890ddd
	m_completerPopup->setFocusProxy(this);
Toshihiro Shimizu 890ddd
	m_completerPopup->installEventFilter(this);
Toshihiro Shimizu 890ddd
	connect(
Toshihiro Shimizu 890ddd
		m_completerPopup, SIGNAL(clicked(const QModelIndex &)),
Toshihiro Shimizu 890ddd
		this, SLOT(insertCompletion(const QModelIndex &)));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	m_syntaxHighlighter = new SyntaxHighlighter(document());
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
ExpressionField::~ExpressionField()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	delete m_syntaxHighlighter;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::showEvent(QShowEvent *e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QTextEdit::showEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::hideEvent(QHideEvent *e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	QTextEdit::hideEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::setExpression(string expression)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	setPlainText(QString::fromStdString(expression));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
string ExpressionField::getExpression() const
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	return toPlainText().toStdString();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ExpressionField::event(QEvent *e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (e->type() == QEvent::ToolTip) {
Toshihiro Shimizu 890ddd
		QHelpEvent *helpEvent = static_cast<qhelpevent *="">(e);</qhelpevent>
Toshihiro Shimizu 890ddd
		// openCompletionPopup();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	} else if (e->type() == QEvent::ShortcutOverride) {
Toshihiro Shimizu 890ddd
		e->accept();
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	//else
Toshihiro Shimizu 890ddd
	return QTextEdit::event(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::keyPressEvent(QKeyEvent *e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	// setStyleSheet("background-color: cyan");
Toshihiro Shimizu 890ddd
	if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
Toshihiro Shimizu 890ddd
		m_editing = false;
Toshihiro Shimizu 890ddd
		emit expressionChanged();
Toshihiro Shimizu 890ddd
	} else if (e->key() == Qt::Key_F10) {
Toshihiro Shimizu 890ddd
		setAutoFillBackground(true);
Toshihiro Shimizu 890ddd
		QPalette p = palette();
Toshihiro Shimizu 890ddd
		p.setColor(QPalette::Base, Qt::cyan);
Toshihiro Shimizu 890ddd
		p.setColor(QPalette::Background, Qt::cyan);
Toshihiro Shimizu 890ddd
		setPalette(p);
Toshihiro Shimizu 890ddd
		update();
Toshihiro Shimizu 890ddd
		setStyleSheet("#ExpressionField {background-color:cyan;}");
Toshihiro Shimizu 890ddd
	} else if (e->key() == Qt::Key_F11) {
Toshihiro Shimizu 890ddd
		m_completerPopup->installEventFilter(this);
Toshihiro Shimizu 890ddd
		QRect cr = cursorRect();
Toshihiro Shimizu 890ddd
		QSize size(100, 200);
Toshihiro Shimizu 890ddd
		QPoint pos = mapToGlobal(QPoint(cr.left(), cr.top() - size.height()));
Toshihiro Shimizu 890ddd
		m_completerPopup->setGeometry(QRect(pos, size));
Toshihiro Shimizu 890ddd
		m_completerPopup->show();
Toshihiro Shimizu 890ddd
		QTextEdit::keyPressEvent(e);
Toshihiro Shimizu 890ddd
	} else {
Toshihiro Shimizu 890ddd
		QTextEdit::keyPressEvent(e);
Toshihiro Shimizu 890ddd
		if (m_completerPopup->isVisible()) {
Toshihiro Shimizu 890ddd
			updateCompleterPopup();
Toshihiro Shimizu 890ddd
		} else if (Qt::Key_A <= e->key() && e->key() <= Qt::Key_Z || string("+&|!*/=?,:-").find(e->key()) != string::npos) {
Toshihiro Shimizu 890ddd
			openCompleterPopup();
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
		setFocus();
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ExpressionField::eventFilter(QObject *obj, QEvent *e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (e->type() == QEvent::KeyPress) {
Toshihiro Shimizu 890ddd
		QKeyEvent *keyEvent = static_cast<qkeyevent *="">(e);</qkeyevent>
Toshihiro Shimizu 890ddd
		switch (keyEvent->key()) {
Toshihiro Shimizu 890ddd
		case Qt::Key_Return:
Toshihiro Shimizu 890ddd
		case Qt::Key_Enter:
Toshihiro Shimizu 890ddd
			insertCompletion(m_completerPopup->currentIndex());
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		case Qt::Key_Left:
Toshihiro Shimizu 890ddd
		case Qt::Key_Right:
Toshihiro Shimizu 890ddd
			event(keyEvent);
Toshihiro Shimizu 890ddd
			m_completerPopup->hide();
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		case Qt::Key_Escape:
Toshihiro Shimizu 890ddd
			m_completerPopup->hide();
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		case Qt::Key_Down:
Toshihiro Shimizu 890ddd
		case Qt::Key_Up:
Toshihiro Shimizu 890ddd
			return false;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		default:
Toshihiro Shimizu 890ddd
			event(e);
Toshihiro Shimizu 890ddd
			return true;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	} else if (e->type() == QEvent::MouseButtonPress) {
Toshihiro Shimizu 890ddd
		m_completerPopup->hide();
Toshihiro Shimizu 890ddd
		event(e);
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	} else if (e->type() == QEvent::ShortcutOverride) {
Toshihiro Shimizu 890ddd
		e->accept();
Toshihiro Shimizu 890ddd
		return true;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	return QObject::eventFilter(obj, e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::onTextChanged()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	if (!m_editing) {
Toshihiro Shimizu 890ddd
		m_editing = true;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		// setStyleSheet("background: rgb(250,200,200)");
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::focusInEvent(QFocusEvent *e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_syntaxHighlighter->m_open = true;
Toshihiro Shimizu 890ddd
	m_syntaxHighlighter->rehighlight();
Toshihiro Shimizu 890ddd
	QTextEdit::focusInEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::focusOutEvent(QFocusEvent *e)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_syntaxHighlighter->m_open = false;
Toshihiro Shimizu 890ddd
	m_syntaxHighlighter->rehighlight();
Toshihiro Shimizu 890ddd
	QTextEdit::focusOutEvent(e);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::onCursorPositionChanged()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::openCompleterPopup()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int n = computeSuggestions();
Toshihiro Shimizu 890ddd
	if (n < 2)
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	if (updateCompleterPopup())
Toshihiro Shimizu 890ddd
		m_completerPopup->show();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
bool ExpressionField::updateCompleterPopup()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	int start = m_completerStartPos;
Toshihiro Shimizu 890ddd
	int pos = textCursor().position();
Toshihiro Shimizu 890ddd
	string text = getExpression();
Toshihiro Shimizu 890ddd
	if (m_suggestions.empty() || start < 0 || start > pos || pos > (int)text.length()) {
Toshihiro Shimizu 890ddd
		if (m_completerPopup->isVisible())
Toshihiro Shimizu 890ddd
			m_completerPopup->hide();
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QStandardItemModel *model = new QStandardItemModel();
Toshihiro Shimizu 890ddd
	string prefix = toLower(text.substr(start, pos - start));
Toshihiro Shimizu 890ddd
	int prefixLength = prefix.length();
Toshihiro Shimizu 890ddd
	int count = 0;
Toshihiro Shimizu 890ddd
	for (int i = 0; i < (int)m_suggestions.size(); i++) {
Toshihiro Shimizu 890ddd
		string item = m_suggestions[i].first;
Toshihiro Shimizu 890ddd
		if ((int)item.length() >= prefixLength && toLower(item.substr(0, prefixLength)) == prefix) {
Toshihiro Shimizu 890ddd
			QStandardItem *item = new QStandardItem();
Toshihiro Shimizu 890ddd
			item->setData(QString::fromStdString(m_suggestions[i].first), Qt::EditRole);
Toshihiro Shimizu 890ddd
			if (m_suggestions[i].second != "")
Toshihiro Shimizu 890ddd
				item->setData(QString::fromStdString(m_suggestions[i].second), Qt::ToolTipRole);
Toshihiro Shimizu 890ddd
			model->appendRow(item);
Toshihiro Shimizu 890ddd
			count++;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (count == 0) {
Toshihiro Shimizu 890ddd
		if (m_completerPopup->isVisible())
Toshihiro Shimizu 890ddd
			m_completerPopup->hide();
Toshihiro Shimizu 890ddd
		return false;
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_completerPopup->setModel(model);
Toshihiro Shimizu 890ddd
	m_completerPopup->setCurrentIndex(model->index(0, 0));
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QTextCursor cursor(textCursor());
Toshihiro Shimizu 890ddd
	cursor.setPosition(m_completerStartPos);
Toshihiro Shimizu 890ddd
	QRect cr = cursorRect(cursor);
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	int w = m_completerPopup->sizeHintForColumn(0) + m_completerPopup->verticalScrollBar()->sizeHint().width() + 5;
Toshihiro Shimizu 890ddd
	int h = (m_completerPopup->sizeHintForRow(0) * qMin(7, model->rowCount()) + 3) + 3;
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	QSize size(w, h);
Toshihiro Shimizu 890ddd
	QPoint popupPos = mapToGlobal(QPoint(cr.left(), cr.bottom() + 3));
Toshihiro Shimizu 890ddd
	m_completerPopup->setGeometry(QRect(popupPos, size));
Toshihiro Shimizu 890ddd
	return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
int ExpressionField::computeSuggestions()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_completerStartPos = -1;
Toshihiro Shimizu 890ddd
	m_suggestions.clear();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
	string text = getExpression();
Toshihiro Shimizu 890ddd
	int pos = textCursor().position();
Toshihiro Shimizu 890ddd
	int start = pos;
Toshihiro Shimizu 890ddd
	if (start > 0) {
Toshihiro Shimizu 890ddd
		start--;
Toshihiro Shimizu 890ddd
		while (start > 0) {
Toshihiro Shimizu 890ddd
			char c = text[start - 1];
Toshihiro Shimizu 890ddd
			if (isascii(c) && isalpha(c) || c == '_' || c == '.' && (start - 2 < 0 || isascii(text[start - 2]) && isalpha(text[start - 2]))) {
Toshihiro Shimizu 890ddd
			} else
Toshihiro Shimizu 890ddd
				break;
Toshihiro Shimizu 890ddd
			start--;
Toshihiro Shimizu 890ddd
		}
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	if (start >= (int)text.length())
Toshihiro Shimizu 890ddd
		return 0;
Toshihiro Shimizu 890ddd
	m_completerStartPos = start;
Toshihiro Shimizu 890ddd
	text = text.substr(0, start);
Toshihiro Shimizu 890ddd
	TSyntax::Parser parser(m_grammar);
Toshihiro Shimizu 890ddd
	parser.getSuggestions(m_suggestions, text);
Toshihiro Shimizu 890ddd
	return (int)m_suggestions.size();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::insertCompletion()
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (!m_completerPopup->isVisible())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	QModelIndex index = m_completerPopup->currentIndex();
Toshihiro Shimizu 890ddd
	if (!index.isValid())
Toshihiro Shimizu 890ddd
		return;
Toshihiro Shimizu 890ddd
	QString item = m_completerPopup->model()->data(index, Qt::EditRole).toString();
Toshihiro Shimizu 890ddd
	QTextCursor tc = textCursor();
Toshihiro Shimizu 890ddd
	int pos = tc.position();
Toshihiro Shimizu 890ddd
	// tc.movePosition(m_completionStartPos, QTextCursor::KeepAnchor);
Toshihiro Shimizu 890ddd
	tc.insertText(item);
Toshihiro Shimizu 890ddd
	m_completerPopup->hide();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::insertCompletion(const QModelIndex &index)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	if (index.isValid()) {
Toshihiro Shimizu 890ddd
		QString item = m_completerPopup->model()->data(index, Qt::EditRole).toString();
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
		QTextCursor tc = textCursor();
Toshihiro Shimizu 890ddd
		int pos = tc.position();
Toshihiro Shimizu 890ddd
		if (pos - m_completerStartPos >= 1)
Toshihiro Shimizu 890ddd
			tc.movePosition(QTextCursor::Left, QTextCursor::KeepAnchor, pos - m_completerStartPos);
Toshihiro Shimizu 890ddd
		tc.insertText(item);
Toshihiro Shimizu 890ddd
	}
Toshihiro Shimizu 890ddd
	m_completerPopup->hide();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
void ExpressionField::setGrammar(const Grammar *grammar)
Toshihiro Shimizu 890ddd
{
Toshihiro Shimizu 890ddd
	m_grammar = grammar;
Toshihiro Shimizu 890ddd
	m_syntaxHighlighter->setGrammar(grammar);
Toshihiro Shimizu 890ddd
};