diff --git a/src/plugins/qmldesigner/components/integration/designdocument.cpp b/src/plugins/qmldesigner/components/integration/designdocument.cpp index 9b02dd94ed4..482c6c3ba5f 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.cpp +++ b/src/plugins/qmldesigner/components/integration/designdocument.cpp @@ -171,7 +171,7 @@ Model* DesignDocument::createInFileComponentModel() /*! Returns any errors that happened when parsing the latest qml file. */ -QList DesignDocument::qmlSyntaxErrors() const +QList DesignDocument::qmlSyntaxErrors() const { return m_rewriterView->errors(); } diff --git a/src/plugins/qmldesigner/components/integration/designdocument.h b/src/plugins/qmldesigner/components/integration/designdocument.h index d39f559d3ad..665a74d966f 100644 --- a/src/plugins/qmldesigner/components/integration/designdocument.h +++ b/src/plugins/qmldesigner/components/integration/designdocument.h @@ -86,7 +86,7 @@ public: Model *documentModel() const; QString contextHelpId() const; - QList qmlSyntaxErrors() const; + QList qmlSyntaxErrors() const; bool hasQmlSyntaxErrors() const; RewriterView *rewriterView() const; @@ -111,7 +111,7 @@ signals: void undoAvailable(bool isAvailable); void redoAvailable(bool isAvailable); void designDocumentClosed(); - void qmlErrorsChanged(const QList &errors); + void qmlErrorsChanged(const QList &errors); public slots: void deleteSelected(); diff --git a/src/plugins/qmldesigner/designercore/include/rewriterview.h b/src/plugins/qmldesigner/designercore/include/rewriterview.h index 9c65dcc3b08..7b5a4441192 100644 --- a/src/plugins/qmldesigner/designercore/include/rewriterview.h +++ b/src/plugins/qmldesigner/designercore/include/rewriterview.h @@ -62,6 +62,45 @@ class ModelNodePositionStorage; } //Internal +class RewriterError { +public: + enum Type { + NoError = 0, + InternalError = 1, + ParseError = 2 + }; + +public: + RewriterError(); + RewriterError(const QmlJS::DiagnosticMessage &qmlError, const QUrl &document); + RewriterError(const QString &shortDescription); + RewriterError(Exception *exception); + + Type type() const + { return m_type; } + + int line() const + { return m_line; } + + int column() const + { return m_column; } + + QString description() const + { return m_description; } + + QUrl url() const + { return m_url; } + + QString toString() const; + +private: + Type m_type; + int m_line; + int m_column; + QString m_description; + QUrl m_url; +}; + class QMLDESIGNERCORE_EXPORT RewriterView : public AbstractView { Q_OBJECT @@ -72,45 +111,6 @@ public: Amend }; - class Error { - public: - enum Type { - NoError = 0, - InternalError = 1, - ParseError = 2 - }; - - public: - Error(); - Error(const QmlJS::DiagnosticMessage &qmlError, const QUrl &document); - Error(const QString &shortDescription); - Error(const Exception *exception); - - Type type() const - { return m_type; } - - int line() const - { return m_line; } - - int column() const - { return m_column; } - - QString description() const - { return m_description; } - - QUrl url() const - { return m_url; } - - QString toString() const; - - private: - Type m_type; - int m_line; - int m_column; - QString m_description; - QUrl m_url; - }; - public: RewriterView(DifferenceHandling differenceHandling, QObject *parent); ~RewriterView(); @@ -171,10 +171,10 @@ public: Internal::ModelNodePositionStorage *positionStorage() const { return m_positionStorage; } - QList errors() const; + QList errors() const; void clearErrors(); - void setErrors(const QList &errors); - void addError(const Error &error); + void setErrors(const QList &errors); + void addError(const RewriterError &error); void enterErrorState(const QString &errorMessage); bool inErrorState() const { return !m_rewritingErrorMessage.isEmpty(); } @@ -209,7 +209,7 @@ public: QSet > qrcMapping() const; signals: - void errorsChanged(const QList &errors); + void errorsChanged(const QList &errors); public slots: void qmlTextChanged(); @@ -233,7 +233,7 @@ private: //variables QScopedPointer m_modelToTextMerger; QScopedPointer m_textToModelMerger; TextModifier *m_textModifier; - QList m_errors; + QList m_errors; int transactionLevel; RewriterTransaction m_removeDefaultPropertyTransaction; QString m_rewritingErrorMessage; diff --git a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp index 55e53700d7a..debda00edd8 100644 --- a/src/plugins/qmldesigner/designercore/model/rewriterview.cpp +++ b/src/plugins/qmldesigner/designercore/model/rewriterview.cpp @@ -50,14 +50,14 @@ using namespace QmlDesigner::Internal; namespace QmlDesigner { -RewriterView::Error::Error(): +RewriterError::RewriterError(): m_type(NoError), m_line(-1), m_column(-1) { } -RewriterView::Error::Error(const Exception *exception): +RewriterError::RewriterError(Exception *exception): m_type(InternalError), m_line(exception->line()), m_column(-1), @@ -66,7 +66,7 @@ RewriterView::Error::Error(const Exception *exception): { } -RewriterView::Error::Error(const QmlJS::DiagnosticMessage &qmlError, const QUrl &document): +RewriterError::RewriterError(const QmlJS::DiagnosticMessage &qmlError, const QUrl &document): m_type(ParseError), m_line(qmlError.loc.startLine), m_column(qmlError.loc.startColumn), @@ -75,7 +75,7 @@ RewriterView::Error::Error(const QmlJS::DiagnosticMessage &qmlError, const QUrl { } -RewriterView::Error::Error(const QString &shortDescription) : +RewriterError::RewriterError(const QString &shortDescription) : m_type(ParseError), m_line(1), m_column(0), @@ -85,33 +85,33 @@ RewriterView::Error::Error(const QString &shortDescription) : } -QString RewriterView::Error::toString() const +QString RewriterError::toString() const { QString str; if (m_type == ParseError) - str += tr("Error parsing"); + str += RewriterView::tr("Error parsing"); else if (m_type == InternalError) - str += tr("Internal error"); + str += RewriterView::tr("Internal error"); if (url().isValid()) { if (!str.isEmpty()) str += QLatin1Char(' '); - str += tr("\"%1\"").arg(url().toString()); + str += RewriterView::tr("\"%1\"").arg(url().toString()); } if (line() != -1) { if (!str.isEmpty()) str += QLatin1Char(' '); - str += tr("line %1").arg(line()); + str += RewriterView::tr("line %1").arg(line()); } if (column() != -1) { if (!str.isEmpty()) str += QLatin1Char(' '); - str += tr("column %1").arg(column()); + str += RewriterView::tr("column %1").arg(column()); } if (!str.isEmpty()) @@ -541,7 +541,7 @@ void RewriterView::applyChanges() } } -QList RewriterView::errors() const +QList RewriterView::errors() const { return m_errors; } @@ -552,13 +552,13 @@ void RewriterView::clearErrors() emit errorsChanged(m_errors); } -void RewriterView::setErrors(const QList &errors) +void RewriterView::setErrors(const QList &errors) { m_errors = errors; emit errorsChanged(m_errors); } -void RewriterView::addError(const RewriterView::Error &error) +void RewriterView::addError(const RewriterError &error) { m_errors.append(error); emit errorsChanged(m_errors); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp index f5c89218264..7e2c95a8069 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.cpp @@ -885,9 +885,9 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH doc->parseQml(); if (!doc->isParsedCorrectly()) { - QList errors; - foreach (const DiagnosticMessage &message, doc->diagnosticMessages()) - errors.append(RewriterView::Error(message, QUrl::fromLocalFile(doc->fileName()))); + QList errors; + foreach (const QmlJS::DiagnosticMessage &message, doc->diagnosticMessages()) + errors.append(RewriterError(message, QUrl::fromLocalFile(doc->fileName()))); m_rewriterView->setErrors(errors); setActive(false); return false; @@ -899,66 +899,19 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH new ScopeChain(ctxt.scopeChain())); m_document = doc; - QList errors; - QList warnings; + QList errors; + QList warnings; - foreach (const DiagnosticMessage &diagnosticMessage, ctxt.diagnosticLinkMessages()) { - errors.append(RewriterView::Error(diagnosticMessage, QUrl::fromLocalFile(doc->fileName()))); - } + collectLinkErrors(&errors, ctxt); setupImports(doc, differenceHandler); setupPossibleImports(snapshot, m_vContext); - if (m_rewriterView->model()->imports().isEmpty()) { - const DiagnosticMessage diagnosticMessage(Severity::Error, AST::SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found")); - errors.append(RewriterView::Error(diagnosticMessage, QUrl::fromLocalFile(doc->fileName()))); - } - - foreach (const QmlDesigner::Import &import, m_rewriterView->model()->imports()) { - if (import.isLibraryImport() && import.url() == QStringLiteral("QtQuick") && !supportedQtQuickVersion(import.version())) { - const DiagnosticMessage diagnosticMessage(Severity::Error, AST::SourceLocation(0, 0, 0, 0), - QCoreApplication::translate("QmlDesigner::TextToModelMerger", "Unsupported QtQuick version")); - errors.append(RewriterView::Error(diagnosticMessage, QUrl::fromLocalFile(doc->fileName()))); - } - } + collectImportErrors(&errors); if (view()->checkSemanticErrors()) { - Check check(doc, m_scopeChain->context()); - check.disableMessage(StaticAnalysis::ErrPrototypeCycle); - check.disableMessage(StaticAnalysis::ErrCouldNotResolvePrototype); - check.disableMessage(StaticAnalysis::ErrCouldNotResolvePrototypeOf); - foreach (StaticAnalysis::Type type, StaticAnalysis::Message::allMessageTypes()) { - StaticAnalysis::PrototypeMessageData prototypeMessageData = StaticAnalysis::Message::prototypeForMessageType(type); - if (prototypeMessageData.severity == Severity::MaybeWarning - || prototypeMessageData.severity == Severity::Warning) { - check.disableMessage(type); - } - } - - check.enableMessage(StaticAnalysis::WarnImperativeCodeNotEditableInVisualDesigner); - check.enableMessage(StaticAnalysis::WarnUnsupportedTypeInVisualDesigner); - check.enableMessage(StaticAnalysis::WarnReferenceToParentItemNotSupportedByVisualDesigner); - check.enableMessage(StaticAnalysis::WarnReferenceToParentItemNotSupportedByVisualDesigner); - check.enableMessage(StaticAnalysis::WarnAboutQtQuick1InsteadQtQuick2); - check.enableMessage(StaticAnalysis::ErrUnsupportedRootTypeInVisualDesigner); - //## triggers too often ## check.enableMessage(StaticAnalysis::WarnUndefinedValueForVisualDesigner); - - foreach (const StaticAnalysis::Message &message, check()) { - if (message.severity == Severity::Error) { - if (message.type == StaticAnalysis::ErrUnknownComponent) - warnings.append(RewriterView::Error(message.toDiagnosticMessage(), QUrl::fromLocalFile(doc->fileName()))); - else - errors.append(RewriterView::Error(message.toDiagnosticMessage(), QUrl::fromLocalFile(doc->fileName()))); - } - if (message.severity == Severity::Warning) { - if (message.type == StaticAnalysis::WarnAboutQtQuick1InsteadQtQuick2) { - errors.append(RewriterView::Error(message.toDiagnosticMessage(), QUrl::fromLocalFile(doc->fileName()))); - } else { - warnings.append(RewriterView::Error(message.toDiagnosticMessage(), QUrl::fromLocalFile(doc->fileName()))); - } - } - } + collectSemanticErrorsAndWarnings(&errors, &warnings); if (!errors.isEmpty()) { m_rewriterView->setErrors(errors); @@ -966,22 +919,17 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH return false; } - if (!warnings.isEmpty() && differenceHandler.isValidator() && !m_rewriterView->inErrorState()) { - - QStringList message; - - foreach (const RewriterView::Error &warning, warnings) { - QString string = QStringLiteral("Line: ") + QString::number(warning.line()) + QStringLiteral(": ") + warning.description(); - //string += QStringLiteral(" Go to error") + QStringLiteral("

