From df16c1b68723a015c96dd1c66442d2ca310855ef Mon Sep 17 00:00:00 2001
From: Roberto Raggi <roberto.raggi@nokia.com>
Date: Wed, 22 Apr 2009 15:21:04 +0200
Subject: [PATCH] Initial work on the DUI editor-plugin.

---
 src/plugins/duieditor/DuiEditor.mimetypes.xml |   8 +
 src/plugins/duieditor/DuiEditor.pluginspec    |  25 +
 src/plugins/duieditor/duicodecompletion.cpp   | 151 ++++++
 src/plugins/duieditor/duicodecompletion.h     |  43 ++
 src/plugins/duieditor/duieditor.cpp           | 432 ++++++++++++++++++
 src/plugins/duieditor/duieditor.h             | 127 +++++
 src/plugins/duieditor/duieditor.pro           |  29 ++
 .../duieditor/duieditoractionhandler.cpp      | 100 ++++
 .../duieditor/duieditoractionhandler.h        |  58 +++
 src/plugins/duieditor/duieditorconstants.h    |  46 ++
 src/plugins/duieditor/duieditorfactory.cpp    |  83 ++++
 src/plugins/duieditor/duieditorfactory.h      |  73 +++
 src/plugins/duieditor/duieditorplugin.cpp     | 163 +++++++
 src/plugins/duieditor/duieditorplugin.h       |  82 ++++
 src/plugins/duieditor/duihighlighter.cpp      | 110 +++++
 src/plugins/duieditor/duihighlighter.h        |  64 +++
 src/plugins/plugins.pro                       |   5 +
 .../qscripthighlighter/qscripthighlighter.cpp |  11 +-
 .../qscripthighlighter/qscripthighlighter.h   |   4 +
 19 files changed, 1612 insertions(+), 2 deletions(-)
 create mode 100644 src/plugins/duieditor/DuiEditor.mimetypes.xml
 create mode 100644 src/plugins/duieditor/DuiEditor.pluginspec
 create mode 100644 src/plugins/duieditor/duicodecompletion.cpp
 create mode 100644 src/plugins/duieditor/duicodecompletion.h
 create mode 100644 src/plugins/duieditor/duieditor.cpp
 create mode 100644 src/plugins/duieditor/duieditor.h
 create mode 100644 src/plugins/duieditor/duieditor.pro
 create mode 100644 src/plugins/duieditor/duieditoractionhandler.cpp
 create mode 100644 src/plugins/duieditor/duieditoractionhandler.h
 create mode 100644 src/plugins/duieditor/duieditorconstants.h
 create mode 100644 src/plugins/duieditor/duieditorfactory.cpp
 create mode 100644 src/plugins/duieditor/duieditorfactory.h
 create mode 100644 src/plugins/duieditor/duieditorplugin.cpp
 create mode 100644 src/plugins/duieditor/duieditorplugin.h
 create mode 100644 src/plugins/duieditor/duihighlighter.cpp
 create mode 100644 src/plugins/duieditor/duihighlighter.h

