From 3a65665d36022c50637fc53d5c9c1ee022c5b3b5 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 10 Feb 2020 10:51:23 -0500 Subject: wstring_view when possible first implementation of NtQueryDirectoryFile --- src/shared/util.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/shared/util.h') diff --git a/src/shared/util.h b/src/shared/util.h index 05522c2d..dc6e72ad 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -41,6 +41,7 @@ std::string ToLowerCopy(const std::string& text); std::wstring& ToLowerInPlace(std::wstring& text); std::wstring ToLowerCopy(const std::wstring& text); +std::wstring ToLowerCopy(std::wstring_view text); bool CaseInsensitiveEqual(const std::wstring &lhs, const std::wstring &rhs); -- cgit v1.3.1 From 5e569d0107aefe292b76ac0458f9420077f350a0 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 15 Feb 2020 17:22:12 -0500 Subject: re-enabled archive parsing --- src/directoryrefresher.cpp | 126 ++++++++++++++++++++------------- src/mainwindow.cpp | 1 + src/shared/directoryentry.cpp | 161 ++++++++++++++++++++++++------------------ src/shared/directoryentry.h | 79 ++++++++++++--------- src/shared/util.h | 10 +++ 5 files changed, 223 insertions(+), 154 deletions(-) (limited to 'src/shared/util.h') diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 8a64d4a9..5e1c05a8 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -210,38 +210,41 @@ void DirectoryRefresher::cleanStructure(DirectoryEntry *structure) } } -void DirectoryRefresher::addModBSAToStructure(DirectoryEntry *directoryStructure, const QString &modName, - int priority, const QString &directory, const QStringList &archives) +void DirectoryRefresher::addModBSAToStructure( + DirectoryEntry* root, const QString& modName, + int priority, const QString& directory, const QStringList& archives) { - std::wstring directoryW = ToWString(QDir::toNativeSeparators(directory)); - IPluginGame *game = qApp->property("managed_game").value(); + const IPluginGame *game = qApp->property("managed_game").value(); GamePlugins *gamePlugins = game->feature(); QStringList loadOrder = QStringList(); gamePlugins->getLoadOrder(loadOrder); - for (const QString &archive : archives) { - QFileInfo fileInfo(archive); - if (m_EnabledArchives.find(fileInfo.fileName()) != m_EnabledArchives.end()) { - - int order = -1; + std::vector lo; + for (auto&& s : loadOrder) { + lo.push_back(s.toStdWString()); + } - for (auto plugin : loadOrder) - { - QString name = plugin.left(plugin.size() - 4); - if (fileInfo.fileName().startsWith(name + " - ", Qt::CaseInsensitive) || fileInfo.fileName().startsWith(name + ".", Qt::CaseInsensitive)) { - order = loadOrder.indexOf(plugin); - } - } + std::vector archivesW; + for (auto&& a : archives) { + archivesW.push_back(a.toStdWString()); + } - try { - IPluginGame *game = qApp->property("managed_game").value(); - directoryStructure->addFromBSA(ToWString(modName), directoryW, ToWString(QDir::toNativeSeparators(fileInfo.absoluteFilePath())), priority, order); - } catch (const std::exception &e) { - throw MyException(tr("failed to parse bsa %1: %2").arg(archive, e.what())); - } - } + std::set enabledArchives; + for (auto&& a : m_EnabledArchives) { + enabledArchives.insert(a.toStdWString()); } + + DirectoryStats dummy; + + root->addFromAllBSAs( + modName.toStdWString(), + QDir::toNativeSeparators(directory).toStdWString(), + priority, + archivesW, + enabledArchives, + lo, + dummy); } void DirectoryRefresher::stealModFilesIntoStructure( @@ -329,6 +332,8 @@ struct ModThread std::wstring modName; std::wstring path; int prio = -1; + std::vector archives; + std::set enabledArchives; DirectoryStats* stats = nullptr; env::DirectoryWalker walker; @@ -354,14 +359,21 @@ struct ModThread SetThisThreadName(QString::fromStdWString(modName + L" refresher")); ds->addFromOrigin(walker, modName, path, prio, *stats); - /*if (Settings::instance().archiveParsing()) { - addModBSAToStructure( - directoryStructure, - entries[i].modName, - prio, - entries[i].absolutePath, - entries[i].archives); - }*/ + if (Settings::instance().archiveParsing()) { + const IPluginGame *game = qApp->property("managed_game").value(); + + GamePlugins *gamePlugins = game->feature(); + QStringList loadOrder = QStringList(); + gamePlugins->getLoadOrder(loadOrder); + + std::vector lo; + for (auto&& s : loadOrder) { + lo.push_back(s.toStdWString()); + } + + ds->addFromAllBSAs( + modName, path, prio, archives, enabledArchives, lo, *stats); + } ready = false; } @@ -377,6 +389,7 @@ void DirectoryRefresher::addMultipleModsFilesToStructure( { std::vector stats(entries.size()); + log::debug("refresher: using {} threads", m_threadCount); g_threads.setMax(m_threadCount); for (std::size_t i=0; igetFileRegister()->reserve(m_lastFileCount); + m_Root.reset(new DirectoryEntry(L"data", nullptr, 0)); + m_Root->getFileRegister()->reserve(m_lastFileCount); - IPluginGame *game = qApp->property("managed_game").value(); + IPluginGame *game = qApp->property("managed_game").value(); - std::wstring dataDirectory = - QDir::toNativeSeparators(game->dataDirectory().absolutePath()).toStdWString(); + std::wstring dataDirectory = + QDir::toNativeSeparators(game->dataDirectory().absolutePath()).toStdWString(); - { - DirectoryStats dummy; - m_Root->addFromOrigin(L"data", dataDirectory, 0, dummy); - } + { + DirectoryStats dummy; + m_Root->addFromOrigin(L"data", dataDirectory, 0, dummy); + } - std::sort(m_Mods.begin(), m_Mods.end(), [](auto lhs, auto rhs) { - return lhs.priority < rhs.priority; - }); + std::sort(m_Mods.begin(), m_Mods.end(), [](auto lhs, auto rhs) { + return lhs.priority < rhs.priority; + }); - addMultipleModsFilesToStructure(m_Root.get(), m_Mods, true); + addMultipleModsFilesToStructure(m_Root.get(), m_Mods, true); - m_Root->getFileRegister()->sortOrigins(); + m_Root->getFileRegister()->sortOrigins(); - cleanStructure(m_Root.get()); + cleanStructure(m_Root.get()); - m_lastFileCount = m_Root->getFileRegister()->highestCount(); - log::debug("refresher saw {} files", m_lastFileCount); + m_lastFileCount = m_Root->getFileRegister()->highestCount(); + log::debug("refresher saw {} files", m_lastFileCount); + } emit progress(100); emit refreshed(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index adbac94e..f5749392 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -87,6 +87,7 @@ along with Mod Organizer. If not, see . #include "envshortcut.h" #include "browserdialog.h" +#include "directoryrefresher.h" #include "shared/directoryentry.h" #include "shared/fileentry.h" #include "shared/filesorigin.h" diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 7f140750..84d68675 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -67,14 +67,14 @@ static bool SupportOptimizedFind() return (::VerifyVersionInfo(&versionInfo, VER_MAJORVERSION | VER_MINORVERSION, mask) == TRUE); } -static bool DirCompareByName(const DirectoryEntry *lhs, const DirectoryEntry *rhs) +static bool DirCompareByName(const DirectoryEntry* lhs, const DirectoryEntry* rhs) { return _wcsicmp(lhs->getName().c_str(), rhs->getName().c_str()) < 0; } DirectoryEntry::DirectoryEntry( - std::wstring name, DirectoryEntry *parent, int originID) : + std::wstring name, DirectoryEntry* parent, int originID) : m_OriginConnection(new OriginConnection), m_Name(std::move(name)), m_Parent(parent), m_Populated(false), m_TopLevel(true) { @@ -83,7 +83,7 @@ DirectoryEntry::DirectoryEntry( } DirectoryEntry::DirectoryEntry( - std::wstring name, DirectoryEntry *parent, int originID, + std::wstring name, DirectoryEntry* parent, int originID, boost::shared_ptr fileRegister, boost::shared_ptr originConnection) : m_FileRegister(fileRegister), m_OriginConnection(originConnection), @@ -166,51 +166,69 @@ void DirectoryEntry::addDir( m_Populated = true; } -void DirectoryEntry::addFromBSA( - const std::wstring &originName, std::wstring &directory, - const std::wstring &fileName, int priority, int order) +void DirectoryEntry::addFromAllBSAs( + const std::wstring& originName, const std::wstring& directory, + int priority, const std::vector& archives, + const std::set& enabledArchives, + const std::vector& loadOrder, + DirectoryStats& stats) { - DirectoryStats dummy; - FilesOrigin &origin = createOrigin(originName, directory, priority, dummy); + for (const auto& archive : archives) { + const std::filesystem::path archivePath(archive); + const auto filename = archivePath.filename().native(); - WIN32_FILE_ATTRIBUTE_DATA fileData; - if (::GetFileAttributesExW(fileName.c_str(), GetFileExInfoStandard, &fileData) == 0) { - throw windows_error(QObject::tr("failed to determine file time").toStdString()); - } + if (!enabledArchives.contains(filename)) { + continue; + } - FILETIME now; - ::GetSystemTimeAsFileTime(&now); + const auto filenameLc = ToLowerCopy(filename); - const double clfSecondsPer100ns = 100. * 1.E-9; + int order = -1; - ((ULARGE_INTEGER *)&now)->QuadPart -= ((double)5) / clfSecondsPer100ns; + for (auto plugin : loadOrder) + { + const auto pluginNameLc = + ToLowerCopy(std::filesystem::path(plugin).stem().native()); + + if (filenameLc.starts_with(pluginNameLc + L" - ") || + filenameLc.starts_with(pluginNameLc + L".")) { + auto itor = std::find(loadOrder.begin(), loadOrder.end(), plugin); + if (itor != loadOrder.end()) { + order = std::distance(loadOrder.begin(), itor); + } + } + } - size_t namePos = fileName.find_last_of(L"\\/"); - if (namePos == std::wstring::npos) { - namePos = 0; + addFromBSA( + originName, directory, archivePath.native(), + priority, order, stats); } - else { - ++namePos; +} + +void DirectoryEntry::addFromBSA( + const std::wstring& originName, const std::wstring& directory, + const std::wstring& archivePath, int priority, int order, DirectoryStats& stats) +{ + FilesOrigin& origin = createOrigin(originName, directory, priority, stats); + const auto archiveName = std::filesystem::path(archivePath).filename().native(); + + if (containsArchive(archiveName)) { + return; } - if (!containsArchive(fileName.substr(namePos)) || ::CompareFileTime(&fileData.ftLastWriteTime, &now) > 0) { - BSA::Archive archive; - BSA::EErrorCode res = archive.read(ToString(fileName, false).c_str(), false); + BSA::Archive archive; + BSA::EErrorCode res = archive.read(ToString(archivePath, false).c_str(), false); - if ((res != BSA::ERROR_NONE) && (res != BSA::ERROR_INVALIDHASHES)) { - std::ostringstream stream; + if ((res != BSA::ERROR_NONE) && (res != BSA::ERROR_INVALIDHASHES)) { + log::error("invalid bsa '{}', error {}", archivePath, res); + return; + } - stream - << QObject::tr("invalid bsa file: ").toStdString() - << ToString(fileName, false) - << " error code " << res << " - " << ::GetLastError(); + const auto ft = ToFILETIME(std::filesystem::last_write_time(archivePath)); - throw std::runtime_error(stream.str()); - } + addFiles(origin, archive.getRoot(), ft, archiveName, order, stats); - addFiles(origin, archive.getRoot(), fileData.ftLastWriteTime, fileName.substr(namePos), order); - m_Populated = true; - } + m_Populated = true; } void DirectoryEntry::propagateOrigin(int origin) @@ -258,7 +276,7 @@ int DirectoryEntry::anyOrigin() const // if we got here, no file directly within this directory is a valid indicator for a mod, thus // we continue looking in subdirectories - for (DirectoryEntry *entry : m_SubDirectories) { + for (DirectoryEntry* entry : m_SubDirectories) { int res = entry->anyOrigin(); if (res != InvalidOriginID){ return res; @@ -279,7 +297,7 @@ std::vector DirectoryEntry::getFiles() const return result; } -DirectoryEntry *DirectoryEntry::findSubDirectory( +DirectoryEntry* DirectoryEntry::findSubDirectory( const std::wstring &name, bool alreadyLowerCase) const { SubDirectoriesLookup::const_iterator itor; @@ -297,9 +315,10 @@ DirectoryEntry *DirectoryEntry::findSubDirectory( return itor->second; } -DirectoryEntry *DirectoryEntry::findSubDirectoryRecursive(const std::wstring &path) +DirectoryEntry* DirectoryEntry::findSubDirectoryRecursive(const std::wstring &path) { - return getSubDirectoryRecursive(path, false, InvalidOriginID); + DirectoryStats dummy; + return getSubDirectoryRecursive(path, false, dummy, InvalidOriginID); } const FileEntryPtr DirectoryEntry::findFile( @@ -349,7 +368,7 @@ bool DirectoryEntry::containsArchive(std::wstring archiveName) } const FileEntryPtr DirectoryEntry::searchFile( - const std::wstring &path, const DirectoryEntry **directory) const + const std::wstring &path, const DirectoryEntry** directory) const { if (directory != nullptr) { *directory = nullptr; @@ -373,7 +392,7 @@ const FileEntryPtr DirectoryEntry::searchFile( if (iter != m_Files.end()) { return m_FileRegister->getFile(iter->second); } else if (directory != nullptr) { - DirectoryEntry *temp = findSubDirectory(path); + DirectoryEntry* temp = findSubDirectory(path); if (temp != nullptr) { *directory = temp; } @@ -381,7 +400,7 @@ const FileEntryPtr DirectoryEntry::searchFile( } else { // file is in a subdirectory, recurse into the matching subdirectory std::wstring pathComponent = path.substr(0, len); - DirectoryEntry *temp = findSubDirectory(pathComponent); + DirectoryEntry* temp = findSubDirectory(pathComponent); if (temp != nullptr) { if (len >= path.size()) { @@ -401,7 +420,7 @@ void DirectoryEntry::removeFile(FileIndex index) removeFileFromList(index); } -bool DirectoryEntry::removeFile(const std::wstring &filePath, int *origin) +bool DirectoryEntry::removeFile(const std::wstring &filePath, int* origin) { size_t pos = filePath.find_first_of(L"\\/"); @@ -411,7 +430,9 @@ bool DirectoryEntry::removeFile(const std::wstring &filePath, int *origin) std::wstring dirName = filePath.substr(0, pos); std::wstring rest = filePath.substr(pos + 1); - DirectoryEntry *entry = getSubDirectoryRecursive(dirName, false); + + DirectoryStats dummy; + DirectoryEntry* entry = getSubDirectoryRecursive(dirName, false, dummy); if (entry != nullptr) { return entry->removeFile(rest, origin); @@ -426,7 +447,7 @@ void DirectoryEntry::removeDir(const std::wstring &path) if (pos == std::string::npos) { for (auto iter = m_SubDirectories.begin(); iter != m_SubDirectories.end(); ++iter) { - DirectoryEntry *entry = *iter; + DirectoryEntry* entry = *iter; if (CaseInsensitiveEqual(entry->getName(), path)) { entry->removeDirRecursive(); @@ -438,7 +459,9 @@ void DirectoryEntry::removeDir(const std::wstring &path) } else { std::wstring dirName = path.substr(0, pos); std::wstring rest = path.substr(pos + 1); - DirectoryEntry *entry = getSubDirectoryRecursive(dirName, false); + + DirectoryStats dummy; + DirectoryEntry* entry = getSubDirectoryRecursive(dirName, false, dummy); if (entry != nullptr) { entry->removeDir(rest); @@ -446,7 +469,7 @@ void DirectoryEntry::removeDir(const std::wstring &path) } } -bool DirectoryEntry::remove(const std::wstring &fileName, int *origin) +bool DirectoryEntry::remove(const std::wstring &fileName, int* origin) { const auto lcFileName = ToLowerCopy(fileName); @@ -661,18 +684,17 @@ void DirectoryEntry::onFile(Context* cx, std::wstring_view path, FILETIME ft) } void DirectoryEntry::addFiles( - FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, - const std::wstring &archiveName, int order) + FilesOrigin& origin, const BSA::Folder::Ptr archiveFolder, FILETIME fileTime, + const std::wstring& archiveName, int order, DirectoryStats& stats) { - DirectoryStats dummy; - // add files - for (unsigned int fileIdx = 0; fileIdx < archiveFolder->getNumFiles(); ++fileIdx) { - BSA::File::Ptr file = archiveFolder->getFile(fileIdx); + const auto fileCount = archiveFolder->getNumFiles(); + for (unsigned int i=0; igetFile(i); auto f = insert( ToWString(file->getName(), true), origin, fileTime, - archiveName, order, dummy); + archiveName, order, stats); if (f) { if (file->getUncompressedFileSize() > 0) { @@ -684,16 +706,18 @@ void DirectoryEntry::addFiles( } // recurse into subdirectories - for (unsigned int folderIdx = 0; folderIdx < archiveFolder->getNumSubFolders(); ++folderIdx) { - BSA::Folder::Ptr folder = archiveFolder->getSubFolder(folderIdx); - DirectoryEntry *folderEntry = getSubDirectoryRecursive( - ToWString(folder->getName(), true), true, origin.getID()); + const auto dirCount = archiveFolder->getNumSubFolders(); + for (unsigned int i=0; igetSubFolder(i); + + DirectoryEntry* folderEntry = getSubDirectoryRecursive( + ToWString(folder->getName(), true), true, stats, origin.getID()); - folderEntry->addFiles(origin, folder, fileTime, archiveName, order); + folderEntry->addFiles(origin, folder, fileTime, archiveName, order, stats); } } -DirectoryEntry *DirectoryEntry::getSubDirectory( +DirectoryEntry* DirectoryEntry::getSubDirectory( std::wstring_view name, bool create, DirectoryStats& stats, int originID) { std::wstring nameLc = ToLowerCopy(name); @@ -728,7 +752,7 @@ DirectoryEntry *DirectoryEntry::getSubDirectory( } } -DirectoryEntry *DirectoryEntry::getSubDirectory( +DirectoryEntry* DirectoryEntry::getSubDirectory( env::Directory& dir, bool create, DirectoryStats& stats, int originID) { SubDirectoriesLookup::iterator itor; @@ -764,8 +788,8 @@ DirectoryEntry *DirectoryEntry::getSubDirectory( } } -DirectoryEntry *DirectoryEntry::getSubDirectoryRecursive( - const std::wstring &path, bool create, int originID) +DirectoryEntry* DirectoryEntry::getSubDirectoryRecursive( + const std::wstring& path, bool create, DirectoryStats& stats, int originID) { if (path.length() == 0) { // path ended with a backslash? @@ -773,19 +797,18 @@ DirectoryEntry *DirectoryEntry::getSubDirectoryRecursive( } const size_t pos = path.find_first_of(L"\\/"); - DirectoryStats dummy; if (pos == std::wstring::npos) { - return getSubDirectory(path, create, dummy); + return getSubDirectory(path, create, stats); } else { - DirectoryEntry *nextChild = getSubDirectory( - path.substr(0, pos), create, dummy, originID); + DirectoryEntry* nextChild = getSubDirectory( + path.substr(0, pos), create, stats, originID); if (nextChild == nullptr) { return nullptr; } else { return nextChild->getSubDirectoryRecursive( - path.substr(pos + 1), create, originID); + path.substr(pos + 1), create, stats, originID); } } } @@ -798,7 +821,7 @@ void DirectoryEntry::removeDirRecursive() m_FilesLookup.clear(); - for (DirectoryEntry *entry : m_SubDirectories) { + for (DirectoryEntry* entry : m_SubDirectories) { entry->removeDirRecursive(); delete entry; } diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 5ca7389d..a28ceeae 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -50,10 +50,10 @@ class DirectoryEntry { public: DirectoryEntry( - std::wstring name, DirectoryEntry *parent, OriginID originID); + std::wstring name, DirectoryEntry* parent, OriginID originID); DirectoryEntry( - std::wstring name, DirectoryEntry *parent, OriginID originID, + std::wstring name, DirectoryEntry* parent, OriginID originID, boost::shared_ptr fileRegister, boost::shared_ptr originConnection); @@ -85,7 +85,7 @@ public: return !m_Files.empty(); } - const DirectoryEntry *getParent() const + const DirectoryEntry* getParent() const { return m_Parent; } @@ -93,24 +93,32 @@ public: // add files to this directory (and subdirectories) from the specified origin. // That origin may exist or not void addFromOrigin( - const std::wstring &originName, - const std::wstring &directory, int priority, DirectoryStats& stats); + const std::wstring& originName, + const std::wstring& directory, int priority, DirectoryStats& stats); void addFromOrigin( - env::DirectoryWalker& walker, const std::wstring &originName, - const std::wstring &directory, int priority, DirectoryStats& stats); + env::DirectoryWalker& walker, const std::wstring& originName, + const std::wstring& directory, int priority, DirectoryStats& stats); + + void addFromAllBSAs( + const std::wstring& originName, const std::wstring& directory, + int priority, const std::vector& archives, + const std::set& enabledArchives, + const std::vector& loadOrder, + DirectoryStats& stats); void addFromBSA( - const std::wstring &originName, std::wstring &directory, - const std::wstring &fileName, int priority, int order); + const std::wstring& originName, const std::wstring& directory, + const std::wstring& archivePath, int priority, int order, + DirectoryStats& stats); void addFromList( - const std::wstring &originName, const std::wstring &directory, + const std::wstring& originName, const std::wstring& directory, env::Directory& root, int priority, DirectoryStats& stats); void propagateOrigin(OriginID origin); - const std::wstring &getName() const + const std::wstring& getName() const { return m_Name; } @@ -120,9 +128,9 @@ public: return m_FileRegister; } - bool originExists(const std::wstring &name) const; - FilesOrigin &getOriginByID(OriginID ID) const; - FilesOrigin &getOriginByName(const std::wstring &name) const; + bool originExists(const std::wstring& name) const; + FilesOrigin& getOriginByID(OriginID ID) const; + FilesOrigin& getOriginByName(const std::wstring& name) const; const FilesOrigin* findOriginByID(OriginID ID) const; OriginID anyOrigin() const; @@ -130,8 +138,8 @@ public: std::vector getFiles() const; void getSubDirectories( - std::vector::const_iterator &begin, - std::vector::const_iterator &end) const + std::vector::const_iterator& begin, + std::vector::const_iterator& end) const { begin = m_SubDirectories.begin(); end = m_SubDirectories.end(); @@ -179,16 +187,16 @@ public: return m_FileRegister->getFile(index); } - DirectoryEntry *findSubDirectory( - const std::wstring &name, bool alreadyLowerCase=false) const; + DirectoryEntry* findSubDirectory( + const std::wstring& name, bool alreadyLowerCase=false) const; - DirectoryEntry *findSubDirectoryRecursive(const std::wstring &path); + DirectoryEntry* findSubDirectoryRecursive(const std::wstring& path); /** retrieve a file in this directory by name. * @param name name of the file * @return fileentry object for the file or nullptr if no file matches */ - const FileEntryPtr findFile(const std::wstring &name, bool alreadyLowerCase=false) const; + const FileEntryPtr findFile(const std::wstring& name, bool alreadyLowerCase=false) const; const FileEntryPtr findFile(const DirectoryEntryFileKey& key) const; bool hasFile(const std::wstring& name) const; @@ -201,29 +209,29 @@ public: // path containing the file // const FileEntryPtr searchFile( - const std::wstring &path, const DirectoryEntry **directory=nullptr) const; + const std::wstring& path, const DirectoryEntry** directory=nullptr) const; void removeFile(FileIndex index); // remove the specified file from the tree. This can be a path leading to a // file in a subdirectory - bool removeFile(const std::wstring &filePath, OriginID *origin = nullptr); + bool removeFile(const std::wstring& filePath, OriginID* origin = nullptr); /** * @brief remove the specified directory * @param path directory to remove */ - void removeDir(const std::wstring &path); + void removeDir(const std::wstring& path); - bool remove(const std::wstring &fileName, OriginID *origin); + bool remove(const std::wstring& fileName, OriginID* origin); bool hasContentsFromOrigin(OriginID originID) const; - FilesOrigin &createOrigin( - const std::wstring &originName, - const std::wstring &directory, int priority, DirectoryStats& stats); + FilesOrigin& createOrigin( + const std::wstring& originName, + const std::wstring& directory, int priority, DirectoryStats& stats); - void removeFiles(const std::set &indices); + void removeFiles(const std::set& indices); void dump(const std::wstring& file) const; @@ -242,7 +250,7 @@ private: SubDirectories m_SubDirectories; SubDirectoriesLookup m_SubDirectoriesLookup; - DirectoryEntry *m_Parent; + DirectoryEntry* m_Parent; std::set m_Origins; bool m_Populated; bool m_TopLevel; @@ -252,20 +260,20 @@ private: FileEntryPtr insert( - std::wstring_view fileName, FilesOrigin &origin, FILETIME fileTime, + std::wstring_view fileName, FilesOrigin& origin, FILETIME fileTime, std::wstring_view archive, int order, DirectoryStats& stats); FileEntryPtr insert( - env::File& file, FilesOrigin &origin, + env::File& file, FilesOrigin& origin, std::wstring_view archive, int order, DirectoryStats& stats); void addFiles( - env::DirectoryWalker& walker, FilesOrigin &origin, + env::DirectoryWalker& walker, FilesOrigin& origin, const std::wstring& path, DirectoryStats& stats); void addFiles( - FilesOrigin &origin, BSA::Folder::Ptr archiveFolder, FILETIME &fileTime, - const std::wstring &archiveName, int order); + FilesOrigin& origin, BSA::Folder::Ptr archiveFolder, FILETIME fileTime, + const std::wstring& archiveName, int order, DirectoryStats& stats); void addDir(FilesOrigin& origin, env::Directory& d, DirectoryStats& stats); @@ -278,7 +286,8 @@ private: OriginID originID = InvalidOriginID); DirectoryEntry* getSubDirectoryRecursive( - const std::wstring &path, bool create, OriginID originID = InvalidOriginID); + const std::wstring& path, bool create, DirectoryStats& stats, + OriginID originID = InvalidOriginID); void removeDirRecursive(); diff --git a/src/shared/util.h b/src/shared/util.h index dc6e72ad..1d3cce82 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see . #define UTIL_H #include +#include #include class Executable; @@ -51,6 +52,15 @@ QString getUsvfsVersionString(); void SetThisThreadName(const QString& s); void checkDuplicateShortcuts(const QMenu& m); +inline FILETIME ToFILETIME(std::filesystem::file_time_type t) +{ + FILETIME ft; + static_assert(sizeof(t) == sizeof(ft)); + + std::memcpy(&ft, &t, sizeof(FILETIME)); + return ft; +} + } // namespace MOShared -- cgit v1.3.1 From d3fe9ff1faed52da8f647d9294e9ce371b0361e4 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 16 Feb 2020 18:57:38 -0500 Subject: moved TimeThis to uibase fixed progress bar --- src/directoryrefresher.cpp | 34 +++++++++++++++----- src/directoryrefresher.h | 74 ++++++++++++++++++++++++++++++++++++++++---- src/mainwindow.cpp | 16 +++++++--- src/mainwindow.h | 4 ++- src/shared/fileregisterfwd.h | 2 ++ src/shared/util.cpp | 20 ------------ src/shared/util.h | 15 +-------- 7 files changed, 113 insertions(+), 52 deletions(-) (limited to 'src/shared/util.h') diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 5e1c05a8..599dd815 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -326,8 +326,10 @@ void DirectoryRefresher::addModToStructure(DirectoryEntry *directoryStructure } } + struct ModThread { + DirectoryRefreshProgress* progress = nullptr; DirectoryEntry* ds = nullptr; std::wstring modName; std::wstring path; @@ -375,6 +377,11 @@ struct ModThread modName, path, prio, archives, enabledArchives, lo, *stats); } + if (progress) { + progress->addDone(); + } + + SetThisThreadName(QString::fromStdWString(L"idle refresher")); ready = false; } }; @@ -382,13 +389,22 @@ struct ModThread env::ThreadPool g_threads; +void DirectoryRefresher::updateProgress(const DirectoryRefreshProgress* p) +{ + // careful: called from multiple threads + emit progress(p); +} void DirectoryRefresher::addMultipleModsFilesToStructure( MOShared::DirectoryEntry *directoryStructure, - const std::vector& entries, bool emitProgress) + const std::vector& entries, DirectoryRefreshProgress* progress) { std::vector stats(entries.size()); + if (progress) { + progress->start(entries.size()); + } + log::debug("refresher: using {} threads", m_threadCount); g_threads.setMax(m_threadCount); @@ -405,9 +421,14 @@ void DirectoryRefresher::addMultipleModsFilesToStructure( if (e.stealFiles.length() > 0) { stealModFilesIntoStructure( directoryStructure, e.modName, prio, e.absolutePath, e.stealFiles); + + if (progress) { + progress->addDone(); + } } else { auto& mt = g_threads.request(); + mt.progress = progress; mt.ds = directoryStructure; mt.modName = e.modName.toStdWString(); mt.path = QDir::toNativeSeparators(e.absolutePath).toStdWString(); @@ -430,10 +451,6 @@ void DirectoryRefresher::addMultipleModsFilesToStructure( } catch (const std::exception& ex) { emit error(tr("failed to read mod (%1): %2").arg(e.modName, ex.what())); } - - if (emitProgress) { - emit progress((static_cast(i) * 100) / static_cast(entries.size()) + 1); - } } g_threads.waitForAll(); @@ -447,6 +464,7 @@ void DirectoryRefresher::refresh() { SetThisThreadName("DirectoryRefresher"); TimeThis tt("refresh"); + auto* p = new DirectoryRefreshProgress(this); { QMutexLocker locker(&m_RefreshLock); @@ -468,7 +486,7 @@ void DirectoryRefresher::refresh() return lhs.priority < rhs.priority; }); - addMultipleModsFilesToStructure(m_Root.get(), m_Mods, true); + addMultipleModsFilesToStructure(m_Root.get(), m_Mods, p); m_Root->getFileRegister()->sortOrigins(); @@ -478,6 +496,8 @@ void DirectoryRefresher::refresh() log::debug("refresher saw {} files", m_lastFileCount); } - emit progress(100); + p->finish(); + + emit progress(p); emit refreshed(); } diff --git a/src/directoryrefresher.h b/src/directoryrefresher.h index e81b55dd..bd08dad6 100644 --- a/src/directoryrefresher.h +++ b/src/directoryrefresher.h @@ -20,14 +20,14 @@ along with Mod Organizer. If not, see . #ifndef DIRECTORYREFRESHER_H #define DIRECTORYREFRESHER_H +#include "fileregisterfwd.h" +#include "profile.h" #include #include #include #include #include #include -#include "profile.h" - /** * @brief used to asynchronously generate the virtual view of the combined data directory @@ -38,11 +38,15 @@ class DirectoryRefresher : public QObject Q_OBJECT public: - struct EntryInfo { + struct EntryInfo + { EntryInfo(const QString &modName, const QString &absolutePath, const QStringList &stealFiles, const QStringList &archives, int priority) : modName(modName), absolutePath(absolutePath), stealFiles(stealFiles) - , archives(archives), priority(priority) {} + , archives(archives), priority(priority) + { + } + QString modName; QString absolutePath; QStringList stealFiles; @@ -121,7 +125,10 @@ public: void addMultipleModsFilesToStructure( MOShared::DirectoryEntry *directoryStructure, - const std::vector& entries, bool emitProgress=false); + const std::vector& entries, + DirectoryRefreshProgress* progress=nullptr); + + void updateProgress(const DirectoryRefreshProgress* p); public slots: @@ -132,7 +139,7 @@ public slots: signals: - void progress(int progress); + void progress(const DirectoryRefreshProgress* p); void error(const QString &error); void refreshed(); @@ -149,4 +156,59 @@ private: int priority, const QString &directory, const QStringList &stealFiles); }; + +class DirectoryRefreshProgress : QObject +{ + Q_OBJECT; + +public: + DirectoryRefreshProgress(DirectoryRefresher* r) : + QObject(r), m_refresher(r), m_modCount(0), m_modDone(0), m_finished(false) + { + } + + void start(std::size_t modCount) + { + m_modCount = modCount; + m_modDone = 0; + m_finished = false; + } + + + bool finished() const + { + return m_finished; + } + + int percentDone() const + { + int percent = 100; + + if (m_modCount > 0) { + const double d = static_cast(m_modDone) / m_modCount; + percent = static_cast(d * 100); + } + + return percent; + } + + + void finish() + { + m_finished = true; + } + + void addDone() + { + ++m_modDone; + m_refresher->updateProgress(this); + } + +private: + DirectoryRefresher* m_refresher; + std::size_t m_modCount; + std::atomic m_modDone; + bool m_finished; +}; + #endif // DIRECTORYREFRESHER_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f5749392..21a6fa41 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -367,7 +367,10 @@ MainWindow::MainWindow(Settings &settings connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(QString))); connect(m_OrganizerCore.directoryRefresher(), SIGNAL(refreshed()), this, SLOT(directory_refreshed())); - connect(m_OrganizerCore.directoryRefresher(), SIGNAL(progress(int)), this, SLOT(refresher_progress(int))); + connect( + m_OrganizerCore.directoryRefresher(), + &DirectoryRefresher::progress, + this, &MainWindow::refresherProgress); connect(m_OrganizerCore.directoryRefresher(), SIGNAL(error(QString)), this, SLOT(showError(QString))); connect(&m_SavesWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(refreshSavesIfOpen())); @@ -2382,10 +2385,15 @@ void MainWindow::setESPListSorting(int index) } } -void MainWindow::refresher_progress(int percent) +void MainWindow::refresherProgress(const DirectoryRefreshProgress* p) { - setEnabled(percent == 100); - ui->statusBar->setProgress(percent); + if (p->finished()) { + setEnabled(true); + ui->statusBar->setProgress(100); + } else { + setEnabled(false); + ui->statusBar->setProgress(p->percentDone()); + } } void MainWindow::directory_refreshed() diff --git a/src/mainwindow.h b/src/mainwindow.h index 6530d8ad..b839e85e 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see . #include "tutorialcontrol.h" #include "plugincontainer.h" //class PluginContainer; #include "iplugingame.h" //namespace MOBase { class IPluginGame; } +#include "shared/fileregisterfwd.h" #include class Executable; @@ -155,7 +156,8 @@ public: public slots: void modorder_changed(); void esplist_changed(); - void refresher_progress(int percent); + void refresherProgress(const DirectoryRefreshProgress* p); + void directory_refreshed(); void toolPluginInvoke(); diff --git a/src/shared/fileregisterfwd.h b/src/shared/fileregisterfwd.h index 6348fee1..720e6e30 100644 --- a/src/shared/fileregisterfwd.h +++ b/src/shared/fileregisterfwd.h @@ -1,6 +1,8 @@ #ifndef MO_REGISTER_FILEREGISTERFWD_INCLUDED #define MO_REGISTER_FILEREGISTERFWD_INCLUDED +class DirectoryRefreshProgress; + namespace MOShared { diff --git a/src/shared/util.cpp b/src/shared/util.cpp index 74e386a3..483b36a9 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -382,26 +382,6 @@ void checkDuplicateShortcuts(const QMenu& m) } // namespace MOShared -TimeThis::TimeThis(QString what) - : m_what(std::move(what)), m_start(Clock::now()) -{ -} - -TimeThis::~TimeThis() -{ - using namespace std::chrono; - - const auto end = Clock::now(); - const auto d = duration_cast(end - m_start).count(); - - if (m_what.isEmpty()) { - log::debug("{} ms", d); - } else { - log::debug("{} {} ms", m_what, d); - } -} - - static bool g_exiting = false; static bool g_canClose = false; diff --git a/src/shared/util.h b/src/shared/util.h index 1d3cce82..2761b64f 100644 --- a/src/shared/util.h +++ b/src/shared/util.h @@ -20,6 +20,7 @@ along with Mod Organizer. If not, see . #ifndef UTIL_H #define UTIL_H +#include #include #include #include @@ -64,20 +65,6 @@ inline FILETIME ToFILETIME(std::filesystem::file_time_type t) } // namespace MOShared -class TimeThis -{ -public: - TimeThis(QString what={}); - ~TimeThis(); - -private: - using Clock = std::chrono::high_resolution_clock; - - QString m_what; - Clock::time_point m_start; -}; - - enum class Exit { None = 0x00, -- cgit v1.3.1