QmlDesigner: Polish error handling for integrated text editor

The integrated text editor requires a couple of fixes and features
in the error handling.

The errors are now handled by the model and not the document management
anymore.
The text editor does not get disabled if there is an error. Instead
we show the error in a status bar.
The form editor is blocked if there is a QML an error and we show the
error message inside the form editor.

Change-Id: I4bfb9b33b09e444ec1de31dd531ce83b32cbcf88
Reviewed-by: Tim Jenssen <tim.jenssen@qt.io>
This commit is contained in:
Thomas Hartmann
2017-01-10 16:36:55 +01:00
committed by Tim Jenssen
parent 8b67458a95
commit 759db2b7b6
30 changed files with 383 additions and 114 deletions

View File

@@ -264,6 +264,25 @@ void DebugView::auxiliaryDataChanged(const ModelNode &node, const PropertyName &
}
}
void DebugView::documentMessagesChanged(const QList<RewriterError> &errors, const QList<RewriterError> &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())

View File

@@ -65,6 +65,7 @@ public:
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
void auxiliaryDataChanged(const ModelNode &node, const PropertyName &name, const QVariant &data) override;
void documentMessagesChanged(const QList<RewriterError> &errors, const QList<RewriterError> &warnings) override;
void rewriterBeginTransaction() override;
void rewriterEndTransaction() override;

View File

@@ -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<ModelNode> &selectedNodeLi
m_scene->update();
}
void FormEditorView::documentMessagesChanged(const QList<RewriterError> &errors, const QList<RewriterError> &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<ModelNode> &/*nodeList*/, const QList<QVariant> &/*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<void (int, int)> gotoErrorCallback)
{
m_gotoErrorCallback = gotoErrorCallback;
}
QList<ModelNode> FormEditorView::adjustStatesForModelNodes(const QList<ModelNode> &nodeList) const
{
QList<ModelNode> adjustedNodeList;

View File

@@ -26,6 +26,7 @@
#include <abstractview.h>
#include <functional>
#include <memory>
QT_BEGIN_NAMESPACE
@@ -74,6 +75,9 @@ public:
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
virtual void documentMessagesChanged(const QList<RewriterError> &errors, const QList<RewriterError> &warnings) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
// FormEditorView
@@ -109,6 +113,8 @@ public:
double containerPadding() const;
double spacing() const;
void deActivateItemCreator();
void gotoError(int, int);
void setGotoErrorCallback(std::function<void(int, int)> gotoErrorCallback);
protected:
void reset();
@@ -135,6 +141,7 @@ private: //variables
std::unique_ptr<DragTool> m_dragTool;
AbstractFormEditorTool *m_currentTool;
int m_transactionCounter;
std::function<void(int, int)> m_gotoErrorCallback;
};
} // namespace QmlDesigner

View File

@@ -252,6 +252,34 @@ void FormEditorWidget::setFocus()
m_graphicsView->setFocus(Qt::OtherFocusReason);
}
void FormEditorWidget::showErrorMessageBox(const QList<RewriterError> &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<RewriterError> &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;
}
}

View File

@@ -24,6 +24,8 @@
****************************************************************************/
#pragma once
#include <documentwarningwidget.h>
#include <QWidget>
#include <QPointer>
@@ -72,9 +74,15 @@ public:
void setFocus();
void showErrorMessageBox(const QList<RewriterError> &errors);
void hideErrorMessageBox();
void showWarningMessageBox(const QList<RewriterError> &warnings);
protected:
void wheelEvent(QWheelEvent *event);
QActionGroup *toolActionGroup() const;
DocumentWarningWidget *errorWidget();
private slots:
void changeTransformTool(bool checked);
@@ -99,6 +107,7 @@ private:
QPointer<LineEditAction> m_rootHeightAction;
QPointer<BackgroundAction> m_backgroundAction;
QPointer<QAction> m_resetAction;
QPointer<DocumentWarningWidget> m_documentErrorWidget;
};
} // namespace QmlDesigner

