2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2019 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2019-11-13 12:09:01 +01:00
|
|
|
|
|
|
|
|
#include "bindingeditorwidget.h"
|
|
|
|
|
|
2023-10-19 17:17:37 +02:00
|
|
|
#include <plaintexteditmodifier.h>
|
|
|
|
|
|
2019-11-13 12:09:01 +01:00
|
|
|
#include <coreplugin/actionmanager/actionmanager.h>
|
2023-02-17 23:21:31 +01:00
|
|
|
#include <coreplugin/coreplugintr.h>
|
|
|
|
|
#include <coreplugin/icore.h>
|
2023-10-19 17:17:37 +02:00
|
|
|
|
|
|
|
|
#include <projectexplorer/projectexplorerconstants.h>
|
|
|
|
|
|
2023-02-17 23:21:31 +01:00
|
|
|
#include <qmljseditor/qmljsautocompleter.h>
|
2019-11-13 12:09:01 +01:00
|
|
|
#include <qmljseditor/qmljscompletionassist.h>
|
2023-02-17 23:21:31 +01:00
|
|
|
#include <qmljseditor/qmljseditor.h>
|
|
|
|
|
#include <qmljseditor/qmljseditordocument.h>
|
2019-11-13 12:09:01 +01:00
|
|
|
#include <qmljseditor/qmljshighlighter.h>
|
|
|
|
|
#include <qmljseditor/qmljshoverhandler.h>
|
|
|
|
|
#include <qmljseditor/qmljssemantichighlighter.h>
|
2023-10-19 17:17:37 +02:00
|
|
|
|
2019-11-13 12:09:01 +01:00
|
|
|
#include <qmljstools/qmljsindenter.h>
|
2021-09-10 18:06:26 +02:00
|
|
|
|
|
|
|
|
#include <utils/fancylineedit.h>
|
2023-10-19 17:17:37 +02:00
|
|
|
#include <utils/mimeconstants.h>
|
2023-09-21 15:51:43 +02:00
|
|
|
#include <utils/transientscroll.h>
|
2019-11-13 12:09:01 +01:00
|
|
|
|
|
|
|
|
#include <QAction>
|
|
|
|
|
|
|
|
|
|
namespace QmlDesigner {
|
|
|
|
|
|
|
|
|
|
BindingEditorWidget::BindingEditorWidget()
|
2020-05-26 16:07:10 +02:00
|
|
|
: m_context(new Core::IContext(this))
|
2019-11-13 12:09:01 +01:00
|
|
|
{
|
2021-09-10 18:06:26 +02:00
|
|
|
Core::Context context(BINDINGEDITOR_CONTEXT_ID,
|
|
|
|
|
ProjectExplorer::Constants::QMLJS_LANGUAGE_ID);
|
|
|
|
|
|
2020-05-26 16:07:10 +02:00
|
|
|
m_context->setWidget(this);
|
2021-09-10 18:06:26 +02:00
|
|
|
m_context->setContext(context);
|
2019-11-13 12:09:01 +01:00
|
|
|
Core::ICore::addContextObject(m_context);
|
|
|
|
|
|
2023-09-21 15:51:43 +02:00
|
|
|
Utils::TransientScrollAreaSupport::support(this);
|
|
|
|
|
|
2019-11-13 12:09:01 +01:00
|
|
|
/*
|
|
|
|
|
* We have to register our own active auto completion shortcut, because the original short cut will
|
|
|
|
|
* use the cursor position of the original editor in the editor manager.
|
|
|
|
|
*/
|
|
|
|
|
m_completionAction = new QAction(tr("Trigger Completion"), this);
|
2021-09-10 18:06:26 +02:00
|
|
|
|
2019-11-13 12:09:01 +01:00
|
|
|
Core::Command *command = Core::ActionManager::registerAction(
|
|
|
|
|
m_completionAction, TextEditor::Constants::COMPLETE_THIS, context);
|
|
|
|
|
command->setDefaultKeySequence(QKeySequence(
|
|
|
|
|
Core::useMacShortcuts
|
|
|
|
|
? tr("Meta+Space")
|
|
|
|
|
: tr("Ctrl+Space")));
|
|
|
|
|
|
2023-09-07 16:11:02 +02:00
|
|
|
connect(m_completionAction, &QAction::triggered, this, [this]() {
|
2019-11-13 12:09:01 +01:00
|
|
|
invokeAssist(TextEditor::Completion);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BindingEditorWidget::~BindingEditorWidget()
|
|
|
|
|
{
|
|
|
|
|
unregisterAutoCompletion();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BindingEditorWidget::unregisterAutoCompletion()
|
|
|
|
|
{
|
|
|
|
|
if (m_completionAction) {
|
|
|
|
|
Core::ActionManager::unregisterAction(m_completionAction, TextEditor::Constants::COMPLETE_THIS);
|
|
|
|
|
delete m_completionAction;
|
|
|
|
|
m_completionAction = nullptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BindingEditorWidget::event(QEvent *event)
|
|
|
|
|
{
|
|
|
|
|
if (event->type() == QEvent::KeyPress) {
|
2023-09-07 16:11:02 +02:00
|
|
|
const QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
|
|
|
|
const bool returnPressed = (keyEvent->key() == Qt::Key_Return)
|
|
|
|
|
|| (keyEvent->key() == Qt::Key_Enter);
|
|
|
|
|
const Qt::KeyboardModifiers mods = keyEvent->modifiers();
|
|
|
|
|
constexpr Qt::KeyboardModifier submitModifier = Qt::ControlModifier;
|
|
|
|
|
const bool submitModed = mods.testFlag(submitModifier);
|
|
|
|
|
|
|
|
|
|
if (!m_isMultiline && (returnPressed && !mods)) {
|
|
|
|
|
emit returnKeyClicked();
|
|
|
|
|
return true;
|
|
|
|
|
} else if (m_isMultiline && (returnPressed && submitModed)) {
|
2019-11-13 12:09:01 +01:00
|
|
|
emit returnKeyClicked();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return QmlJSEditor::QmlJSEditorWidget::event(event);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-15 14:19:06 +01:00
|
|
|
std::unique_ptr<TextEditor::AssistInterface> BindingEditorWidget::createAssistInterface(
|
2022-07-07 18:04:18 +02:00
|
|
|
[[maybe_unused]] TextEditor::AssistKind assistKind, TextEditor::AssistReason assistReason) const
|
2019-11-13 12:09:01 +01:00
|
|
|
{
|
2022-11-15 14:19:06 +01:00
|
|
|
return std::make_unique<QmlJSEditor::QmlJSCompletionAssistInterface>(
|
2023-09-07 16:11:02 +02:00
|
|
|
textCursor(), Utils::FilePath(), assistReason, qmljsdocument->semanticInfo());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BindingEditorWidget::setEditorTextWithIndentation(const QString &text)
|
|
|
|
|
{
|
|
|
|
|
auto *doc = document();
|
|
|
|
|
doc->setPlainText(text);
|
|
|
|
|
|
|
|
|
|
//we don't need to indent an empty text
|
|
|
|
|
//but is also needed for safer text.length()-1 below
|
|
|
|
|
if (text.isEmpty())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
auto modifier = std::make_unique<IndentingTextEditModifier>(
|
|
|
|
|
doc, QTextCursor{doc});
|
|
|
|
|
modifier->indent(0, text.length()-1);
|
2019-11-13 12:09:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BindingDocument::BindingDocument()
|
|
|
|
|
: QmlJSEditor::QmlJSEditorDocument(BINDINGEDITOR_CONTEXT_ID)
|
|
|
|
|
, m_semanticHighlighter(new QmlJSEditor::SemanticHighlighter(this))
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BindingDocument::~BindingDocument()
|
|
|
|
|
{
|
|
|
|
|
delete m_semanticHighlighter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BindingDocument::applyFontSettings()
|
|
|
|
|
{
|
|
|
|
|
TextDocument::applyFontSettings();
|
|
|
|
|
m_semanticHighlighter->updateFontSettings(fontSettings());
|
|
|
|
|
if (!isSemanticInfoOutdated())
|
|
|
|
|
m_semanticHighlighter->rerun(semanticInfo());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BindingDocument::triggerPendingUpdates()
|
|
|
|
|
{
|
|
|
|
|
TextDocument::triggerPendingUpdates(); // calls applyFontSettings if necessary
|
|
|
|
|
if (!isSemanticInfoOutdated())
|
|
|
|
|
m_semanticHighlighter->rerun(semanticInfo());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BindingEditorFactory::BindingEditorFactory()
|
|
|
|
|
{
|
|
|
|
|
setId(BINDINGEDITOR_CONTEXT_ID);
|
2023-02-17 23:21:31 +01:00
|
|
|
setDisplayName(::Core::Tr::tr("Binding Editor"));
|
2020-06-22 11:45:14 +02:00
|
|
|
setEditorActionHandlers(0);
|
2021-09-10 18:06:26 +02:00
|
|
|
addMimeType(BINDINGEDITOR_CONTEXT_ID);
|
2023-10-19 17:17:37 +02:00
|
|
|
addMimeType(Utils::Constants::QML_MIMETYPE);
|
|
|
|
|
addMimeType(Utils::Constants::QMLTYPES_MIMETYPE);
|
|
|
|
|
addMimeType(Utils::Constants::JS_MIMETYPE);
|
2019-11-13 12:09:01 +01:00
|
|
|
|
|
|
|
|
setDocumentCreator([]() { return new BindingDocument; });
|
|
|
|
|
setEditorWidgetCreator([]() { return new BindingEditorWidget; });
|
|
|
|
|
setEditorCreator([]() { return new QmlJSEditor::QmlJSEditor; });
|
|
|
|
|
setAutoCompleterCreator([]() { return new QmlJSEditor::AutoCompleter; });
|
|
|
|
|
setCommentDefinition(Utils::CommentDefinition::CppStyle);
|
|
|
|
|
setParenthesesMatchingEnabled(true);
|
|
|
|
|
setCodeFoldingSupported(true);
|
|
|
|
|
|
|
|
|
|
addHoverHandler(new QmlJSEditor::QmlJSHoverHandler);
|
|
|
|
|
setCompletionAssistProvider(new QmlJSEditor::QmlJSCompletionAssistProvider);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BindingEditorFactory::decorateEditor(TextEditor::TextEditorWidget *editor)
|
|
|
|
|
{
|
2023-05-04 14:43:37 +02:00
|
|
|
editor->textDocument()->setSyntaxHighlighterCreator(
|
|
|
|
|
[] { return new QmlJSEditor::QmlJSHighlighter(); });
|
2019-11-13 12:09:01 +01:00
|
|
|
editor->textDocument()->setIndenter(new QmlJSEditor::Internal::Indenter(
|
|
|
|
|
editor->textDocument()->document()));
|
|
|
|
|
editor->setAutoCompleter(new QmlJSEditor::AutoCompleter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
} // QmlDesigner namespace
|