/* * 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. // Description : Tagged files database for 'SmartFileOpen' dialog #include "StdAfx.h" #include "IndexedFiles.h" volatile TIntAtomic CIndexedFiles::s_bIndexingDone; CIndexedFiles* CIndexedFiles::s_pIndexedFiles = NULL; bool CIndexedFiles::m_startedFileIndexing = false; void CIndexedFiles::Initialize(const QString& path, IFileUtil::ScanDirectoryUpdateCallBack updateCB) { m_files.clear(); m_pathToIndex.clear(); m_tags.clear(); m_rootPath = path; bool anyFiles = CFileUtil::ScanDirectory(path, "*.*", m_files, true, true, updateCB); if (anyFiles == false) { m_files.clear(); return; } if (updateCB) { updateCB("Parsing & tagging..."); } for (int i = 0; i < m_files.size(); ++i) { m_pathToIndex[m_files[i].filename] = i; } PrepareTagTable(); InvokeUpdateCallbacks(); } void CIndexedFiles::AddFile(const IFileUtil::FileDesc& path) { assert(m_pathToIndex.find(path.filename) == m_pathToIndex.end()); m_files.push_back(path); m_pathToIndex[path.filename] = m_files.size() - 1; QStringList tags; GetTags(tags, path.filename); for (int k = 0; k < tags.size(); ++k) { m_tags[tags[k]].insert(m_files.size() - 1); } } void CIndexedFiles::RemoveFile(const QString& path) { if (m_pathToIndex.find(path) == m_pathToIndex.end()) { return; } std::map::iterator itr = m_pathToIndex.find(path); int index = itr->second; m_pathToIndex.erase(itr); m_files.erase(m_files.begin() + index); QStringList tags; GetTags(tags, path); for (int k = 0; k < tags.size(); ++k) { m_tags[tags[k]].erase(index); } } void CIndexedFiles::Refresh(const QString& path, bool recursive) { IFileUtil::FileArray files; bool anyFiles = CFileUtil::ScanDirectory(m_rootPath, Path::Make(path, "*.*"), files, recursive, recursive ? true : false); if (anyFiles == false) { return; } for (int i = 0; i < files.size(); ++i) { if (m_pathToIndex.find(files[i].filename) == m_pathToIndex.end()) { AddFile(files[i]); } } InvokeUpdateCallbacks(); } void CIndexedFiles::GetFilesWithTags(IFileUtil::FileArray& files, const QStringList& tags) const { files.clear(); if (tags.empty()) { return; } int_set candidates; TagTable::const_iterator i; // Gets candidate files from the first tag. for (i = m_tags.begin(); i != m_tags.end(); ++i) { if (i->first.startsWith(tags[0])) { candidates.insert(i->second.begin(), i->second.end()); } } // Reduces the candidates further using additional tags, if any. for (int k = 1; k < tags.size(); ++k) { // Gathers the filter set. int_set filter; for (i = m_tags.begin(); i != m_tags.end(); ++i) { if (i->first.startsWith(tags[k])) { filter.insert(i->second.begin(), i->second.end()); } } // Filters the candidates using it. for (int_set::iterator m = candidates.begin(); m != candidates.end(); ) { if (filter.find(*m) == filter.end()) { int_set::iterator target = m; ++m; candidates.erase(target); } else { ++m; } } } // Outputs the result. files.reserve(candidates.size()); for (int_set::const_iterator m = candidates.begin(); m != candidates.end(); ++m) { files.push_back(m_files[*m]); } } void CIndexedFiles::GetTags(QStringList& tags, const QString& path) const { tags = path.split(QRegularExpression(QStringLiteral(R"([\\/.])")), Qt::SkipEmptyParts); } void CIndexedFiles::GetTagsOfPrefix(QStringList& tags, const QString& prefix) const { tags.clear(); TagTable::const_iterator i; for (i = m_tags.begin(); i != m_tags.end(); ++i) { if (i->first.startsWith(prefix)) { tags.push_back(i->first); } } } void CIndexedFiles::PrepareTagTable() { QStringList tags; for (int i = 0; i < m_files.size(); ++i) { GetTags(tags, m_files[i].filename); for (int k = 0; k < tags.size(); ++k) { m_tags[tags[k]].insert(i); } } } void CIndexedFiles::AddUpdateCallback(std::function updateCallback) { CryAutoLock lock(m_updateCallbackMutex); m_updateCallbacks.push_back(updateCallback); } void CIndexedFiles::InvokeUpdateCallbacks() { CryAutoLock lock(m_updateCallbackMutex); for (auto updateCallback : m_updateCallbacks) { updateCallback(); } }