diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2020-02-01 05:21:34 -0500 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2020-02-04 03:33:22 -0500 |
| commit | 34bc2191e6ebb1458438180bd75a5cd2cd7e4f7b (patch) | |
| tree | 2321ec91c241dcfea50c9debb78e8c7cca35a666 /src | |
| parent | 85a9f810a0ecbf10facc8b8b070eda6f13a65d6b (diff) | |
don't get meta for fields that are not used
show compressed file size if available
remember file sizes for files in archives
Diffstat (limited to 'src')
| -rw-r--r-- | src/datatab.cpp | 73 | ||||
| -rw-r--r-- | src/datatab.h | 3 | ||||
| -rw-r--r-- | src/filetreeitem.cpp | 134 | ||||
| -rw-r--r-- | src/filetreeitem.h | 59 | ||||
| -rw-r--r-- | src/filetreemodel.cpp | 35 | ||||
| -rw-r--r-- | src/filetreemodel.h | 1 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 2 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 21 | ||||
| -rw-r--r-- | src/shared/directoryentry.h | 22 |
9 files changed, 234 insertions, 116 deletions
diff --git a/src/datatab.cpp b/src/datatab.cpp index af457b33..6b403f66 100644 --- a/src/datatab.cpp +++ b/src/datatab.cpp @@ -59,7 +59,7 @@ void DataTab::saveState(Settings& s) const void DataTab::restoreState(const Settings& s) { s.geometry().restoreState(ui.tree->header()); - + // prior to 2.3, the list was not sortable, and this remembered in the // widget state, for whatever reason ui.tree->setSortingEnabled(true); @@ -67,7 +67,7 @@ void DataTab::restoreState(const Settings& s) void DataTab::activated() { - //refreshDataTreeKeepExpandedNodes(); + updateTree(); } void DataTab::onRefresh() @@ -79,76 +79,11 @@ void DataTab::onRefresh() m_core.refreshDirectoryStructure(); } -void DataTab::refreshDataTree() +void DataTab::updateTree() { m_filetree->refresh(); } -void DataTab::refreshDataTreeKeepExpandedNodes() -{ - //m_model->refreshKeepExpandedNodes(); - m_filetree->refresh(); // temp - - /*QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder); - QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File); - QStringList expandedNodes; - QTreeWidgetItemIterator it1(ui.tree, QTreeWidgetItemIterator::NotHidden | QTreeWidgetItemIterator::HasChildren); - while (*it1) { - QTreeWidgetItem *current = (*it1); - if (current->isExpanded() && !(current->text(0)=="data")) { - expandedNodes.append(current->text(0)+"/"+current->parent()->text(0)); - } - ++it1; - } - - ui.tree->clear(); - QStringList columns("data"); - columns.append(""); - QTreeWidgetItem *subTree = new QTreeWidgetItem(columns); - subTree->setData(0, Qt::DecorationRole, (new QFileIconProvider())->icon(QFileIconProvider::Folder)); - updateTo(subTree, L"", *m_core.directoryStructure(), ui.conflicts->isChecked(), &fileIcon, &folderIcon); - ui.tree->insertTopLevelItem(0, subTree); - subTree->setExpanded(true); - QTreeWidgetItemIterator it2(ui.tree, QTreeWidgetItemIterator::HasChildren); - while (*it2) { - QTreeWidgetItem *current = (*it2); - if (!(current->text(0)=="data") && expandedNodes.contains(current->text(0)+"/"+current->parent()->text(0))) { - current->setExpanded(true); - } - ++it2; - }*/ -} - -void DataTab::onItemExpanded(QTreeWidgetItem* item) -{ - /*if ((item->childCount() == 1) && (item->child(0)->data(0, Qt::UserRole).toString() == "__loaded_on_demand__")) { - // read the data we need from the sub-item, then dispose of it - QTreeWidgetItem *onDemandDataItem = item->child(0); - const QString path = onDemandDataItem->data(0, Qt::UserRole + 1).toString(); - std::wstring wspath = path.toStdWString(); - bool conflictsOnly = onDemandDataItem->data(0, Qt::UserRole + 2).toBool(); - - std::wstring virtualPath = (wspath + L"\\").substr(6) + item->text(0).toStdWString(); - DirectoryEntry *dir = m_core.directoryStructure()->findSubDirectoryRecursive(virtualPath); - if (dir != nullptr) { - QIcon folderIcon = (new QFileIconProvider())->icon(QFileIconProvider::Folder); - QIcon fileIcon = (new QFileIconProvider())->icon(QFileIconProvider::File); - updateTo(item, wspath, *dir, conflictsOnly, &fileIcon, &folderIcon); - } else { - log::warn("failed to update view of {}", path); - } - - m_removeLater.push_back(item); - - QTimer::singleShot(5, [this]{ - for (QTreeWidgetItem *item : m_removeLater) { - item->removeChild(item->child(0)); - } - m_removeLater.clear(); - }); - }*/ -} - void DataTab::onConflicts() { updateOptions(); @@ -172,5 +107,5 @@ void DataTab::updateOptions() } m_filetree->model()->setFlags(flags); - refreshDataTree(); + updateTree(); } diff --git a/src/datatab.h b/src/datatab.h index fd93514c..4545dc5a 100644 --- a/src/datatab.h +++ b/src/datatab.h @@ -25,8 +25,7 @@ public: void restoreState(const Settings& s); void activated(); - void refreshDataTreeKeepExpandedNodes(); - void refreshDataTree(); + void updateTree(); signals: void executablesChanged(); diff --git a/src/filetreeitem.cpp b/src/filetreeitem.cpp index a506f0f0..6d42f2dc 100644 --- a/src/filetreeitem.cpp +++ b/src/filetreeitem.cpp @@ -4,9 +4,38 @@ #include "util.h" #include "modinfodialogfwd.h" #include <log.h> +#include <utility.h> using namespace MOBase; using namespace MOShared; +namespace fs = std::filesystem; + +const QString& directoryFileType() +{ + static QString name; + + if (name.isEmpty()) { + const DWORD flags = SHGFI_TYPENAME; + SHFILEINFOW sfi = {}; + + // "." for the current directory, which should always exist + const auto r = SHGetFileInfoW(L".", 0, &sfi, sizeof(sfi), flags); + + if (!r) { + const auto e = GetLastError(); + + log::error( + "SHGetFileInfoW failed for folder file type, {}", + formatSystemMessage(e)); + + name = "File folder"; + } else { + name = QString::fromWCharArray(sfi.szTypeName); + } + } + + return name; +} FileTreeItem::FileTreeItem( @@ -16,6 +45,7 @@ FileTreeItem::FileTreeItem( m_parent(parent), m_indexGuess(NoIndexGuess), m_originID(originID), m_virtualParentPath(QString::fromStdWString(dataRelativeParentPath)), + m_wsRealPath(realPath), m_realPath(QString::fromStdWString(realPath)), m_flags(flags), m_wsFile(file), @@ -94,13 +124,19 @@ public: return naturalCompare(a->m_mod, b->m_mod); case FileTreeModel::FileType: - return naturalCompare(a->meta().type, b->meta().type); + return naturalCompare( + a->fileType().value_or(QString()), + b->fileType().value_or(QString())); case FileTreeModel::FileSize: - return threeWayCompare(a->meta().size, b->meta().size); + return threeWayCompare( + a->fileSize().value_or(0), + b->fileSize().value_or(0)); case FileTreeModel::LastModified: - return threeWayCompare(a->meta().lastModified, b->meta().lastModified); + return threeWayCompare( + a->lastModified().value_or(QDateTime()), + b->lastModified().value_or(QDateTime())); default: return 0; @@ -166,34 +202,88 @@ QFont FileTreeItem::font() const return f; } -const FileTreeItem::Meta& FileTreeItem::meta() const +std::optional<uint64_t> FileTreeItem::fileSize() const { - if (!m_meta) { - QFileInfo fi(m_realPath); + if (m_fileSize.empty()) { + std::error_code ec; + const auto size = fs::file_size(fs::path(m_wsRealPath), ec); - SHFILEINFOW sfi = {}; - const auto r = SHGetFileInfoW( - m_realPath.toStdWString().c_str(), 0, &sfi, sizeof(sfi), - SHGFI_TYPENAME); + if (ec) { + log::error("can't get file size for '{}', {}", m_realPath, ec.message()); + m_fileSize.fail(); + } else { + m_fileSize.set(size); + } + } - if (!r) { - const auto e = GetLastError(); + return m_fileSize.value; +} - log::error( - "SHGetFileInfoW failed for '{}', {}", - m_realPath, e); +std::optional<QDateTime> FileTreeItem::lastModified() const +{ + if (m_lastModified.empty()) { + if (m_realPath.isEmpty()) { + // this is a virtual directory + m_lastModified.set({}); + } else if (isFromArchive()) { + // can't get last modified date for files in archives + m_lastModified.set({}); + } else { + // looks like a regular file on the filesystem + const QFileInfo fi(m_realPath); + const auto d = fi.lastModified(); - sfi = {}; + if (!d.isValid()) { + log::error("can't get last modified date for '{}'", m_realPath); + m_lastModified.fail(); + } else { + m_lastModified.set(d); + } } + } + + return m_lastModified.value; +} - m_meta = { - static_cast<uint64_t>(fi.size()), - fi.lastModified(), - QString::fromWCharArray(sfi.szTypeName) - }; +std::optional<QString> FileTreeItem::fileType() const +{ + if (m_fileType.empty()) { + getFileType(); } - return *m_meta; + return m_fileType.value; +} + +void FileTreeItem::getFileType() const +{ + if (isDirectory()) { + m_fileType.set(directoryFileType()); + return; + } + + DWORD flags = SHGFI_TYPENAME; + + if (isFromArchive()) { + // files from archives are not on the filesystem; this flag forces + // SHGetFileInfoW() to only work with the filename + flags |= SHGFI_USEFILEATTRIBUTES; + } + + SHFILEINFOW sfi = {}; + const auto r = SHGetFileInfoW( + m_wsRealPath.c_str(), 0, &sfi, sizeof(sfi), flags); + + if (!r) { + const auto e = GetLastError(); + + log::error( + "SHGetFileInfoW failed for '{}', {}", + m_realPath, formatSystemMessage(e)); + + m_fileType.fail(); + } else { + m_fileType.set(QString::fromWCharArray(sfi.szTypeName)); + } } QFileIconProvider::IconType FileTreeItem::icon() const diff --git a/src/filetreeitem.h b/src/filetreeitem.h index fc27b0c0..c5418d43 100644 --- a/src/filetreeitem.h +++ b/src/filetreeitem.h @@ -19,13 +19,6 @@ public: Conflicted = 0x04 }; - struct Meta - { - uint64_t size; - QDateTime lastModified; - QString type; - }; - Q_DECLARE_FLAGS(Flags, Flag); @@ -136,7 +129,24 @@ public: QFont font() const; - const Meta& meta() const; + std::optional<uint64_t> fileSize() const; + std::optional<QDateTime> lastModified() const; + std::optional<QString> fileType() const; + + std::optional<uint64_t> compressedFileSize() const + { + return m_compressedFileSize; + } + + void setFileSize(uint64_t size) + { + m_fileSize.set(size); + } + + void setCompressedFileSize(uint64_t compressedSize) + { + m_compressedFileSize = compressedSize; + } const QString& realPath() const { @@ -210,6 +220,30 @@ public: QString debugName() const; private: + template <class T> + struct Cached + { + std::optional<T> value; + bool failed = false; + + bool empty() const + { + return !failed && !value; + } + + void set(T t) + { + value = std::move(t); + failed = false; + } + + void fail() + { + value = {}; + failed = true; + } + }; + static constexpr std::size_t NoIndexGuess = std::numeric_limits<std::size_t>::max(); @@ -218,17 +252,24 @@ private: const int m_originID; const QString m_virtualParentPath; + const std::wstring m_wsRealPath; const QString m_realPath; const Flags m_flags; const std::wstring m_wsFile, m_wsLcFile; const MOShared::DirectoryEntry::FileKey m_key; const QString m_file; const QString m_mod; - mutable std::optional<Meta> m_meta; + + mutable Cached<uint64_t> m_fileSize; + mutable Cached<QDateTime> m_lastModified; + mutable Cached<QString> m_fileType; + mutable std::optional<uint64_t> m_compressedFileSize; bool m_loaded; bool m_expanded; Children m_children; + + void getFileType() const; }; #endif // MODORGANIZER_FILETREEITEM_INCLUDED diff --git a/src/filetreemodel.cpp b/src/filetreemodel.cpp index aa053eeb..cb7e94fa 100644 --- a/src/filetreemodel.cpp +++ b/src/filetreemodel.cpp @@ -127,7 +127,7 @@ private: FileTreeModel::FileTreeModel(OrganizerCore& core, QObject* parent) : QAbstractItemModel(parent), m_core(core), m_root(nullptr, 0, L"", L"", FileTreeItem::Directory, L"", L"<root>"), - m_flags(NoFlags), m_isRefreshing(false) + m_flags(NoFlags) { m_root.setExpanded(true); @@ -136,9 +136,6 @@ FileTreeModel::FileTreeModel(OrganizerCore& core, QObject* parent) : void FileTreeModel::refresh() { - m_isRefreshing = true; - Guard g([&]{ m_isRefreshing = false; }); - TimeThis tt("FileTreeModel::refresh()"); update(m_root, *m_core.directoryStructure(), L""); } @@ -695,6 +692,14 @@ std::unique_ptr<FileTreeItem> FileTreeModel::createFileItem( &parentItem, originID, parentPath, file.getFullPath(), flags, file.getName(), makeModName(file, originID)); + if (file.getFileSize() != FileEntry::NoFileSize) { + item->setFileSize(file.getFileSize()); + } + + if (file.getCompressedFileSize() != FileEntry::NoFileSize) { + item->setCompressedFileSize(file.getCompressedFileSize()); + } + item->setLoaded(true); return item; @@ -716,7 +721,7 @@ QVariant FileTreeModel::displayData(const FileTreeItem* item, int column) const case FileType: { - return item->meta().type; + return item->fileType().value_or(QString()); } case FileSize: @@ -724,13 +729,29 @@ QVariant FileTreeModel::displayData(const FileTreeItem* item, int column) const if (item->isDirectory()) { return {}; } else { - return localizedByteSize(item->meta().size); + QString fs; + + if (auto n=item->fileSize()) { + fs = localizedByteSize(*n); + } + + if (auto n=item->compressedFileSize()) { + return QString("%1 (%2)").arg(fs).arg(localizedByteSize(*n)); + } else { + return fs; + } } } case LastModified: { - return item->meta().lastModified.toString(Qt::SystemLocaleDate); + if (auto d=item->lastModified()) { + if (d->isValid()) { + return d->toString(Qt::SystemLocaleDate); + } + } + + return {}; } default: diff --git a/src/filetreemodel.h b/src/filetreemodel.h index 38f611f9..0fbcf521 100644 --- a/src/filetreemodel.h +++ b/src/filetreemodel.h @@ -81,7 +81,6 @@ private: mutable IconFetcher m_iconFetcher; mutable std::vector<QModelIndex> m_iconPending; mutable QTimer m_iconPendingTimer; - bool m_isRefreshing; Sort m_sort; bool showConflicts() const diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c71a877d..bf0dc61f 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2364,7 +2364,7 @@ void MainWindow::directory_refreshed() //Some better check for the current tab is needed. if (ui->tabWidget->currentIndex() == 2) { - m_DataTab->refreshDataTreeKeepExpandedNodes(); + m_DataTab->updateTree(); } } diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 4181098c..92b6c2bf 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -167,13 +167,15 @@ private: FileEntry::FileEntry() :
m_Index(UINT_MAX), m_Name(), m_Origin(-1), m_Parent(nullptr),
+ m_FileSize(NoFileSize), m_CompressedFileSize(NoFileSize),
m_LastAccessed(time(nullptr))
{
}
FileEntry::FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent) :
- m_Index(index), m_Name(name), m_Origin(-1), m_Archive(L"", -1),
- m_Parent(parent), m_LastAccessed(time(nullptr))
+ m_Index(index), m_Name(name), m_Origin(-1), m_Archive(L"", -1), m_Parent(parent),
+ m_FileSize(NoFileSize), m_CompressedFileSize(NoFileSize),
+ m_LastAccessed(time(nullptr))
{
}
@@ -1020,7 +1022,7 @@ void DirectoryEntry::removeFiles(const std::set<FileEntry::Index> &indices) removeFilesFromList(indices);
}
-void DirectoryEntry::insert(
+FileEntry::Ptr DirectoryEntry::insert(
const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime,
const std::wstring &archive, int order)
{
@@ -1036,6 +1038,8 @@ void DirectoryEntry::insert( file->addOrigin(origin.getID(), fileTime, archive, order);
origin.addFile(file->getIndex());
+
+ return file;
}
void DirectoryEntry::addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOffset)
@@ -1085,7 +1089,16 @@ void DirectoryEntry::addFiles( // add files
for (unsigned int fileIdx = 0; fileIdx < archiveFolder->getNumFiles(); ++fileIdx) {
BSA::File::Ptr file = archiveFolder->getFile(fileIdx);
- insert(ToWString(file->getName(), true), origin, fileTime, archiveName, order);
+
+ auto f = insert(ToWString(file->getName(), true), origin, fileTime, archiveName, order);
+
+ if (f) {
+ if (file->getUncompressedFileSize() > 0) {
+ f->setFileSize(file->getFileSize(), file->getUncompressedFileSize());
+ } else {
+ f->setFileSize(file->getFileSize(), FileEntry::NoFileSize);
+ }
+ }
}
// recurse into subdirectories
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 6102c88f..7e45493d 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -61,6 +61,9 @@ class FileRegister; class FileEntry
{
public:
+ static constexpr uint64_t NoFileSize =
+ std::numeric_limits<uint64_t>::max();
+
typedef unsigned int Index;
typedef boost::shared_ptr<FileEntry> Ptr;
@@ -150,6 +153,22 @@ public: return m_FileTime;
}
+ void setFileSize(uint64_t size, uint64_t compressedSize)
+ {
+ m_FileSize = size;
+ m_CompressedFileSize = compressedSize;
+ }
+
+ uint64_t getFileSize() const
+ {
+ return m_FileSize;
+ }
+
+ uint64_t getCompressedFileSize() const
+ {
+ return m_CompressedFileSize;
+ }
+
private:
Index m_Index;
std::wstring m_Name;
@@ -158,6 +177,7 @@ private: AlternativesVector m_Alternatives;
DirectoryEntry *m_Parent;
mutable FILETIME m_FileTime;
+ uint64_t m_FileSize, m_CompressedFileSize;
time_t m_LastAccessed;
@@ -480,7 +500,7 @@ private: DirectoryEntry(const DirectoryEntry &reference);
- void insert(
+ FileEntry::Ptr insert(
const std::wstring &fileName, FilesOrigin &origin, FILETIME fileTime,
const std::wstring &archive, int order);
|
