/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of Qt Creator. ** ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ****************************************************************************/ #include "texteditorview.h" #include "texteditorwidget.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace QmlDesigner { const char TEXTEDITOR_CONTEXT_ID[] = "QmlDesigner.TextEditorContext"; TextEditorView::TextEditorView(QObject *parent) : AbstractView(parent) , m_widget(new TextEditorWidget(this)) , m_textEditorContext(new Internal::TextEditorContext(m_widget)) { Core::ICore::addContextObject(m_textEditorContext); Core::Context context(TEXTEDITOR_CONTEXT_ID); /* * 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. */ QAction *completionAction = new QAction(tr("Trigger Completion"), this); Core::Command *command = Core::ActionManager::registerAction(completionAction, TextEditor::Constants::COMPLETE_THIS, context); command->setDefaultKeySequence(QKeySequence(Core::useMacShortcuts ? tr("Meta+Space") : tr("Ctrl+Space"))); connect(completionAction, &QAction::triggered, [this]() { if (m_widget->textEditor()) m_widget->textEditor()->editorWidget()->invokeAssist(TextEditor::Completion); }); } TextEditorView::~TextEditorView() { // m_textEditorContext is responsible for deleting the widget } void TextEditorView::modelAttached(Model *model) { Q_ASSERT(model); m_widget->clearStatusBar(); AbstractView::modelAttached(model); auto textEditor = qobject_cast( QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor()->duplicate()); Core::Context context = textEditor->context(); context.prepend(TEXTEDITOR_CONTEXT_ID); /* * Set the context of the text editor, but we add another special context to override shortcuts. */ m_textEditorContext->setContext(context); m_widget->setTextEditor(textEditor); } void TextEditorView::modelAboutToBeDetached(Model *model) { AbstractView::modelAboutToBeDetached(model); m_widget->setTextEditor(nullptr); // in case the user closed it explicit we do not want to do anything with the editor if (TextEditor::BaseTextEditor *textEditor = QmlDesignerPlugin::instance()->currentDesignDocument()->textEditor()) { QmlDesignerPlugin::instance()->emitCurrentTextEditorChanged(textEditor); } } void TextEditorView::importsChanged(const QList &/*addedImports*/, const QList &/*removedImports*/) { } void TextEditorView::nodeAboutToBeRemoved(const ModelNode &/*removedNode*/) { } void TextEditorView::rootNodeTypeChanged(const QString &/*type*/, int /*majorVersion*/, int /*minorVersion*/) { } void TextEditorView::propertiesAboutToBeRemoved(const QList& /*propertyList*/) { } void TextEditorView::nodeReparented(const ModelNode &/*node*/, const NodeAbstractProperty &/*newPropertyParent*/, const NodeAbstractProperty &/*oldPropertyParent*/, AbstractView::PropertyChangeFlags /*propertyChange*/) { } WidgetInfo TextEditorView::widgetInfo() { return createWidgetInfo(m_widget, nullptr, "TextEditor", WidgetInfo::CentralPane, 0, tr("Text Editor"), DesignerWidgetFlags::IgnoreErrors); } void TextEditorView::contextHelp(const Core::IContext::HelpCallback &callback) const { AbstractView::contextHelp(callback); } void TextEditorView::qmlJSEditorContextHelp(const Core::IContext::HelpCallback &callback) const { if (m_widget->textEditor()) m_widget->textEditor()->contextHelp(callback); else callback({}); } void TextEditorView::nodeIdChanged(const ModelNode& /*node*/, const QString &/*newId*/, const QString &/*oldId*/) { } void TextEditorView::selectedNodesChanged(const QList &/*selectedNodeList*/, const QList &/*lastSelectedNodeList*/) { if (!m_errorState) m_widget->jumpTextCursorToSelectedModelNode(); } void TextEditorView::customNotification(const AbstractView * /*view*/, const QString &identifier, const QList &/*nodeList*/, const QList &/*data*/) { if (identifier == StartRewriterApply) m_widget->setBlockCursorSelectionSynchronisation(true); else if (identifier == EndRewriterApply) m_widget->setBlockCursorSelectionSynchronisation(false); } void TextEditorView::documentMessagesChanged(const QList &errors, const QList &) { if (errors.isEmpty()) { m_widget->clearStatusBar(); m_errorState = false; } else { const DocumentMessage &error = errors.constFirst(); m_widget->setStatusText(QString("%1 (Line: %2)").arg(error.description()).arg(error.line())); m_errorState = true; } } bool TextEditorView::changeToMoveTool() { return true; } void TextEditorView::changeToDragTool() { } bool TextEditorView::changeToMoveTool(const QPointF &/*beginPoint*/) { return true; } void TextEditorView::changeToSelectionTool() { } void TextEditorView::changeToResizeTool() { } void TextEditorView::changeToTransformTools() { } void TextEditorView::changeToCustomTool() { } void TextEditorView::auxiliaryDataChanged(const ModelNode &/*node*/, const PropertyName &/*name*/, const QVariant &/*data*/) { } void TextEditorView::instancesCompleted(const QVector &/*completedNodeList*/) { } void TextEditorView::instanceInformationsChanged(const QMultiHash &/*informationChangeHash*/) { } void TextEditorView::instancesRenderImageChanged(const QVector &/*nodeList*/) { } void TextEditorView::instancesChildrenChanged(const QVector &/*nodeList*/) { } void TextEditorView::rewriterBeginTransaction() { } void TextEditorView::rewriterEndTransaction() { } void TextEditorView::gotoCursorPosition(int line, int column) { if (m_widget) m_widget->gotoCursorPosition(line, column); } void TextEditorView::reformatFile() { int oldLine = -1; if (m_widget) oldLine = m_widget->currentLine(); QByteArray editorState = m_widget->textEditor()->saveState(); auto document = qobject_cast(Core::EditorManager::instance()->currentDocument()); /* Reformat document if we have a .ui.qml file */ if (document && document->filePath().toString().endsWith(".ui.qml") && DesignerSettings::getValue(DesignerSettingsKey::REFORMAT_UI_QML_FILES).toBool()) { QmlJS::Document::Ptr currentDocument(document->semanticInfo().document); QmlJS::Snapshot snapshot = QmlJS::ModelManagerInterface::instance()->snapshot(); if (document->isSemanticInfoOutdated()) { QmlJS::Document::MutablePtr latestDocument; const QString fileName = document->filePath().toString(); latestDocument = snapshot.documentFromSource(QString::fromUtf8(document->contents()), fileName, QmlJS::ModelManagerInterface::guessLanguageOfFile(fileName)); latestDocument->parseQml(); snapshot.insert(latestDocument); currentDocument = latestDocument; } if (!currentDocument->isParsedCorrectly()) return; const QString &newText = QmlJS::reformat(currentDocument); QTextCursor tc(document->document()); Utils::ChangeSet changeSet; changeSet.replace(0, document->plainText().length(), newText); changeSet.apply(&tc); m_widget->textEditor()->restoreState(editorState); if (m_widget) m_widget->gotoCursorPosition(oldLine, 0); } } void TextEditorView::instancePropertyChanged(const QList > &/*propertyList*/) { } } // namespace QmlDesigner