diff --git a/src/plugins/duieditor/DuiEditor.mimetypes.xml b/src/plugins/duieditor/DuiEditor.mimetypes.xml
new file mode 100644
index 00000000000..a5e9425e2d5
--- /dev/null
+++ b/src/plugins/duieditor/DuiEditor.mimetypes.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+    <mime-type type="application/x-dui">
+        <sub-class-of type="text/plain"/>
+        <comment>DUI file</comment>
+        <glob pattern="*.dui"/>
+    </mime-type>
+</mime-info>
diff --git a/src/plugins/duieditor/DuiEditor.pluginspec b/src/plugins/duieditor/DuiEditor.pluginspec
new file mode 100644
index 00000000000..989651ddaea
--- /dev/null
+++ b/src/plugins/duieditor/DuiEditor.pluginspec
@@ -0,0 +1,25 @@
+<plugin name="DuiEditor" version="1.1.80" compatVersion="1.1.80">
+    <vendor>Nokia Corporation</vendor>
+    <copyright>(C) 2008-2009 Nokia Corporation</copyright>
+    <license>
+Commercial Usage
+
+Licensees holding valid Qt Commercial licenses may use this plugin in
+accordance with the Qt Commercial License Agreement provided with the
+Software or, alternatively, in accordance with the terms contained in
+a written agreement between you and Nokia.
+
+GNU Lesser General Public License Usage
+
+Alternatively, this plugin may be used under the terms of the GNU Lesser
+General Public License version 2.1 as published by the Free Software
+Foundation.  Please review the following information to
+ensure the GNU Lesser General Public License version 2.1 requirements
+will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
+    <description>Editor for DUI.</description>
+    <url>http://www.qtsoftware.com</url>
+    <dependencyList>
+        <dependency name="Core" version="1.1.80"/>
+        <dependency name="TextEditor" version="1.1.80"/>
+    </dependencyList>
+</plugin>
diff --git a/src/plugins/duieditor/duicodecompletion.cpp b/src/plugins/duieditor/duicodecompletion.cpp
new file mode 100644
index 00000000000..6dbbce8e9d5
--- /dev/null
+++ b/src/plugins/duieditor/duicodecompletion.cpp
@@ -0,0 +1,151 @@
+
+#include "duicodecompletion.h"
+#include "duieditor.h"
+#include <texteditor/basetexteditor.h>
+#include <QtDebug>
+
+using namespace DuiEditor::Internal;
+
+DuiCodeCompletion::DuiCodeCompletion(QObject *parent)
+    : TextEditor::ICompletionCollector(parent),
+      m_editor(0),
+      m_startPosition(0),
+      m_caseSensitivity(Qt::CaseSensitive)
+{ }
+
+DuiCodeCompletion::~DuiCodeCompletion()
+{ }
+
+Qt::CaseSensitivity DuiCodeCompletion::caseSensitivity() const
+{ return m_caseSensitivity; }
+
+void DuiCodeCompletion::setCaseSensitivity(Qt::CaseSensitivity caseSensitivity)
+{ m_caseSensitivity = caseSensitivity; }
+
+bool DuiCodeCompletion::supportsEditor(TextEditor::ITextEditable *editor)
+{
+    if (qobject_cast<ScriptEditor *>(editor->widget()))
+        return true;
+
+    return false;
+}
+
+bool DuiCodeCompletion::triggersCompletion(TextEditor::ITextEditable *)
+{ return false; }
+
+int DuiCodeCompletion::startCompletion(TextEditor::ITextEditable *editor)
+{
+    m_editor = editor;
+
+    ScriptEditor *edit = qobject_cast<ScriptEditor *>(m_editor->widget());
+    if (! edit)
+        return -1;
+
+    int pos = editor->position();
+
+    while (editor->characterAt(pos - 1).isLetterOrNumber() || editor->characterAt(pos - 1) == QLatin1Char('_'))
+        --pos;
+
+    m_startPosition = pos;
+    m_completions.clear();
+
+    foreach (const QString &word, edit->words()) {
+        TextEditor::CompletionItem item(this);
+        item.m_text = word;
+        m_completions.append(item);
+    }
+
+    return pos;
+}
+
+void DuiCodeCompletion::completions(QList<TextEditor::CompletionItem> *completions)
+{
+    // ### FIXME: this code needs to be generalized.
+
+    const int length = m_editor->position() - m_startPosition;
+
+    if (length == 0)
+        *completions = m_completions;
+    else if (length > 0) {
+        const QString key = m_editor->textAt(m_startPosition, length);
+
+        /*
+         * This code builds a regular expression in order to more intelligently match
+         * camel-case style. This means upper-case characters will be rewritten as follows:
+         *
+         *   A => [a-z0-9_]*A (for any but the first capital letter)
+         *
+         * Meaning it allows any sequence of lower-case characters to preceed an
+         * upper-case character. So for example gAC matches getActionController.
+         */
+        QString keyRegExp;
+        keyRegExp += QLatin1Char('^');
+        bool first = true;
+        foreach (const QChar &c, key) {
+            if (c.isUpper() && !first) {
+                keyRegExp += QLatin1String("[a-z0-9_]*");
+                keyRegExp += c;
+            } else if (m_caseSensitivity == Qt::CaseInsensitive && c.isLower()) {
+                keyRegExp += QLatin1Char('[');
+                keyRegExp += c;
+                keyRegExp += c.toUpper();
+                keyRegExp += QLatin1Char(']');
+            } else {
+                keyRegExp += QRegExp::escape(c);
+            }
+            first = false;
+        }
+        const QRegExp regExp(keyRegExp, Qt::CaseSensitive);
+
+        foreach (TextEditor::CompletionItem item, m_completions) {
+            if (regExp.indexIn(item.m_text) == 0) {
+                item.m_relevance = (key.length() > 0 &&
+                                    item.m_text.startsWith(key, Qt::CaseInsensitive)) ? 1 : 0;
+                (*completions) << item;
+            }
+        }
+    }
+}
+
+void DuiCodeCompletion::complete(const TextEditor::CompletionItem &item)
+{
+    const QString toInsert = item.m_text;
+    const int length = m_editor->position() - m_startPosition;
+    m_editor->setCurPos(m_startPosition);
+    m_editor->replace(length, toInsert);
+}
+
+bool DuiCodeCompletion::partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems)
+{
+    if (completionItems.count() == 1) {
+        complete(completionItems.first());
+        return true;
+    } else {
+        // Compute common prefix
+        QString firstKey = completionItems.first().m_text;
+        QString lastKey = completionItems.last().m_text;
+        const int length = qMin(firstKey.length(), lastKey.length());
+        firstKey.truncate(length);
+        lastKey.truncate(length);
+
+        while (firstKey != lastKey) {
+            firstKey.chop(1);
+            lastKey.chop(1);
+        }
+
+        int typedLength = m_editor->position() - m_startPosition;
+        if (!firstKey.isEmpty() && firstKey.length() > typedLength) {
+            m_editor->setCurPos(m_startPosition);
+            m_editor->replace(typedLength, firstKey);
+        }
+    }
+    return false;
+}
+
+void DuiCodeCompletion::cleanup()
+{
+    m_editor = 0;
+    m_startPosition = 0;
+    m_completions.clear();
+}
+
diff --git a/src/plugins/duieditor/duicodecompletion.h b/src/plugins/duieditor/duicodecompletion.h
new file mode 100644
index 00000000000..dbd91b15cfb
--- /dev/null
+++ b/src/plugins/duieditor/duicodecompletion.h
@@ -0,0 +1,43 @@
+#ifndef DUICODECOMPLETION_H
+#define DUICODECOMPLETION_H
+
+#include <texteditor/icompletioncollector.h>
+
+namespace TextEditor {
+class ITextEditable;
+}
+
+namespace DuiEditor {
+namespace Internal {
+
+class DuiCodeCompletion: public TextEditor::ICompletionCollector
+{
+    Q_OBJECT
+
+public:
+    DuiCodeCompletion(QObject *parent = 0);
+    virtual ~DuiCodeCompletion();
+
+    Qt::CaseSensitivity caseSensitivity() const;
+    void setCaseSensitivity(Qt::CaseSensitivity caseSensitivity);
+
+    virtual bool supportsEditor(TextEditor::ITextEditable *editor);
+    virtual bool triggersCompletion(TextEditor::ITextEditable *editor);
+    virtual int startCompletion(TextEditor::ITextEditable *editor);
+    virtual void completions(QList<TextEditor::CompletionItem> *completions);
+    virtual void complete(const TextEditor::CompletionItem &item);
+    virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems);
+    virtual void cleanup();
+
+private:
+    TextEditor::ITextEditable *m_editor;
+    int m_startPosition;
+    QList<TextEditor::CompletionItem> m_completions;
+    Qt::CaseSensitivity m_caseSensitivity;
+};
+
+
+} // end of namespace Internal
+} // end of namespace DuiEditor
+
+#endif // DUICODECOMPLETION_H
diff --git a/src/plugins/duieditor/duieditor.cpp b/src/plugins/duieditor/duieditor.cpp
new file mode 100644
index 00000000000..ec658d9ac67
--- /dev/null
+++ b/src/plugins/duieditor/duieditor.cpp
@@ -0,0 +1,432 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "duieditor.h"
+#include "duieditorconstants.h"
+#include "duihighlighter.h"
+#include "duieditorplugin.h"
+
+#include "parser/javascriptengine_p.h"
+#include "parser/javascriptparser_p.h"
+#include "parser/javascriptlexer_p.h"
+#include "parser/javascriptnodepool_p.h"
+#include "parser/javascriptastvisitor_p.h"
+#include "parser/javascriptast_p.h"
+
+#include <indenter.h>
+
+#include <coreplugin/icore.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <texteditor/basetextdocument.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/textblockiterator.h>
+#include <texteditor/texteditorconstants.h>
+#include <texteditor/texteditorsettings.h>
+
+#include <QtCore/QTimer>
+#include <QtCore/QtDebug>
+
+#include <QtGui/QMenu>
+#include <QtGui/QComboBox>
+
+enum {
+    UPDATE_DOCUMENT_DEFAULT_INTERVAL = 250
+};
+
+using namespace JavaScript::AST;
+
+
+namespace DuiEditor {
+namespace Internal {
+
+class FindDeclarations: protected Visitor
+{
+    QList<Declaration> declarations;
+
+public:
+    QList<Declaration> accept(JavaScript::AST::Node *node)
+    {
+        JavaScript::AST::Node::acceptChild(node, this);
+        return declarations;
+    }
+
+protected:
+    using Visitor::visit;
+
+    virtual bool visit(FunctionExpression *)
+    {
+        return false;
+    }
+
+    virtual bool visit(FunctionDeclaration *ast)
+    {
+        if (! ast->name)
+            return false;
+
+        QString text = ast->name->asString();
+
+        text += QLatin1Char('(');
+        for (FormalParameterList *it = ast->formals; it; it = it->next) {
+            if (it->name)
+                text += it->name->asString();
+
+            if (it->next)
+                text += QLatin1String(", ");
+        }
+
+        text += QLatin1Char(')');
+
+        Declaration d;
+        d.text = text;
+#if 0 // ### FIXME
+        d.startLine = ast->startLine;
+        d.startColumn = ast->startColumn;
+        d.endLine = ast->endLine;
+        d.endColumn = ast->endColumn;
+#endif
+
+        declarations.append(d);
+
+        return false;
+    }
+
+    virtual bool visit(VariableDeclaration *ast)
+    {
+        if (! ast->name)
+            return false;
+
+        Declaration d;
+        d.text = ast->name->asString();
+#if 0 // ### FIXME
+        d.startLine= ast->startLine;
+        d.startColumn = ast->startColumn;
+        d.endLine = ast->endLine;
+        d.endColumn = ast->endColumn;
+#endif
+        declarations.append(d);
+        return false;
+    }
+};
+
+ScriptEditorEditable::ScriptEditorEditable(ScriptEditor *editor, const QList<int>& context)
+    : BaseTextEditorEditable(editor), m_context(context)
+{
+}
+
+ScriptEditor::ScriptEditor(const Context &context,
+                           QWidget *parent) :
+    TextEditor::BaseTextEditor(parent),
+    m_context(context),
+    m_methodCombo(0)
+{
+    setParenthesesMatchingEnabled(true);
+    setMarksVisible(true);
+    setCodeFoldingSupported(true);
+    setCodeFoldingVisible(true);
+    setMimeType(DuiEditor::Constants::C_DUIEDITOR_MIMETYPE);
+
+    m_updateDocumentTimer = new QTimer(this);
+    m_updateDocumentTimer->setInterval(UPDATE_DOCUMENT_DEFAULT_INTERVAL);
+    m_updateDocumentTimer->setSingleShot(true);
+
+    connect(m_updateDocumentTimer, SIGNAL(timeout()), this, SLOT(updateDocumentNow()));
+
+    connect(this, SIGNAL(textChanged()), this, SLOT(updateDocument()));
+
+    baseTextDocument()->setSyntaxHighlighter(new DuiHighlighter);
+}
+
+ScriptEditor::~ScriptEditor()
+{
+}
+
+QList<Declaration> ScriptEditor::declarations() const
+{ return m_declarations; }
+
+QStringList ScriptEditor::words() const
+{ return m_words; }
+
+Core::IEditor *ScriptEditorEditable::duplicate(QWidget *parent)
+{
+    ScriptEditor *newEditor = new ScriptEditor(m_context, parent);
+    newEditor->duplicateFrom(editor());
+    DuiEditorPlugin::instance()->initializeEditor(newEditor);
+    return newEditor->editableInterface();
+}
+
+const char *ScriptEditorEditable::kind() const
+{
+    return DuiEditor::Constants::C_DUIEDITOR;
+}
+
+ScriptEditor::Context ScriptEditorEditable::context() const
+{
+    return m_context;
+}
+
+void ScriptEditor::updateDocument()
+{
+    m_updateDocumentTimer->start(UPDATE_DOCUMENT_DEFAULT_INTERVAL);
+}
+
+void ScriptEditor::updateDocumentNow()
+{
+    // ### move in the parser thread.
+
+    m_updateDocumentTimer->stop();
+
+    const QString fileName = file()->fileName();
+    const QString code = toPlainText();
+
+    JavaScriptParser parser;
+    JavaScriptEnginePrivate driver;
+
+    JavaScript::NodePool nodePool(fileName, &driver);
+    driver.setNodePool(&nodePool);
+
+    JavaScript::Lexer lexer(&driver);
+    lexer.setCode(code, /*line = */ 1);
+    driver.setLexer(&lexer);
+
+    if (parser.parse(&driver)) {
+        FindDeclarations decls;
+        m_declarations = decls.accept(driver.ast());
+
+        m_words.clear();
+        foreach (const JavaScriptNameIdImpl &id, driver.literals())
+            m_words.append(id.asString());
+
+        QStringList items;
+        items.append(tr("<Select Symbol>"));
+
+        foreach (Declaration decl, m_declarations)
+            items.append(decl.text);
+
+        m_methodCombo->clear();
+        m_methodCombo->addItems(items);
+        updateMethodBoxIndex();
+    }
+
+    QList<QTextEdit::ExtraSelection> selections;
+
+    QTextCharFormat errorFormat;
+    errorFormat.setUnderlineColor(Qt::red);
+    errorFormat.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+
+    QTextEdit::ExtraSelection sel;
+
+    foreach (const JavaScriptParser::DiagnosticMessage &d, parser.diagnosticMessages()) {
+        if (d.isWarning())
+            continue;
+
+        int line = d.line;
+        int column = d.column;
+
+        if (column == 0)
+            column = 1;
+
+        QTextCursor c(document()->findBlockByNumber(line - 1));
+        sel.cursor = c;
+        sel.cursor.setPosition(c.position() + column - 1);
+        sel.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
+        sel.format = errorFormat;
+
+        selections.append(sel);
+    }
+
+    setExtraSelections(CodeWarningsSelection, selections);
+}
+
+void ScriptEditor::jumpToMethod(int index)
+{
+    if (index) {
+        Declaration d = m_declarations.at(index - 1);
+        gotoLine(d.startLine, d.startColumn - 1);
+        setFocus();
+    }
+}
+
+void ScriptEditor::updateMethodBoxIndex()
+{
+    int line = 0, column = 0;
+    convertPosition(position(), &line, &column);
+
+    int currentSymbolIndex = 0;
+
+    int index = 0;
+    while (index < m_declarations.size()) {
+        const Declaration &d = m_declarations.at(index++);
+
+        if (line < d.startLine)
+            break;
+        else
+            currentSymbolIndex = index;
+    }
+
+    m_methodCombo->setCurrentIndex(currentSymbolIndex);
+}
+
+void ScriptEditor::updateMethodBoxToolTip()
+{
+}
+
+void ScriptEditor::updateFileName()
+{
+}
+
+void ScriptEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+    TextEditor::BaseTextEditor::setFontSettings(fs);
+    DuiHighlighter *highlighter = qobject_cast<DuiHighlighter*>(baseTextDocument()->syntaxHighlighter());
+    if (!highlighter)
+        return;
+
+    static QVector<QString> categories;
+    if (categories.isEmpty()) {
+        categories << QLatin1String(TextEditor::Constants::C_NUMBER)
+                   << QLatin1String(TextEditor::Constants::C_STRING)
+                   << QLatin1String(TextEditor::Constants::C_TYPE)
+                   << QLatin1String(TextEditor::Constants::C_KEYWORD)
+                   << QLatin1String(TextEditor::Constants::C_PREPROCESSOR)
+                   << QLatin1String(TextEditor::Constants::C_LABEL)
+                   << QLatin1String(TextEditor::Constants::C_COMMENT);
+    }
+
+    highlighter->setFormats(fs.toTextCharFormats(categories));
+    highlighter->rehighlight();
+}
+
+bool ScriptEditor::isElectricCharacter(const QChar &ch) const
+{
+    if (ch == QLatin1Char('{') || ch == QLatin1Char('}'))
+        return true;
+    return false;
+}
+
+    // Indent a code line based on previous
+template <class Iterator>
+static void indentScriptBlock(const TextEditor::TabSettings &ts,
+                              const QTextBlock &block,
+                              const Iterator &programBegin,
+                              const Iterator &programEnd,
+                              QChar typedChar)
+{
+    typedef typename SharedTools::Indenter<Iterator> Indenter ;
+    Indenter &indenter = Indenter::instance();
+    indenter.setTabSize(ts.m_tabSize);
+    indenter.setIndentSize(ts.m_indentSize);
+    const TextEditor::TextBlockIterator current(block);
+    const int indent = indenter.indentForBottomLine(current, programBegin,
+                                                    programEnd, typedChar);
+    ts.indentLine(block, indent);
+}
+
+void ScriptEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar)
+{
+#if 0
+    const TextEditor::TextBlockIterator begin(doc->begin());
+    const TextEditor::TextBlockIterator end(block.next());
+    indentScriptBlock(tabSettings(), block, begin, end, typedChar);
+#else
+    Q_UNUSED(doc)
+    Q_UNUSED(typedChar)
+
+    TextEditor::TabSettings ts = tabSettings();
+    const int tabSize = qMax(1, ts.m_tabSize);
+
+    int indent = 0;
+    QTextBlock it = block.previous();
+    for (; it.isValid(); it = it.previous()) {
+        const QString blockText = it.text();
+
+        if (! blockText.isEmpty()) {
+            for (int i = 0; i < blockText.length(); ++i) {
+                const QChar ch = blockText.at(i);
+    
+                if (ch == QLatin1Char('\t'))
+                    indent += (indent + tabSize) % tabSize;
+                else if (ch.isSpace())
+                    ++indent;
+                else
+                    break;
+            }
+
+            break;
+        }
+    }
+    ts.indentLine(block, indent);
+#endif
+}
+
+TextEditor::BaseTextEditorEditable *ScriptEditor::createEditableInterface()
+{
+    ScriptEditorEditable *editable = new ScriptEditorEditable(this, m_context);
+    createToolBar(editable);
+    return editable;
+}
+
+void ScriptEditor::createToolBar(ScriptEditorEditable *editable)
+{
+    m_methodCombo = new QComboBox;
+    m_methodCombo->setMinimumContentsLength(22);
+    //m_methodCombo->setSizeAdjustPolicy(QComboBox::AdjustToContents);
+
+    // Make the combo box prefer to expand
+    QSizePolicy policy = m_methodCombo->sizePolicy();
+    policy.setHorizontalPolicy(QSizePolicy::Expanding);
+    m_methodCombo->setSizePolicy(policy);
+
+    connect(m_methodCombo, SIGNAL(activated(int)), this, SLOT(jumpToMethod(int)));
+    connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(updateMethodBoxIndex()));
+    connect(m_methodCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(updateMethodBoxToolTip()));
+
+    connect(file(), SIGNAL(changed()), this, SLOT(updateFileName()));
+
+    QToolBar *toolBar = editable->toolBar();
+
+    QList<QAction*> actions = toolBar->actions();
+    toolBar->insertWidget(actions.first(), m_methodCombo);
+}
+
+void ScriptEditor::contextMenuEvent(QContextMenuEvent *e)
+{
+    QMenu *menu = createStandardContextMenu();
+
+    if (Core::ActionContainer *mcontext = Core::ICore::instance()->actionManager()->actionContainer(DuiEditor::Constants::M_CONTEXT)) {
+        QMenu *contextMenu = mcontext->menu();
+        foreach (QAction *action, contextMenu->actions())
+            menu->addAction(action);
+    }
+
+    menu->exec(e->globalPos());
+    delete menu;
+}
+
+} // namespace Internal
+} // namespace DuiEditor
diff --git a/src/plugins/duieditor/duieditor.h b/src/plugins/duieditor/duieditor.h
new file mode 100644
index 00000000000..7d7a8284817
--- /dev/null
+++ b/src/plugins/duieditor/duieditor.h
@@ -0,0 +1,127 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef DUIDITORW_H
+#define DUIDITORW_H
+
+#include <texteditor/basetexteditor.h>
+
+QT_BEGIN_NAMESPACE
+class QComboBox;
+class QTimer;
+QT_END_NAMESPACE
+
+namespace Core {
+    class ICore;
+}
+
+namespace DuiEditor {
+namespace Internal {
+
+class DuiHighlighter;
+
+class ScriptEditor;
+
+class ScriptEditorEditable : public TextEditor::BaseTextEditorEditable
+{
+public:
+    ScriptEditorEditable(ScriptEditor *, const QList<int> &);
+    QList<int> context() const;
+
+    bool duplicateSupported() const { return true; }
+    Core::IEditor *duplicate(QWidget *parent);
+    const char *kind() const;
+
+private:
+    QList<int> m_context;
+};
+
+
+struct Declaration
+{
+    QString text;
+    int startLine;
+    int startColumn;
+    int endLine;
+    int endColumn;
+
+    Declaration()
+        : startLine(0),
+          startColumn(0),
+          endLine(0),
+          endColumn(0)
+    { }
+};
+
+class ScriptEditor : public TextEditor::BaseTextEditor
+{
+    Q_OBJECT
+
+public:
+    typedef QList<int> Context;
+
+    ScriptEditor(const Context &context,
+                 QWidget *parent = 0);
+    ~ScriptEditor();
+
+    QList<Declaration> declarations() const;
+    QStringList words() const;
+
+public slots:
+    virtual void setFontSettings(const TextEditor::FontSettings &);
+
+private slots:
+    void updateDocument();
+    void updateDocumentNow();
+    void jumpToMethod(int index);
+    void updateMethodBoxIndex();
+    void updateMethodBoxToolTip();
+    void updateFileName();
+
+protected:
+    void contextMenuEvent(QContextMenuEvent *e);
+    TextEditor::BaseTextEditorEditable *createEditableInterface();
+    void createToolBar(ScriptEditorEditable *editable);
+
+private:
+    virtual bool isElectricCharacter(const QChar &ch) const;
+    virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+
+    const Context m_context;
+
+    QTimer *m_updateDocumentTimer;
+    QComboBox *m_methodCombo;
+    QList<Declaration> m_declarations;
+    QStringList m_words;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // DUIDITORW_H
diff --git a/src/plugins/duieditor/duieditor.pro b/src/plugins/duieditor/duieditor.pro
new file mode 100644
index 00000000000..4af552b625b
--- /dev/null
+++ b/src/plugins/duieditor/duieditor.pro
@@ -0,0 +1,29 @@
+TEMPLATE = lib
+TARGET = DuiEditor
+QT += script
+
+include(../../qworkbenchplugin.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
+include(../../plugins/texteditor/texteditor.pri)
+include(../../shared/qscripthighlighter/qscripthighlighter.pri)
+include(../../shared/indenter/indenter.pri)
+include($$(QTDIR_DUI)/src/declarative/qml/parser/parser.pri)
+
+INCLUDEPATH += $$(QTDIR_DUI)/src/declarative/qml    # FIXME: remove me
+
+HEADERS += duieditor.h \
+duieditorfactory.h \
+duieditorplugin.h \
+duihighlighter.h \
+duieditoractionhandler.h \
+duicodecompletion.h \
+duieditorconstants.h
+
+SOURCES += duieditor.cpp \
+duieditorfactory.cpp \
+duieditorplugin.cpp \
+duihighlighter.cpp \
+duieditoractionhandler.cpp \
+duicodecompletion.cpp
+
+RESOURCES += duieditor.qrc
diff --git a/src/plugins/duieditor/duieditoractionhandler.cpp b/src/plugins/duieditor/duieditoractionhandler.cpp
new file mode 100644
index 00000000000..23e437faea4
--- /dev/null
+++ b/src/plugins/duieditor/duieditoractionhandler.cpp
@@ -0,0 +1,100 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "duieditoractionhandler.h"
+#include "duieditorconstants.h"
+#include "duieditor.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <coreplugin/scriptmanager/scriptmanager.h>
+
+#include <QtCore/QDebug>
+#include <QtGui/QAction>
+#include <QtGui/QMainWindow>
+#include <QtGui/QMessageBox>
+
+static QAction *actionFromId(const QString &id)
+{
+    Core::Command *cmd = Core::ICore::instance()->actionManager()->command(id);
+    if (!cmd)
+        return 0;
+    return cmd->action();
+}
+
+namespace DuiEditor {
+namespace Internal {
+
+DuiEditorActionHandler::DuiEditorActionHandler()
+  : TextEditor::TextEditorActionHandler(QLatin1String(DuiEditor::Constants::C_DUIEDITOR),
+                                        Format),
+    m_runAction(0)
+{
+}
+
+void DuiEditorActionHandler::createActions()
+{
+    TextEditor::TextEditorActionHandler::createActions();
+    m_runAction = actionFromId(QLatin1String(DuiEditor::Constants::RUN));
+    connect(m_runAction, SIGNAL(triggered()), this, SLOT(run()));
+}
+
+
+void DuiEditorActionHandler::run()
+{
+    typedef Core::ScriptManager::Stack Stack;
+    if (!currentEditor())
+        return;
+
+    const QString script = currentEditor()->toPlainText();
+
+    // run
+    Stack errorStack;
+    QString errorMessage;
+    if (Core::ICore::instance()->scriptManager()->runScript(script, &errorMessage, &errorStack))
+        return;
+
+    // try to find a suitable error line in the stack
+    // ignoring 0 and other files (todo: open other files?)
+    int errorLineNumber = 0;
+    if (const int numFrames = errorStack.size()) {
+        for (int f = 0; f < numFrames; f++) {
+            if (errorStack[f].lineNumber && errorStack[f].fileName.isEmpty()) {
+                errorLineNumber = errorStack[f].lineNumber;
+                break;
+            }
+        }
+    }
+    if (errorLineNumber)
+        currentEditor()->gotoLine(errorLineNumber);
+    QMessageBox::critical(Core::ICore::instance()->mainWindow(), tr("Qt Script Error"), errorMessage);
+}
+
+} // namespace Internal
+} // namespace DuiEditor
diff --git a/src/plugins/duieditor/duieditoractionhandler.h b/src/plugins/duieditor/duieditoractionhandler.h
new file mode 100644
index 00000000000..13300515f87
--- /dev/null
+++ b/src/plugins/duieditor/duieditoractionhandler.h
@@ -0,0 +1,58 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef DUIDITORACTIONHANDLER_H
+#define DUIDITORACTIONHANDLER_H
+
+#include <texteditor/texteditoractionhandler.h>
+
+namespace DuiEditor {
+namespace Internal {
+
+class DuiEditorActionHandler : public TextEditor::TextEditorActionHandler
+{
+    Q_OBJECT
+
+public:
+    DuiEditorActionHandler();
+
+private:
+    virtual void createActions();
+
+private slots:
+    void run();
+
+private:
+    QAction *m_runAction;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // DUIDITORACTIONHANDLER_H
diff --git a/src/plugins/duieditor/duieditorconstants.h b/src/plugins/duieditor/duieditorconstants.h
new file mode 100644
index 00000000000..0c24f88854c
--- /dev/null
+++ b/src/plugins/duieditor/duieditorconstants.h
@@ -0,0 +1,46 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef DUIEDITOR_CONSTANTS_H
+#define DUIEDITOR_CONSTANTS_H
+
+namespace DuiEditor {
+namespace Constants {
+
+const char * const M_CONTEXT = "DUI Editor.ContextMenu";
+const char * const RUN = "DuiEditor.Run";
+const char * const RUN_SEP = "DuiEditor.Run.Separator";
+const char * const C_DUIEDITOR = "DUI Editor";
+
+const char * const C_DUIEDITOR_MIMETYPE = "application/x-dui";
+
+} // namespace Constants
+} // namespace DuiEditor
+
+#endif // DUIEDITOR_CONSTANTS_H
diff --git a/src/plugins/duieditor/duieditorfactory.cpp b/src/plugins/duieditor/duieditorfactory.cpp
new file mode 100644
index 00000000000..1cc4fac6d2c
--- /dev/null
+++ b/src/plugins/duieditor/duieditorfactory.cpp
@@ -0,0 +1,83 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "duieditorfactory.h"
+#include "duieditor.h"
+#include "duieditoractionhandler.h"
+#include "duieditorconstants.h"
+#include "duieditorplugin.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QFileInfo>
+#include <QtCore/QDebug>
+
+using namespace DuiEditor::Internal;
+using namespace DuiEditor::Constants;
+
+DuiEditorFactory::DuiEditorFactory(const Context &context, QObject *parent)
+  : Core::IEditorFactory(parent),
+    m_kind(QLatin1String(C_DUIEDITOR)),
+    m_mimeTypes(QLatin1String(DuiEditor::Constants::C_DUIEDITOR_MIMETYPE)),
+    m_context(context),
+    m_actionHandler(new DuiEditorActionHandler)
+{
+}
+
+DuiEditorFactory::~DuiEditorFactory()
+{
+    delete m_actionHandler;
+}
+
+QString DuiEditorFactory::kind() const
+{
+    return m_kind;
+}
+
+Core::IFile *DuiEditorFactory::open(const QString &fileName)
+{
+    Core::IEditor *iface = Core::EditorManager::instance()->openEditor(fileName, kind());
+    if (!iface) {
+        qWarning() << "DuiEditorFactory::open: openEditor failed for " << fileName;
+        return 0;
+    }
+    return iface->file();
+}
+
+Core::IEditor *DuiEditorFactory::createEditor(QWidget *parent)
+{
+    ScriptEditor *rc = new ScriptEditor(m_context, parent);
+    DuiEditorPlugin::instance()->initializeEditor(rc);
+    return rc->editableInterface();
+}
+
+QStringList DuiEditorFactory::mimeTypes() const
+{
+    return m_mimeTypes;
+}
diff --git a/src/plugins/duieditor/duieditorfactory.h b/src/plugins/duieditor/duieditorfactory.h
new file mode 100644
index 00000000000..e5e33d8e220
--- /dev/null
+++ b/src/plugins/duieditor/duieditorfactory.h
@@ -0,0 +1,73 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef RDUIEDITORFACTORY_H
+#define RDUIEDITORFACTORY_H
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+
+#include <QtCore/QStringList>
+
+namespace TextEditor {
+class TextEditorActionHandler;
+}
+
+namespace DuiEditor {
+namespace Internal {
+
+class DuiEditorActionHandler;
+
+class DuiEditorFactory : public Core::IEditorFactory
+{
+    Q_OBJECT
+
+public:
+    typedef QList<int> Context;
+
+    DuiEditorFactory(const Context &context, QObject *parent);
+    ~DuiEditorFactory();
+
+    virtual QStringList mimeTypes() const;
+    // IEditorFactory
+    QString kind() const;
+    Core::IFile *open(const QString &fileName);
+    Core::IEditor *createEditor(QWidget *parent);
+
+private:
+    const QString m_kind;
+    const QStringList m_mimeTypes;
+    const Context m_context;
+
+    TextEditor::TextEditorActionHandler *m_actionHandler;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // RDUIEDITORFACTORY_H
diff --git a/src/plugins/duieditor/duieditorplugin.cpp b/src/plugins/duieditor/duieditorplugin.cpp
new file mode 100644
index 00000000000..aa93f12b9e6
--- /dev/null
+++ b/src/plugins/duieditor/duieditorplugin.cpp
@@ -0,0 +1,163 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "duieditorplugin.h"
+
+#include "qscripthighlighter.h"
+#include "duieditor.h"
+#include "duieditorconstants.h"
+#include "duieditorfactory.h"
+#include "duicodecompletion.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanager.h>
+#include <extensionsystem/pluginmanager.h>
+#include <texteditor/fontsettings.h>
+#include <texteditor/storagesettings.h>
+#include <texteditor/texteditorconstants.h>
+#include <texteditor/texteditorsettings.h>
+#include <texteditor/textfilewizard.h>
+#include <texteditor/texteditoractionhandler.h>
+#include <texteditor/completionsupport.h>
+#include <utils/qtcassert.h>
+
+#include <QtCore/QtPlugin>
+#include <QtCore/QDebug>
+#include <QtCore/QSettings>
+#include <QtGui/QAction>
+
+using namespace DuiEditor::Internal;
+using namespace DuiEditor::Constants;
+
+DuiEditorPlugin *DuiEditorPlugin::m_instance = 0;
+
+DuiEditorPlugin::DuiEditorPlugin() :
+    m_wizard(0),
+    m_editor(0),
+    m_actionHandler(0),
+    m_completion(0)
+{
+    m_instance = this;
+}
+
+DuiEditorPlugin::~DuiEditorPlugin()
+{
+    removeObject(m_editor);
+    removeObject(m_wizard);
+    delete m_actionHandler;
+    m_instance = 0;
+}
+
+bool DuiEditorPlugin::initialize(const QStringList & /*arguments*/, QString *error_message)
+{
+    typedef SharedTools::QScriptHighlighter QScriptHighlighter;
+
+    Core::ICore *core = Core::ICore::instance();
+    if (!core->mimeDatabase()->addMimeTypes(QLatin1String(":/duieditor/DuiEditor.mimetypes.xml"), error_message))
+        return false;
+    m_scriptcontext << core->uniqueIDManager()->uniqueIdentifier(DuiEditor::Constants::C_DUIEDITOR);
+    m_context = m_scriptcontext;
+    m_context << core->uniqueIDManager()->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+
+    registerActions();
+
+    m_editor = new DuiEditorFactory(m_context, this);
+    addObject(m_editor);
+
+    Core::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
+    wizardParameters.setDescription(tr("Qt Script file"));
+    wizardParameters.setName(tr("Qt Script file"));
+    wizardParameters.setCategory(QLatin1String("Qt"));
+    wizardParameters.setTrCategory(tr("Qt"));
+    m_wizard = new TextEditor::TextFileWizard(QLatin1String(DuiEditor::Constants::C_DUIEDITOR_MIMETYPE),
+                                              QLatin1String(DuiEditor::Constants::C_DUIEDITOR),
+                                              QLatin1String("dui$"),
+                                              wizardParameters, this);
+    addObject(m_wizard);
+
+    m_actionHandler = new TextEditor::TextEditorActionHandler(DuiEditor::Constants::C_DUIEDITOR,
+          TextEditor::TextEditorActionHandler::Format
+        | TextEditor::TextEditorActionHandler::UnCommentSelection
+        | TextEditor::TextEditorActionHandler::UnCollapseAll);
+
+    m_completion = new DuiCodeCompletion();
+    addAutoReleasedObject(m_completion);
+
+    // Restore settings
+    QSettings *settings = Core::ICore::instance()->settings();
+    settings->beginGroup(QLatin1String("CppTools")); // ### FIXME:
+    settings->beginGroup(QLatin1String("Completion"));
+    const bool caseSensitive = settings->value(QLatin1String("CaseSensitive"), true).toBool();
+    m_completion->setCaseSensitivity(caseSensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
+    settings->endGroup();
+    settings->endGroup();
+    
+    error_message->clear();
+
+    return true;
+}
+
+void DuiEditorPlugin::extensionsInitialized()
+{
+    m_actionHandler->initializeActions();
+}
+
+void DuiEditorPlugin::initializeEditor(DuiEditor::Internal::ScriptEditor *editor)
+{
+    QTC_ASSERT(m_instance, /**/);
+
+    m_actionHandler->setupActions(editor);
+
+    TextEditor::TextEditorSettings::instance()->initializeEditor(editor);
+
+    // auto completion
+    connect(editor, SIGNAL(requestAutoCompletion(ITextEditable*, bool)),
+            TextEditor::Internal::CompletionSupport::instance(), SLOT(autoComplete(ITextEditable*, bool)));
+}
+
+void DuiEditorPlugin::registerActions()
+{
+    Core::ActionManager *am = Core::ICore::instance()->actionManager();
+    Core::ActionContainer *mcontext = am->createMenu(DuiEditor::Constants::M_CONTEXT);
+
+    QAction *action = new QAction(this);
+    action->setSeparator(true);
+    Core::Command *cmd = am->registerAction(action, DuiEditor::Constants::RUN_SEP, m_scriptcontext);
+    mcontext->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+
+    action = new QAction(tr("Run"), this);
+    cmd = am->registerAction(action, DuiEditor::Constants::RUN, m_scriptcontext);
+    cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+R")));
+    mcontext->addAction(cmd, Core::Constants::G_DEFAULT_THREE);
+}
+
+Q_EXPORT_PLUGIN(DuiEditorPlugin)
diff --git a/src/plugins/duieditor/duieditorplugin.h b/src/plugins/duieditor/duieditorplugin.h
new file mode 100644
index 00000000000..5429a878eb4
--- /dev/null
+++ b/src/plugins/duieditor/duieditorplugin.h
@@ -0,0 +1,82 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef DUIEDITORPLUGIN_H
+#define DUIEDITORPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+namespace TextEditor {
+class TextFileWizard;
+class TextEditorActionHandler;
+} // namespace TextEditor
+
+namespace DuiEditor {
+namespace Internal {
+
+class DuiEditorFactory;
+class DuiCodeCompletion;
+class ScriptEditor;
+
+class DuiEditorPlugin : public ExtensionSystem::IPlugin
+{
+    Q_OBJECT
+
+public:
+    DuiEditorPlugin();
+    virtual ~DuiEditorPlugin();
+
+    // IPlugin
+    bool initialize(const QStringList &arguments, QString *errorMessage = 0);
+    void extensionsInitialized();
+
+    static DuiEditorPlugin *instance()
+    { return m_instance; }
+
+    void initializeEditor(ScriptEditor *editor);
+
+private:
+    void registerActions();
+
+    static DuiEditorPlugin *m_instance;
+
+    typedef QList<int> Context;
+    Context m_context;
+    Context m_scriptcontext;
+
+    TextEditor::TextFileWizard *m_wizard;
+    DuiEditorFactory *m_editor;
+    TextEditor::TextEditorActionHandler *m_actionHandler;
+    DuiCodeCompletion *m_completion;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // DUIEDITORPLUGIN_H
diff --git a/src/plugins/duieditor/duihighlighter.cpp b/src/plugins/duieditor/duihighlighter.cpp
new file mode 100644
index 00000000000..7c8d3ec5980
--- /dev/null
+++ b/src/plugins/duieditor/duihighlighter.cpp
@@ -0,0 +1,110 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#include "duihighlighter.h"
+
+#include <utils/qtcassert.h>
+
+namespace DuiEditor {
+namespace Internal {
+
+DuiHighlighter::DuiHighlighter(QTextDocument *parent) :
+     SharedTools::QScriptHighlighter(parent)
+{
+    setDuiEnabled(true);
+    m_currentBlockParentheses.reserve(20);
+    m_braceDepth = 0;
+}
+
+int DuiHighlighter::onBlockStart()
+{
+    m_currentBlockParentheses.clear();
+    m_braceDepth = 0;
+
+    int state = 0;
+    int previousState = previousBlockState();
+    if (previousState != -1) {
+        state = previousState & 0xff;
+        m_braceDepth = previousState >> 8;
+    }
+
+    return state;
+}
+
+void DuiHighlighter::onOpeningParenthesis(QChar parenthesis, int pos)
+{
+    if (parenthesis == QLatin1Char('{'))
+        ++m_braceDepth;
+     m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Opened, parenthesis, pos));
+}
+
+void DuiHighlighter::onClosingParenthesis(QChar parenthesis, int pos)
+{
+    if (parenthesis == QLatin1Char('}'))
+        --m_braceDepth;
+    m_currentBlockParentheses.push_back(Parenthesis(Parenthesis::Closed, parenthesis, pos));
+}
+
+void DuiHighlighter::onBlockEnd(int state, int firstNonSpace)
+{
+    typedef TextEditor::TextBlockUserData TextEditorBlockData;
+
+    setCurrentBlockState((m_braceDepth << 8) | state);
+
+    // Set block data parentheses. Force creation of block data unless empty
+    TextEditorBlockData *blockData = 0;
+
+    if (QTextBlockUserData *userData = currentBlockUserData())
+        blockData = static_cast<TextEditorBlockData *>(userData);
+
+    if (!blockData && !m_currentBlockParentheses.empty()) {
+        blockData = new TextEditorBlockData;
+        setCurrentBlockUserData(blockData);
+    }
+    if (blockData) {
+        blockData->setParentheses(m_currentBlockParentheses);
+        blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
+        blockData->setCollapseMode(TextEditor::TextBlockUserData::NoCollapse);
+    }
+    if (!m_currentBlockParentheses.isEmpty()) {
+        QTC_ASSERT(blockData, return);
+        int collapse = Parenthesis::collapseAtPos(m_currentBlockParentheses);
+        if (collapse >= 0) {
+            if (collapse == firstNonSpace)
+                blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseThis);
+            else
+                blockData->setCollapseMode(TextEditor::TextBlockUserData::CollapseAfter);
+        }
+        if (Parenthesis::hasClosingCollapse(m_currentBlockParentheses))
+            blockData->setClosingCollapseMode(TextEditor::TextBlockUserData::NoClosingCollapse);
+    }
+}
+
+} // namespace Internal
+} // namespace DuiEditor
diff --git a/src/plugins/duieditor/duihighlighter.h b/src/plugins/duieditor/duihighlighter.h
new file mode 100644
index 00000000000..3994d36bd3b
--- /dev/null
+++ b/src/plugins/duieditor/duihighlighter.h
@@ -0,0 +1,64 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact:  Qt Software Information (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at qt-sales@nokia.com.
+**
+**************************************************************************/
+
+#ifndef DUISYNTAXHIGHLIGHTER_H
+#define DUISYNTAXHIGHLIGHTER_H
+
+#include "qscripthighlighter.h"
+#include <texteditor/basetexteditor.h>
+
+namespace DuiEditor {
+namespace Internal {
+
+// Highlighter for Scripts that stores
+// the parentheses encountered in the block data
+// for parentheses matching to work.
+
+class DuiHighlighter : public SharedTools::QScriptHighlighter
+{
+    Q_OBJECT
+public:
+    DuiHighlighter(QTextDocument *parent = 0);
+
+private:
+    virtual int onBlockStart();
+    virtual void onOpeningParenthesis(QChar parenthesis, int pos);
+    virtual void onClosingParenthesis(QChar parenthesis, int pos);
+    virtual void onBlockEnd(int state, int firstNonSpace);
+
+    typedef TextEditor::Parenthesis Parenthesis;
+    typedef TextEditor::Parentheses Parentheses;
+    Parentheses m_currentBlockParentheses;
+    int m_braceDepth;
+};
+
+} // namespace Internal
+} // namespace DuiEditor
+
+#endif // DUISYNTAXHIGHLIGHTER_H
diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro
index 3b06779d980..388a8c53bc7 100644
--- a/src/plugins/plugins.pro
+++ b/src/plugins/plugins.pro
@@ -24,6 +24,7 @@ SUBDIRS   = plugin_coreplugin \
             plugin_help \
 #            plugin_regexp \ # don't know what to do with this
             plugin_qtscripteditor \
+            plugin_duieditor \
             plugin_cpaster \
             plugin_cmakeprojectmanager \
             plugin_fakevim \
@@ -139,6 +140,10 @@ plugin_qtscripteditor.subdir = qtscripteditor
 plugin_qtscripteditor.depends = plugin_texteditor
 plugin_qtscripteditor.depends += plugin_coreplugin
 
+plugin_duieditor.subdir = duieditor
+plugin_duieditor.depends = plugin_texteditor
+plugin_duieditor.depends += plugin_coreplugin
+
 plugin_cpaster.subdir = cpaster
 plugin_cpaster.depends += plugin_texteditor
 plugin_cpaster.depends += plugin_coreplugin
diff --git a/src/shared/qscripthighlighter/qscripthighlighter.cpp b/src/shared/qscripthighlighter/qscripthighlighter.cpp
index 5b07644e01c..f56ccd6dcea 100644
--- a/src/shared/qscripthighlighter/qscripthighlighter.cpp
+++ b/src/shared/qscripthighlighter/qscripthighlighter.cpp
@@ -105,11 +105,18 @@ static const QSet<QString> &qscriptKeywords() {
 namespace SharedTools {
 
 QScriptHighlighter::QScriptHighlighter(QTextDocument *parent)
-    : QSyntaxHighlighter(parent)
+    : QSyntaxHighlighter(parent),
+      m_duiEnabled(false)
 {
     setFormats(defaultFormats());
 }
 
+bool QScriptHighlighter::isDuiEnabled() const
+{ return m_duiEnabled; }
+
+void QScriptHighlighter::setDuiEnabled(bool enabled)
+{ m_duiEnabled = enabled; }
+
 void QScriptHighlighter::highlightBlock(const QString &text)
 {
     // states
@@ -428,7 +435,7 @@ void QScriptHighlighter::highlightKeyword(int currentPos, const QString &buffer)
     if (buffer.isEmpty())
         return;
 
-    if (buffer.at(0) == QLatin1Char('Q')) {
+    if (m_duiEnabled && buffer.at(0).isUpper() || (! m_duiEnabled && buffer.at(0) == QLatin1Char('Q'))) {
         setFormat(currentPos - buffer.length(), buffer.length(), m_formats[TypeFormat]);
     } else {
         if (qscriptKeywords().contains(buffer))
diff --git a/src/shared/qscripthighlighter/qscripthighlighter.h b/src/shared/qscripthighlighter/qscripthighlighter.h
index 5b0f1587dea..51c4932d5df 100644
--- a/src/shared/qscripthighlighter/qscripthighlighter.h
+++ b/src/shared/qscripthighlighter/qscripthighlighter.h
@@ -46,6 +46,9 @@ public:
            KeywordFormat, PreProcessorFormat, LabelFormat, CommentFormat,
            NumFormats };
 
+    bool isDuiEnabled() const;
+    void setDuiEnabled(bool enabled);
+
     // MS VC 6 compatible, still.
     void setFormats(const QVector<QTextCharFormat> &s);
     static const QVector<QTextCharFormat> &defaultFormats();
@@ -61,6 +64,7 @@ private:
 
     void highlightKeyword(int currentPos, const QString &buffer);
 
+    bool m_duiEnabled;
     QTextCharFormat m_formats[NumFormats];
 };
 
-- 
GitLab