/* * 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 #include #include #include #include #include #include #include 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 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 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 row, col; QMap roleDataMap; stream >> row >> col >> 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 row, col; QMap roleDataMap; stream >> row >> col >> 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