Qt Quick: Separate Qt Quick Designer and QMLJS editor factories

Currently the QmlJSEditorFactory hardcodes that .qml.ui files are opened
"in Design mode", without any option to explicitly open them directly in
text mode.
While this is the preferred way of working, there are always exceptions.

Separate the "Edit mode by default" and the "Design mode by default"
parts into separate editor factories. The former one is the default
editor for .qml files, the latter for .qml.ui files.

This allows users to explicitly choose "Open With > QML JS Editor" to
open .qml.ui files directly in Edit mode.

Fixes: QTCREATORBUG-18123
Change-Id: I72ab2d25fdc538210123782f6611f9c6e3157dea
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Eike Ziller
2019-07-18 16:19:33 +02:00
parent bc6628d037
commit 59e2774d0d
8 changed files with 83 additions and 35 deletions

View File

@@ -39,7 +39,9 @@
#include <timelineeditor/timelineview.h> #include <timelineeditor/timelineview.h>
#include <pathtool/pathtool.h> #include <pathtool/pathtool.h>
#include <qmljseditor/qmljseditor.h>
#include <qmljseditor/qmljseditorconstants.h> #include <qmljseditor/qmljseditorconstants.h>
#include <qmljseditor/qmljseditordocument.h>
#include <qmljstools/qmljstoolsconstants.h> #include <qmljstools/qmljstoolsconstants.h>
@@ -77,6 +79,29 @@ using namespace QmlDesigner::Internal;
namespace QmlDesigner { namespace QmlDesigner {
namespace Internal {
class QtQuickDesignerFactory : public QmlJSEditor::QmlJSEditorFactory
{
public:
QtQuickDesignerFactory();
};
QtQuickDesignerFactory::QtQuickDesignerFactory()
: QmlJSEditorFactory(QmlJSEditor::Constants::C_QTQUICKDESIGNEREDITOR_ID)
{
setDisplayName(QCoreApplication::translate("OpenWith::Editors", "Qt Quick Designer"));
addMimeType(QmlJSTools::Constants::QMLUI_MIMETYPE);
setDocumentCreator([this]() {
auto document = new QmlJSEditor::QmlJSEditorDocument(id());
document->setIsDesignModePreferred(true);
return document;
});
}
} // namespace Internal
class QmlDesignerPluginPrivate class QmlDesignerPluginPrivate
{ {
public: public:
@@ -87,6 +112,7 @@ public:
DesignModeWidget mainWidget; DesignModeWidget mainWidget;
DesignerSettings settings; DesignerSettings settings;
DesignModeContext *context = nullptr; DesignModeContext *context = nullptr;
QtQuickDesignerFactory m_qtQuickDesignerFactory;
bool blockEditorChange = false; bool blockEditorChange = false;
}; };
@@ -99,7 +125,9 @@ static bool isInDesignerMode()
static bool checkIfEditorIsQtQuick(Core::IEditor *editor) static bool checkIfEditorIsQtQuick(Core::IEditor *editor)
{ {
if (editor && editor->document()->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID) { if (editor
&& (editor->document()->id() == QmlJSEditor::Constants::C_QMLJSEDITOR_ID
|| editor->document()->id() == QmlJSEditor::Constants::C_QTQUICKDESIGNEREDITOR_ID)) {
QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance(); QmlJS::ModelManagerInterface *modelManager = QmlJS::ModelManagerInterface::instance();
QmlJS::Document::Ptr document = modelManager->ensuredGetDocumentForPath(editor->document()->filePath().toString()); QmlJS::Document::Ptr document = modelManager->ensuredGetDocumentForPath(editor->document()->filePath().toString());
if (!document.isNull()) if (!document.isNull())
@@ -545,4 +573,4 @@ void QmlDesignerPlugin::setSettings(const DesignerSettings &s)
} }
} }
} } // namespace QmlDesigner

View File

