From 77008bc45f52be5338d6be4abc76035ca6d40c8b Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Tue, 2 Nov 2010 11:10:27 +0100
Subject: [PATCH] Exported Header cleanup: QmlJSEditor

Move internal classes QmlJSEditorEditable/SemanticHighlighter
out of qmljseditor.h. Move QmlJSEditor from namespace
QmlJSEditor::Internal to QmlJSEditor.

Reviewed-by: Christian Kamm <christian.d.kamm@nokia.com>
---
 .../model/basetexteditmodifier.cpp            |   2 +-
 src/plugins/qmljseditor/qmljseditor.cpp       | 176 +-----------------
 src/plugins/qmljseditor/qmljseditor.h         | 119 ++----------
 src/plugins/qmljseditor/qmljseditor.pro       |   8 +-
 .../qmljseditor/qmljseditoreditable.cpp       |  92 +++++++++
 src/plugins/qmljseditor/qmljseditoreditable.h |  62 ++++++
 .../qmljseditor/qmljseditorfactory.cpp        |   3 +-
 src/plugins/qmljseditor/qmljseditorplugin.cpp |   2 +-
 src/plugins/qmljseditor/qmljseditorplugin.h   |   4 +-
 src/plugins/qmljseditor/qmljshoverhandler.cpp |   7 +-
 src/plugins/qmljseditor/qmljshoverhandler.h   |   5 +-
 src/plugins/qmljseditor/qmljsoutline.cpp      |   1 +
 src/plugins/qmljseditor/qmljsquickfix.h       |   4 +-
 .../qmljseditor/qmljssemantichighlighter.cpp  | 152 +++++++++++++++
 .../qmljseditor/qmljssemantichighlighter.h    | 113 +++++++++++
 src/plugins/qmljsinspector/qmljsinspector.cpp |   2 +-
 .../qmljsinspector/qmljslivetextpreview.cpp   |   8 +-
 .../qmljsinspector/qmljslivetextpreview.h     |   4 +-
 18 files changed, 470 insertions(+), 294 deletions(-)
 create mode 100644 src/plugins/qmljseditor/qmljseditoreditable.cpp
 create mode 100644 src/plugins/qmljseditor/qmljseditoreditable.h
 create mode 100644 src/plugins/qmljseditor/qmljssemantichighlighter.cpp
 create mode 100644 src/plugins/qmljseditor/qmljssemantichighlighter.h

