diff --git a/src/plugins/qmldesigner/components/debugview/debugview.cpp b/src/plugins/qmldesigner/components/debugview/debugview.cpp index 19b49711ab6..ce4b982267e 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.cpp +++ b/src/plugins/qmldesigner/components/debugview/debugview.cpp @@ -264,6 +264,25 @@ void DebugView::auxiliaryDataChanged(const ModelNode &node, const PropertyName & } } +void DebugView::documentMessagesChanged(const QList &errors, const QList &warnings) +{ + if (isDebugViewEnabled()) { + QTextStream message; + QString string; + message.setString(&string); + + foreach (const RewriterError &error, errors) { + message << error.toString(); + } + + foreach (const RewriterError &warning, warnings) { + message << warning.toString(); + } + + log("::documentMessageChanged:", string); + } +} + void DebugView::rewriterBeginTransaction() { if (isDebugViewEnabled()) diff --git a/src/plugins/qmldesigner/components/debugview/debugview.h b/src/plugins/qmldesigner/components/debugview/debugview.h index 23e6a7db155..c25f655d75a 100644 --- a/src/plugins/qmldesigner/components/debugview/debugview.h +++ b/src/plugins/qmldesigner/components/debugview/debugview.h @@ -65,6 +65,7 @@ public: void propertiesRemoved(const QList &propertyList) override; void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override; + void documentMessagesChanged(const QList &errors, const QList &warnings) override; void rewriterBeginTransaction() override; void rewriterEndTransaction() override; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp index 7a242a1a961..e8ffa47a946 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.cpp @@ -258,7 +258,7 @@ WidgetInfo FormEditorView::widgetInfo() if (!m_formEditorWidget) createFormEditorWidget(); - return createWidgetInfo(m_formEditorWidget.data(), 0, "FormEditor", WidgetInfo::CentralPane, 0, tr("Form Editor")); + return createWidgetInfo(m_formEditorWidget.data(), 0, "FormEditor", WidgetInfo::CentralPane, 0, tr("Form Editor"), DesignerWidgetFlags::IgnoreErrors); } FormEditorWidget *FormEditorView::formEditorWidget() @@ -284,6 +284,17 @@ void FormEditorView::selectedNodesChanged(const QList &selectedNodeLi m_scene->update(); } +void FormEditorView::documentMessagesChanged(const QList &errors, const QList &warnings) +{ + if (!errors.isEmpty()) + formEditorWidget()->showErrorMessageBox(errors); + else + formEditorWidget()->hideErrorMessageBox(); + + if (!warnings.isEmpty()) + formEditorWidget()->showWarningMessageBox(warnings); +} + void FormEditorView::customNotification(const AbstractView * /*view*/, const QString &identifier, const QList &/*nodeList*/, const QList &/*data*/) { if (identifier == QStringLiteral("puppet crashed")) @@ -511,6 +522,17 @@ double FormEditorView::spacing() const return m_formEditorWidget->spacing(); } +void FormEditorView::gotoError(int line, int column) +{ + if (m_gotoErrorCallback) + m_gotoErrorCallback(line, column); +} + +void FormEditorView::setGotoErrorCallback(std::function gotoErrorCallback) +{ + m_gotoErrorCallback = gotoErrorCallback; +} + QList FormEditorView::adjustStatesForModelNodes(const QList &nodeList) const { QList adjustedNodeList; diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorview.h b/src/plugins/qmldesigner/components/formeditor/formeditorview.h index 00b4e637a07..d4b55fb3b1d 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorview.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorview.h @@ -26,6 +26,7 @@ #include +#include #include QT_BEGIN_NAMESPACE @@ -74,6 +75,9 @@ public: void selectedNodesChanged(const QList &selectedNodeList, const QList &lastSelectedNodeList) override; + + virtual void documentMessagesChanged(const QList &errors, const QList &warnings) override; + void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; // FormEditorView @@ -109,6 +113,8 @@ public: double containerPadding() const; double spacing() const; void deActivateItemCreator(); + void gotoError(int, int); + void setGotoErrorCallback(std::function gotoErrorCallback); protected: void reset(); @@ -135,6 +141,7 @@ private: //variables std::unique_ptr m_dragTool; AbstractFormEditorTool *m_currentTool; int m_transactionCounter; + std::function m_gotoErrorCallback; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp index d4053e5ae53..0fb9389262d 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.cpp @@ -252,6 +252,34 @@ void FormEditorWidget::setFocus() m_graphicsView->setFocus(Qt::OtherFocusReason); } +void FormEditorWidget::showErrorMessageBox(const QList &errors) +{ + errorWidget()->setErrors(errors); + errorWidget()->setVisible(true); + m_graphicsView->setDisabled(true); + m_toolBox->setDisabled(true); +} + +void FormEditorWidget::hideErrorMessageBox() +{ + if (!m_documentErrorWidget.isNull()) + errorWidget()->setVisible(false); + + m_graphicsView->setDisabled(false); + m_toolBox->setDisabled(false); +} + +void FormEditorWidget::showWarningMessageBox(const QList &warnings) +{ + if (!errorWidget()->warningsEnabled()) + return; + + errorWidget()->setWarnings(warnings); + errorWidget()->setVisible(true); + m_graphicsView->setDisabled(true); + m_toolBox->setDisabled(true); +} + ZoomAction *FormEditorWidget::zoomAction() const { return m_zoomAction.data(); @@ -325,6 +353,19 @@ QRectF FormEditorWidget::rootItemRect() const return m_graphicsView->rootItemRect(); } +DocumentWarningWidget *FormEditorWidget::errorWidget() +{ + if (m_documentErrorWidget.isNull()) { + m_documentErrorWidget = new DocumentWarningWidget(this); + connect(m_documentErrorWidget.data(), &DocumentWarningWidget::gotoCodeClicked, [=] + (const QString &, int codeLine, int codeColumn) { + m_formEditorView->gotoError(codeLine, codeColumn); + }); + } + return m_documentErrorWidget; +} + + } diff --git a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h index 95c10bcd82b..be6e37b3cec 100644 --- a/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h +++ b/src/plugins/qmldesigner/components/formeditor/formeditorwidget.h @@ -24,6 +24,8 @@ ****************************************************************************/ #pragma once +#include + #include #include @@ -72,9 +74,15 @@ public: void setFocus(); + void showErrorMessageBox(const QList &errors); + void hideErrorMessageBox(); + + void showWarningMessageBox(const QList &warnings); + protected: void wheelEvent(QWheelEvent *event); QActionGroup *toolActionGroup() const; + DocumentWarningWidget *errorWidget(); private slots: void changeTransformTool(bool checked); @@ -99,6 +107,7 @@ private: QPointer m_rootHeightAction; QPointer m_backgroundAction; QPointer m_resetAction; + QPointer m_documentErrorWidget; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/texteditor/texteditor.pri b/src/plugins/qmldesigner/components/texteditor/texteditor.pri index ae66f38eef7..d1583631b3d 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditor.pri +++ b/src/plugins/qmldesigner/components/texteditor/texteditor.pri @@ -1,5 +1,7 @@ VPATH += $$PWD SOURCES += texteditorview.cpp \ - texteditorwidget.cpp + texteditorwidget.cpp \ + $$PWD/texteditorstatusbar.cpp HEADERS += texteditorview.h \ - texteditorwidget.h + texteditorwidget.h \ + $$PWD/texteditorstatusbar.h diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp new file mode 100644 index 00000000000..98622ebaedb --- /dev/null +++ b/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.cpp @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** 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 "texteditorstatusbar.h" + +#include + +#include + +namespace QmlDesigner { + +TextEditorStatusBar::TextEditorStatusBar(QWidget *parent) : QToolBar(parent), m_label(new QLabel(this)) +{ + QWidget *spacer = new QWidget(this); + spacer->setMinimumWidth(50); + addWidget(spacer); + addWidget(m_label); + + /* We have to set another .css, since the central widget has already a style sheet */ + m_label->setStyleSheet(QString("QLabel { color :%1 }").arg(Utils::creatorTheme()->color(Utils::Theme::TextColorError).name())); +} + +void TextEditorStatusBar::clearText() +{ + m_label->clear(); +} + +void TextEditorStatusBar::setText(const QString &text) +{ + m_label->setText(text); +} + +} // namespace QmlDesigner + diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.h b/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.h new file mode 100644 index 00000000000..493c3a9b814 --- /dev/null +++ b/src/plugins/qmldesigner/components/texteditor/texteditorstatusbar.h @@ -0,0 +1,45 @@ +/**************************************************************************** +** +** 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. +** +****************************************************************************/ +#pragma once + +#include +#include + +namespace QmlDesigner { + +class TextEditorStatusBar : public QToolBar +{ + Q_OBJECT +public: + explicit TextEditorStatusBar(QWidget *parent = 0); + void clearText(); + void setText(const QString &text); +private: + QLabel *m_label; +}; + +} // namespace QmlDesigner + + diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp index 2c40d5ea278..20758c46b38 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.cpp @@ -51,7 +51,6 @@ TextEditorView::TextEditorView(QObject *parent) : AbstractView(parent) , m_widget(new TextEditorWidget(this)) { - // not completely sure that we need this to just call the right help method -> Internal::TextEditorContext *textEditorContext = new Internal::TextEditorContext(m_widget.get()); Core::ICore::addContextObject(textEditorContext); } @@ -96,7 +95,7 @@ void TextEditorView::nodeReparented(const ModelNode &/*node*/, const NodeAbstrac WidgetInfo TextEditorView::widgetInfo() { - return createWidgetInfo(m_widget.get(), 0, "TextEditor", WidgetInfo::CentralPane, 0, tr("Text Editor")); + return createWidgetInfo(m_widget.get(), 0, "TextEditor", WidgetInfo::CentralPane, 0, tr("Text Editor"), DesignerWidgetFlags::IgnoreErrors); } QString TextEditorView::contextHelpId() const @@ -123,6 +122,16 @@ void TextEditorView::customNotification(const AbstractView * /*view*/, const QSt { } +void TextEditorView::documentMessagesChanged(const QList &errors, const QList &) +{ + if (errors.isEmpty()) { + m_widget->clearStatusBar(); + } else { + const RewriterError error = errors.first(); + m_widget->setStatusText(QString("%1 (Line: %2)").arg(error.description()).arg(error.line())); + } +} + bool TextEditorView::changeToMoveTool() { return true; @@ -181,6 +190,12 @@ void TextEditorView::rewriterEndTransaction() { } +void TextEditorView::gotoCursorPosition(int line, int column) +{ + if (m_widget) + m_widget->gotoCursorPosition(line, column); +} + void TextEditorView::instancePropertyChanged(const QList > &/*propertyList*/) { } diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorview.h b/src/plugins/qmldesigner/components/texteditor/texteditorview.h index 2c18f178c1a..178096481cb 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorview.h +++ b/src/plugins/qmldesigner/components/texteditor/texteditorview.h @@ -59,6 +59,7 @@ public: void selectedNodesChanged(const QList &selectedNodeList, const QList &lastSelectedNodeList) override; void customNotification(const AbstractView *view, const QString &identifier, const QList &nodeList, const QList &data) override; + void documentMessagesChanged(const QList &errors, const QList &warnings) override; // TextEditorView WidgetInfo widgetInfo() override; @@ -87,6 +88,8 @@ public: void deActivateItemCreator(); + void gotoCursorPosition(int line, int column); + private: std::unique_ptr m_widget; }; diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp index 91c99606a8f..c287993c85d 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.cpp @@ -25,7 +25,9 @@ #include "texteditorwidget.h" +#include #include + #include #include @@ -38,10 +40,13 @@ namespace QmlDesigner { TextEditorWidget::TextEditorWidget(TextEditorView *textEditorView) : QWidget() , m_textEditorView(textEditorView) + , m_statusBar(new TextEditorStatusBar(this)) { QBoxLayout *layout = new QVBoxLayout(this); - layout->setMargin(0); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(m_statusBar); m_updateSelectionTimer.setSingleShot(true); m_updateSelectionTimer.setInterval(200); @@ -52,7 +57,9 @@ TextEditorWidget::TextEditorWidget(TextEditorView *textEditorView) : QWidget() void TextEditorWidget::setTextEditor(TextEditor::BaseTextEditor *textEditor) { m_textEditor.reset(textEditor); + layout()->removeWidget(m_statusBar); layout()->addWidget(textEditor->editorWidget()); + layout()->addWidget(m_statusBar); connect(textEditor->editorWidget(), &QPlainTextEdit::cursorPositionChanged, @@ -104,4 +111,22 @@ void TextEditorWidget::jumpTextCursorToSelectedModelNode() } } +void TextEditorWidget::gotoCursorPosition(int line, int column) +{ + if (m_textEditor) { + m_textEditor->editorWidget()->gotoLine(line, column); + m_textEditor->editorWidget()->setFocus(); + } +} + +void TextEditorWidget::setStatusText(const QString &text) +{ + m_statusBar->setText(text); +} + +void TextEditorWidget::clearStatusBar() +{ + m_statusBar->clearText(); +} + } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h index 26eca933c9e..5922729ceb9 100644 --- a/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h +++ b/src/plugins/qmldesigner/components/texteditor/texteditorwidget.h @@ -34,6 +34,7 @@ namespace QmlDesigner { class TextEditorView; +class TextEditorStatusBar; class TextEditorWidget : public QWidget { @@ -51,6 +52,10 @@ public: QString contextHelpId() const; void jumpTextCursorToSelectedModelNode(); + void gotoCursorPosition(int line, int column); + + void setStatusText(const QString &text); + void clearStatusBar(); private: void updateSelectionByCursorPosition(); @@ -58,6 +63,7 @@ private: std::unique_ptr m_textEditor; QPointer m_textEditorView; QTimer m_updateSelectionTimer; + TextEditorStatusBar *m_statusBar; }; } // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/include/abstractview.h b/src/plugins/qmldesigner/designercore/include/abstractview.h index 435335f4404..98bb27982f0 100644 --- a/src/plugins/qmldesigner/designercore/include/abstractview.h +++ b/src/plugins/qmldesigner/designercore/include/abstractview.h @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -55,6 +56,11 @@ class NodeInstanceView; class RewriterView; class QmlModelState; +enum DesignerWidgetFlags { + DisableOnError, + IgnoreErrors +}; + class WidgetInfo { public: @@ -93,18 +99,13 @@ public: CentralPane // not used }; - WidgetInfo() - : widget(0), - toolBarWidgetFactory(0) - { - } - QString uniqueId; QString tabName; - QWidget *widget; + QWidget *widget = nullptr; int placementPriority; PlacementHint placementHint; - ToolBarWidgetFactoryInterface *toolBarWidgetFactory; + ToolBarWidgetFactoryInterface *toolBarWidgetFactory = nullptr; + DesignerWidgetFlags widgetFlags = DesignerWidgetFlags::DisableOnError; }; class QMLDESIGNERCORE_EXPORT AbstractView : public QObject @@ -162,6 +163,8 @@ public: QList allModelNodes() const; + void emitDocumentMessage(const QList &errors, const QList &warnings = QList()); + void emitDocumentMessage(const QString &error); void emitCustomNotification(const QString &identifier); void emitCustomNotification(const QString &identifier, const QList &nodeList); void emitCustomNotification(const QString &identifier, const QList &nodeList, const QList &data); @@ -227,6 +230,8 @@ public: virtual void scriptFunctionsChanged(const ModelNode &node, const QStringList &scriptFunctionList); + virtual void documentMessagesChanged(const QList &errors, const QList &warnings); + void changeRootNodeType(const TypeName &type, int majorVersion, int minorVersion); NodeInstanceView *nodeInstanceView() const; @@ -256,7 +261,7 @@ protected: const QString &uniqueId = QString(), WidgetInfo::PlacementHint placementHint = WidgetInfo::NoPane, int placementPriority = 0, - const QString &tabName = QString()); + const QString &tabName = QString(), DesignerWidgetFlags widgetFlags = DesignerWidgetFlags::DisableOnError); private: //functions QList toModelNodeList(const QList &nodeList) const; diff --git a/src/plugins/qmldesigner/designercore/include/model.h b/src/plugins/qmldesigner/designercore/include/model.h index dafc4d2c466..8d9998a8a21 100644 --- a/src/plugins/qmldesigner/designercore/include/model.h +++ b/src/plugins/qmldesigner/designercore/include/model.h @@ -26,6 +26,9 @@ #pragma once #include + +#include + #include #include @@ -108,6 +111,7 @@ public: TextModifier *textModifier() const; void setTextModifier(TextModifier *textModifier); + void setDocumentMessages(const QList &errors, const QList &warnings); protected: Model(); diff --git a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h index 3a450884854..86c734083e0 100644 --- a/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h +++ b/src/plugins/qmldesigner/designercore/include/nodeinstanceview.h @@ -133,10 +133,6 @@ public: void sendToken(const QString &token, int number, const QVector &nodeVector); -signals: - void qmlPuppetCrashed(); - void qmlPuppetError(const QString &errorMessage); - protected: void timerEvent(QTimerEvent *event) override; diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index d8ea075273f..3d3ea3b72a1 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -34,6 +34,8 @@ #include #include +#include + namespace QmlJS { class Document; class ScopeChain; @@ -154,8 +156,7 @@ public: QList getCppTypes(); -signals: - void errorsChanged(const QList &errors); + void setWidgetStatusCallback(std::function setWidgetStatusCallback); public slots: void qmlTextChanged(); @@ -172,6 +173,7 @@ protected: // functions void applyModificationGroupChanges(); void applyChanges(); void amendQmlText(); + void notifyErrorsAndWarnings(const QList &errors); private: //variables TextModifier *m_textModifier = nullptr; @@ -190,6 +192,7 @@ private: //variables QString m_lastCorrectQmlSource; QTimer m_amendTimer; bool m_instantQmlTextUpdate = false; + std::function m_setWidgetStatusCallback; }; } //QmlDesigner diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp index f507fb83619..b92e31f04c5 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.cpp @@ -84,14 +84,15 @@ namespace QmlDesigner { -static void showCannotConnectToPuppetWarningAndSwitchToEditMode() +void NodeInstanceServerProxy::showCannotConnectToPuppetWarningAndSwitchToEditMode() { #ifndef QMLDESIGNER_TEST - Core::AsynchronousMessageBox::warning(QCoreApplication::translate("NodeInstanceServerProxy", "Cannot Connect to QML Emulation Layer (QML Puppet)"), - QCoreApplication::translate("NodeInstanceServerProxy", "The executable of the QML emulation layer (QML Puppet) may not be responding. " - "Switching to another kit might help.")); + Core::AsynchronousMessageBox::warning(tr("Cannot Connect to QML Emulation Layer (QML Puppet)"), + tr("The executable of the QML emulation layer (QML Puppet) may not be responding. " + "Switching to another kit might help.")); QmlDesignerPlugin::instance()->switchToTextModeDeferred(); + m_nodeInstanceView->emitDocumentMessage(tr("Cannot Connect to QML Emulation Layer (QML Puppet)")); #endif } @@ -192,12 +193,7 @@ NodeInstanceServerProxy::NodeInstanceServerProxy(NodeInstanceView *nodeInstanceV } } else { - Core::AsynchronousMessageBox::warning(tr("Cannot Start QML Emulation Layer (QML Puppet)"), - tr("The executable of the QML emulation layer (QML Puppet) process cannot be started or does not respond.")); - -#ifndef QMLDESIGNER_TEST - QmlDesignerPlugin::instance()->switchToTextModeDeferred(); -#endif + showCannotConnectToPuppetWarningAndSwitchToEditMode(); } m_localServer->close(); diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h index 009c4b27630..f0984f7304b 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceserverproxy.h @@ -102,6 +102,7 @@ private slots: void printEditorProcessOutput(); void printPreviewProcessOutput(); void printRenderProcessOutput(); + void showCannotConnectToPuppetWarningAndSwitchToEditMode(); private: QFile m_captureFileForTest; QTimer m_firstTimer; diff --git a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp index 595ed1db6c8..e22b745a1e8 100644 --- a/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp +++ b/src/plugins/qmldesigner/designercore/instances/nodeinstanceview.cpp @@ -191,13 +191,11 @@ void NodeInstanceView::handleCrash() if (elaspsedTimeSinceLastCrash > forceRestartTime) restartProcess(); else - emit qmlPuppetCrashed(); + emitDocumentMessage(tr("Qt Quick emulation layer crashed.")); emitCustomNotification(QStringLiteral("puppet crashed")); } - - void NodeInstanceView::restartProcess() { if (m_restartProcessTimerId) @@ -1266,14 +1264,14 @@ void NodeInstanceView::token(const TokenCommand &command) nodeVector.append(modelNodeForInternalId(instanceId)); } - emitInstanceToken(command.tokenName(), command.tokenNumber(), nodeVector); } void NodeInstanceView::debugOutput(const DebugOutputCommand & command) { + RewriterError error(tr("Qt Quick emulation layer crashed.")); if (command.instanceIds().isEmpty()) { - qmlPuppetError(command.text()); // TODO: connect that somewhere to show that to the user + emitDocumentMessage(command.text()); } else { QVector instanceIdsWithChangedErrors; foreach (qint32 instanceId, command.instanceIds()) { @@ -1282,7 +1280,7 @@ void NodeInstanceView::debugOutput(const DebugOutputCommand & command) if (instance.setError(command.text())) instanceIdsWithChangedErrors.append(instanceId); } else { - qmlPuppetError(command.text()); // TODO: connect that somewhere to show that to the user + emitDocumentMessage(command.text()); } } emitInstanceErrorChange(instanceIdsWithChangedErrors); diff --git a/src/plugins/qmldesigner/designercore/model/abstractview.cpp b/src/plugins/qmldesigner/designercore/model/abstractview.cpp index 0d8c1ba789b..907156c9186 100644 --- a/src/plugins/qmldesigner/designercore/model/abstractview.cpp +++ b/src/plugins/qmldesigner/designercore/model/abstractview.cpp @@ -122,7 +122,8 @@ WidgetInfo AbstractView::createWidgetInfo(QWidget *widget, const QString &uniqueId, WidgetInfo::PlacementHint placementHint, int placementPriority, - const QString &tabName) + const QString &tabName, + DesignerWidgetFlags widgetFlags) { WidgetInfo widgetInfo; @@ -132,6 +133,7 @@ WidgetInfo AbstractView::createWidgetInfo(QWidget *widget, widgetInfo.placementHint = placementHint; widgetInfo.placementPriority = placementPriority; widgetInfo.tabName = tabName; + widgetInfo.widgetFlags = widgetFlags; return widgetInfo; } @@ -346,6 +348,10 @@ void AbstractView::scriptFunctionsChanged(const ModelNode &/*node*/, const QStri { } +void AbstractView::documentMessagesChanged(const QList &/*errors*/, const QList &/*warnings*/) +{ +} + QList AbstractView::toModelNodeList(const QList &nodeList) const { return QmlDesigner::toModelNodeList(nodeList, const_cast(this)); @@ -566,7 +572,17 @@ QString AbstractView::contextHelpId() const QList AbstractView::allModelNodes() const { - return toModelNodeList(model()->d->allNodes()); + return toModelNodeList(model()->d->allNodes()); +} + +void AbstractView::emitDocumentMessage(const QString &error) +{ + emitDocumentMessage( { RewriterError(error) } ); +} + +void AbstractView::emitDocumentMessage(const QList &errors, const QList &warnings) +{ + model()->d->setDocumentMessages(errors, warnings); } void AbstractView::emitCustomNotification(const QString &identifier) diff --git a/src/plugins/qmldesigner/designercore/model/model.cpp b/src/plugins/qmldesigner/designercore/model/model.cpp index 9ca36c0f9ae..9d385e032d4 100644 --- a/src/plugins/qmldesigner/designercore/model/model.cpp +++ b/src/plugins/qmldesigner/designercore/model/model.cpp @@ -174,6 +174,12 @@ QUrl ModelPrivate::fileUrl() const return m_fileUrl; } +void ModelPrivate::setDocumentMessages(const QList &errors, const QList &warnings) +{ + foreach (const QPointer &view, m_viewList) + view->documentMessagesChanged(errors, warnings); +} + void ModelPrivate::setFileUrl(const QUrl &fileUrl) { QUrl oldPath = m_fileUrl; @@ -1942,6 +1948,11 @@ void Model::setTextModifier(TextModifier *textModifier) d->m_textModifier = textModifier; } +void Model::setDocumentMessages(const QList &errors, const QList &warnings) +{ + d->setDocumentMessages(errors, warnings); +} + /*! \brief Returns the URL against which relative URLs within the model should be resolved. \return The base URL. diff --git a/src/plugins/qmldesigner/designercore/model/model_p.h b/src/plugins/qmldesigner/designercore/model/model_p.h index b5a6e97474a..6acbfbca53b 100644 --- a/src/plugins/qmldesigner/designercore/model/model_p.h +++ b/src/plugins/qmldesigner/designercore/model/model_p.h @@ -158,6 +158,8 @@ public: void notifyCurrentStateChanged(const ModelNode &node); + void setDocumentMessages(const QList &errors, const QList &warnings); + void notifyRewriterBeginTransaction(); void notifyRewriterEndTransaction(); diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 5cc829c528d..639d5b1b3a5 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -82,6 +82,9 @@ void RewriterView::modelAttached(Model *model) const QString qmlSource = m_textModifier->text(); if (m_textToModelMerger->load(qmlSource, differenceHandler)) m_lastCorrectQmlSource = qmlSource; + + if (!(m_errors.isEmpty() && m_warnings.isEmpty())) + notifyErrorsAndWarnings(m_errors); } void RewriterView::modelAboutToBeDetached(Model * /*model*/) @@ -425,6 +428,14 @@ void RewriterView::amendQmlText() emitCustomNotification(EndRewriterAmend); } +void RewriterView::notifyErrorsAndWarnings(const QList &errors) +{ + if (m_setWidgetStatusCallback) + m_setWidgetStatusCallback(errors.isEmpty()); + + emitDocumentMessage(errors, m_warnings); +} + Internal::ModelNodePositionStorage *RewriterView::positionStorage() const { return m_positionStorage.data(); @@ -444,24 +455,25 @@ void RewriterView::clearErrorAndWarnings() { m_errors.clear(); m_warnings.clear(); - emit errorsChanged(m_errors); + notifyErrorsAndWarnings(m_errors); } void RewriterView::setWarnings(const QList &warnings) { m_warnings = warnings; + notifyErrorsAndWarnings(m_errors); } void RewriterView::setErrors(const QList &errors) { m_errors = errors; - emit errorsChanged(m_errors); + notifyErrorsAndWarnings(m_errors); } void RewriterView::addError(const RewriterError &error) { m_errors.append(error); - emit errorsChanged(m_errors); + notifyErrorsAndWarnings(m_errors); } void RewriterView::enterErrorState(const QString &errorMessage) @@ -722,6 +734,11 @@ QList RewriterView::getCppTypes() return cppDataList; } +void RewriterView::setWidgetStatusCallback(std::function setWidgetStatusCallback) +{ + m_setWidgetStatusCallback = setWidgetStatusCallback; +} + void RewriterView::qmlTextChanged() { getCppTypes(); diff --git a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp index c0ce8759a39..f49f2b2eb12 100644 --- a/src/plugins/qmldesigner/designercore/model/viewmanager.cpp +++ b/src/plugins/qmldesigner/designercore/model/viewmanager.cpp @@ -47,6 +47,8 @@ #include +#include + namespace QmlDesigner { class ViewManagerData @@ -75,6 +77,12 @@ static CrumbleBar *crumbleBar() { ViewManager::ViewManager() : d(new ViewManagerData) { + d->formEditorView.setGotoErrorCallback([this](int line, int column) { + d->textEditorView.gotoCursorPosition(line, column); + Internal::DesignModeWidget *designModeWidget = QmlDesignerPlugin::instance()->mainWidget(); + if (designModeWidget && designModeWidget->centralTabWidget()) + designModeWidget->centralTabWidget()->setCurrentIndex(1); + }); } ViewManager::~ViewManager() @@ -99,6 +107,13 @@ void ViewManager::attachNodeInstanceView() void ViewManager::attachRewriterView() { if (currentDesignDocument()->rewriterView()) { + currentDesignDocument()->rewriterView()->setWidgetStatusCallback([this](bool enable) { + if (enable) + enableWidgets(); + else + disableWidgets(); + }); + currentModel()->setRewriterView(currentDesignDocument()->rewriterView()); currentDesignDocument()->rewriterView()->reactivateTextMofifierChangeSignals(); } @@ -263,13 +278,15 @@ QList ViewManager::widgetInfos() void ViewManager::disableWidgets() { foreach (const WidgetInfo &widgetInfo, widgetInfos()) - widgetInfo.widget->setEnabled(false); + if (widgetInfo.widgetFlags == DesignerWidgetFlags::DisableOnError) + widgetInfo.widget->setEnabled(false); } void ViewManager::enableWidgets() { foreach (const WidgetInfo &widgetInfo, widgetInfos()) - widgetInfo.widget->setEnabled(true); + if (widgetInfo.widgetFlags == DesignerWidgetFlags::DisableOnError) + widgetInfo.widget->setEnabled(true); } void ViewManager::pushFileOnCrumbleBar(const Utils::FileName &fileName) diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 39d78ab0223..a60c54c9e2a 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -132,12 +132,6 @@ DesignModeWidget::DesignModeWidget(QWidget *parent) , m_toolBar(new Core::EditorToolBar(this)) , m_crumbleBar(new CrumbleBar(this)) { - connect(viewManager().nodeInstanceView(), &NodeInstanceView::qmlPuppetCrashed, - [=]() { - RewriterError error(tr("Qt Quick emulation layer crashed")); - updateErrorStatus(QList() << error); - } - ); } DesignModeWidget::~DesignModeWidget() @@ -221,8 +215,6 @@ void DesignModeWidget::enableWidgets() qDebug() << Q_FUNC_INFO; hideWarningWidget(); viewManager().enableWidgets(); - m_leftSideBar->setEnabled(true); - m_rightSideBar->setEnabled(true); m_isDisabled = false; } @@ -232,8 +224,6 @@ void DesignModeWidget::disableWidgets() qDebug() << Q_FUNC_INFO; viewManager().disableWidgets(); - m_leftSideBar->setEnabled(false); - m_rightSideBar->setEnabled(false); m_isDisabled = true; } @@ -242,17 +232,18 @@ void DesignModeWidget::showTextEdit() m_centralTabWidget->setCurrentIndex(m_centralTabWidget->currentIndex() == 0 ? 1 : 0); } -void DesignModeWidget::updateErrorStatus(const QList &errors) +void DesignModeWidget::showWarningMessageBox(const QList &warnings) { - if (debug) - qDebug() << Q_FUNC_INFO << errors.count(); + Q_ASSERT(!warnings.isEmpty()); + warningWidget()->setWarnings(warnings); + warningWidget()->setVisible(true); +} - if (m_isDisabled && errors.isEmpty()) { - enableWidgets(); - } else if (!errors.isEmpty()) { - disableWidgets(); - showErrorMessageBox(errors); - } +bool DesignModeWidget::gotoCodeWasClicked() +{ + if (m_warningWidget) + return warningWidget()->gotoCodeWasClicked(); + return false; } static void hideToolButtons(QList &buttons) @@ -576,27 +567,6 @@ void DesignModeWidget::hideWarningWidget() m_warningWidget->setVisible(false); } -void DesignModeWidget::showErrorMessageBox(const QList &errors) -{ - Q_ASSERT(!errors.isEmpty()); - warningWidget()->setErrors(errors); - warningWidget()->setVisible(true); -} - -void DesignModeWidget::showWarningMessageBox(const QList &warnings) -{ - Q_ASSERT(!warnings.isEmpty()); - warningWidget()->setWarnings(warnings); - warningWidget()->setVisible(true); -} - -bool DesignModeWidget::gotoCodeWasClicked() -{ - if (m_warningWidget) - return warningWidget()->gotoCodeWasClicked(); - return false; -} - CrumbleBar *DesignModeWidget::crumbleBar() const { return m_crumbleBar; diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h index ff3acb9914e..ec78be11d7e 100644 --- a/src/plugins/qmldesigner/designmodewidget.h +++ b/src/plugins/qmldesigner/designmodewidget.h @@ -49,13 +49,13 @@ namespace QmlDesigner { class ItemLibraryWidget; class CrumbleBar; +class DocumentWarningWidget; namespace Internal { class DesignMode; class DocumentWidget; class DesignModeWidget; -class DocumentWarningWidget; class DesignModeWidget : public QWidget { @@ -80,7 +80,7 @@ public: void enableWidgets(); void disableWidgets(); void showTextEdit(); - void showErrorMessageBox(const QList &errors); + void showWarningMessageBox(const QList &warnings); bool gotoCodeWasClicked(); @@ -88,7 +88,6 @@ public: QTabWidget* centralTabWidget() const; public slots: - void updateErrorStatus(const QList &errors); void restoreDefaultView(); void toggleSidebars(); void toggleLeftSidebar(); diff --git a/src/plugins/qmldesigner/documentwarningwidget.cpp b/src/plugins/qmldesigner/documentwarningwidget.cpp index 50ea460b131..475ab5c3dd5 100644 --- a/src/plugins/qmldesigner/documentwarningwidget.cpp +++ b/src/plugins/qmldesigner/documentwarningwidget.cpp @@ -46,8 +46,6 @@ static QString errorToString(const RewriterError &error) return QString("Line: %1: %2").arg(error.line()).arg(error.description()); } -namespace Internal { - DocumentWarningWidget::DocumentWarningWidget(QWidget *parent) : Utils::FakeToolTip(parent) , m_headerLabel(new QLabel(this)) @@ -69,7 +67,6 @@ DocumentWarningWidget::DocumentWarningWidget(QWidget *parent) connect(m_navigateLabel, &QLabel::linkActivated, this, [=](const QString &link) { if (link == QLatin1String("goToCode")) { - hide(); emitGotoCodeClicked(m_messages.at(m_currentMessage)); } else if (link == QLatin1String("previous")) { --m_currentMessage; @@ -81,9 +78,10 @@ DocumentWarningWidget::DocumentWarningWidget(QWidget *parent) }); connect(m_continueButton, &QPushButton::clicked, this, [=]() { - hide(); if (m_mode == ErrorMode) emitGotoCodeClicked(m_messages.at(m_currentMessage)); + else + hide(); }); connect(m_ignoreWarningsCheckBox, &QCheckBox::toggled, this, &DocumentWarningWidget::ignoreCheckBoxToggled); @@ -233,5 +231,4 @@ void DocumentWarningWidget::setMessages(const QList &messages) refreshContent(); } -} // namespace Internal } // namespace Designer diff --git a/src/plugins/qmldesigner/documentwarningwidget.h b/src/plugins/qmldesigner/documentwarningwidget.h index 1ab183fc92e..1161d719167 100644 --- a/src/plugins/qmldesigner/documentwarningwidget.h +++ b/src/plugins/qmldesigner/documentwarningwidget.h @@ -36,7 +36,6 @@ QT_END_NAMESPACE namespace QmlDesigner { -namespace Internal { class DocumentWarningWidget : public Utils::FakeToolTip { @@ -79,5 +78,4 @@ private: bool m_gotoCodeWasClicked = false; }; -} // namespace Internal } // namespace Designer diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index a9fdeaad102..c35a0e8eaa2 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -78,8 +78,6 @@ public: DocumentManager documentManager; ShortCutManager shortCutManager; - QMetaObject::Connection rewriterErrorConnection; - Internal::DesignModeWidget *mainWidget; DesignerSettings settings; @@ -354,11 +352,11 @@ void QmlDesignerPlugin::hideDesigner() { if (currentDesignDocument() && currentModel()) { // the message box handle the cursor jump itself - if (mainWidget()->gotoCodeWasClicked() == false) - jumpTextCursorToSelectedModelNode(); } if (d->documentManager.hasCurrentDesignDocument()) { + if (currentModel() && !mainWidget()->gotoCodeWasClicked()) + jumpTextCursorToSelectedModelNode(); deactivateAutoSynchronization(); d->mainWidget->saveSettings(); } @@ -426,6 +424,7 @@ void QmlDesignerPlugin::activateAutoSynchronization() currentDesignDocument()->updateActiveQtVersion(); currentDesignDocument()->updateCurrentProject(); + d->mainWidget->enableWidgets(); currentDesignDocument()->attachRewriterToModel(); resetModelSelection(); @@ -433,22 +432,13 @@ void QmlDesignerPlugin::activateAutoSynchronization() viewManager().attachComponentView(); viewManager().attachViewsExceptRewriterAndComponetView(); - QList errors = currentDesignDocument()->qmlParseErrors(); - if (errors.isEmpty()) { - selectModelNodeUnderTextCursor(); - d->mainWidget->enableWidgets(); - d->mainWidget->setupNavigatorHistory(currentDesignDocument()->textEditor()); - if (showWarningsForFeaturesInDesigner() && currentDesignDocument()->hasQmlParseWarnings()) - d->mainWidget->showWarningMessageBox(currentDesignDocument()->qmlParseWarnings()); - } else { - d->mainWidget->disableWidgets(); - d->mainWidget->showErrorMessageBox(errors); - } + selectModelNodeUnderTextCursor(); + + d->mainWidget->setupNavigatorHistory(currentDesignDocument()->textEditor()); + if (showWarningsForFeaturesInDesigner() && currentDesignDocument()->hasQmlParseWarnings()) + d->mainWidget->showWarningMessageBox(currentDesignDocument()->qmlParseWarnings()); currentDesignDocument()->updateSubcomponentManager(); - - d->rewriterErrorConnection = connect(rewriterView(), &RewriterView::errorsChanged, - d->mainWidget, &Internal::DesignModeWidget::updateErrorStatus); } void QmlDesignerPlugin::deactivateAutoSynchronization() @@ -457,8 +447,6 @@ void QmlDesignerPlugin::deactivateAutoSynchronization() viewManager().detachComponentView(); viewManager().detachRewriterView(); documentManager().currentDesignDocument()->resetToDocumentModel(); - - disconnect(d->rewriterErrorConnection); } void QmlDesignerPlugin::resetModelSelection()