/* edit.cc */ #include "edit.h" #include // #include #if QT_VERSION >= 0x040300 #define QT_4_3 #endif #ifdef QT_4_3 #include #endif /* ---------------------------------------------------------------------- */ class Highlighter : public QSyntaxHighlighter { // Q_OBJECT public: Highlighter (QTextDocument *parent = 0); protected: void highlightBlock (const QString &text); private: struct HighlightingRule { QRegExp pattern; QTextCharFormat format; }; QVector highlightingRules; QRegExp commentStartExpression; QRegExp commentEndExpression; QTextCharFormat keywordFormat; QTextCharFormat classFormat; QTextCharFormat singleLineCommentFormat; QTextCharFormat multiLineCommentFormat; QTextCharFormat quotationFormat; QTextCharFormat functionFormat; }; Highlighter::Highlighter (QTextDocument *parent) : QSyntaxHighlighter (parent) { HighlightingRule rule; keywordFormat.setForeground (Qt::blue); keywordFormat.setFontWeight (QFont::Bold); QStringList keywordPatterns; keywordPatterns << "char" << "class" << "const" << "double" << "enum" << "explicit" << "friend" << "inline" << "int" << "long" << "namespace" << "operator" << "private" << "protected" << "public" << "short" << "signals" << "signed" << "slots" << "static" << "struct" << "template" << "typedef" << "typename" << "union" << "unsigned" << "virtual" << "void" << "volatile" << "function" << "for"; foreach (const QString &pattern, keywordPatterns) { rule.pattern = QRegExp ("\\b" + pattern + "\\b"); rule.format = keywordFormat; highlightingRules.append (rule); } classFormat.setFontWeight (QFont::Bold); classFormat.setForeground (QColor ("darkorange")); rule.pattern = QRegExp ("\\bQ[A-Za-z]+\\b"); rule.format = classFormat; highlightingRules.append (rule); singleLineCommentFormat.setForeground (Qt::red); rule.pattern = QRegExp ("//[^\n]*"); rule.format = singleLineCommentFormat; highlightingRules.append (rule); multiLineCommentFormat.setForeground (Qt::red); quotationFormat.setForeground (Qt::darkGreen); rule.pattern = QRegExp ("\".*\""); rule.format = quotationFormat; highlightingRules.append (rule); functionFormat.setFontItalic (true); functionFormat.setForeground (QColor ("coral")); rule.pattern = QRegExp ("\\b[A-Za-z0-9_]+(?=\\()"); rule.format = functionFormat; highlightingRules.append (rule); commentStartExpression = QRegExp ("/\\*"); commentEndExpression = QRegExp ("\\*/"); } void Highlighter::highlightBlock (const QString &text) { foreach (const HighlightingRule &rule, highlightingRules) { QRegExp expression (rule.pattern); int index = expression.indexIn (text); while (index >= 0) { int length = expression.matchedLength(); setFormat (index, length, rule.format); index = expression.indexIn (text, index + length); } } setCurrentBlockState (0); int startIndex = 0; if (previousBlockState() != 1) startIndex = commentStartExpression.indexIn (text); while (startIndex >= 0) { int endIndex = commentEndExpression.indexIn (text, startIndex); int commentLength; if (endIndex == -1) { setCurrentBlockState (1); commentLength = text.length() - startIndex; } else { commentLength = endIndex - startIndex + commentEndExpression.matchedLength(); } setFormat (startIndex, commentLength, multiLineCommentFormat); startIndex = commentStartExpression.indexIn (text, startIndex + commentLength); } } /* ---------------------------------------------------------------------- */ void MyEdit::setCompleter (QCompleter *completer) { if (c) QObject::disconnect (c, 0, this, 0); c = completer; if (!c) return; c->setWidget (this); c->setCompletionMode (QCompleter::PopupCompletion); c->setCaseSensitivity (Qt::CaseInsensitive); QObject::connect (c, SIGNAL (activated (const QString&)), this, SLOT (insertCompletion (const QString&))); } QCompleter *MyEdit::completer () const { return c; } void MyEdit::insertCompletion (const QString& completion) { if (c->widget() != this) return; QTextCursor tc = textCursor(); int extra = completion.length() - c->completionPrefix().length(); tc.movePosition (QTextCursor::Left); tc.movePosition (QTextCursor::EndOfWord); tc.insertText (completion.right (extra)); setTextCursor (tc); } QString MyEdit::textUnderCursor () const { QTextCursor tc = textCursor(); tc.select (QTextCursor::WordUnderCursor); return tc.selectedText(); } void MyEdit::focusInEvent (QFocusEvent *e) { if (c) c->setWidget (this); QTextEdit::focusInEvent (e); } void MyEdit::keyPressEvent (QKeyEvent *e) { if (c && c->popup()->isVisible()) { // The following keys are forwarded by the completer to the widget switch (e->key()) { case Qt::Key_Enter: case Qt::Key_Return: case Qt::Key_Escape: case Qt::Key_Tab: case Qt::Key_Backtab: e->ignore(); return; // let the completer do default behavior default: break; } } bool isShortcut = ( (e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E if (!c || !isShortcut) // dont process the shortcut when we have a completer QTextEdit::keyPressEvent (e); const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier); if (!c || (ctrlOrShift && e->text().isEmpty())) return; static QString eow ("~!@#$%^&*()_+{}|:\"<>?,./;'[]\\-="); // end of word bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift; QString completionPrefix = textUnderCursor(); if (!isShortcut && (hasModifier || e->text().isEmpty() || completionPrefix.length() < 3 || eow.contains (e->text().right (1)))) { c->popup()->hide(); return; } if (completionPrefix != c->completionPrefix()) { c->setCompletionPrefix (completionPrefix); c->popup()->setCurrentIndex (c->completionModel()->index (0, 0)); } QRect cr = cursorRect(); cr.setWidth (c->popup()->sizeHintForColumn (0) + c->popup()->verticalScrollBar()->sizeHint().width()); c->complete (cr); // popup it up! } /* ---------------------------------------------------------------------- */ void MyEdit::setInfo (QTextEdit * p_info) { info = p_info; } QScriptValue color (QScriptContext * context, QScriptEngine *engine) { QScriptValue s = context->argument(0); return engine->toScriptValue (QColor (s.toString())); } QScriptValue rgb (QScriptContext * context, QScriptEngine * engine) { QScriptValue r = context->argument(0); QScriptValue g = context->argument(1); QScriptValue b = context->argument(2); return engine->toScriptValue (QColor::fromRgb (r.toNumber (), g.toNumber(), b.toNumber())); } void MyEdit::execute () { #ifdef QT_4_3 QScriptEngine engine; QScriptValue infoObject = engine.newQObject (info); engine.globalObject().setProperty ("info", infoObject); QScriptValue colorFunc = engine.newFunction (color); engine.globalObject().setProperty ("color", colorFunc); QScriptValue rgbFunc = engine.newFunction (rgb); engine.globalObject().setProperty ("rgb", rgbFunc); engine.evaluate (this->toPlainText ()); #endif } /* ---------------------------------------------------------------------- */ MyEdit::MyEdit (QWidget* parent) : QTextEdit (parent), c (NULL), info (NULL) { Highlighter * highlighter = new Highlighter (document()); QStringList wordList; wordList << "alpha" << "beta" << "gamma"; QCompleter * completer = new QCompleter (wordList, this); completer->setModelSorting (QCompleter::CaseInsensitivelySortedModel); completer->setCaseSensitivity (Qt::CaseInsensitive); #ifdef QT_4_3 completer->setWrapAround (false); #endif this->setCompleter (completer); /* append ("Hello"); append ("class"); append ("fce ()"); append ("QButton"); append ("\"abc\""); */ append ("// comment"); append ("/* comment */"); append (""); append ("info.append (\"hello\");"); append (""); append ("info.setTextColor (color (\"yellow\"));"); append ("info.append (\"yellow\");"); append (""); append ("info.setTextColor (color (\"orange\"));"); append ("info.append (\"orange\");"); append (""); append ("info.setTextColor (rgb (0, 0, 255));"); append ("info.append (\"blue\");"); append (""); append ("info.setTextColor (color (\"green\"));"); append (""); append ("function print (k)"); append ("{"); append (" info.append (\"Hello \" + k);"); append ("}"); append (""); append ("for ( i = 1; i <= 3; i++)"); append (" print (i);"); } /* ---------------------------------------------------------------------- */ // #include "edit.moc"