diff --git a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
index 113ee3b471e..7575d7dcee2 100644
--- a/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
+++ b/src/plugins/qmldesigner/designercore/model/basetexteditmodifier.cpp
@@ -70,7 +70,7 @@ int BaseTextEditModifier::indentDepth() const
 
 bool BaseTextEditModifier::renameId(const QString &oldId, const QString &newId)
 {
-    if (QmlJSEditor::Internal::QmlJSTextEditor *qmljse = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(plainTextEdit())) {
+    if (QmlJSEditor::QmlJSTextEditor *qmljse = qobject_cast<QmlJSEditor::QmlJSTextEditor*>(plainTextEdit())) {
         qmljse->renameId(oldId, newId);
         return true;
     } else {
diff --git a/src/plugins/qmljseditor/qmljseditor.cpp b/src/plugins/qmljseditor/qmljseditor.cpp
index 54cf860b635..f399b32ed0e 100644
--- a/src/plugins/qmljseditor/qmljseditor.cpp
+++ b/src/plugins/qmljseditor/qmljseditor.cpp
@@ -28,6 +28,7 @@
 **************************************************************************/
 
 #include "qmljseditor.h"
+#include "qmljseditoreditable.h"
 #include "qmljseditorconstants.h"
 #include "qmljshighlighter.h"
 #include "qmljseditorplugin.h"
@@ -36,13 +37,12 @@
 #include "qmljsquickfix.h"
 #include "qmloutlinemodel.h"
 #include "qmljsfindreferences.h"
+#include "qmljssemantichighlighter.h"
 
 #include <qmljs/qmljsbind.h>
-#include <qmljs/qmljscheck.h>
 #include <qmljs/qmljsdocument.h>
 #include <qmljs/qmljsicontextpane.h>
 #include <qmljs/qmljslookupcontext.h>
-#include <qmljs/qmljslink.h>
 #include <qmljs/parser/qmljsastvisitor_p.h>
 #include <qmljs/parser/qmljsast_p.h>
 #include <qmljs/parser/qmljsengine_p.h>
@@ -52,9 +52,6 @@
 #include <coreplugin/actionmanager/command.h>
 #include <coreplugin/editormanager/editormanager.h>
 #include <coreplugin/icore.h>
-#include <coreplugin/coreconstants.h>
-#include <coreplugin/modemanager.h>
-#include <coreplugin/designmode.h>
 #include <coreplugin/mimedatabase.h>
 #include <extensionsystem/pluginmanager.h>
 #include <texteditor/basetextdocument.h>
@@ -89,6 +86,7 @@ enum {
 
 using namespace QmlJS;
 using namespace QmlJS::AST;
+using namespace QmlJSEditor;
 using namespace QmlJSEditor::Internal;
 
 static int blockStartState(const QTextBlock &block)
@@ -628,51 +626,6 @@ int SemanticInfo::revision() const
     return 0;
 }
 
-QmlJSEditorEditable::QmlJSEditorEditable(QmlJSTextEditor *editor)
-    : BaseTextEditorEditable(editor)
-{
-    m_context.add(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);
-    m_context.add(TextEditor::Constants::C_TEXTEDITOR);
-}
-
-// Use preferred mode from Bauhaus settings
-static bool openInDesignMode()
-{
-    static bool bauhausDetected = false;
-    static bool bauhausPresent = false;
-    // Check if Bauhaus is loaded, that is, a Design mode widget is
-    // registered for the QML mime type.
-    if (!bauhausDetected) {
-        if (const Core::IMode *dm = Core::ModeManager::instance()->mode(QLatin1String(Core::Constants::MODE_DESIGN)))
-            if (const Core::DesignMode *designMode = qobject_cast<const Core::DesignMode *>(dm))
-                bauhausPresent = designMode->registeredMimeTypes().contains(QLatin1String(QmlJSEditor::Constants::QML_MIMETYPE));
-        bauhausDetected =  true;
-    }
-    if (!bauhausPresent)
-        return false;
-
-    return bool(QmlDesigner::Constants::QML_OPENDESIGNMODE_DEFAULT);
-}
-
-QString QmlJSEditorEditable::preferredModeType() const
-{
-    Core::ModeManager *modeManager = Core::ModeManager::instance();
-    if (modeManager->currentMode()
-            && (modeManager->currentMode()->type() == Core::Constants::MODE_DESIGN_TYPE
-                || modeManager->currentMode()->type() == Core::Constants::MODE_EDIT_TYPE))
-    {
-        return modeManager->currentMode()->type();
-    }
-
-    // if we are in other mode than edit or design, use the hard-coded default.
-    // because the editor opening decision is modal, it would be confusing to
-    // have the user also access to this failsafe setting.
-    if (editor()->mimeType() == QLatin1String(QmlJSEditor::Constants::QML_MIMETYPE)
-        && openInDesignMode())
-        return QLatin1String(Core::Constants::MODE_DESIGN_TYPE);
-    return QString();
-}
-
 QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
     TextEditor::BaseTextEditor(parent),
     m_outlineCombo(0),
@@ -682,7 +635,7 @@ QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
     m_updateSelectedElements(false),
     m_findReferences(new FindReferences(this))
 {
-    qRegisterMetaType<QmlJSEditor::Internal::SemanticInfo>("QmlJSEditor::Internal::SemanticInfo");
+    qRegisterMetaType<QmlJSEditor::SemanticInfo>("QmlJSEditor::SemanticInfo");
 
     m_semanticHighlighter = new SemanticHighlighter(this);
     m_semanticHighlighter->start();
@@ -748,8 +701,8 @@ QmlJSTextEditor::QmlJSTextEditor(QWidget *parent) :
         connect(this->document(), SIGNAL(modificationChanged(bool)), this, SLOT(modificationChanged(bool)));
     }
 
-    connect(m_semanticHighlighter, SIGNAL(changed(QmlJSEditor::Internal::SemanticInfo)),
-            this, SLOT(updateSemanticInfo(QmlJSEditor::Internal::SemanticInfo)));
+    connect(m_semanticHighlighter, SIGNAL(changed(QmlJSEditor::SemanticInfo)),
+            this, SLOT(updateSemanticInfo(QmlJSEditor::SemanticInfo)));
 
     connect(this, SIGNAL(refactorMarkerClicked(TextEditor::RefactorMarker)),
             SLOT(onRefactorMarkerClicked(TextEditor::RefactorMarker)));
@@ -885,7 +838,7 @@ void QmlJSTextEditor::onDocumentUpdated(QmlJS::Document::Ptr doc)
     if (doc->ast()) {
         // got a correctly parsed (or recovered) file.
 
-        const SemanticHighlighter::Source source = currentSource(/*force = */ true);
+        const SemanticHighlighterSource source = currentSource(/*force = */ true);
         m_semanticHighlighter->rehighlight(source);
     } else {
         // show parsing errors
@@ -1857,7 +1810,7 @@ bool QmlJSTextEditor::hideContextPane()
     return b;
 }
 
-SemanticHighlighter::Source QmlJSTextEditor::currentSource(bool force)
+SemanticHighlighterSource QmlJSTextEditor::currentSource(bool force)
 {
     int line = 0, column = 0;
     convertPosition(position(), &line, &column);
@@ -1870,119 +1823,8 @@ SemanticHighlighter::Source QmlJSTextEditor::currentSource(bool force)
         code = toPlainText(); // get the source code only when needed.
 
     const unsigned revision = document()->revision();
-    SemanticHighlighter::Source source(snapshot, fileName, code,
+    SemanticHighlighterSource source(snapshot, fileName, code,
                                        line, column, revision);
     source.force = force;
     return source;
 }
-
-SemanticHighlighter::SemanticHighlighter(QObject *parent)
-        : QThread(parent),
-          m_done(false),
-          m_modelManager(0)
-{
-}
-
-SemanticHighlighter::~SemanticHighlighter()
-{
-}
-
-void SemanticHighlighter::abort()
-{
-    QMutexLocker locker(&m_mutex);
-    m_done = true;
-    m_condition.wakeOne();
-}
-
-void SemanticHighlighter::rehighlight(const Source &source)
-{
-    QMutexLocker locker(&m_mutex);
-    m_source = source;
-    m_condition.wakeOne();
-}
-
-bool SemanticHighlighter::isOutdated()
-{
-    QMutexLocker locker(&m_mutex);
-    const bool outdated = ! m_source.fileName.isEmpty() || m_done;
-    return outdated;
-}
-
-void SemanticHighlighter::run()
-{
-    setPriority(QThread::LowestPriority);
-
-    forever {
-        m_mutex.lock();
-
-        while (! (m_done || ! m_source.fileName.isEmpty()))
-            m_condition.wait(&m_mutex);
-
-        const bool done = m_done;
-        const Source source = m_source;
-        m_source.clear();
-
-        m_mutex.unlock();
-
-        if (done)
-            break;
-
-        const SemanticInfo info = semanticInfo(source);
-
-        if (! isOutdated()) {
-            m_mutex.lock();
-            m_lastSemanticInfo = info;
-            m_mutex.unlock();
-
-            emit changed(info);
-        }
-    }
-}
-
-SemanticInfo SemanticHighlighter::semanticInfo(const Source &source)
-{
-    m_mutex.lock();
-    const int revision = m_lastSemanticInfo.revision();
-    m_mutex.unlock();
-
-    Snapshot snapshot;
-    Document::Ptr doc;
-
-    if (! source.force && revision == source.revision) {
-        m_mutex.lock();
-        snapshot = m_lastSemanticInfo.snapshot;
-        doc = m_lastSemanticInfo.document;
-        m_mutex.unlock();
-    }
-
-    if (! doc) {
-        snapshot = source.snapshot;
-        doc = snapshot.documentFromSource(source.code, source.fileName);
-        doc->setEditorRevision(source.revision);
-        doc->parse();
-        snapshot.insert(doc);
-    }
-
-    SemanticInfo semanticInfo;
-    semanticInfo.snapshot = snapshot;
-    semanticInfo.document = doc;
-
-    Interpreter::Context *ctx = new Interpreter::Context;
-    Link link(ctx, doc, snapshot, ModelManagerInterface::instance()->importPaths());
-    semanticInfo.m_context = QSharedPointer<const QmlJS::Interpreter::Context>(ctx);
-    semanticInfo.semanticMessages = link.diagnosticMessages();
-
-    QStringList importPaths;
-    if (m_modelManager)
-        importPaths = m_modelManager->importPaths();
-    Check checker(doc, snapshot, ctx);
-    semanticInfo.semanticMessages.append(checker());
-
-    return semanticInfo;
-}
-
-void SemanticHighlighter::setModelManager(QmlJS::ModelManagerInterface *modelManager)
-{
-    m_modelManager = modelManager;
-}
-
diff --git a/src/plugins/qmljseditor/qmljseditor.h b/src/plugins/qmljseditor/qmljseditor.h
index 4c625cf60c6..f22336a4dbd 100644
--- a/src/plugins/qmljseditor/qmljseditor.h
+++ b/src/plugins/qmljseditor/qmljseditor.h
@@ -38,10 +38,8 @@
 #include <texteditor/basetexteditor.h>
 #include <texteditor/quickfix.h>
 
-#include <QtCore/QWaitCondition>
+#include <QtCore/QSharedPointer>
 #include <QtCore/QModelIndex>
-#include <QtCore/QMutex>
-#include <QtCore/QThread>
 
 QT_BEGIN_NAMESPACE
 class QComboBox;
@@ -62,34 +60,16 @@ namespace QmlJS {
     The top-level namespace of the QmlJSEditor plug-in.
  */
 namespace QmlJSEditor {
-class Highlighter;
 class FindReferences;
 
 namespace Internal {
-
-class QmlJSTextEditor;
 class QmlOutlineModel;
+class QmlJSEditorEditable;
+class SemanticHighlighter;
+struct SemanticHighlighterSource;
+} // namespace Internal
 
-class QmlJSEditorEditable : public TextEditor::BaseTextEditorEditable
-{
-    Q_OBJECT
-
-public:
-    QmlJSEditorEditable(QmlJSTextEditor *);
-    Core::Context context() const;
-
-    bool duplicateSupported() const { return true; }
-    Core::IEditor *duplicate(QWidget *parent);
-    QString id() const;
-    bool isTemporary() const { return false; }
-    virtual bool open(const QString & fileName);
-    virtual QString preferredModeType() const;
-
-private:
-    Core::Context m_context;
-};
-
-struct Declaration
+struct QMLJSEDITOR_EXPORT Declaration
 {
     QString text;
     int startLine;
@@ -105,7 +85,7 @@ struct Declaration
     { }
 };
 
-class Range
+class QMLJSEDITOR_EXPORT Range
 {
 public:
     Range(): ast(0) {}
@@ -116,8 +96,6 @@ public: // attributes
     QTextCursor end;
 };
 
-class SemanticHighlighter;
-
 class QMLJSEDITOR_EXPORT SemanticInfo
 {
 public:
@@ -152,75 +130,7 @@ public: // attributes
 private:
     QSharedPointer<const QmlJS::Interpreter::Context> m_context;
 
-    friend class SemanticHighlighter;
-};
-
-class SemanticHighlighter: public QThread
-{
-    Q_OBJECT
-
-public:
-    SemanticHighlighter(QObject *parent = 0);
-    virtual ~SemanticHighlighter();
-
-    void abort();
-
-    struct Source
-    {
-        QmlJS::Snapshot snapshot;
-        QString fileName;
-        QString code;
-        int line;
-        int column;
-        int revision;
-        bool force;
-
-        Source()
-            : line(0), column(0), revision(0), force(false)
-        { }
-
-        Source(const QmlJS::Snapshot &snapshot,
-               const QString &fileName,
-               const QString &code,
-               int line, int column,
-               int revision)
-            : snapshot(snapshot), fileName(fileName),
-              code(code), line(line), column(column),
-              revision(revision), force(false)
-        { }
-
-        void clear()
-        {
-            snapshot = QmlJS::Snapshot();
-            fileName.clear();
-            code.clear();
-            line = 0;
-            column = 0;
-            revision = 0;
-            force = false;
-        }
-    };
-
-    void rehighlight(const Source &source);
-    void setModelManager(QmlJS::ModelManagerInterface *modelManager);
-
-Q_SIGNALS:
-    void changed(const QmlJSEditor::Internal::SemanticInfo &semanticInfo);
-
-protected:
-    virtual void run();
-
-private:
-    bool isOutdated();
-    SemanticInfo semanticInfo(const Source &source);
-
-private:
-    QMutex m_mutex;
-    QWaitCondition m_condition;
-    bool m_done;
-    Source m_source;
-    SemanticInfo m_lastSemanticInfo;
-    QmlJS::ModelManagerInterface *m_modelManager;
+    friend class Internal::SemanticHighlighter;
 };
 
 class QMLJSEDITOR_EXPORT QmlJSTextEditor : public TextEditor::BaseTextEditor
@@ -237,7 +147,7 @@ public:
     int editorRevision() const;
     bool isOutdated() const;
 
-    QmlOutlineModel *outlineModel() const;
+    Internal::QmlOutlineModel *outlineModel() const;
     QModelIndex outlineModelIndex();
 
     bool updateSelectedElements() const;
@@ -276,7 +186,7 @@ private slots:
 
     void semanticRehighlight();
     void forceSemanticRehighlight();
-    void updateSemanticInfo(const QmlJSEditor::Internal::SemanticInfo &semanticInfo);
+    void updateSemanticInfo(const QmlJSEditor::SemanticInfo &semanticInfo);
     void onCursorPositionChanged();
     void onRefactorMarkerClicked(const TextEditor::RefactorMarker &marker);
 
@@ -289,7 +199,7 @@ protected:
     void resizeEvent(QResizeEvent *event);
     void scrollContentsBy(int dx, int dy);
     TextEditor::BaseTextEditorEditable *createEditableInterface();
-    void createToolBar(QmlJSEditorEditable *editable);
+    void createToolBar(Internal::QmlJSEditorEditable *editable);
     TextEditor::BaseTextEditor::Link findLinkAt(const QTextCursor &cursor, bool resolveTarget = true);
 
     //// brace matching
@@ -307,7 +217,7 @@ private:
     void setSelectedElements();
     QString wordUnderCursor() const;
 
-    SemanticHighlighter::Source currentSource(bool force = false);
+    Internal::SemanticHighlighterSource currentSource(bool force = false);
     QModelIndex indexForPosition(unsigned cursorPosition, const QModelIndex &rootIndex = QModelIndex()) const;
     bool hideContextPane();
 
@@ -320,14 +230,14 @@ private:
     QTimer *m_updateOutlineIndexTimer;
     QTimer *m_cursorPositionTimer;
     QComboBox *m_outlineCombo;
-    QmlOutlineModel *m_outlineModel;
+    Internal::QmlOutlineModel *m_outlineModel;
     QModelIndex m_outlineModelIndex;
     QmlJS::ModelManagerInterface *m_modelManager;
     QTextCharFormat m_occurrencesFormat;
     QTextCharFormat m_occurrencesUnusedFormat;
     QTextCharFormat m_occurrenceRenameFormat;
 
-    SemanticHighlighter *m_semanticHighlighter;
+    Internal::SemanticHighlighter *m_semanticHighlighter;
     SemanticInfo m_semanticInfo;
 
     QList<TextEditor::QuickFixOperation::Ptr> m_quickFixes;
@@ -339,7 +249,6 @@ private:
     FindReferences *m_findReferences;
 };
 
-} // namespace Internal
 } // namespace QmlJSEditor
 
 #endif // QMLJSEDITOR_H
diff --git a/src/plugins/qmljseditor/qmljseditor.pro b/src/plugins/qmljseditor/qmljseditor.pro
index 8a6c725379c..2c3c302e295 100644
--- a/src/plugins/qmljseditor/qmljseditor.pro
+++ b/src/plugins/qmljseditor/qmljseditor.pro
@@ -32,7 +32,9 @@ HEADERS += \
     quicktoolbarsettingspage.h \
     quicktoolbar.h \
     qmljscomponentnamedialog.h \
-    qmljsfindreferences.h
+    qmljsfindreferences.h \
+    qmljseditoreditable.h \
+    qmljssemantichighlighter.h
 
 SOURCES += \
     qmljscodecompletion.cpp \
@@ -58,7 +60,9 @@ SOURCES += \
     quicktoolbarsettingspage.cpp \
     quicktoolbar.cpp \
     qmljscomponentnamedialog.cpp \
-    qmljsfindreferences.cpp
+    qmljsfindreferences.cpp \
+    qmljseditoreditable.cpp \
+    qmljssemantichighlighter.cpp
 
 RESOURCES += qmljseditor.qrc
 OTHER_FILES += QmlJSEditor.pluginspec QmlJSEditor.mimetypes.xml
diff --git a/src/plugins/qmljseditor/qmljseditoreditable.cpp b/src/plugins/qmljseditor/qmljseditoreditable.cpp
new file mode 100644
index 00000000000..0013fc9277b
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljseditoreditable.cpp
@@ -0,0 +1,92 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "qmljseditoreditable.h"
+#include "qmljseditor.h"
+#include "qmljseditorconstants.h"
+
+#include <texteditor/texteditorconstants.h>
+#include <qmldesigner/qmldesignerconstants.h>
+
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/designmode.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/coreconstants.h>
+
+namespace QmlJSEditor {
+namespace Internal {
+
+QmlJSEditorEditable::QmlJSEditorEditable(QmlJSTextEditor *editor)
+    : BaseTextEditorEditable(editor)
+{
+    m_context.add(QmlJSEditor::Constants::C_QMLJSEDITOR_ID);
+    m_context.add(TextEditor::Constants::C_TEXTEDITOR);
+}
+
+// Use preferred mode from Bauhaus settings
+static bool openInDesignMode()
+{
+    static bool bauhausDetected = false;
+    static bool bauhausPresent = false;
+    // Check if Bauhaus is loaded, that is, a Design mode widget is
+    // registered for the QML mime type.
+    if (!bauhausDetected) {
+        if (const Core::IMode *dm = Core::ModeManager::instance()->mode(QLatin1String(Core::Constants::MODE_DESIGN)))
+            if (const Core::DesignMode *designMode = qobject_cast<const Core::DesignMode *>(dm))
+                bauhausPresent = designMode->registeredMimeTypes().contains(QLatin1String(QmlJSEditor::Constants::QML_MIMETYPE));
+        bauhausDetected =  true;
+    }
+    if (!bauhausPresent)
+        return false;
+
+    return bool(QmlDesigner::Constants::QML_OPENDESIGNMODE_DEFAULT);
+}
+
+QString QmlJSEditorEditable::preferredModeType() const
+{
+    Core::ModeManager *modeManager = Core::ModeManager::instance();
+    if (modeManager->currentMode()
+            && (modeManager->currentMode()->type() == Core::Constants::MODE_DESIGN_TYPE
+                || modeManager->currentMode()->type() == Core::Constants::MODE_EDIT_TYPE))
+    {
+        return modeManager->currentMode()->type();
+    }
+
+    // if we are in other mode than edit or design, use the hard-coded default.
+    // because the editor opening decision is modal, it would be confusing to
+    // have the user also access to this failsafe setting.
+    if (editor()->mimeType() == QLatin1String(QmlJSEditor::Constants::QML_MIMETYPE)
+        && openInDesignMode())
+        return QLatin1String(Core::Constants::MODE_DESIGN_TYPE);
+    return QString();
+}
+
+} // namespace Internal
+} // namespace QmlJSEditor
diff --git a/src/plugins/qmljseditor/qmljseditoreditable.h b/src/plugins/qmljseditor/qmljseditoreditable.h
new file mode 100644
index 00000000000..86253b5c995
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljseditoreditable.h
@@ -0,0 +1,62 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef QMLJSEDITOREDITABLE_H
+#define QMLJSEDITOREDITABLE_H
+
+#include <texteditor/basetexteditor.h>
+
+namespace QmlJSEditor {
+class QmlJSTextEditor;
+
+namespace Internal {
+
+class QmlJSEditorEditable : public TextEditor::BaseTextEditorEditable
+{
+    Q_OBJECT
+
+public:
+    explicit QmlJSEditorEditable(QmlJSTextEditor *);
+    Core::Context context() const;
+
+    bool duplicateSupported() const { return true; }
+    Core::IEditor *duplicate(QWidget *parent);
+    QString id() const;
+    bool isTemporary() const { return false; }
+    virtual bool open(const QString & fileName);
+    virtual QString preferredModeType() const;
+
+private:
+    Core::Context m_context;
+};
+
+} // namespace Internal
+} // namespace QmlJSEditor
+
+#endif // QMLJSEDITOREDITABLE_H
diff --git a/src/plugins/qmljseditor/qmljseditorfactory.cpp b/src/plugins/qmljseditor/qmljseditorfactory.cpp
index 61d30e9247e..dbdafac4975 100644
--- a/src/plugins/qmljseditor/qmljseditorfactory.cpp
+++ b/src/plugins/qmljseditor/qmljseditorfactory.cpp
@@ -28,6 +28,7 @@
 **************************************************************************/
 
 #include "qmljseditorfactory.h"
+#include "qmljseditoreditable.h"
 #include "qmljseditor.h"
 #include "qmljseditoractionhandler.h"
 #include "qmljseditorconstants.h"
@@ -124,7 +125,7 @@ Core::IEditor *QmlJSEditorFactory::createEditor(QWidget *parent)
                      SLOT(updateEditorInfoBar(Core::IEditor*)));
         }
     }
