RulesFileTableModel.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <source/models/RulesFileTableModel.h>
  9. #include <AzCore/std/smart_ptr/shared_ptr.h>
  10. #include <AzCore/std/smart_ptr/make_shared.h>
  11. #include <AzFramework/IO/LocalFileIO.h>
  12. #include <AzFramework/StringFunc/StringFunc.h>
  13. #include <QFileInfo>
  14. #include <QFont>
  15. namespace AssetBundler
  16. {
  17. RulesFileInfo::RulesFileInfo(const AZStd::string& absolutePath, const QString& fileName, bool loadFromFile)
  18. : m_absolutePath(absolutePath)
  19. , m_fileName(fileName)
  20. {
  21. AzFramework::StringFunc::Path::Normalize(m_absolutePath);
  22. m_comparisonSteps = AZStd::make_shared<AzToolsFramework::AssetFileInfoListComparison>();
  23. if (loadFromFile)
  24. {
  25. auto outcome = AzToolsFramework::AssetFileInfoListComparison::Load(m_absolutePath);
  26. if (!outcome.IsSuccess())
  27. {
  28. AZ_Error("AssetBundler", false, outcome.GetError().c_str());
  29. return;
  30. }
  31. m_comparisonSteps = AZStd::make_unique<AzToolsFramework::AssetFileInfoListComparison>(outcome.TakeValue());
  32. QFileInfo fileInfo(m_absolutePath.c_str());
  33. m_fileModificationTime = fileInfo.fileTime(QFileDevice::FileModificationTime);
  34. }
  35. else
  36. {
  37. m_fileModificationTime = QDateTime::currentDateTime();
  38. }
  39. }
  40. bool RulesFileInfo::SaveRulesFile()
  41. {
  42. if (!m_comparisonSteps->Save(m_absolutePath))
  43. {
  44. return false;
  45. }
  46. m_hasUnsavedChanges = false;
  47. m_fileModificationTime = QDateTime::currentDateTime();
  48. return true;
  49. }
  50. RulesFileTableModel::RulesFileTableModel()
  51. : AssetBundlerAbstractFileTableModel()
  52. {
  53. }
  54. AZStd::vector<AZStd::string> RulesFileTableModel::CreateNewFiles(
  55. const AZStd::string& absoluteFilePath,
  56. const AzFramework::PlatformFlags& /*platforms*/,
  57. const QString& /*project*/)
  58. {
  59. if (absoluteFilePath.empty())
  60. {
  61. AZ_Error(AssetBundler::AppWindowName, false, "Input file path is empty");
  62. return {};
  63. }
  64. // Create a platform-specific file path
  65. if (AZ::IO::FileIOBase::GetInstance()->Exists(absoluteFilePath.c_str()))
  66. {
  67. AZ_Error(AssetBundler::AppWindowName, false, "Cannot Create New File: (%s) already exists", absoluteFilePath.c_str());
  68. return {};
  69. }
  70. // Get the file name without the extension for display purposes
  71. AZStd::string fileName = absoluteFilePath;
  72. AzToolsFramework::RemovePlatformIdentifier(fileName);
  73. AzFramework::StringFunc::Path::GetFileName(fileName.c_str(), fileName);
  74. // Create a Rules File and save it to disk
  75. AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
  76. RulesFileInfoPtr newRulesFile = AZStd::make_shared<RulesFileInfo>(absoluteFilePath, QString(fileName.c_str()), false);
  77. if (!newRulesFile->SaveRulesFile())
  78. {
  79. return {};
  80. }
  81. // Add the new file to the model
  82. m_rulesFileInfoMap[key] = newRulesFile;
  83. AddFileKey(key);
  84. return { absoluteFilePath };
  85. }
  86. bool RulesFileTableModel::DeleteFile(const QModelIndex& index)
  87. {
  88. AZStd::string key = GetFileKey(index);
  89. if (key.empty())
  90. {
  91. // Error has already been thrown
  92. return false;
  93. }
  94. RulesFileInfoPtr rulesFileInfo = m_rulesFileInfoMap[key];
  95. // Remove file from disk
  96. if (AZ::IO::FileIOBase::GetInstance()->IsReadOnly(rulesFileInfo->m_absolutePath.c_str()))
  97. {
  98. AZ_Error(AssetBundler::AppWindowName, false, ReadOnlyFileErrorMessage, rulesFileInfo->m_absolutePath.c_str());
  99. return false;
  100. }
  101. auto deleteResult = AZ::IO::FileIOBase::GetInstance()->Remove(rulesFileInfo->m_absolutePath.c_str());
  102. if (!deleteResult)
  103. {
  104. AZ_Error(AssetBundler::AppWindowName, false,
  105. "Unable to delete (%s). Result code: %u", rulesFileInfo->m_absolutePath.c_str(),
  106. deleteResult.GetResultCode());
  107. return false;
  108. }
  109. // Remove file from model
  110. m_rulesFileInfoMap.erase(key);
  111. RemoveFileKey(index);
  112. return true;
  113. }
  114. void RulesFileTableModel::LoadFile(
  115. const AZStd::string& absoluteFilePath,
  116. const AZStd::string& /*projectName*/,
  117. bool /*isDefaultFile*/)
  118. {
  119. // Get the file name without the extension for display purposes
  120. AZStd::string fileName(absoluteFilePath);
  121. AzFramework::StringFunc::Path::GetFileName(fileName.c_str(), fileName);
  122. // Read the Rules file into memory and store it
  123. AZStd::string key = AssetBundler::GenerateKeyFromAbsolutePath(absoluteFilePath);
  124. auto fileInfoIt = m_rulesFileInfoMap.find(key);
  125. if (fileInfoIt != m_rulesFileInfoMap.end() && fileInfoIt->second->m_hasUnsavedChanges)
  126. {
  127. AZ_Warning(AssetBundler::AppWindowName, false,
  128. "Rules File %s has unsaved changes and couldn't be reloaded", absoluteFilePath.c_str());
  129. return;
  130. }
  131. m_rulesFileInfoMap[key] = AZStd::make_shared<RulesFileInfo>(absoluteFilePath, QString(fileName.c_str()), true);
  132. AddFileKey(key);
  133. }
  134. bool RulesFileTableModel::WriteToDisk(const AZStd::string& key)
  135. {
  136. auto rulesFileIt = m_rulesFileInfoMap.find(key);
  137. return rulesFileIt != m_rulesFileInfoMap.end() && rulesFileIt->second->SaveRulesFile();
  138. }
  139. AZStd::string RulesFileTableModel::GetFileAbsolutePath(const QModelIndex& index) const
  140. {
  141. RulesFileInfoPtr rulesFileInfo = GetRulesFileInfoPtr(index);
  142. if (!rulesFileInfo)
  143. {
  144. return AZStd::string();
  145. }
  146. return rulesFileInfo->m_absolutePath;
  147. }
  148. int RulesFileTableModel::GetFileNameColumnIndex() const
  149. {
  150. return Column::ColumnFileName;
  151. }
  152. int RulesFileTableModel::GetTimeStampColumnIndex() const
  153. {
  154. return Column::ColumnFileModificationTime;
  155. }
  156. AZStd::shared_ptr<AzToolsFramework::AssetFileInfoListComparison> RulesFileTableModel::GetComparisonSteps(const QModelIndex& index) const
  157. {
  158. RulesFileInfoPtr rulesFileInfo = GetRulesFileInfoPtr(index);
  159. if (!rulesFileInfo)
  160. {
  161. return nullptr;
  162. }
  163. return rulesFileInfo->m_comparisonSteps;
  164. }
  165. bool RulesFileTableModel::MarkFileChanged(const QModelIndex& index)
  166. {
  167. AZStd::string key = GetFileKey(index);
  168. if (key.empty())
  169. {
  170. // Error has already been thrown
  171. return false;
  172. }
  173. m_rulesFileInfoMap[key]->m_hasUnsavedChanges = true;
  174. // Update display so the user knows there are unsaved changes
  175. m_keysWithUnsavedChanges.emplace(key);
  176. QModelIndex changedIndex = QAbstractTableModel::index(index.row(), Column::ColumnFileName);
  177. emit dataChanged(changedIndex, changedIndex, { Qt::DisplayRole, Qt::FontRole });
  178. return true;
  179. }
  180. int RulesFileTableModel::columnCount(const QModelIndex& parent) const
  181. {
  182. return parent.isValid() ? 0 : Column::Max;
  183. }
  184. QVariant RulesFileTableModel::headerData(int section, Qt::Orientation orientation, int role) const
  185. {
  186. if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
  187. {
  188. switch (section)
  189. {
  190. case Column::ColumnFileName:
  191. return QString(tr("Name"));
  192. case Column::ColumnFileModificationTime:
  193. return QString(tr("Modification Time"));
  194. default:
  195. break;
  196. }
  197. }
  198. return QVariant();
  199. }
  200. QVariant RulesFileTableModel::data(const QModelIndex& index, int role) const
  201. {
  202. AZStd::string key = GetFileKey(index);
  203. if (key.empty())
  204. {
  205. return QVariant();
  206. }
  207. RulesFileInfoPtr rulesFileInfo = m_rulesFileInfoMap.at(key);
  208. int col = index.column();
  209. bool hasUnsavedChanges = rulesFileInfo->m_hasUnsavedChanges;
  210. switch (role)
  211. {
  212. case Qt::DisplayRole:
  213. [[fallthrough]];
  214. case SortRole:
  215. {
  216. if (col == Column::ColumnFileName)
  217. {
  218. QString displayName = rulesFileInfo->m_fileName;
  219. if (hasUnsavedChanges)
  220. {
  221. displayName.append("*");
  222. }
  223. return displayName;
  224. }
  225. else if (col == Column::ColumnFileModificationTime)
  226. {
  227. if (role == SortRole)
  228. {
  229. return rulesFileInfo->m_fileModificationTime;
  230. }
  231. else
  232. {
  233. return rulesFileInfo->m_fileModificationTime.toString(DateTimeFormat);
  234. }
  235. }
  236. break;
  237. }
  238. case Qt::FontRole:
  239. {
  240. if (col == Column::ColumnFileName && hasUnsavedChanges)
  241. {
  242. QFont boldFont;
  243. boldFont.setBold(true);
  244. return boldFont;
  245. }
  246. break;
  247. }
  248. default:
  249. break;
  250. }
  251. return QVariant();
  252. }
  253. RulesFileInfoPtr RulesFileTableModel::GetRulesFileInfoPtr(const QModelIndex& index) const
  254. {
  255. AZStd::string key = GetFileKey(index);
  256. if (key.empty())
  257. {
  258. return nullptr;
  259. }
  260. return m_rulesFileInfoMap.at(key);
  261. }
  262. } // namespace AssetBundler