You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Gems/ScriptCanvas/Code/Editor/View/Widgets/ValidationPanel/GraphValidationDockWidget.h

306 lines
9.7 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <QAbstractItemModel>
#include <QIcon>
#include <QSortFilterProxyModel>
#include <AzCore/Debug/TraceMessageBus.h>
#include <AzQtComponents/Components/StyledDockWidget.h>
#include <AzToolsFramework/UI/Notifications/ToastBus.h>
#include <GraphCanvas/Editor/AssetEditorBus.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <ScriptCanvas/Debugger/ValidationEvents/ValidationEvent.h>
#include <ScriptCanvas/Debugger/StatusBus.h>
#endif
namespace Ui
{
class GraphValidationPanel;
}
namespace ScriptCanvas
{
class ScopedDataConnectionEvent;
class InvalidVariableTypeEvent;
class ScriptEventVersionMismatch;
}
namespace ScriptCanvasEditor
{
//! Visual effect interface
class ValidationEffect
{
public:
AZ_CLASS_ALLOCATOR(ValidationEffect, AZ::SystemAllocator, 0);
virtual ~ValidationEffect() = default;
virtual void DisplayEffect(const GraphCanvas::GraphId& graphId) = 0;
virtual void CancelEffect() = 0;
};
//! Highlights the border of a graph element to display its status
class HighlightElementValidationEffect
: public ValidationEffect
{
public:
AZ_CLASS_ALLOCATOR(HighlightElementValidationEffect, AZ::SystemAllocator, 0);
HighlightElementValidationEffect();
HighlightElementValidationEffect(const QColor& color);
HighlightElementValidationEffect(const GraphCanvas::SceneMemberGlowOutlineConfiguration& glowConfiguration);
void AddTarget(const AZ::EntityId& targetId);
void DisplayEffect(const GraphCanvas::GraphId& graphId) override;
void CancelEffect() override;
private:
AZStd::vector< AZ::EntityId > m_targets;
GraphCanvas::GraphId m_graphId;
AZStd::vector< GraphCanvas::GraphicsEffectId > m_graphicEffectIds;
GraphCanvas::SceneMemberGlowOutlineConfiguration m_templateConfiguration;
};
//! Effect used to show when a node is unused
class UnusedNodeValidationEffect
: public ValidationEffect
{
public:
void AddUnusedNode(const AZ::EntityId& graphCanvasNodeId);
void RemoveUnusedNode(const AZ::EntityId& graphCanvasNodeId);
void DisplayEffect(const GraphCanvas::GraphId& graphId) override;
void CancelEffect() override;
public:
void ClearStyleSelectors();
void ApplySelector(const AZ::EntityId& nodeId, AZStd::string_view styleSelector);
void RemoveSelector(const AZ::EntityId& nodeId);
bool m_isDirty;
AZStd::unordered_set< AZ::EntityId > m_unprocessedIds;
AZStd::unordered_set< AZ::EntityId > m_rootUnusedNodes;
AZStd::unordered_set< AZ::EntityId > m_inactiveNodes;
AZStd::unordered_map< AZ::EntityId, AZStd::string > m_styleSelectors;
};
class GraphValidationModel
: public QAbstractItemModel
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(GraphValidationModel, AZ::SystemAllocator, 0);
enum ColumnIndex
{
IndexForce = -1,
Description,
AutoFix,
Count
};
GraphValidationModel();
~GraphValidationModel() override;
void RunValidation(const ScriptCanvas::ScriptCanvasId& scriptCanvasId);
void AddEvents(ScriptCanvas::ValidationResults& validationEvents);
void Clear();
// QAbstractItemModel
QModelIndex index(int row, int column, const QModelIndex& parent) const override;
QModelIndex parent(const QModelIndex& index = QModelIndex()) const override;
int columnCount(const QModelIndex& parent = QModelIndex()) const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
////
const ScriptCanvas::ValidationEvent* FindItemForIndex(const QModelIndex& index) const;
const ScriptCanvas::ValidationEvent* FindItemForRow(int row) const;
const ScriptCanvas::ValidationResults& GetValidationResults() const;
private:
ScriptCanvas::ValidationResults m_validationResults;
QIcon m_errorIcon;
QIcon m_warningIcon;
QIcon m_messageIcon;
QIcon m_autoFixIcon;
};
class GraphValidationSortFilterProxyModel
: public QSortFilterProxyModel
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(GraphValidationSortFilterProxyModel, AZ::SystemAllocator, 0);
GraphValidationSortFilterProxyModel();
bool filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const override;
void SetFilter(const QString& filterString);
void SetSeverityFilter(ScriptCanvas::ValidationSeverity severityFilter);
ScriptCanvas::ValidationSeverity GetSeverityFilter() const;
bool IsShowingErrors();
bool IsShowingWarnings();
private:
ScriptCanvas::ValidationSeverity m_severityFilter;
QString m_filter;
QRegExp m_regex;
};
//! Owns the model for each currently opened graph
class ValidationData
: private ScriptCanvas::StatusRequestBus::Handler
, private AzToolsFramework::ToastNotificationBus::MultiHandler
{
public:
AZ_CLASS_ALLOCATOR(ValidationData, AZ::SystemAllocator, 0);
ValidationData();
ValidationData(GraphCanvas::GraphId graphCanvasId, ScriptCanvas::ScriptCanvasId scriptCanvasId);
~ValidationData() override;
// ScriptCanvas::StatusRequestBus
void ValidateGraph(ScriptCanvas::ValidationResults& validationEvents) override;
void ReportValidationResults(ScriptCanvas::ValidationResults& validationEvents) override;
////
ValidationEffect* GetEffect(int row);
void SetEffect(int row, ValidationEffect* effect);
void ClearEffect(int row);
void ClearEffects();
GraphValidationModel* GetModel() { return m_model.get(); }
void DisplayToast();
private:
// ToastNotification
void OnToastInteraction() override;
void OnToastDismissed() override;
////
AZStd::unique_ptr<GraphValidationModel> m_model;
using ValidationEffectMap = AZStd::unordered_map< int, ValidationEffect* >;
ValidationEffectMap m_validationEffects;
GraphCanvas::GraphId m_graphCanvasId;
};
//! Displays warnings or errors related for a Script Canvas graph
class GraphValidationDockWidget
: public AzQtComponents::StyledDockWidget
, public GraphCanvas::AssetEditorNotificationBus::Handler
, public GraphCanvas::SceneNotificationBus::Handler
, public AzToolsFramework::ToastNotificationBus::Handler
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(GraphValidationDockWidget, AZ::SystemAllocator, 0);
GraphValidationDockWidget(QWidget* parent = nullptr);
~GraphValidationDockWidget();
// GraphCanvas::AssetEditorNotificationBus::Handler
void OnActiveGraphChanged(const GraphCanvas::GraphId& graphCanvasGraphId) override;
////
// GrpahCanvas::SceneNotificationBus
void OnSelectionChanged() override;
void OnConnectionDragBegin() override;
////
bool HasValidationIssues() const;
public Q_SLOTS:
void OnRunValidator(bool displayAsNotification = false);
void OnShowErrors();
void OnShowWarnings();
void OnTableSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected);
void FocusOnEvent(const QModelIndex& modelIndex);
void TryAutoFixEvent(const QModelIndex& modelIndex);
void FixSelected();
void OnSeverityFilterChanged();
void OnFilterChanged(const QString& filterString);
private:
// AutoFixes
void AutoFixEvent(const ScriptCanvas::ValidationEvent* validationEvent);
void AutoFixScopedDataConnection(const ScriptCanvas::ScopedDataConnectionEvent* connectionEvent);
void AutoFixDeleteInvalidVariables(const ScriptCanvas::InvalidVariableTypeEvent* invalidVariableEvent);
void AutoFixScriptEventVersionMismatch(const ScriptCanvas::ScriptEventVersionMismatch* scriptEventMismatchEvent);
////
void UpdateText();
void UpdateSelectedText();
void OnRowSelected(int row);
void OnRowDeselected(int row);
void Refresh();
GraphValidationSortFilterProxyModel* m_proxyModel;
AZStd::unique_ptr<Ui::GraphValidationPanel> ui;
UnusedNodeValidationEffect m_unusedNodeValidationEffect;
//! Every graph will store its own validation model, this makes it possible to display the latest
//! validation state even if the active graph changes
using GraphModelPair = AZStd::pair<ScriptCanvas::ScriptCanvasId, AZStd::unique_ptr<ValidationData>>;
AZStd::unordered_map<GraphCanvas::GraphId, GraphModelPair> m_models;
const GraphValidationModel* GetActiveModel() const;
GraphModelPair& GetActiveData();
// We use the IDs of the active graph for different functions, so we keep both for easy access
struct IdPair
{
GraphCanvas::GraphId graphCanvasId;
ScriptCanvas::ScriptCanvasId scriptCanvasId;
};
IdPair m_activeGraphIds;
};
}