@@ -1008,37 +1008,39 @@ QmlJSEditor::QmlJSEditor()
addContext(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID); addContext(ProjectExplorer::Constants::QMLJS_LANGUAGE_ID);
} }
QmlJSEditorDocument *QmlJSEditor::qmlJSDocument() const
{
return qobject_cast<QmlJSEditorDocument *>(document());
}
bool QmlJSEditor::isDesignModePreferred() const bool QmlJSEditor::isDesignModePreferred() const
{ {
bool alwaysPreferDesignMode = false;
// always prefer design mode for .ui.qml files
if (textDocument() && textDocument()->mimeType() == QLatin1String(QmlJSTools::Constants::QMLUI_MIMETYPE))
alwaysPreferDesignMode = true;
// stay in design mode if we are there // stay in design mode if we are there
Id mode = ModeManager::currentModeId(); const Id mode = ModeManager::currentModeId();
return alwaysPreferDesignMode || mode == Core::Constants::MODE_DESIGN; return qmlJSDocument()->isDesignModePreferred() || mode == Core::Constants::MODE_DESIGN;
} }
// //
// QmlJSEditorFactory // QmlJSEditorFactory
// //
QmlJSEditorFactory::QmlJSEditorFactory() QmlJSEditorFactory::QmlJSEditorFactory()
: QmlJSEditorFactory(Constants::C_QMLJSEDITOR_ID)
{}
QmlJSEditorFactory::QmlJSEditorFactory(Core::Id _id)
{ {
setId(Constants::C_QMLJSEDITOR_ID); setId(_id);
setDisplayName(QCoreApplication::translate("OpenWith::Editors", "QMLJS Editor")); setDisplayName(QCoreApplication::translate("OpenWith::Editors", "QMLJS Editor"));
addMimeType(QmlJSTools::Constants::QML_MIMETYPE); addMimeType(QmlJSTools::Constants::QML_MIMETYPE);
addMimeType(QmlJSTools::Constants::QMLUI_MIMETYPE);
addMimeType(QmlJSTools::Constants::QMLPROJECT_MIMETYPE); addMimeType(QmlJSTools::Constants::QMLPROJECT_MIMETYPE);
addMimeType(QmlJSTools::Constants::QBS_MIMETYPE); addMimeType(QmlJSTools::Constants::QBS_MIMETYPE);
addMimeType(QmlJSTools::Constants::QMLTYPES_MIMETYPE); addMimeType(QmlJSTools::Constants::QMLTYPES_MIMETYPE);
addMimeType(QmlJSTools::Constants::JS_MIMETYPE); addMimeType(QmlJSTools::Constants::JS_MIMETYPE);
setDocumentCreator([]() { return new QmlJSEditorDocument; }); setDocumentCreator([this]() { return new QmlJSEditorDocument(id()); });
setEditorWidgetCreator([]() { return new QmlJSEditorWidget; }); setEditorWidgetCreator([]() { return new QmlJSEditorWidget; });
setEditorCreator([]() { return new QmlJSEditor; }); setEditorCreator([]() { return new QmlJSEditor; });
setAutoCompleterCreator([]() { return new AutoCompleter; }); setAutoCompleterCreator([]() { return new AutoCompleter; });

View File

@@ -136,6 +136,7 @@ class QMLJSEDITOR_EXPORT QmlJSEditor : public TextEditor::BaseTextEditor
public: public:
QmlJSEditor(); QmlJSEditor();
QmlJSEditorDocument *qmlJSDocument() const;
bool isDesignModePreferred() const override; bool isDesignModePreferred() const override;
}; };
@@ -145,6 +146,7 @@ class QMLJSEDITOR_EXPORT QmlJSEditorFactory : public TextEditor::TextEditorFacto
public: public:
QmlJSEditorFactory(); QmlJSEditorFactory();
QmlJSEditorFactory(Core::Id id);
static void decorateEditor(TextEditor::TextEditorWidget *editor); static void decorateEditor(TextEditor::TextEditorWidget *editor);
}; };

View File

@@ -34,7 +34,8 @@ const char M_CONTEXT[] = "QML JS Editor.ContextMenu";
const char M_REFACTORING_MENU_INSERTION_POINT[] = "QmlJSEditor.RefactorGroup"; const char M_REFACTORING_MENU_INSERTION_POINT[] = "QmlJSEditor.RefactorGroup";
const char C_QMLJSEDITOR_ID[] = "QMLProjectManager.QMLJSEditor"; const char C_QMLJSEDITOR_ID[] = "QmlJSEditor.QMLJSEditor";
const char C_QTQUICKDESIGNEREDITOR_ID[] = "QmlJSEditor.QtQuickDesignerEditor";
const char SETTINGS_CATEGORY_QML[] = "J.QtQuick"; const char SETTINGS_CATEGORY_QML[] = "J.QtQuick";
const char SHOW_QT_QUICK_HELPER[] = "QmlJSEditor.ShowQtQuickHelper"; const char SHOW_QT_QUICK_HELPER[] = "QmlJSEditor.ShowQtQuickHelper";

