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/AudioSystem/Code/Source/Editor/QATLControlsTreeModel.cpp

371 lines
14 KiB
C++

/*
* 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.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include <QATLControlsTreeModel.h>
#include <ACEEnums.h>
#include <AudioControl.h>
#include <AudioControlsEditorUndo.h>
#include <IEditor.h>
#include <QAudioControlTreeWidget.h>
#include <QStandardItem>
#include <QMessageBox>
namespace AudioControls
{
//-------------------------------------------------------------------------------------------//
QATLTreeModel::QATLTreeModel()
: m_pControlsModel(nullptr)
{
}
//-------------------------------------------------------------------------------------------//
QATLTreeModel::~QATLTreeModel()
{
if (m_pControlsModel)
{
m_pControlsModel->RemoveListener(this);
}
}
//-------------------------------------------------------------------------------------------//
void QATLTreeModel::Initialize(CATLControlsModel* pControlsModel)
{
m_pControlsModel = pControlsModel;
m_pControlsModel->AddListener(this);
}
//-------------------------------------------------------------------------------------------//
QStandardItem* QATLTreeModel::GetItemFromControlID(CID nID)
{
QModelIndexList indexes = match(index(0, 0, QModelIndex()), eDR_ID, nID, 1, Qt::MatchRecursive);
if (!indexes.empty())
{
return itemFromIndex(indexes.at(0));
}
return nullptr;
}
//-------------------------------------------------------------------------------------------//
QStandardItem* QATLTreeModel::AddControl(CATLControl* pControl, QStandardItem* pParent, int nRow)
{
if (pControl && pParent)
{
QStandardItem* pItem = new QAudioControlItem(QString(pControl->GetName().c_str()), pControl);
if (pItem)
{
pParent->insertRow(nRow, pItem);
SetItemAsDirty(pItem);
}
return pItem;
}
return nullptr;
}
//-------------------------------------------------------------------------------------------//
QStandardItem* QATLTreeModel::CreateFolder(QStandardItem* pParent, const AZStd::string_view sName, int nRow)
{
if (pParent)
{
// Make a valid name for the folder (avoid having folders with the same name under same root)
QString sRootName(sName.data());
QString sFolderName(sRootName);
int number = 1;
bool bFoundName = false;
while (!bFoundName)
{
bFoundName = true;
const int size = pParent->rowCount();
for (int i = 0; i < size; ++i)
{
QStandardItem* pItem = pParent->child(i);
if (pItem && (pItem->data(eDR_TYPE) == eIT_FOLDER) && (QString::compare(sFolderName, pItem->text(), Qt::CaseInsensitive) == 0))
{
bFoundName = false;
sFolderName = sRootName + "_" + QString::number(number);
++number;
break;
}
}
}
if (!sFolderName.isEmpty())
{
if (QStandardItem* pFolderItem = new QFolderItem(sFolderName))
{
SetItemAsDirty(pFolderItem);
pParent->insertRow(nRow, pFolderItem);
if (!CUndo::IsSuspended())
{
CUndo undo("Audio Folder Created");
CUndo::Record(new CUndoFolderAdd(pFolderItem));
}
return pFolderItem;
}
}
}
return nullptr;
}
//-------------------------------------------------------------------------------------------//
void QATLTreeModel::RemoveItem(QModelIndex index)
{
QModelIndexList indexList;
indexList.push_back(index);
RemoveItems(indexList);
}
//-------------------------------------------------------------------------------------------//
void QATLTreeModel::RemoveItems(QModelIndexList indexList)
{
// Sort the controls by the level they are inside the tree
// (the deepest in the tree first) and then by their row number.
// This way we guarantee we don't delete the parent of a
// control before its children
struct STreeIndex
{
QPersistentModelIndex m_index;
int m_level;
STreeIndex(QPersistentModelIndex index, int level)
: m_index(index)
, m_level(level) {}
bool operator< (const STreeIndex& index) const
{
if (m_level == index.m_level)
{
return m_index.row() > index.m_index.row();
}
return m_level > index.m_level;
}
};
AZStd::vector<STreeIndex> sortedIndexList;
const int size = indexList.length();
for (int i = 0; i < size; ++i)
{
int level = 0;
QModelIndex index = indexList[i];
while (index.isValid())
{
++level;
index = index.parent();
}
sortedIndexList.push_back(STreeIndex(indexList[i], level));
}
std::sort(sortedIndexList.begin(), sortedIndexList.end());
for (int i = 0; i < size; ++i)
{
QModelIndex index = sortedIndexList[i].m_index;
if (index.isValid())
{
DeleteInternalData(index);
// Mark parent as modified
QModelIndex parent = index.parent();
if (parent.isValid())
{
SetItemAsDirty(itemFromIndex(parent));
}
removeRow(index.row(), index.parent());
}
}
}
//-------------------------------------------------------------------------------------------//
void QATLTreeModel::DeleteInternalData(QModelIndex root)
{
// Delete children first and in reverse order
// of their row (so that we can undo them in the same order)
AZStd::vector<QModelIndex> childs;
QModelIndex child = index(0, 0, root);
for (int i = 1; child.isValid(); ++i)
{
childs.push_back(child);
child = index(i, 0, root);
}
const size_t size = childs.size();
for (size_t i = 0; i < size; ++i)
{
DeleteInternalData(childs[(size - 1) - i]);
}
if (root.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
{
m_pControlsModel->RemoveControl(root.data(eDR_ID).toUInt());
}
else
{
if (!CUndo::IsSuspended())
{
CUndo::Record(new CUndoFolderRemove(itemFromIndex(root)));
}
}
}
//-------------------------------------------------------------------------------------------//
CATLControl* QATLTreeModel::GetControlFromIndex(QModelIndex index)
{
if (m_pControlsModel && index.isValid() && (index.data(eDR_TYPE) == eIT_AUDIO_CONTROL))
{
return m_pControlsModel->GetControlByID(index.data(eDR_ID).toUInt());
}
return nullptr;
}
//-------------------------------------------------------------------------------------------//
void QATLTreeModel::OnControlModified(CATLControl* pControl)
{
if (pControl)
{
if (QStandardItem* pItem = GetItemFromControlID(pControl->GetId()))
{
QString sNewName(pControl->GetName().c_str());
if (pItem->text() != sNewName)
{
pItem->setText(sNewName);
}
SetItemAsDirty(pItem);
}
}
}
//-------------------------------------------------------------------------------------------//
void QATLTreeModel::SetItemAsDirty(QStandardItem* pItem)
{
if (pItem)
{
blockSignals(true);
pItem->setData(true, eDR_MODIFIED);
blockSignals(false);
SetItemAsDirty(pItem->parent());
}
}
//-------------------------------------------------------------------------------------------//
CATLControl* QATLTreeModel::CreateControl(EACEControlType eControlType, const AZStd::string_view sName, CATLControl* pParent)
{
AZStd::string sFinalName = m_pControlsModel->GenerateUniqueName(sName, eControlType, pParent ? pParent->GetScope() : "", pParent);
return m_pControlsModel->CreateControl(sFinalName, eControlType, pParent);
}
//-------------------------------------------------------------------------------------------//
bool QATLTreeModel::dropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
// LY-17684
QStandardItem* rootItem = invisibleRootItem();
QStandardItem* targetItem = rootItem;
if (parent.isValid())
{
targetItem = itemFromIndex(parent);
}
if (targetItem)
{
if (targetItem && (targetItem->data(eDR_TYPE) == eIT_FOLDER || targetItem == rootItem))
{
const QString format = "application/x-qabstractitemmodeldatalist";
if (mimeData->hasFormat(format))
{
QByteArray encoded = mimeData->data(format);
QDataStream stream(&encoded, QIODevice::ReadOnly);
while (!stream.atEnd())
{
int streamRow, streamCol;
QMap<int, QVariant> roleDataMap;
stream >> streamRow >> streamCol >> roleDataMap;
if (!roleDataMap.isEmpty())
{
// If dropping a folder, make sure that folder name doesn't already exist where it is being dropped
if (roleDataMap[eDR_TYPE] == eIT_FOLDER)
{
// Make sure the target folder doesn't have a folder with the same name
QString droppedFolderName = roleDataMap[Qt::DisplayRole].toString();
const int size = targetItem->rowCount();
for (int i = 0; i < size; ++i)
{
QStandardItem* pItem = targetItem->child(i);
if (pItem && (pItem->data(eDR_TYPE) == eIT_FOLDER) && (QString::compare(droppedFolderName, pItem->text(), Qt::CaseInsensitive) == 0))
{
QMessageBox messageBox;
messageBox.setStandardButtons(QMessageBox::Ok);
messageBox.setWindowTitle("Audio Controls Editor");
messageBox.setText("This destination already contains a folder named '" + droppedFolderName + "'.");
messageBox.exec();
return false;
}
}
}
}
}
}
}
}
if (mimeData && action == Qt::MoveAction)
{
if (!CUndo::IsSuspended())
{
CUndo undo("Audio Control Moved");
CUndo::Record(new CUndoItemMove());
}
}
return QStandardItemModel::dropMimeData(mimeData, action, row, column, parent);
}
//-------------------------------------------------------------------------------------------//
bool QATLTreeModel::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, int column, const QModelIndex& parent) const
{
if (!parent.isValid())
{
// Prevent moving controls to the root (outside a folder)
const QString format = "application/x-qabstractitemmodeldatalist";
if (mimeData->hasFormat(format))
{
QByteArray data = mimeData->data(format);
QDataStream stream(&data, QIODevice::ReadOnly);
int streamRow, streamCol;
QMap<int, QVariant> roleDataMap;
stream >> streamRow >> streamCol >> roleDataMap;
if (!roleDataMap.isEmpty() && roleDataMap[eDR_TYPE] != eIT_FOLDER)
{
return false;
}
}
}
else if (parent.data(eDR_TYPE) == eIT_AUDIO_CONTROL)
{
// Prevent dropping on switches
CID nID = parent.data(eDR_ID).toUInt();
if (CATLControl* pControl = m_pControlsModel->GetControlByID(nID))
{
EACEControlType eType = pControl->GetType();
if (eType == eACET_SWITCH || eType == eACET_SWITCH_STATE)
{
return false;
}
}
}
return QStandardItemModel::canDropMimeData(mimeData, action, row, column, parent);
}
} // namespace AudioControls