View File

@@ -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

View File

@@ -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 <utils/theme/theme.h>
#include <QVBoxLayout>
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

View File

@@ -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 <QToolBar>
#include <QLabel>
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

View File

@@ -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<RewriterError> &errors, const QList<RewriterError> &)
{
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<QPair<ModelNode, PropertyName> > &/*propertyList*/)
{
}

View File

@@ -59,6 +59,7 @@ public:
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
const QList<ModelNode> &lastSelectedNodeList) override;
void customNotification(const AbstractView *view, const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data) override;
void documentMessagesChanged(const QList<RewriterError> &errors, const QList<RewriterError> &warnings) override;
// TextEditorView
WidgetInfo widgetInfo() override;
@@ -87,6 +88,8 @@ public:
void deActivateItemCreator();
void gotoCursorPosition(int line, int column);
private:
std::unique_ptr<TextEditorWidget> m_widget;
};

View File

@@ -25,7 +25,9 @@
#include "texteditorwidget.h"
#include <texteditorstatusbar.h>
#include <texteditorview.h>
#include <rewriterview.h>
#include <theming.h>
@@ -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

View File

@@ -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<TextEditor::BaseTextEditor> m_textEditor;
QPointer<TextEditorView> m_textEditorView;
QTimer m_updateSelectionTimer;
TextEditorStatusBar *m_statusBar;
};
} // namespace QmlDesigner

View File

@@ -30,6 +30,7 @@
#include <model.h>
#include <modelnode.h>
#include <abstractproperty.h>
#include <rewritererror.h>
#include <rewritertransaction.h>
#include <commondefines.h>
@@ -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<ModelNode> allModelNodes() const;
void emitDocumentMessage(const QList<RewriterError> &errors, const QList<RewriterError> &warnings = QList<RewriterError>());
void emitDocumentMessage(const QString &error);
void emitCustomNotification(const QString &identifier);
void emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList);
void emitCustomNotification(const QString &identifier, const QList<ModelNode> &nodeList, const QList<QVariant> &data);
@@ -227,6 +230,8 @@ public:
virtual void scriptFunctionsChanged(const ModelNode &node, const QStringList &scriptFunctionList);
virtual void documentMessagesChanged(const QList<RewriterError> &errors, const QList<RewriterError> &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<ModelNode> toModelNodeList(const QList<Internal::InternalNodePointer> &nodeList) const;

View File

@@ -26,6 +26,9 @@
#pragma once
#include <qmldesignercorelib_global.h>
#include <rewritererror.h>
#include <QObject>
#include <QPair>
@@ -108,6 +111,7 @@ public:
TextModifier *textModifier() const;
void setTextModifier(TextModifier *textModifier);
void setDocumentMessages(const QList<RewriterError> &errors, const QList<RewriterError> &warnings);
protected:
Model();

View File

@@ -133,10 +133,6 @@ public:
void sendToken(const QString &token, int number, const QVector<ModelNode> &nodeVector);
signals:
void qmlPuppetCrashed();
void qmlPuppetError(const QString &errorMessage);
protected:
void timerEvent(QTimerEvent *event) override;

View File

@@ -34,6 +34,8 @@
#include <QTimer>
#include <QUrl>
#include <functional>
namespace QmlJS {
class Document;
class ScopeChain;
@@ -154,8 +156,7 @@ public:
QList<CppTypeData> getCppTypes();
signals:
void errorsChanged(const QList<RewriterError> &errors);
void setWidgetStatusCallback(std::function<void(bool)> setWidgetStatusCallback);
public slots:
void qmlTextChanged();
@@ -172,6 +173,7 @@ protected: // functions
void applyModificationGroupChanges();
void applyChanges();
void amendQmlText();
void notifyErrorsAndWarnings(const QList<RewriterError> &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<void(bool)> m_setWidgetStatusCallback;
};
} //QmlDesigner

View File

@@ -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();

View File

@@ -102,6 +102,7 @@ private slots:
void printEditorProcessOutput();
void printPreviewProcessOutput();
void printRenderProcessOutput();
void showCannotConnectToPuppetWarningAndSwitchToEditMode();
private:
QFile m_captureFileForTest;
QTimer m_firstTimer;

View File

@@ -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<qint32> 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);

