Initial commit

This commit is contained in:
alexpete
2021-03-05 11:26:34 -08:00
commit a10351f38d
27091 changed files with 5521199 additions and 0 deletions
@@ -0,0 +1,213 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "precompiled.h"
#include "EntityMimeDataHandler.h"
#include <QMimeData>
#include <QDragEnterEvent>
#include <QDragMoveEvent>
#include <QDropEvent>
#include <QGraphicsView>
#include <Editor/Nodes/NodeUtils.h>
#include <ScriptCanvas/Bus/RequestBus.h>
#include <ScriptCanvas/Bus/NodeIdPair.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <AzToolsFramework/ToolsComponents/EditorEntityIdContainer.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
#include <AzCore/Component/Entity.h>
#include <GraphCanvas/Components/SceneBus.h>
#include <GraphCanvas/Components/GridBus.h>
#include <GraphCanvas/Components/ViewBus.h>
#include <GraphCanvas/Components/VisualBus.h>
#include <Core/GraphBus.h>
#include <ScriptCanvas/Variable/VariableBus.h>
#include <GraphCanvas/Utils/GraphUtils.h>
namespace ScriptCanvasEditor
{
namespace EntityMimeData
{
static QString GetMimeType()
{
return AzToolsFramework::EditorEntityIdContainer::GetMimeType();
}
}
void EntityMimeDataHandler::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
if (!serializeContext)
{
return;
}
serializeContext->Class<EntityMimeDataHandler, AZ::Component>()
->Version(1)
;
}
EntityMimeDataHandler::EntityMimeDataHandler()
{}
void EntityMimeDataHandler::Activate()
{
GraphCanvas::SceneMimeDelegateHandlerRequestBus::Handler::BusConnect(GetEntityId());
}
void EntityMimeDataHandler::Deactivate()
{
GraphCanvas::SceneMimeDelegateHandlerRequestBus::Handler::BusDisconnect();
}
bool EntityMimeDataHandler::IsInterestedInMimeData(const AZ::EntityId& sceneId, const QMimeData* mimeData)
{
(void)sceneId;
return mimeData->hasFormat(EntityMimeData::GetMimeType());
}
void EntityMimeDataHandler::HandleMove(const AZ::EntityId&, const QPointF&, const QMimeData*)
{
}
void EntityMimeDataHandler::HandleDrop(const AZ::EntityId& graphCanvasGraphId, const QPointF& dropPoint, const QMimeData* mimeData)
{
if (!mimeData->hasFormat(EntityMimeData::GetMimeType()))
{
return;
}
QByteArray arrayData = mimeData->data(EntityMimeData::GetMimeType());
AzToolsFramework::EditorEntityIdContainer entityIdListContainer;
if (!entityIdListContainer.FromBuffer(arrayData.constData(), arrayData.size()) || entityIdListContainer.m_entityIds.empty())
{
return;
}
bool areEntitiesEditable = true;
AzToolsFramework::ToolsApplicationRequests::Bus::BroadcastResult(areEntitiesEditable, &AzToolsFramework::ToolsApplicationRequests::AreEntitiesEditable, entityIdListContainer.m_entityIds);
if (!areEntitiesEditable)
{
return;
}
ScriptCanvas::ScriptCanvasId scriptCanvasId;
GeneralRequestBus::BroadcastResult(scriptCanvasId, &GeneralRequests::GetScriptCanvasId, graphCanvasGraphId);
ScriptCanvas::GraphVariableManagerRequests* variableManagerRequests = ScriptCanvas::GraphVariableManagerRequestBus::FindFirstHandler(scriptCanvasId);
if (variableManagerRequests == nullptr)
{
return;
}
AZStd::vector< ScriptCanvas::VariableId > variableIds;
variableIds.reserve(entityIdListContainer.m_entityIds.size());
{
GraphCanvas::ScopedGraphUndoBlocker undoBlocker(graphCanvasGraphId);
AZ::Vector2 pos(aznumeric_cast<float>(dropPoint.x()), aznumeric_cast<float>(dropPoint.y()));
for (const AZ::EntityId& entityId : entityIdListContainer.m_entityIds)
{
AZStd::string variableName;
AZ::Entity* entity = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(entity, &AZ::ComponentApplicationRequests::FindEntity, entityId);
if (entity)
{
// Because we add in the entity id to this.
// we make the name mostly unique.
// If we just use the name, we'll run into some potential rename issues when looking things up.
variableName = AZStd::string::format("%s %s", entity->GetName().c_str(), entityId.ToString().c_str());
ScriptCanvas::GraphVariable* graphVariable = variableManagerRequests->FindVariable(variableName);
int counter = 0;
AZStd::string baseName = variableName;
baseName.append(" (Copy)");
// If the variable datum already exists. That means we already have a reference to that. So we don't need to create it.
while (graphVariable != nullptr)
{
if (graphVariable->GetDataType() == ScriptCanvas::Data::Type::EntityID())
{
variableIds.emplace_back(graphVariable->GetVariableId());
break;
}
if (counter == 0)
{
variableName = baseName;
}
else
{
variableName = AZStd::string::format("%s (%i)", baseName.c_str(), counter);
}
++counter;
graphVariable = variableManagerRequests->FindVariable(variableName);
}
if (graphVariable == nullptr)
{
ScriptCanvas::Datum datum = ScriptCanvas::Datum(entityId);
AZ::Outcome<ScriptCanvas::VariableId, AZStd::string > addVariableOutcome = variableManagerRequests->AddVariable(variableName, datum);
if (addVariableOutcome.IsSuccess())
{
variableIds.emplace_back(addVariableOutcome.GetValue());
}
}
}
}
if (!variableIds.empty())
{
AZ::EntityId gridId;
GraphCanvas::SceneRequestBus::EventResult(gridId, graphCanvasGraphId, &GraphCanvas::SceneRequests::GetGrid);
AZ::Vector2 gridStep;
GraphCanvas::GridRequestBus::EventResult(gridStep, gridId, &GraphCanvas::GridRequests::GetMinorPitch);
for (const ScriptCanvas::VariableId& variableId : variableIds)
{
NodeIdPair nodePair = Nodes::CreateGetVariableNode(variableId, scriptCanvasId);
GraphCanvas::SceneRequestBus::Event(graphCanvasGraphId, &GraphCanvas::SceneRequests::AddNode, nodePair.m_graphCanvasId, pos);
pos += gridStep;
}
}
}
if (!variableIds.empty())
{
GeneralRequestBus::Broadcast(&GeneralRequests::PostUndoPoint, scriptCanvasId);
}
}
void EntityMimeDataHandler::HandleLeave(const AZ::EntityId&, const QMimeData*)
{
}
} // namespace ScriptCanvasEditor
@@ -0,0 +1,45 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <AzCore/Component/EntityId.h>
#include <AzCore/Component/Component.h>
#include <GraphCanvas/Components/MimeDataHandlerBus.h>
namespace ScriptCanvasEditor
{
class EntityMimeDataHandler
: public AZ::Component
, protected GraphCanvas::SceneMimeDelegateHandlerRequestBus::Handler
{
public:
AZ_COMPONENT(EntityMimeDataHandler, "{C5557609-DBB6-4ACA-A042-D03844B1EB2B}");
static void Reflect(AZ::ReflectContext* context);
EntityMimeDataHandler();
// SceneMimeDelegateHandlerRequestBus
bool IsInterestedInMimeData(const AZ::EntityId& sceneId, const QMimeData* mimeData) override;
void HandleMove(const AZ::EntityId& sceneId, const QPointF& movePoint, const QMimeData* mimeData) override;
void HandleDrop(const AZ::EntityId& sceneId, const QPointF& dropPoint, const QMimeData* mimeData) override;
void HandleLeave(const AZ::EntityId& sceneId, const QMimeData* mimeData) override;
////
//AZ::Component
void Activate() override;
void Deactivate() override;
};
}
@@ -0,0 +1,130 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "precompiled.h"
#include "LibraryDataModel.h"
#include <QIcon>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Component/ComponentApplicationBus.h>
#include <Libraries/Libraries.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
namespace ScriptCanvasEditor
{
namespace Model
{
LibraryData::LibraryData(QObject* parent /*= nullptr*/) : QAbstractTableModel(parent)
{
Add("All", AZ::Uuid::CreateNull());
AZ::SerializeContext* serializeContext = nullptr;
AZ::ComponentApplicationBus::BroadcastResult(serializeContext, &AZ::ComponentApplicationRequests::GetSerializeContext);
serializeContext->EnumerateDerived<ScriptCanvas::Library::LibraryDefinition>(
[this]
(const AZ::SerializeContext::ClassData* classData, [[maybe_unused]] const AZ::Uuid& classUuid) -> bool
{
Add(classData->m_name, classData->m_typeId);
return true;
});
}
int LibraryData::rowCount([[maybe_unused]] const QModelIndex &parent /*= QModelIndex()*/) const
{
return m_data.size();
}
int LibraryData::columnCount([[maybe_unused]] const QModelIndex &parent /*= QModelIndex()*/) const
{
return ColumnIndex::Count;
}
QVariant LibraryData::data(const QModelIndex &index, int role /*= Qt::DisplayRole*/) const
{
switch (role)
{
case DataSetRole:
{
if (index.column() == ColumnIndex::Name)
{
const Data* data = &m_data[index.row()];
return QVariant::fromValue<void*>(reinterpret_cast<void*>(const_cast<Data*>(data)));
}
}
break;
case Qt::DisplayRole:
{
if (index.column() == ColumnIndex::Name)
{
return m_data[index.row()].m_name;
}
}
break;
case Qt::DecorationRole:
{
AZ::SerializeContext* serializeContext = nullptr;
EBUS_EVENT_RESULT(serializeContext, AZ::ComponentApplicationBus, GetSerializeContext);
const AZ::SerializeContext::ClassData* classData = serializeContext->FindClassData(m_data[index.row()].m_uuid);
if (classData && classData->m_editData)
{
const auto& editorElementData = classData->m_editData->FindElementData(AZ::Edit::ClassElements::EditorData);
if (editorElementData)
{
if (auto iconAttribute = editorElementData->FindAttribute(AZ::Edit::Attributes::Icon))
{
if (auto iconAttributeData = azdynamic_cast<const AZ::Edit::AttributeData<const char*>*>(iconAttribute))
{
AZStd::string iconAttributeValue = iconAttributeData->Get(nullptr);
if (!iconAttributeValue.empty())
{
return QVariant(QIcon(QString(iconAttributeValue.c_str())));
}
}
}
}
}
else
{
QString defaultIcon = QStringLiteral("Editor/Icons/ScriptCanvas/Libraries/All.png");
return QVariant(QIcon(defaultIcon));
}
return QVariant();
}
break;
default:
break;
}
return QVariant();
}
Qt::ItemFlags LibraryData::flags([[maybe_unused]] const QModelIndex &index) const
{
return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
}
void LibraryData::Add(const char* name, const AZ::Uuid& uuid)
{
m_data.push_back({ QString(name), uuid });
}
}
}
@@ -0,0 +1,60 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#include <QAbstractTableModel>
#include <AzCore/Math/Uuid.h>
namespace ScriptCanvasEditor
{
namespace Model
{
//! Stores the data for the list of ScriptCanvas libraries
class LibraryData
: public QAbstractTableModel
{
public:
enum Role
{
DataSetRole = Qt::UserRole
};
enum ColumnIndex
{
Name,
Count
};
LibraryData(QObject* parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
void Add(const char* name, const AZ::Uuid& uuid);
struct Data
{
QString m_name;
AZ::Uuid m_uuid;
};
typedef QVector<Data> DataSet;
DataSet m_data;
};
}
}
@@ -0,0 +1,534 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include <precompiled.h>
#include <AzFramework/StringFunc/StringFunc.h>
#include <Editor/Model/UnitTestBrowserFilterModel.h>
#include <Editor/Model/moc_UnitTestBrowserFilterModel.cpp>
#include <AzToolsFramework/AssetBrowser/AssetBrowserModel.h>
#include <AzToolsFramework/AssetBrowser/Search/Filter.h>
namespace ScriptCanvasEditor
{
UnitTestBrowserFilterModel::UnitTestBrowserFilterModel(QObject* parent)
: AssetBrowserFilterModel(parent)
, m_iconRunning("Editor/Icons/AssetBrowser/in_progress.gif")
, m_iconPassed(":/ScriptCanvasEditorResources/Resources/valid_icon.png")
, m_iconPassedOld(":/ScriptCanvasEditorResources/Resources/valid_icon_grey.png")
, m_iconFailed(":/ScriptCanvasEditorResources/Resources/error_icon.png")
, m_iconFailedOld(":/ScriptCanvasEditorResources/Resources/error_icon_grey.png")
, m_hoveredIndex(QModelIndex())
{
setDynamicSortFilter(true);
m_showColumn.insert(AssetBrowserModel::m_column);
UnitTestWidgetNotificationBus::Handler::BusConnect();
m_iconRunning.setCacheMode(QMovie::CacheMode::CacheAll);
m_iconRunning.setScaledSize(QSize(14, 14));
m_iconRunning.start();
insertColumn(columnCount());
}
UnitTestBrowserFilterModel::~UnitTestBrowserFilterModel()
{
UnitTestWidgetNotificationBus::Handler::BusDisconnect();
}
QVariant UnitTestBrowserFilterModel::data(const QModelIndex &index, int role) const
{
QModelIndex sourceIndex = mapToSource(index);
if (index.column() == 0 && role == Qt::CheckStateRole)
{
return QVariant(GetCheckState(sourceIndex));
}
else if (role == Qt::DecorationRole)
{
AssetBrowserEntry* entry = GetAssetEntry(sourceIndex);
if (entry == nullptr)
{
AZ_Assert(false, "ERROR - index internal pointer not pointing to an AssetEntry. Tree provided by the AssetBrowser invalid?");
return Qt::PartiallyChecked;
}
if (entry->GetEntryType() == AssetBrowserEntry::AssetEntryType::Source)
{
SourceAssetBrowserEntry* sourceEntry = static_cast<SourceAssetBrowserEntry*>(entry);
AZ::Uuid sourceID = sourceEntry->GetSourceUuid();
if (m_testResults.find(sourceID) != m_testResults.end())
{
UnitTestResult testResult = m_testResults.at(sourceID);
if (testResult.m_running)
{
return m_iconRunning.currentPixmap();
}
else
{
if (testResult.m_success)
{
if (testResult.m_latestTestingRound)
{
return m_iconPassed;
}
else
{
return m_iconPassedOld;
}
}
else
{
if (testResult.m_latestTestingRound)
{
return m_iconFailed;
}
else
{
return m_iconFailedOld;
}
}
}
}
}
return QVariant();
}
return sourceIndex.data(role);
}
bool UnitTestBrowserFilterModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
m_folderCheckStateCache.clear();
QModelIndex sourceIndex = mapToSource(index);
if (index.column() == 0 && role == Qt::CheckStateRole)
{
Qt::CheckState state = static_cast<Qt::CheckState>(value.toInt());
bool result = SetCheckState(sourceIndex, state);
UpdateParentsCheckState(sourceIndex);
UnitTestWidgetNotificationBus::Broadcast(&UnitTestWidgetNotifications::OnCheckStateCountChange, static_cast<int>(m_checkedScripts.size()));
return result;
}
return QSortFilterProxyModel::sourceModel()->setData(sourceIndex, value, role);
}
Qt::ItemFlags UnitTestBrowserFilterModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
{
return Qt::NoItemFlags;
}
QModelIndex sourceIndex = mapToSource(index);
Qt::ItemFlags flags = sourceIndex.flags();
if (index.column() == 0)
{
flags |= Qt::ItemIsUserCheckable;
if (sourceIndex.model()->hasChildren(sourceIndex))
{
flags |= Qt::ItemIsTristate;
}
}
return flags;
}
void UnitTestBrowserFilterModel::SetSearchFilter(const QString& filter)
{
m_textFilter = filter.toUtf8().data();
invalidateFilter();
}
void UnitTestBrowserFilterModel::OnTestStart(const AZ::Uuid& sourceID)
{
UnitTestResult testRunning = UnitTestResult(true, false, "Test is running...");
if (HasTestResults(sourceID))
{
m_testResults.at(sourceID) = testRunning;
}
else
{
m_testResults.insert({ sourceID, testRunning });
}
}
void UnitTestBrowserFilterModel::OnTestResult(const AZ::Uuid& sourceID, UnitTestResult result)
{
m_testResults[sourceID] = result;
}
void UnitTestBrowserFilterModel::GetCheckedScriptsUuidsList(AZStd::vector<AZ::Uuid>& scriptUuids) const
{
scriptUuids.assign(m_checkedScripts.begin(), m_checkedScripts.end());
}
bool UnitTestBrowserFilterModel::HasTestResults(AZ::Uuid sourceUuid)
{
return (m_testResults.find(sourceUuid) != m_testResults.end());
}
UnitTestResult* UnitTestBrowserFilterModel::GetTestResult(AZ::Uuid sourceUuid)
{
return HasTestResults(sourceUuid) ? &m_testResults.at(sourceUuid) : nullptr;
}
void UnitTestBrowserFilterModel::FlushLatestTestRun()
{
for (auto& testResult : m_testResults)
{
testResult.second.m_latestTestingRound = false;
}
}
void UnitTestBrowserFilterModel::OnTick([[maybe_unused]] float deltaTime, AZ::ScriptTimePoint /*time*/)
{
Q_EMIT dataChanged(index(0, 1), index(rowCount() - 1, 1));
}
Qt::CheckState UnitTestBrowserFilterModel::GetCheckState(QModelIndex sourceIndex) const
{
AssetBrowserEntry* entry = GetAssetEntry(sourceIndex);
if (entry == nullptr)
{
AZ_Error("ScriptCanvasEditor", false, "Error - entry was Null pointer");
return Qt::PartiallyChecked;
}
switch (entry->GetEntryType())
{
case AssetBrowserEntry::AssetEntryType::Folder:
{
if (m_folderCheckStateCache.find(sourceIndex) == m_folderCheckStateCache.end())
{
m_folderCheckStateCache[sourceIndex] = GetChildrenCheckState(sourceIndex);
}
return m_folderCheckStateCache[sourceIndex];
}
case AssetBrowserEntry::AssetEntryType::Source:
{
SourceAssetBrowserEntry* sourceEntry = static_cast<SourceAssetBrowserEntry*>(entry);
AZ::Uuid sourceID = sourceEntry->GetSourceUuid();
if(m_checkedScripts.find(sourceID) != m_checkedScripts.end())
{
return Qt::Checked;
}
else
{
return Qt::Unchecked;
}
break;
}
default:
{
AZ_Error("ScriptCanvasEditor", false, "Inconsistent Unit Test Widget tree! (checking state of entry that is not source or folder)");
return Qt::PartiallyChecked;
}
}
}
Qt::CheckState UnitTestBrowserFilterModel::GetChildrenCheckState(QModelIndex sourceIndex) const
{
if (!sourceIndex.isValid())
{
AZ_Error("ScriptCanvasEditor", false, "Inconsistent states for checkboxes in Unit Test Widget tree! (invalid source index)");
return Qt::PartiallyChecked;
}
int rows = sourceModel()->rowCount(sourceIndex);
if (rows == 0)
{
AZ_Error("ScriptCanvasEditor", false, "Inconsistent states for checkboxes in Unit Test Widget tree! (no children detected)");
return Qt::PartiallyChecked;
}
bool checkedChildFound = false;
bool uncheckedChildFound = false;
for (int i = 0; i < rows; ++i)
{
if (filterAcceptsRow(i, sourceIndex))
{
QModelIndex childIndex = sourceModel()->index(i, 0, sourceIndex);
switch (GetCheckState(childIndex))
{
case Qt::Checked:
{
checkedChildFound = true;
if (uncheckedChildFound)
{
return Qt::PartiallyChecked;
}
break;
}
case Qt::Unchecked:
{
uncheckedChildFound = true;
if (checkedChildFound)
{
return Qt::PartiallyChecked;
}
break;
}
case Qt::PartiallyChecked:
{
return Qt::PartiallyChecked;
}
default:
{
AZ_Error("ScriptCanvasEditor", false, "Inconsistent states for checkboxes in Unit Test Widget tree! (wrong default child state)");
return Qt::PartiallyChecked;
}
}
}
}
if (checkedChildFound)
{
return Qt::Checked;
}
else if (uncheckedChildFound)
{
return Qt::Unchecked;
}
AZ_Error("ScriptCanvasEditor", false, "Inconsistent tree in Unit Test Widget tree! (folder with no test children shown)");
return Qt::PartiallyChecked;
}
bool UnitTestBrowserFilterModel::SetCheckState(QModelIndex sourceIndex, Qt::CheckState newState)
{
QPersistentModelIndex pIndex(sourceIndex);
if (newState == Qt::PartiallyChecked)
{
AZ_Error("ScriptCanvasEditor", false, "Unexpected input state for checkbox in Unit Test Widget tree!");
return false;
}
AssetBrowserEntry* entry = GetAssetEntry(sourceIndex);
if (entry == nullptr)
{
AZ_Error("ScriptCanvasEditor", false, "Error - entry was Null pointer");
return Qt::PartiallyChecked;
}
switch (entry->GetEntryType())
{
case AssetBrowserEntry::AssetEntryType::Folder:
{
int rowCount = sourceModel()->rowCount(sourceIndex);
for (int i = 0; i < rowCount; ++i)
{
if (filterAcceptsRow(i, sourceIndex))
{
bool updateOk = SetCheckState(sourceIndex.model()->index(i, 0, sourceIndex), newState);
if (!updateOk)
{
AZ_Error("ScriptCanvasEditor", false, "Issue with updating children in SetCheckState.");
return false;
}
}
}
if (rowCount > 0)
{
Q_EMIT dataChanged(sourceModel()->index(0, 0, sourceIndex), sourceModel()->index(rowCount - 1, 0, sourceIndex));
}
break;
}
case AssetBrowserEntry::AssetEntryType::Source:
{
SourceAssetBrowserEntry* sourceEntry = static_cast<SourceAssetBrowserEntry*>(entry);
AZ::Uuid sourceID = sourceEntry->GetSourceUuid();
if ((newState == Qt::Checked && m_checkedScripts.find(sourceID) != m_checkedScripts.end()) ||
(newState == Qt::Unchecked && m_checkedScripts.find(sourceID) == m_checkedScripts.end()))
{
return true;
}
switch (newState)
{
case Qt::Checked:
{
m_checkedScripts.insert(sourceID);
break;
}
case Qt::Unchecked:
{
m_checkedScripts.erase(sourceID);
break;
}
}
QModelIndex changedIndex = mapFromSource(sourceIndex);
Q_EMIT dataChanged(changedIndex, changedIndex);
break;
}
default:
{
AZ_Error("ScriptCanvasEditor", false, "Inconsistent Unit Test Widget tree! (setting state of entry that is not source or folder)");
return false;
}
}
return true;
}
void UnitTestBrowserFilterModel::UpdateParentsCheckState(QModelIndex sourceIndex)
{
for(QModelIndex currentParent = sourceIndex.parent(); currentParent.isValid(); currentParent = currentParent.parent())
{
QModelIndex changedParent = mapFromSource(currentParent);
Q_EMIT dataChanged(changedParent, changedParent);
}
}
AssetBrowserEntry* UnitTestBrowserFilterModel::GetAssetEntry(QModelIndex index) const
{
if (index.isValid())
{
return static_cast<AssetBrowserEntry*>(index.internalPointer());
}
else
{
AZ_Error("ScriptCanvasEditor", false, "Invalid Source Index provided to GetAssetEntry.");
return nullptr;
}
}
void UnitTestBrowserFilterModel::SetHoveredIndex(QModelIndex newHoveredIndex)
{
m_hoveredIndex = newHoveredIndex;
}
void UnitTestBrowserFilterModel::FilterSetup()
{
sort(0, Qt::DescendingOrder);
AssetTypeFilter* typeFilter = new AssetTypeFilter();
typeFilter->SetAssetType("Script Canvas");
typeFilter->SetFilterPropagation(AssetBrowserEntryFilter::PropagateDirection::Down);
SetFilter(FilterConstType(typeFilter));
}
void UnitTestBrowserFilterModel::TestsStart()
{
AZ::TickBus::Handler::BusConnect();
}
void UnitTestBrowserFilterModel::TestsEnd()
{
AZ::TickBus::Handler::BusDisconnect();
Q_EMIT dataChanged(index(0, 1), index(rowCount() - 1, 1));
}
bool UnitTestBrowserFilterModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
{
QModelIndex index = sourceModel()->index(source_row, 0, source_parent);
if (!sourceModel()->hasChildren(index))
{
/* Do not display leaf - Asset Browser would show the source file as the leaf, but we only care about the product file */
return false;
}
if (!AssetBrowserFilterModel::filterAcceptsRow(source_row, source_parent))
{
return false;
}
bool forcedByParent = false;
if (!m_textFilter.empty())
{
for (QModelIndex currentParent = source_parent; currentParent.isValid(); currentParent = currentParent.parent())
{
AssetBrowserEntry* parentEntry = GetAssetEntry(currentParent);
AZStd::string parentName = parentEntry->GetDisplayName().toUtf8().data();
if (AzFramework::StringFunc::Find(parentName.c_str(), m_textFilter.c_str()) != AZStd::string::npos)
{
forcedByParent = true;
break;
}
}
}
AssetBrowserEntry* entry = GetAssetEntry(index);
AZStd::string testString = entry->GetDisplayName().toUtf8().data();
switch (entry->GetEntryType())
{
case AssetBrowserEntry::AssetEntryType::Folder:
{
int rows = sourceModel()->rowCount(index);
for (int i = 0; i < rows; ++i)
{
if (filterAcceptsRow(i, index))
{
return true;
}
}
break;
}
case AssetBrowserEntry::AssetEntryType::Source:
{
if(AzFramework::StringFunc::StartsWith(testString, "test_"))
{
if (m_textFilter.empty() || AzFramework::StringFunc::Find(testString.c_str(), m_textFilter.c_str()) != AZStd::string::npos || forcedByParent)
{
return true;
}
}
break;
}
}
return false;
}
}
@@ -0,0 +1,100 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#pragma once
#if !defined(Q_MOC_RUN)
#include <AzToolsFramework/AssetBrowser/AssetBrowserFilterModel.h>
#include <AzToolsFramework/AssetBrowser/AssetBrowserEntry.h>
#include <AzToolsFramework/AssetBrowser/Search/Filter.h>
#include <ScriptCanvas/Bus/UnitTestVerificationBus.h>
#include <QSharedPointer>
#include <QCollator>
#include <QIcon>
AZ_PUSH_DISABLE_WARNING(4251, "-Wunknown-warning-option") // 4251: 'QImageIOHandler::d_ptr': class 'QScopedPointer<QImageIOHandlerPrivate,QScopedPointerDeleter<T>>' needs to have dll-interface to be used by clients of class 'QImageIOHandler'
#include <QMovie>
#endif
AZ_POP_DISABLE_WARNING
namespace ScriptCanvasEditor
{
using namespace AzToolsFramework;
using namespace AzToolsFramework::AssetBrowser;
class UnitTestBrowserFilterModel
: public AssetBrowserFilterModel
, public UnitTestWidgetNotificationBus::Handler
, public AZ::TickBus::Handler
{
Q_OBJECT
public:
AZ_CLASS_ALLOCATOR(UnitTestBrowserFilterModel, AZ::SystemAllocator, 0);
explicit UnitTestBrowserFilterModel(QObject* parent = nullptr);
~UnitTestBrowserFilterModel();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
bool setData(const QModelIndex &index, const QVariant &value, int role) Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex &index) const Q_DECL_OVERRIDE;
void SetSearchFilter(const QString& filter);
// ScriptCanvasEditor::UnitTestWidgetNotificationBus
virtual void OnTestStart(const AZ::Uuid& sourceID) override;
virtual void OnTestResult(const AZ::Uuid& sourceID, UnitTestResult result) override;
////
void GetCheckedScriptsUuidsList(AZStd::vector<AZ::Uuid>& scriptUuids) const;
bool HasTestResults(AZ::Uuid sourceUuid);
UnitTestResult* GetTestResult(AZ::Uuid sourceUuid);
void FlushLatestTestRun();
// TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint /*time*/) override;
////
void SetHoveredIndex(QModelIndex newHoveredIndex);
void FilterSetup();
void TestsStart();
void TestsEnd();
private:
Qt::CheckState GetCheckState(QModelIndex index) const;
Qt::CheckState GetChildrenCheckState(QModelIndex index) const;
bool SetCheckState(QModelIndex sourceIndex, Qt::CheckState state);
void UpdateParentsCheckState(QModelIndex sourceIndex);
AssetBrowserEntry* GetAssetEntry(QModelIndex index) const;
AZStd::string m_textFilter;
AZStd::unordered_set<AZ::Uuid> m_checkedScripts;
AZStd::unordered_map<AZ::Uuid, UnitTestResult> m_testResults;
mutable QHash<QModelIndex, Qt::CheckState> m_folderCheckStateCache;
QModelIndex m_hoveredIndex;
// ICONS
QMovie m_iconRunning;
const QIcon m_iconPassed;
const QIcon m_iconPassedOld;
const QIcon m_iconFailed;
const QIcon m_iconFailedOld;
protected:
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
};
}