-    QmlJSTextEditor *rc = new QmlJSTextEditor(parent);
+    QmlJSEditor::QmlJSTextEditor *rc = new QmlJSEditor::QmlJSTextEditor(parent);
     QmlJSEditorPlugin::instance()->initializeEditor(rc);
     return rc->editableInterface();
 }
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.cpp b/src/plugins/qmljseditor/qmljseditorplugin.cpp
index 0b1cc3f39a7..4aae75e28a5 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.cpp
+++ b/src/plugins/qmljseditor/qmljseditorplugin.cpp
@@ -247,7 +247,7 @@ ExtensionSystem::IPlugin::ShutdownFlag QmlJSEditorPlugin::aboutToShutdown()
     return IPlugin::aboutToShutdown();
 }
 
-void QmlJSEditorPlugin::initializeEditor(QmlJSEditor::Internal::QmlJSTextEditor *editor)
+void QmlJSEditorPlugin::initializeEditor(QmlJSEditor::QmlJSTextEditor *editor)
 {
     QTC_ASSERT(m_instance, /**/);
 
diff --git a/src/plugins/qmljseditor/qmljseditorplugin.h b/src/plugins/qmljseditor/qmljseditorplugin.h
index b45c867dbc7..786a2f26755 100644
--- a/src/plugins/qmljseditor/qmljseditorplugin.h
+++ b/src/plugins/qmljseditor/qmljseditorplugin.h
@@ -58,11 +58,11 @@ namespace QmlJS {
 namespace QmlJSEditor {
 
 class QmlFileWizard;
+class QmlJSTextEditor;
 
 namespace Internal {
 
 class QmlJSEditorFactory;
-class QmlJSTextEditor;
 class QmlJSPreviewRunner;
 class QmlJSQuickFixCollector;
 class QmlTaskManager;
@@ -85,7 +85,7 @@ public:
 
     QmlJSQuickFixCollector *quickFixCollector() const;
 
-    void initializeEditor(QmlJSTextEditor *editor);
+    void initializeEditor(QmlJSEditor::QmlJSTextEditor *editor);
 
 public Q_SLOTS:
     void followSymbolUnderCursor();
diff --git a/src/plugins/qmljseditor/qmljshoverhandler.cpp b/src/plugins/qmljseditor/qmljshoverhandler.cpp
index 5e7f24ddf0c..b2ac1eb4574 100644
--- a/src/plugins/qmljseditor/qmljshoverhandler.cpp
+++ b/src/plugins/qmljseditor/qmljshoverhandler.cpp
@@ -28,6 +28,7 @@
 **************************************************************************/
 
 #include "qmljseditor.h"
+#include "qmljseditoreditable.h"
 #include "qmlexpressionundercursor.h"
 #include "qmljshoverhandler.h"
 
@@ -104,12 +105,12 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
     if (!m_modelManager)
         return;
 
-    QmlJSTextEditor *qmlEditor = qobject_cast<QmlJSTextEditor *>(editor->widget());
+    QmlJSEditor::QmlJSTextEditor *qmlEditor = qobject_cast<QmlJSEditor::QmlJSTextEditor *>(editor->widget());
     if (!qmlEditor)
         return;
 
     if (!matchDiagnosticMessage(qmlEditor, pos)) {
-        const SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
+        const QmlJSEditor::SemanticInfo &semanticInfo = qmlEditor->semanticInfo();
         if (! semanticInfo.isValid() || semanticInfo.revision() != qmlEditor->editorRevision())
             return;
 
@@ -129,7 +130,7 @@ void HoverHandler::identifyMatch(TextEditor::ITextEditor *editor, int pos)
     }
 }
 
-bool HoverHandler::matchDiagnosticMessage(QmlJSTextEditor *qmlEditor, int pos)
+bool HoverHandler::matchDiagnosticMessage(QmlJSEditor::QmlJSTextEditor *qmlEditor, int pos)
 {
     foreach (const QTextEdit::ExtraSelection &sel,
              qmlEditor->extraSelections(TextEditor::BaseTextEditor::CodeWarningsSelection)) {
diff --git a/src/plugins/qmljseditor/qmljshoverhandler.h b/src/plugins/qmljseditor/qmljshoverhandler.h
index 77e967e39df..ea59ccdb79f 100644
--- a/src/plugins/qmljseditor/qmljshoverhandler.h
+++ b/src/plugins/qmljseditor/qmljshoverhandler.h
@@ -49,10 +49,11 @@ class ITextEditor;
 }
 
 namespace QmlJSEditor {
+class QmlJSTextEditor;
+
 namespace Internal {
 
 class SemanticInfo;
-class QmlJSTextEditor;
 
 class HoverHandler : public TextEditor::BaseHoverHandler
 {
@@ -67,7 +68,7 @@ private:
     virtual void identifyMatch(TextEditor::ITextEditor *editor, int pos);
     virtual void operateTooltip(TextEditor::ITextEditor *editor, const QPoint &point);
 
-    bool matchDiagnosticMessage(QmlJSTextEditor *qmlEditor, int pos);
+    bool matchDiagnosticMessage(QmlJSEditor::QmlJSTextEditor *qmlEditor, int pos);
     bool matchColorItem(const QmlJS::LookupContext::Ptr &lookupContext,
                         const QmlJS::Document::Ptr &qmlDocument,
                         const QList<QmlJS::AST::Node *> &astPath,
diff --git a/src/plugins/qmljseditor/qmljsoutline.cpp b/src/plugins/qmljseditor/qmljsoutline.cpp
index b1465819dee..fcfdb885fc7 100644
--- a/src/plugins/qmljseditor/qmljsoutline.cpp
+++ b/src/plugins/qmljseditor/qmljsoutline.cpp
@@ -1,5 +1,6 @@
 #include "qmljsoutline.h"
 #include "qmloutlinemodel.h"
+#include "qmljseditoreditable.h"
 #include "qmljsoutlinetreeview.h"
 
 #include <coreplugin/icore.h>
diff --git a/src/plugins/qmljseditor/qmljsquickfix.h b/src/plugins/qmljseditor/qmljsquickfix.h
index 57e6b2521f6..b316e117e04 100644
--- a/src/plugins/qmljseditor/qmljsquickfix.h
+++ b/src/plugins/qmljseditor/qmljsquickfix.h
@@ -65,7 +65,7 @@ public:
     /// Creates a new state for the given editor.
     QmlJSQuickFixState(TextEditor::BaseTextEditor *editor);
 
-    Internal::SemanticInfo semanticInfo() const;
+    SemanticInfo semanticInfo() const;
 
     /// \returns the snapshot holding the document of the editor.
     QmlJS::Snapshot snapshot() const;
@@ -76,7 +76,7 @@ public:
     const QmlJSRefactoringFile currentFile() const;
 
 private:
-    Internal::SemanticInfo _semanticInfo;
+    SemanticInfo _semanticInfo;
 };
 
 /*!
diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.cpp b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
new file mode 100644
index 00000000000..0881ee879b9
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljssemantichighlighter.cpp
@@ -0,0 +1,152 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "qmljssemantichighlighter.h"
+#include "qmljsmodelmanager.h"
+
+#include <qmljs/qmljsdocument.h>
+#include <qmljs/qmljscheck.h>
+#include <qmljs/qmljsinterpreter.h>
+#include <qmljs/qmljslink.h>
+
+namespace QmlJSEditor {
+namespace Internal {
+
+SemanticHighlighter::SemanticHighlighter(QObject *parent)
+        : QThread(parent),
+          m_done(false),
+          m_modelManager(0)
+{
+}
+
+SemanticHighlighter::~SemanticHighlighter()
+{
+}
+
+void SemanticHighlighter::abort()
+{
+    QMutexLocker locker(&m_mutex);
+    m_done = true;
+    m_condition.wakeOne();
+}
+
+void SemanticHighlighter::rehighlight(const SemanticHighlighterSource &source)
+{
+    QMutexLocker locker(&m_mutex);
+    m_source = source;
+    m_condition.wakeOne();
+}
+
+bool SemanticHighlighter::isOutdated()
+{
+    QMutexLocker locker(&m_mutex);
+    const bool outdated = ! m_source.fileName.isEmpty() || m_done;
+    return outdated;
+}
+
+void SemanticHighlighter::run()
+{
+    setPriority(QThread::LowestPriority);
+
+    forever {
+        m_mutex.lock();
+
+        while (! (m_done || ! m_source.fileName.isEmpty()))
+            m_condition.wait(&m_mutex);
+
+        const bool done = m_done;
+        const SemanticHighlighterSource source = m_source;
+        m_source.clear();
+
+        m_mutex.unlock();
+
+        if (done)
+            break;
+
+        const SemanticInfo info = semanticInfo(source);
+
+        if (! isOutdated()) {
+            m_mutex.lock();
+            m_lastSemanticInfo = info;
+            m_mutex.unlock();
+
+            emit changed(info);
+        }
+    }
+}
+
+SemanticInfo SemanticHighlighter::semanticInfo(const SemanticHighlighterSource &source)
+{
+    m_mutex.lock();
+    const int revision = m_lastSemanticInfo.revision();
+    m_mutex.unlock();
+
+    QmlJS::Snapshot snapshot;
+    QmlJS::Document::Ptr doc;
+
+    if (! source.force && revision == source.revision) {
+        m_mutex.lock();
+        snapshot = m_lastSemanticInfo.snapshot;
+        doc = m_lastSemanticInfo.document;
+        m_mutex.unlock();
+    }
+
+    if (! doc) {
+        snapshot = source.snapshot;
+        doc = snapshot.documentFromSource(source.code, source.fileName);
+        doc->setEditorRevision(source.revision);
+        doc->parse();
+        snapshot.insert(doc);
+    }
+
+    SemanticInfo semanticInfo;
+    semanticInfo.snapshot = snapshot;
+    semanticInfo.document = doc;
+
+    QmlJS::Interpreter::Context *ctx = new QmlJS::Interpreter::Context;
+    QmlJS::Link link(ctx, doc, snapshot, QmlJS::ModelManagerInterface::instance()->importPaths());
+    semanticInfo.m_context = QSharedPointer<const QmlJS::Interpreter::Context>(ctx);
+    semanticInfo.semanticMessages = link.diagnosticMessages();
+
+    QStringList importPaths;
+    if (m_modelManager)
+        importPaths = m_modelManager->importPaths();
+    QmlJS::Check checker(doc, snapshot, ctx);
+    semanticInfo.semanticMessages.append(checker());
+
+    return semanticInfo;
+}
+
+void SemanticHighlighter::setModelManager(QmlJS::ModelManagerInterface *modelManager)
+{
+    m_modelManager = modelManager;
+}
+
+} // namespace Internal
+} // namespace QmlJSEditor
diff --git a/src/plugins/qmljseditor/qmljssemantichighlighter.h b/src/plugins/qmljseditor/qmljssemantichighlighter.h
new file mode 100644
index 00000000000..dff097ba7f2
--- /dev/null
+++ b/src/plugins/qmljseditor/qmljssemantichighlighter.h
@@ -0,0 +1,113 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (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 http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef SEMANTICHIGHLIGHTER_H
+#define SEMANTICHIGHLIGHTER_H
+
+#include "qmljseditor.h"
+
+#include <QtCore/QWaitCondition>
+#include <QtCore/QModelIndex>
+#include <QtCore/QMutex>
+#include <QtCore/QThread>
+
+namespace QmlJSEditor {
+namespace Internal {
+
+struct SemanticHighlighterSource
+{
+    QmlJS::Snapshot snapshot;
+    QString fileName;
+    QString code;
+    int line;
+    int column;
+    int revision;
+    bool force;
+
+    SemanticHighlighterSource()
+        : line(0), column(0), revision(0), force(false)
+    { }
+
+    SemanticHighlighterSource(const QmlJS::Snapshot &snapshot,
+           const QString &fileName,
+           const QString &code,
+           int line, int column,
+           int revision)
+        : snapshot(snapshot), fileName(fileName),
+          code(code), line(line), column(column),
+          revision(revision), force(false)
+    { }
+
+    void clear()
+    {
+        snapshot = QmlJS::Snapshot();
+        fileName.clear();
+        code.clear();
+        line = 0;
+        column = 0;
+        revision = 0;
+        force = false;
+    }
+};
+
+class SemanticHighlighter: public QThread
+{
+    Q_OBJECT
+
+public:
+    SemanticHighlighter(QObject *parent = 0);
+    virtual ~SemanticHighlighter();
+
+    void abort();
+    void rehighlight(const SemanticHighlighterSource &source);
+    void setModelManager(QmlJS::ModelManagerInterface *modelManager);
+
+Q_SIGNALS:
+    void changed(const QmlJSEditor::SemanticInfo &semanticInfo);
+
+protected:
+    virtual void run();
+
+private:
+    bool isOutdated();
+    SemanticInfo semanticInfo(const SemanticHighlighterSource &source);
+
+private:
+    QMutex m_mutex;
+    QWaitCondition m_condition;
+    bool m_done;
+    SemanticHighlighterSource m_source;
+    SemanticInfo m_lastSemanticInfo;
+    QmlJS::ModelManagerInterface *m_modelManager;
+};
+
+} // namespace Internal
+} // namespace QmlJSEditor
+
+#endif // SEMANTICHIGHLIGHTER_H
diff --git a/src/plugins/qmljsinspector/qmljsinspector.cpp b/src/plugins/qmljsinspector/qmljsinspector.cpp
index 997be7ee553..66c9b4333a6 100644
--- a/src/plugins/qmljsinspector/qmljsinspector.cpp
+++ b/src/plugins/qmljsinspector/qmljsinspector.cpp
@@ -187,7 +187,7 @@ void InspectorUi::showDebuggerTooltip(const QPoint &mousePos, TextEditor::ITextE
 {
     Q_UNUSED(mousePos);
     if (m_clientProxy && editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
-        QmlJSEditor::Internal::QmlJSTextEditor *qmlEditor = static_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(editor->widget());
+        QmlJSEditor::QmlJSTextEditor *qmlEditor = static_cast<QmlJSEditor::QmlJSTextEditor*>(editor->widget());
 
         QTextCursor tc(qmlEditor->document());
         tc.setPosition(cursorPos);
diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
index 7dca4c4e428..966ac15e8f0 100644
--- a/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
+++ b/src/plugins/qmljsinspector/qmljslivetextpreview.cpp
@@ -128,7 +128,7 @@ QmlJS::ModelManagerInterface *QmlJSLiveTextPreview::modelManager()
 void QmlJSLiveTextPreview::associateEditor(Core::IEditor *editor)
 {
     if (editor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
-        QmlJSEditor::Internal::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(editor->widget());
+        QmlJSEditor::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::QmlJSTextEditor*>(editor->widget());
         if (qmljsEditor && !m_editors.contains(qmljsEditor)) {
             qmljsEditor->setUpdateSelectedElements(true);
             m_editors << qmljsEditor;
@@ -142,7 +142,7 @@ void QmlJSLiveTextPreview::associateEditor(Core::IEditor *editor)
 void QmlJSLiveTextPreview::unassociateEditor(Core::IEditor *oldEditor)
 {
     if (oldEditor && oldEditor->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) {
-        QmlJSEditor::Internal::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::Internal::QmlJSTextEditor*>(oldEditor->widget());
+        QmlJSEditor::QmlJSTextEditor* qmljsEditor = qobject_cast<QmlJSEditor::QmlJSTextEditor*>(oldEditor->widget());
         if (qmljsEditor && m_editors.contains(qmljsEditor)) {
             m_editors.removeOne(qmljsEditor);
             qmljsEditor->setUpdateSelectedElements(false);
@@ -630,12 +630,12 @@ void QmlJSLiveTextPreview::setClientProxy(ClientProxy *clientProxy)
         connect(m_clientProxy.data(), SIGNAL(objectTreeUpdated()),
                    SLOT(updateDebugIds()));
 
-        foreach(QWeakPointer<QmlJSEditor::Internal::QmlJSTextEditor> qmlEditor, m_editors) {
+        foreach(QWeakPointer<QmlJSEditor::QmlJSTextEditor> qmlEditor, m_editors) {
             if (qmlEditor)
                 qmlEditor.data()->setUpdateSelectedElements(true);
         }
     } else {
-        foreach(QWeakPointer<QmlJSEditor::Internal::QmlJSTextEditor> qmlEditor, m_editors) {
+        foreach(QWeakPointer<QmlJSEditor::QmlJSTextEditor> qmlEditor, m_editors) {
             if (qmlEditor)
                 qmlEditor.data()->setUpdateSelectedElements(false);
         }
diff --git a/src/plugins/qmljsinspector/qmljslivetextpreview.h b/src/plugins/qmljsinspector/qmljslivetextpreview.h
index 0681e6e2cba..da25d594208 100644
--- a/src/plugins/qmljsinspector/qmljslivetextpreview.h
+++ b/src/plugins/qmljsinspector/qmljslivetextpreview.h
@@ -48,10 +48,8 @@ namespace QmlJS {
 }
 
 namespace QmlJSEditor {
-namespace Internal {
     class QmlJSTextEditor;
 }
-}
 
 namespace QmlJSInspector {
 namespace Internal {
@@ -114,7 +112,7 @@ private:
     QmlJS::Document::Ptr m_initialDoc; //the document that was loaded by the server
     QString m_filename;
 
-    QList<QWeakPointer<QmlJSEditor::Internal::QmlJSTextEditor> > m_editors;
+    QList<QWeakPointer<QmlJSEditor::QmlJSTextEditor> > m_editors;
 
     bool m_applyChangesToQmlObserver;
     QmlJS::Document::Ptr m_docWithUnappliedChanges;
-- 
GitLab