View File

@@ -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<RewriterError> &/*errors*/, const QList<RewriterError> &/*warnings*/)
{
}
QList<ModelNode> AbstractView::toModelNodeList(const QList<Internal::InternalNode::Pointer> &nodeList) const
{
return QmlDesigner::toModelNodeList(nodeList, const_cast<AbstractView*>(this));
@@ -566,7 +572,17 @@ QString AbstractView::contextHelpId() const
QList<ModelNode> 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<RewriterError> &errors, const QList<RewriterError> &warnings)
{
model()->d->setDocumentMessages(errors, warnings);
}
void AbstractView::emitCustomNotification(const QString &identifier)

View File

@@ -174,6 +174,12 @@ QUrl ModelPrivate::fileUrl() const
return m_fileUrl;
}
void ModelPrivate::setDocumentMessages(const QList<RewriterError> &errors, const QList<RewriterError> &warnings)
{
foreach (const QPointer<AbstractView> &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<RewriterError> &errors, const QList<RewriterError> &warnings)
{
d->setDocumentMessages(errors, warnings);
}
/*!
\brief Returns the URL against which relative URLs within the model should be resolved.
\return The base URL.

View File

@@ -158,6 +158,8 @@ public:
void notifyCurrentStateChanged(const ModelNode &node);
void setDocumentMessages(const QList<RewriterError> &errors, const QList<RewriterError> &warnings);
void notifyRewriterBeginTransaction();
void notifyRewriterEndTransaction();

View File

@@ -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<RewriterError> &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<RewriterError> &warnings)
{
m_warnings = warnings;
notifyErrorsAndWarnings(m_errors);
}
void RewriterView::setErrors(const QList<RewriterError> &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<CppTypeData> RewriterView::getCppTypes()
return cppDataList;
}
void RewriterView::setWidgetStatusCallback(std::function<void (bool)> setWidgetStatusCallback)
{
m_setWidgetStatusCallback = setWidgetStatusCallback;
}
void RewriterView::qmlTextChanged()
{
getCppTypes();

View File

@@ -47,6 +47,8 @@
#include <utils/algorithm.h>
#include <QTabWidget>
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<WidgetInfo> 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)

View File

@@ -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<RewriterError>() << 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<RewriterError> &errors)
void DesignModeWidget::showWarningMessageBox(const QList<RewriterError> &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<QToolButton*> &buttons)
@@ -576,27 +567,6 @@ void DesignModeWidget::hideWarningWidget()
m_warningWidget->setVisible(false);
}
void DesignModeWidget::showErrorMessageBox(const QList<RewriterError> &errors)
{
Q_ASSERT(!errors.isEmpty());
warningWidget()->setErrors(errors);
warningWidget()->setVisible(true);
}
void DesignModeWidget::showWarningMessageBox(const QList<RewriterError> &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;

View File

@@ -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<RewriterError> &errors);
void showWarningMessageBox(const QList<RewriterError> &warnings);
bool gotoCodeWasClicked();
@@ -88,7 +88,6 @@ public:
QTabWidget* centralTabWidget() const;
public slots:
void updateErrorStatus(const QList<RewriterError> &errors);
void restoreDefaultView();
void toggleSidebars();
void toggleLeftSidebar();

View File

@@ -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<RewriterError> &messages)
refreshContent();
}
} // namespace Internal
} // namespace Designer

View File

@@ -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

View File

@@ -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<RewriterError> 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()