"); - message << string; - } - - QmlWarningDialog warningDialog(0, message); - if (warningDialog.warningsEnabled() && warningDialog.exec()) { - m_rewriterView->setErrors(warnings); - setActive(false); - return false; - } + /* + * If there are warnings and we are validating the document, then show a warning dialog. + * If the warning dialog is not ignored we set the warnings as errors and do not load the document + */ + if (!warnings.isEmpty() + && differenceHandler.isValidator() + && !m_rewriterView->inErrorState() + && !showWarningsDialogIgnored(warnings)) { + m_rewriterView->setErrors(warnings); + setActive(false); + return false; } } setupUsedImports(); @@ -997,8 +945,8 @@ bool TextToModelMerger::load(const QString &data, DifferenceHandler &differenceH setActive(false); return true; - } catch (const Exception &e) { - RewriterView::Error error(&e); + } catch (Exception &e) { + RewriterError error(&e); // Somehow, the error below gets eaten in upper levels, so printing the // exception info here for debugging purposes: qDebug() << "*** An exception occurred while reading the QML file:" @@ -1932,6 +1880,80 @@ void TextToModelMerger::setupComponent(const ModelNode &node) ModelNode(node).setNodeSource(result); } +void TextToModelMerger::collectLinkErrors(QList *errors, const ReadingContext &ctxt) +{ + foreach (const QmlJS::DiagnosticMessage &diagnosticMessage, ctxt.diagnosticLinkMessages()) { + errors->append(RewriterError(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); + } +} + +void TextToModelMerger::collectImportErrors(QList *errors) +{ + if (m_rewriterView->model()->imports().isEmpty()) { + const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, AST::SourceLocation(0, 0, 0, 0), QCoreApplication::translate("QmlDesigner::TextToModelMerger", "No import statements found")); + errors->append(RewriterError(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); + } + + foreach (const QmlDesigner::Import &import, m_rewriterView->model()->imports()) { + if (import.isLibraryImport() && import.url() == QStringLiteral("QtQuick") && !supportedQtQuickVersion(import.version())) { + const QmlJS::DiagnosticMessage diagnosticMessage(QmlJS::Severity::Error, AST::SourceLocation(0, 0, 0, 0), + QCoreApplication::translate("QmlDesigner::TextToModelMerger", "Unsupported QtQuick version")); + errors->append(RewriterError(diagnosticMessage, QUrl::fromLocalFile(m_document->fileName()))); + } + } +} + +void TextToModelMerger::collectSemanticErrorsAndWarnings(QList *errors, QList *warnings) +{ + Check check(m_document, m_scopeChain->context()); + check.disableMessage(StaticAnalysis::ErrPrototypeCycle); + check.disableMessage(StaticAnalysis::ErrCouldNotResolvePrototype); + check.disableMessage(StaticAnalysis::ErrCouldNotResolvePrototypeOf); + + foreach (StaticAnalysis::Type type, StaticAnalysis::Message::allMessageTypes()) { + StaticAnalysis::PrototypeMessageData prototypeMessageData = StaticAnalysis::Message::prototypeForMessageType(type); + if (prototypeMessageData.severity == Severity::MaybeWarning + || prototypeMessageData.severity == Severity::Warning) { + check.disableMessage(type); + } + } + + check.enableQmlDesignerChecks(); + + foreach (const StaticAnalysis::Message &message, check()) { + if (message.severity == Severity::Error) { + if (message.type == StaticAnalysis::ErrUnknownComponent) + warnings->append(RewriterError(message.toDiagnosticMessage(), QUrl::fromLocalFile(m_document->fileName()))); + else + errors->append(RewriterError(message.toDiagnosticMessage(), QUrl::fromLocalFile(m_document->fileName()))); + } + if (message.severity == Severity::Warning) { + if (message.type == StaticAnalysis::WarnAboutQtQuick1InsteadQtQuick2) { + errors->append(RewriterError(message.toDiagnosticMessage(), QUrl::fromLocalFile(m_document->fileName()))); + } else { + warnings->append(RewriterError(message.toDiagnosticMessage(), QUrl::fromLocalFile(m_document->fileName()))); + } + } + } +} + +bool TextToModelMerger::showWarningsDialogIgnored(const QList &warnings) +{ + QStringList message; + + foreach (const RewriterError &warning, warnings) { + QString string = QStringLiteral("Line: ") + QString::number(warning.line()) + QStringLiteral(": ") + warning.description(); + message << string; + } + + QmlWarningDialog warningDialog(0, message); + if (warningDialog.warningsEnabled() && warningDialog.exec()) { + return false; + } + + return true; +} + void TextToModelMerger::populateQrcMapping(const QString &filePath) { QString path = removeFileFromQrcPath(filePath); diff --git a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h index c9cf71a8b00..93672a942bf 100644 --- a/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h +++ b/src/plugins/qmldesigner/designercore/model/texttomodelmerger.h @@ -44,6 +44,7 @@ namespace QmlDesigner { class RewriterView; +class RewriterError; namespace Internal { @@ -137,6 +138,11 @@ public: private: void setupCustomParserNode(const ModelNode &node); void setupComponent(const ModelNode &node); + void collectLinkErrors(QList *errors, const ReadingContext &ctxt); + void collectImportErrors(QList *errors); + void collectSemanticErrorsAndWarnings(QList *errors, + QList *warnings); + bool showWarningsDialogIgnored(const QList &warnings); void populateQrcMapping(const QString &filePath); diff --git a/src/plugins/qmldesigner/designmodewidget.cpp b/src/plugins/qmldesigner/designmodewidget.cpp index 5638c6d19a5..20b1fa3df93 100644 --- a/src/plugins/qmldesigner/designmodewidget.cpp +++ b/src/plugins/qmldesigner/designmodewidget.cpp @@ -98,14 +98,14 @@ DocumentWarningWidget::DocumentWarningWidget(DesignModeWidget *parent) : layout->addWidget(m_goToError, 1, Qt::AlignRight); } -void DocumentWarningWidget::setError(const RewriterView::Error &error) +void DocumentWarningWidget::setError(const RewriterError &error) { m_error = error; QString str; - if (error.type() == RewriterView::Error::ParseError) { + if (error.type() == RewriterError::ParseError) { str = tr("%3 (%1:%2)").arg(QString::number(error.line()), QString::number(error.column()), error.description()); m_goToError->show(); - } else if (error.type() == RewriterView::Error::InternalError) { + } else if (error.type() == RewriterError::InternalError) { str = tr("Internal error (%1)").arg(error.description()); m_goToError->hide(); } @@ -278,7 +278,7 @@ void DesignModeWidget::disableWidgets() m_isDisabled = true; } -void DesignModeWidget::updateErrorStatus(const QList &errors) +void DesignModeWidget::updateErrorStatus(const QList &errors) { if (debug) qDebug() << Q_FUNC_INFO << errors.count(); @@ -459,8 +459,8 @@ void DesignModeWidget::deleteSidebarWidgets() void DesignModeWidget::qmlPuppetCrashed() { - QList errorList; - RewriterView::Error error(tr("Qt Quick emulation layer crashed")); + QList errorList; + RewriterError error(tr("Qt Quick emulation layer crashed")); errorList.append(error); disableWidgets(); @@ -616,7 +616,7 @@ QWidget *DesignModeWidget::createCrumbleBarFrame() return frame; } -void DesignModeWidget::showErrorMessage(const QList &errors) +void DesignModeWidget::showErrorMessage(const QList &errors) { Q_ASSERT(!errors.isEmpty()); m_warningWidget->setError(errors.first()); diff --git a/src/plugins/qmldesigner/designmodewidget.h b/src/plugins/qmldesigner/designmodewidget.h index 1d873ba7e89..e64c20e8f88 100644 --- a/src/plugins/qmldesigner/designmodewidget.h +++ b/src/plugins/qmldesigner/designmodewidget.h @@ -73,7 +73,7 @@ class DocumentWarningWidget : public Utils::FakeToolTip public: explicit DocumentWarningWidget(DesignModeWidget *parent = 0); - void setError(const RewriterView::Error &error); + void setError(const RewriterError &error); private slots: void goToError(); @@ -81,7 +81,7 @@ private slots: private: QLabel *m_errorMessage; QLabel *m_goToError; - RewriterView::Error m_error; + RewriterError m_error; DesignModeWidget *m_designModeWidget; }; @@ -109,12 +109,12 @@ public: void enableWidgets(); void disableWidgets(); - void showErrorMessage(const QList &errors); + void showErrorMessage(const QList &errors); CrumbleBar* crumbleBar() const; public slots: - void updateErrorStatus(const QList &errors); + void updateErrorStatus(const QList &errors); void restoreDefaultView(); void toggleSidebars(); void toggleLeftSidebar(); diff --git a/src/plugins/qmldesigner/qmldesignerplugin.cpp b/src/plugins/qmldesigner/qmldesignerplugin.cpp index 11e67f24eba..fb714d6bc63 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.cpp +++ b/src/plugins/qmldesigner/qmldesignerplugin.cpp @@ -316,7 +316,7 @@ void QmlDesignerPlugin::activateAutoSynchronization() viewManager().attachComponentView(); viewManager().attachViewsExceptRewriterAndComponetView(); - QList errors = currentDesignDocument()->qmlSyntaxErrors(); + QList errors = currentDesignDocument()->qmlSyntaxErrors(); if (errors.isEmpty()) { selectModelNodeUnderTextCursor(); data->mainWidget->enableWidgets(); @@ -329,9 +329,9 @@ void QmlDesignerPlugin::activateAutoSynchronization() currentDesignDocument()->updateSubcomponentManager(); connect(rewriterView(), - SIGNAL(errorsChanged(QList)), + SIGNAL(errorsChanged(QList)), data->mainWidget, - SLOT(updateErrorStatus(QList))); + SLOT(updateErrorStatus(QList))); } void QmlDesignerPlugin::deactivateAutoSynchronization() @@ -342,9 +342,9 @@ void QmlDesignerPlugin::deactivateAutoSynchronization() documentManager().currentDesignDocument()->resetToDocumentModel(); disconnect(rewriterView(), - SIGNAL(errorsChanged(QList)), + SIGNAL(errorsChanged(QList)), data->mainWidget, - SLOT(updateErrorStatus(QList))); + SLOT(updateErrorStatus(QList))); }