View File

@@ -563,19 +563,6 @@ void QmlJSEditorDocumentPrivate::acceptNewSemanticInfo(const SemanticInfo &seman
m_outlineModelNeedsUpdate = true; m_outlineModelNeedsUpdate = true;
m_semanticHighlightingNecessary = true; m_semanticHighlightingNecessary = true;
if (m_firstSementicInfo) {
m_firstSementicInfo = false;
if (semanticInfo.document->language() == Dialect::QmlQtQuick2Ui
&& !q->infoBar()->containsInfo(Core::Id(QML_UI_FILE_WARNING))) {
Core::InfoBarEntry info(Core::Id(QML_UI_FILE_WARNING),
tr("This file should only be edited in <b>Design</b> mode."));
info.setCustomButtonInfo(tr("Switch Mode"), []() {
Core::ModeManager::activateMode(Core::Constants::MODE_DESIGN);
});
q->infoBar()->addInfo(info);
}
}
createTextMarks(m_semanticInfo); createTextMarks(m_semanticInfo);
emit q->semanticInfoUpdated(m_semanticInfo); // calls triggerPendingUpdates as necessary emit q->semanticInfoUpdated(m_semanticInfo); // calls triggerPendingUpdates as necessary
} }
@@ -648,10 +635,10 @@ void QmlJSEditorDocumentPrivate::cleanSemanticMarks()
} // Internal } // Internal
QmlJSEditorDocument::QmlJSEditorDocument() QmlJSEditorDocument::QmlJSEditorDocument(Core::Id id)
: d(new Internal::QmlJSEditorDocumentPrivate(this)) : d(new Internal::QmlJSEditorDocumentPrivate(this))
{ {
setId(Constants::C_QMLJSEDITOR_ID); setId(id);
connect(this, &TextEditor::TextDocument::tabSettingsChanged, connect(this, &TextEditor::TextDocument::tabSettingsChanged,
d, &Internal::QmlJSEditorDocumentPrivate::invalidateFormatterCache); d, &Internal::QmlJSEditorDocumentPrivate::invalidateFormatterCache);
setSyntaxHighlighter(new QmlJSHighlighter(document())); setSyntaxHighlighter(new QmlJSHighlighter(document()));
@@ -688,6 +675,28 @@ TextEditor::IAssistProvider *QmlJSEditorDocument::quickFixAssistProvider() const
return Internal::QmlJSEditorPlugin::quickFixAssistProvider(); return Internal::QmlJSEditorPlugin::quickFixAssistProvider();
} }
void QmlJSEditorDocument::setIsDesignModePreferred(bool value)
{
d->m_isDesignModePreferred = value;
if (value) {
if (infoBar()->canInfoBeAdded(QML_UI_FILE_WARNING)) {
Core::InfoBarEntry info(QML_UI_FILE_WARNING,
tr("This file should only be edited in <b>Design</b> mode."));
info.setCustomButtonInfo(tr("Switch Mode"), []() {
Core::ModeManager::activateMode(Core::Constants::MODE_DESIGN);
});
infoBar()->addInfo(info);
}
} else if (infoBar()->containsInfo(QML_UI_FILE_WARNING)) {
infoBar()->removeInfo(QML_UI_FILE_WARNING);
}
}
bool QmlJSEditorDocument::isDesignModePreferred() const
{
return d->m_isDesignModePreferred;
}
void QmlJSEditorDocument::setDiagnosticRanges(const QVector<QTextLayout::FormatRange> &ranges) void QmlJSEditorDocument::setDiagnosticRanges(const QVector<QTextLayout::FormatRange> &ranges)
{ {
d->m_diagnosticRanges = ranges; d->m_diagnosticRanges = ranges;

View File

@@ -43,7 +43,7 @@ class QMLJSEDITOR_EXPORT QmlJSEditorDocument : public TextEditor::TextDocument
{ {
Q_OBJECT Q_OBJECT
public: public:
QmlJSEditorDocument(); QmlJSEditorDocument(Core::Id id);
~QmlJSEditorDocument() override; ~QmlJSEditorDocument() override;
const QmlJSTools::SemanticInfo &semanticInfo() const; const QmlJSTools::SemanticInfo &semanticInfo() const;
@@ -54,6 +54,9 @@ public:
TextEditor::IAssistProvider *quickFixAssistProvider() const override; TextEditor::IAssistProvider *quickFixAssistProvider() const override;
void setIsDesignModePreferred(bool value);
bool isDesignModePreferred() const;
signals: signals:
void updateCodeWarnings(QmlJS::Document::Ptr doc); void updateCodeWarnings(QmlJS::Document::Ptr doc);
void semanticInfoUpdated(const QmlJSTools::SemanticInfo &semanticInfo); void semanticInfoUpdated(const QmlJSTools::SemanticInfo &semanticInfo);

View File

@@ -76,11 +76,11 @@ public:
SemanticHighlighter *m_semanticHighlighter = nullptr; SemanticHighlighter *m_semanticHighlighter = nullptr;
bool m_semanticHighlightingNecessary = false; bool m_semanticHighlightingNecessary = false;
bool m_outlineModelNeedsUpdate = false; bool m_outlineModelNeedsUpdate = false;
bool m_firstSementicInfo = true;
QTimer m_updateOutlineModelTimer; QTimer m_updateOutlineModelTimer;
Internal::QmlOutlineModel *m_outlineModel = nullptr; Internal::QmlOutlineModel *m_outlineModel = nullptr;
QVector<TextEditor::TextMark *> m_diagnosticMarks; QVector<TextEditor::TextMark *> m_diagnosticMarks;
QVector<TextEditor::TextMark *> m_semanticMarks; QVector<TextEditor::TextMark *> m_semanticMarks;
bool m_isDesignModePreferred = false;
}; };
} // Internal } // Internal

View File

@@ -141,10 +141,12 @@ QmlJSEditorPluginPrivate::QmlJSEditorPluginPrivate()
// recompute messages when project data changes (files added or removed) // recompute messages when project data changes (files added or removed)
connect(modelManager, &QmlJS::ModelManagerInterface::projectInfoUpdated, connect(modelManager, &QmlJS::ModelManagerInterface::projectInfoUpdated,
&m_qmlTaskManager, &QmlTaskManager::updateMessages); &m_qmlTaskManager, &QmlTaskManager::updateMessages);
connect(modelManager, &QmlJS::ModelManagerInterface::aboutToRemoveFiles, connect(modelManager,
&m_qmlTaskManager, &QmlTaskManager::documentsRemoved); &QmlJS::ModelManagerInterface::aboutToRemoveFiles,
&m_qmlTaskManager,
&QmlTaskManager::documentsRemoved);
Context context(Constants::C_QMLJSEDITOR_ID); Context context(Constants::C_QMLJSEDITOR_ID, Constants::C_QTQUICKDESIGNEREDITOR_ID);
ActionContainer *contextMenu = ActionManager::createMenu(Constants::M_CONTEXT); ActionContainer *contextMenu = ActionManager::createMenu(Constants::M_CONTEXT);
ActionContainer *qmlToolsMenu = ActionManager::actionContainer(Id(QmlJSTools::Constants::M_TOOLS_QMLJS)); ActionContainer *qmlToolsMenu = ActionManager::actionContainer(Id(QmlJSTools::Constants::M_TOOLS_QMLJS));
@@ -352,7 +354,8 @@ void QmlJSEditorPluginPrivate::autoFormatOnSave(IDocument *document)
return; return;
// Check that we are dealing with a QML/JS editor // Check that we are dealing with a QML/JS editor
if (document->id() != Constants::C_QMLJSEDITOR_ID) if (document->id() != Constants::C_QMLJSEDITOR_ID
&& document->id() != Constants::C_QTQUICKDESIGNEREDITOR_ID)
return; return;
// Check if file is contained in the current project (if wished) // Check if file is contained in the current project (if wished)