!XT (BREAK-16) (Sandbox) Remove double-newlines at the end of files.
[CRYENGINE.git] / Code / Sandbox / Plugins / EditorCommon / AssetSystem / AssetEditor.cpp
blobdd4496f86050ceee4ffd32a2f4a418ac3ef9fd3b
1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
2 #include "StdAfx.h"
3 #include "AssetEditor.h"
5 #include "AssetManager.h"
6 #include "FileOperationsExecutor.h"
7 #include "AssetType.h"
8 #include "EditableAsset.h"
9 #include "Loader/AssetLoaderHelpers.h"
10 #include "Browser/AssetBrowserDialog.h"
11 #include "Controls/SingleSelectionDialog.h"
12 #include "Controls/QuestionDialog.h"
13 #include "QtUtil.h"
14 #include "FilePathUtil.h"
15 #include "CryExtension/CryGUID.h"
16 #include "DragDrop.h"
17 #include "AssetFilesGroupProvider.h"
18 #include "ThreadingUtils.h"
20 #include <QCloseEvent>
22 namespace Private_AssetEditor
25 //! Makes a temporary copy of files in construct time
26 //! and moves them back in the destructor.
27 class CAutoFileRecovery
29 public:
30 CAutoFileRecovery(const std::vector<string>& files)
32 if (files.empty())
34 return;
37 static const string tempPrefix = GetTemporaryDirectoryPath();
39 m_files.reserve(files.size());
41 ICryPak* const pCryPak = GetISystem()->GetIPak();
42 pCryPak->MakeDir(tempPrefix.c_str());
43 for (const string& file : files)
45 const string tempFilemane = PathUtil::Make(tempPrefix, CryGUID::Create().ToString(), "tmp");
46 if (!pCryPak->CopyFileOnDisk(file.c_str(), tempFilemane.c_str(), false))
48 break;
51 m_files.emplace_back(file, tempFilemane);
54 if (files.size() != m_files.size())
56 Discard();
60 bool IsValid() const { return !m_files.empty() || !m_files.capacity(); }
62 void Discard()
64 ICryPak* const pCryPak = GetISystem()->GetIPak();
65 for (const auto& file : m_files)
67 pCryPak->RemoveFile(file.second.c_str());
69 m_files.clear();
72 virtual ~CAutoFileRecovery()
74 ICryPak* const pCryPak = GetISystem()->GetIPak();
75 for (const auto& file : m_files)
77 pCryPak->CopyFileOnDisk(file.second.c_str(), file.first.c_str(), false);
78 pCryPak->RemoveFile(file.second.c_str());
81 private:
82 static string GetTemporaryDirectoryPath()
84 char path[ICryPak::g_nMaxPath] = {};
85 return GetISystem()->GetIPak()->AdjustFileName("%USER%/temp", path, ICryPak::FLAGS_PATH_REAL | ICryPak::FLAGS_FOR_WRITING | ICryPak::FLAGS_ADD_TRAILING_SLASH);
88 private:
89 std::vector<std::pair<string, string>> m_files;
92 class CAutoAssetRecovery : public CAutoFileRecovery
94 public:
95 CAutoAssetRecovery(const CAsset& asset)
96 : CAutoFileRecovery(GetAssetFiles(asset, false))
100 static std::vector<string> GetAssetFiles(const CAsset& asset, bool bIncludeSourceFile)
102 std::vector<string> files = asset.GetType()->GetAssetFiles(asset, bIncludeSourceFile, true);
104 files.erase(std::remove_if(files.begin(), files.end(), [](const string& filename)
106 return !GetISystem()->GetIPak()->IsFileExist(filename.c_str(), ICryPak::eFileLocation_OnDisk);
107 }), files.end());
109 return files;
115 CAssetEditor* CAssetEditor::OpenAssetForEdit(const char* szEditorClassName, CAsset* pAsset)
117 CRY_ASSERT(pAsset);
118 IPane* pPane = GetIEditor()->CreateDockable(szEditorClassName);
119 if (pPane)
121 CAssetEditor* assetEditor = static_cast<CAssetEditor*>(pPane);
122 if (assetEditor->OpenAsset(pAsset))
124 return assetEditor;
127 return nullptr;
130 CAssetEditor::CAssetEditor(const char* assetType, QWidget* pParent /*= nullptr*/)
131 : CDockableEditor(pParent)
132 , m_assetBeingEdited(nullptr)
134 auto type = CAssetManager::GetInstance()->FindAssetType(assetType);
135 CRY_ASSERT(type);//type must exist
136 m_supportedAssetTypes.push_back(type);
138 Init();
141 CAssetEditor::CAssetEditor(const QStringList& assetTypes, QWidget* pParent /*= nullptr*/)
142 : CDockableEditor(pParent)
143 , m_assetBeingEdited(nullptr)
145 m_supportedAssetTypes.reserve(assetTypes.size());
146 for (const QString& typeName : assetTypes)
148 auto type = CAssetManager::GetInstance()->FindAssetType(typeName.toStdString().c_str());
149 CRY_ASSERT(type);//type must exist
150 m_supportedAssetTypes.push_back(type);
153 Init();
156 void CAssetEditor::Init()
158 InitGenericMenu();
160 setAcceptDrops(true);
163 bool CAssetEditor::OpenAsset(CAsset* pAsset)
165 //An asset can only be opened once in one editor
166 if (pAsset->IsBeingEdited())
167 return false;
169 if (pAsset == m_assetBeingEdited)
170 return true;
172 if (!Close())
174 // User cancelled closing of currently opened asset.
175 return false;
178 if (!OnOpenAsset(pAsset))
180 return false;
183 AddRecentFile(QString(pAsset->GetMetadataFile()));
184 SetAssetBeingEdited(pAsset);
186 CEditableAsset editableAsset(*pAsset);
187 editableAsset.SetOpenedInAssetEditor(this);
189 return true;
192 bool CAssetEditor::CanOpenAsset(CAsset* pAsset)
194 return pAsset && CanOpenAsset(pAsset->GetType());
197 bool CAssetEditor::CanOpenAsset(const CAssetType* pType)
199 if (!pType)
200 return false;
202 return std::find(m_supportedAssetTypes.begin(), m_supportedAssetTypes.end(), pType) != m_supportedAssetTypes.end();
205 void CAssetEditor::InitGenericMenu()
207 AddToMenu(CEditor::MenuItems::FileMenu);
209 AddToMenu(CEditor::MenuItems::Open);
210 AddToMenu(CEditor::MenuItems::Close);
211 AddToMenu(CEditor::MenuItems::Save);
212 AddToMenu(CEditor::MenuItems::RecentFiles);
214 //TODO: help menu doesn't always occupy last position
215 AddToMenu(CEditor::MenuItems::HelpMenu);
216 AddToMenu(CEditor::MenuItems::Help);
218 InitNewMenu();
221 int CAssetEditor::GetNewableAssetCount() const
223 int newableAssets = 0;
224 for (const auto& type : m_supportedAssetTypes)
226 newableAssets += type->CanBeCreated();
228 return newableAssets;
231 void CAssetEditor::UpdateWindowTitle()
233 if (m_assetBeingEdited)
235 if (m_assetBeingEdited->IsModified())
236 setWindowTitle(QString(m_assetBeingEdited->GetName()) + " *");
237 else
238 setWindowTitle(m_assetBeingEdited->GetName().c_str());
240 setWindowIcon(m_assetBeingEdited->GetType()->GetIcon());
242 else
244 setWindowTitle(GetPaneTitle());
245 setWindowIcon(QIcon());//TODO : this should be the pane's default icon, panes already have an icon from the Tools menu
249 void CAssetEditor::SetAssetBeingEdited(CAsset* pAsset)
251 if (m_assetBeingEdited == pAsset)
252 return;
254 bool bWasReadOnly = false;
256 if (m_assetBeingEdited)
258 m_assetBeingEdited->signalChanged.DisconnectObject(this);
259 bWasReadOnly = m_assetBeingEdited->IsReadOnly();
262 m_assetBeingEdited = pAsset;
264 UpdateWindowTitle();
266 if (pAsset)
268 CAssetManager::GetInstance()->signalBeforeAssetsRemoved.Connect([this](const std::vector<CAsset*>& assets)
270 if (std::find(assets.begin(), assets.end(), GetAssetBeingEdited()) != assets.end())
272 OnCloseAsset();
273 CRY_ASSERT(GetAssetBeingEdited() != nullptr);
274 signalAssetClosed(GetAssetBeingEdited());
275 SetAssetBeingEdited(nullptr);
277 }, (uintptr_t)this);
279 pAsset->signalChanged.Connect(this, &CAssetEditor::OnAssetChanged);
281 if (bWasReadOnly != pAsset->IsReadOnly())
282 OnReadOnlyChanged();
284 else
286 CAssetManager::GetInstance()->signalBeforeAssetsRemoved.DisconnectById((uintptr_t)this);
288 //No longer considered read only after closing the asset
289 if (bWasReadOnly)
290 OnReadOnlyChanged();
294 bool CAssetEditor::OnAboutToCloseAssetInternal(string& reason) const
296 reason.clear();
298 if (!m_assetBeingEdited)
300 return true;
303 if (m_assetBeingEdited->GetEditingSession())
305 return true;
308 if (m_assetBeingEdited->IsModified())
310 reason = QtUtil::ToString(tr("Asset '%1' has unsaved modifications.").arg(m_assetBeingEdited->GetName().c_str()));
311 return false;
314 return OnAboutToCloseAsset(reason);
317 bool CAssetEditor::TryCloseAsset()
319 if (!m_assetBeingEdited)
321 return true;
324 string reason;
325 bool bClose = true;
326 if (!GetIEditor()->IsMainFrameClosing() && !OnAboutToCloseAssetInternal(reason))
328 if (reason.empty())
330 // Show generic modification message.
331 reason = QtUtil::ToString(tr("Asset '%1' has unsaved modifications.").arg(m_assetBeingEdited->GetName().c_str()));
334 const QString title = tr("Closing %1").arg(GetEditorName());
335 const auto button = CQuestionDialog::SQuestion(title, QtUtil::ToQString(reason), QDialogButtonBox::Save | QDialogButtonBox::Discard | QDialogButtonBox::Cancel, QDialogButtonBox::Cancel);
336 switch (button)
338 case QDialogButtonBox::Save:
339 OnSave();
340 bClose = true;
341 break;
342 case QDialogButtonBox::Discard:
343 DiscardAssetChanges();
344 bClose = true;
345 break;
346 case QDialogButtonBox::No:
347 // Fall-through.
348 // "No" is returned when a user clicked the "x" in the window bar.
349 case QDialogButtonBox::Cancel:
350 bClose = false;
351 break;
352 default:
353 CRY_ASSERT(0 && "Unknown button");
354 bClose = false;
355 break;
359 if (bClose)
361 OnCloseAsset();
362 CRY_ASSERT(GetAssetBeingEdited() != nullptr);
363 signalAssetClosed(GetAssetBeingEdited());
364 SetAssetBeingEdited(nullptr);
365 return true;
367 else
369 return false;
373 void CAssetEditor::OnAssetChanged(CAsset& asset, int changeFlags)
375 CRY_ASSERT(&asset == m_assetBeingEdited);
377 if (changeFlags & eAssetChangeFlags_ReadOnly)
379 OnReadOnlyChanged();
382 if (changeFlags & eAssetChangeFlags_Modified)
384 UpdateWindowTitle();
388 void CAssetEditor::InitNewMenu()
390 const int newableAssets = GetNewableAssetCount();
392 if (!newableAssets)
394 return;
396 else if (newableAssets == 1)
398 AddToMenu(MenuItems::New);
400 else
402 CAbstractMenu* const pSubMenu = GetMenu(MenuItems::FileMenu)->CreateMenu(tr("New"), 0, 0);
403 for (const auto& type : m_supportedAssetTypes)
405 if (type->CanBeCreated())
407 QAction* const pAction = pSubMenu->CreateAction(tr("%1").arg(type->GetUiTypeName()));
408 connect(pAction, &QAction::triggered, [this, type]()
410 InternalNewAsset(type);
417 bool CAssetEditor::OnNew()
419 const int newableAssetCount = GetNewableAssetCount();
420 if (newableAssetCount == 1)
422 InternalNewAsset(m_supportedAssetTypes[0]);
424 else if (newableAssetCount > 1)
426 std::vector<string> assetTypeNames;
427 std::transform(m_supportedAssetTypes.begin(), m_supportedAssetTypes.end(), std::back_inserter(assetTypeNames), [](const auto& t)
429 return t->GetTypeName();
431 CSingleSelectionDialog assetTypeSelection;
432 assetTypeSelection.setWindowTitle(tr("New asset type"));
433 assetTypeSelection.SetOptions(assetTypeNames);
434 if (assetTypeSelection.Execute())
436 InternalNewAsset(m_supportedAssetTypes[assetTypeSelection.GetSelectedIndex()]);
439 return true;
442 void CAssetEditor::InternalNewAsset(CAssetType* pAssetType)
444 if (!Close())
445 return;
447 const string assetTypeName = pAssetType->GetTypeName();
449 const string assetBasePath = CAssetBrowserDialog::CreateSingleAssetForType(assetTypeName, CAssetBrowserDialog::OverwriteMode::NoOverwrite);
450 if (assetBasePath.empty())
452 return; // Operation cancelled by user.
455 const string assetPath = assetBasePath + string().Format(".%s.cryasset", pAssetType->GetFileExtension());
456 if (pAssetType->Create(assetPath))
458 CAsset* const pAsset = CAssetManager::GetInstance()->FindAssetForMetadata(assetPath);
459 if (pAsset)
461 OpenAsset(pAsset);
466 bool CAssetEditor::OnOpen()
468 std::vector<string> supportedAssetTypeNames;
469 supportedAssetTypeNames.reserve(m_supportedAssetTypes.size());
470 for (auto& assetType : m_supportedAssetTypes)
472 supportedAssetTypeNames.push_back(assetType->GetTypeName());
475 CAsset* const asset = CAssetBrowserDialog::OpenSingleAssetForTypes(supportedAssetTypeNames);
476 if (asset)
478 (void)OpenAsset(asset);
480 return true;
483 bool CAssetEditor::OnOpenFile(const QString& path)
485 auto asset = CAssetManager::GetInstance()->FindAssetForFile(path.toStdString().c_str());
486 if (asset)
488 (void)OpenAsset(asset);
490 return true;
493 bool CAssetEditor::Close()
495 if (!GetAssetBeingEdited())
497 return true;
500 return TryCloseAsset();
503 bool CAssetEditor::OnClose()
505 //Note: this is only the callback for menu action, every other place should call close()
506 (void)Close();
507 return true;//returns true because the menu action is handled
510 bool CAssetEditor::CanQuit(std::vector<string>& unsavedChanges)
512 string reason;
513 if (!OnAboutToCloseAssetInternal(reason))
515 unsavedChanges.push_back(reason);
516 return false;
518 return true;
521 void CAssetEditor::closeEvent(QCloseEvent* pEvent)
523 if (TryCloseAsset())
525 pEvent->accept();
527 else
529 pEvent->ignore();
532 for (CAssetType* pAssetType : m_supportedAssetTypes)
534 if (pAssetType->GetInstantEditor() == this)
536 pAssetType->SetInstantEditor(nullptr);
541 void CAssetEditor::dragEnterEvent(QDragEnterEvent* pEvent)
543 auto pDragDropData = CDragDropData::FromMimeData(pEvent->mimeData());
544 if (pDragDropData->HasCustomData("Assets"))
546 QByteArray byteArray = pDragDropData->GetCustomData("Assets");
547 QDataStream stream(byteArray);
549 QVector<quintptr> tmp;
550 stream >> tmp;
552 QVector<CAsset*> assets = *reinterpret_cast<QVector<CAsset*>*>(&tmp);
554 if (assets.size() == 1 && CanOpenAsset(assets[0]))
556 CDragDropData::ShowDragText(this, tr("Open"));
557 pEvent->acceptProposedAction();
558 return;
562 if (pDragDropData->HasCustomData("EngineFilePaths"))
564 QByteArray byteArray = pDragDropData->GetCustomData("EngineFilePaths");
565 QDataStream stream(byteArray);
567 QStringList engineFilePaths;
568 stream >> engineFilePaths;
570 const auto meshType = CAssetManager::GetInstance()->FindAssetType("Mesh");
572 if (engineFilePaths.size() == 1)
574 CAsset* asset = CAssetManager::GetInstance()->FindAssetForFile(engineFilePaths[0].toStdString().c_str());
575 if (asset && CanOpenAsset(asset))
577 CDragDropData::ShowDragText(this, tr("Open"));
578 pEvent->acceptProposedAction();
579 return;
584 if (pDragDropData->HasFilePaths())
586 const auto filePaths = pDragDropData->GetFilePaths();
587 const auto meshType = CAssetManager::GetInstance()->FindAssetType("Mesh");
589 if (filePaths.size() == 1)
591 CAsset* asset = CAssetManager::GetInstance()->FindAssetForFile(filePaths[0].toStdString().c_str());
592 if (asset && CanOpenAsset(asset))
594 CDragDropData::ShowDragText(this, tr("Open"));
595 pEvent->acceptProposedAction();
596 return;
602 void CAssetEditor::dropEvent(QDropEvent* pEvent)
604 auto pDragDropData = CDragDropData::FromMimeData(pEvent->mimeData());
605 if (pDragDropData->HasCustomData("Assets"))
607 QByteArray byteArray = pDragDropData->GetCustomData("Assets");
608 QDataStream stream(byteArray);
610 QVector<quintptr> tmp;
611 stream >> tmp;
613 QVector<CAsset*> assets = *reinterpret_cast<QVector<CAsset*>*>(&tmp);
615 if (assets.size() == 1 && CanOpenAsset(assets[0]))
617 OpenAsset(assets[0]);
618 pEvent->acceptProposedAction();
619 return;
623 if (pDragDropData->HasCustomData("EngineFilePaths"))
625 QByteArray byteArray = pDragDropData->GetCustomData("EngineFilePaths");
626 QDataStream stream(byteArray);
628 QStringList engineFilePaths;
629 stream >> engineFilePaths;
631 const auto meshType = CAssetManager::GetInstance()->FindAssetType("Mesh");
633 if (engineFilePaths.size() == 1)
635 CAsset* asset = CAssetManager::GetInstance()->FindAssetForFile(engineFilePaths[0].toStdString().c_str());
636 if (asset && CanOpenAsset(asset))
638 OpenAsset(asset);
639 pEvent->acceptProposedAction();
640 return;
645 if (pDragDropData->HasFilePaths())
647 const auto filePaths = pDragDropData->GetFilePaths();
648 const auto meshType = CAssetManager::GetInstance()->FindAssetType("Mesh");
650 if (filePaths.size() == 1)
652 CAsset* asset = CAssetManager::GetInstance()->FindAssetForFile(filePaths[0].toStdString().c_str());
653 if (asset && CanOpenAsset(asset))
655 OpenAsset(asset);
656 pEvent->acceptProposedAction();
657 return;
663 QToolButton* CAssetEditor::CreateLockButton()
665 if (m_pLockButton)
667 return m_pLockButton;
670 m_pLockButton = new QToolButton();
671 m_pLockButton->setCheckable(true);
672 m_pLockButton->setIcon(CryIcon("icons:General/Instant_Editing.ico"));
673 m_pLockButton->setToolTip(tr("Instant Editing"));
675 connect(m_pLockButton, &QToolButton::toggled, this, &CAssetEditor::SetInstantEditingMode);
677 const bool foundInstantEditor = std::any_of(m_supportedAssetTypes.cbegin(), m_supportedAssetTypes.cend(), [](const CAssetType* pType)
679 return pType->GetInstantEditor() != nullptr;
682 if (!foundInstantEditor)
684 SetInstantEditingMode(true);
687 return m_pLockButton;
690 bool CAssetEditor::InternalSaveAsset(CAsset* pAsset)
692 //TODO: Figure out how to handle writing metadata generically without opening the file twice
693 //(one in OnSaveAsset implementation and one here)
695 //TODO: here the editable asset retains every metadata of the old asset, which means if it is not overwritten in OnSaveAsset, some metadata could carry over.
696 //Perhaps the safest way would be to clear it before passing it. Also means that calling things like AddFile() in there will result in warnings because the file was duplicated etc...
698 CEditableAsset editAsset(*pAsset);
699 if (!OnSaveAsset(editAsset))
701 return false;
704 editAsset.InvalidateThumbnail();
705 editAsset.WriteToFile();
706 pAsset->SetModified(false);
708 return true;
711 bool CAssetEditor::Save()
713 if (!m_assetBeingEdited)
715 return true;
718 return InternalSaveAsset(m_assetBeingEdited);
721 void CAssetEditor::DiscardAssetChanges()
723 CAsset* pAsset = GetAssetBeingEdited();
724 if (pAsset)
726 CEditableAsset editAsset(*pAsset);
727 OnDiscardAssetChanges(editAsset);
728 pAsset->SetModified(false);
732 bool CAssetEditor::OnSave()
734 Save();
735 return true;
738 bool CAssetEditor::OnSaveAs()
740 if (!m_assetBeingEdited)
742 return true;
745 CRY_ASSERT(!m_supportedAssetTypes.empty());
746 CAssetType* const pAssetType = m_supportedAssetTypes[0];
747 const string assetTypeName = pAssetType->GetTypeName();
749 // #TODO: Let user save any of the supported asset types.
750 const string assetBasePath = CAssetBrowserDialog::SaveSingleAssetForType(assetTypeName);
751 if (assetBasePath.empty())
753 return true; // Operation cancelled by user.
755 const string newAssetPath = assetBasePath + string().Format(".%s.cryasset", pAssetType->GetFileExtension());
757 if (newAssetPath.Compare(m_assetBeingEdited->GetMetadataFile()) == 0)
759 return OnSave();
762 CAssetManager* const pAssetManager = CAssetManager::GetInstance();
763 CAsset* pAsset = pAssetManager->FindAssetForMetadata(newAssetPath);
764 if (pAsset)
766 // Cancel if unable to delete.
767 pAssetManager->DeleteAssetsWithFiles({ pAsset });
768 pAsset = pAssetManager->FindAssetForMetadata(newAssetPath);
769 if (pAsset)
771 return true;
775 // Create new asset on disk.
776 if (!InternalSaveAs(newAssetPath))
778 return true;
781 pAsset = AssetLoader::CAssetFactory::LoadAssetFromXmlFile(newAssetPath);
782 pAssetManager->MergeAssets({ pAsset });
784 if (pAsset)
786 // Close previous asset and unconditionally discard all changes.
787 DiscardAssetChanges();
788 OnCloseAsset();
789 CRY_ASSERT(GetAssetBeingEdited() != nullptr);
790 signalAssetClosed(GetAssetBeingEdited());
791 SetAssetBeingEdited(nullptr);
793 OpenAsset(pAsset);
795 return true;
798 bool CAssetEditor::InternalSaveAs(const string& newAssetPath)
800 CRY_ASSERT(m_assetBeingEdited);
802 using namespace Private_AssetEditor;
804 // 1. Make a temp copy of asset files.
805 // 2. Save asset changes.
806 // 3. Move updated files under the new asset name.
807 // 4. Restore old files from the temp copy.
808 // TODO: consider a direct implementation of the SaveAs. e.g CAssetType::SaveAs(CAsset& asset, string newAssetPath)
810 CAutoAssetRecovery tempCopy(*m_assetBeingEdited);
811 if (!tempCopy.IsValid() || !OnSave())
813 CryWarning(EValidatorModule::VALIDATOR_MODULE_EDITOR, EValidatorSeverity::VALIDATOR_ERROR, "Unable to copy asset: %s", m_assetBeingEdited->GetName());
814 return false;
817 const bool result = m_assetBeingEdited->GetType()->CopyAsset(m_assetBeingEdited, newAssetPath);
819 ThreadingUtils::AsyncQueue([this]()
821 std::vector<std::unique_ptr<IFilesGroupProvider>> fileGroups;
822 fileGroups.emplace_back(new CAssetFilesGroupProvider(m_assetBeingEdited, false));
823 CFileOperationExecutor::GetDefaultExecutor()->Delete(std::move(fileGroups));
824 }).wait(); // we need to wait here it needs to be finished before tempCopy gets destroyed. Hopefully this method will die soon.
826 return result;
829 bool CAssetEditor::SaveBackup(const string& backupFolder)
831 CRY_ASSERT(m_assetBeingEdited);
832 using namespace Private_AssetEditor;
834 // 1. Make a temporary copy of the current asset files.
835 // 2. Save asset changes.
836 // 3. Move updated files to the backupFolder.
837 // 4. Restore old files from the temp copy.
839 CAutoAssetRecovery tempCopy(*m_assetBeingEdited);
841 if (!tempCopy.IsValid() || !OnSave())
843 return false;
846 std::vector<string> files = CAutoAssetRecovery::GetAssetFiles(*m_assetBeingEdited, false);
848 ICryPak* const pCryPak = GetISystem()->GetIPak();
849 pCryPak->MakeDir(backupFolder.c_str());
850 const string assetsRoot = PathUtil::GetGameProjectAssetsPath();
851 for (const auto& file : files)
853 CRY_ASSERT(strncmp(file.c_str(), assetsRoot.c_str(), assetsRoot.size()));
854 CryPathString destFile = PathUtil::Make(backupFolder.c_str(), file.c_str() + assetsRoot.size());
855 pCryPak->MakeDir(PathUtil::GetDirectory(destFile.c_str()));
856 PathUtil::MoveFileAllowOverwrite(file.c_str(), destFile.c_str());
859 // tempCopy restores asset files.
860 return true;
863 bool CAssetEditor::IsReadOnly() const
865 return GetAssetBeingEdited() != nullptr ? GetAssetBeingEdited()->IsReadOnly() : false;
868 void CAssetEditor::SetInstantEditingMode(bool isActive)
870 if (isActive)
872 for (CAssetType* pAssetType : m_supportedAssetTypes)
874 if (pAssetType->GetInstantEditor() == this)
876 continue;
879 if (pAssetType->GetInstantEditor())
881 pAssetType->GetInstantEditor()->SetInstantEditingMode(false);
883 pAssetType->SetInstantEditor(this);
886 else
888 for (CAssetType* pAssetType : m_supportedAssetTypes)
890 if (pAssetType->GetInstantEditor() == this)
892 pAssetType->SetInstantEditor(nullptr);
897 if (m_pLockButton && m_pLockButton->isChecked() != isActive)
899 m_pLockButton->setChecked(isActive);