GUI: Refactored RemoteDirModel to rely on unified engine statistics

This commit is contained in:
jolavillette 2026-05-16 16:02:09 +02:00
parent bfd7b3e427
commit 1ef920e456
3 changed files with 31 additions and 234 deletions

View File

@ -148,7 +148,8 @@ protected:
return false;
}
if (!m_dirModel->hasUploads(ref)) {
DirDetails details;
if (!m_dirModel->requestDirDetails(ref, m_dirModel->isRemote(), details) || details.uploads == 0) {
return false;
}
}

View File

@ -39,6 +39,8 @@
#include <QTimer>
#include <QUrl>
#include "util/rsdebug.h"
#include <algorithm>
#include <set>
#include <time.h>
@ -149,104 +151,10 @@ void RetroshareDirModel::treeStyle()
peerIcon = FilesDefs::getIconFromQtResourcePath(":/icons/folder-account.svg");
}
void TreeStyle_RDM::recalculateDirectoryTotals()
{
m_folderTotals.clear();
// Stats are primarily calculated for local files.
// For remote files, branch stats are limited by what the core provides.
if(RemoteMode)
return;
// Start recursion from Root (NULL)
collectStatsRecursive(NULL);
}
TreeStyle_RDM::FolderStats TreeStyle_RDM::collectStatsRecursive(void* ref)
{
FolderStats stats;
// CRITICAL FIX: Safety check for NULL pointers (except for Root which can be NULL start)
// Actually requestDirDetails handles NULL ref for Root correctly.
DirDetails details;
if(!requestDirDetails(ref, RemoteMode, details))
{
return stats;
}
// If it's a file, we return its stats
if(details.type == DIR_TYPE_FILE || details.type == DIR_TYPE_EXTRA_FILE)
{
stats.size = details.size;
stats.count = 1;
stats.uploads = rsFiles->getCumulativeUpload(details.hash);
// Special handling for Extra Files (virtual root)
if (details.type == DIR_TYPE_EXTRA_FILE)
{
m_folderTotals["!!RS_EXTRA_FILES_ROOT!!"] += stats;
}
return stats;
}
// If it's a directory or root node, we dive into children
if(details.type == DIR_TYPE_DIR || details.type == DIR_TYPE_ROOT || details.type == DIR_TYPE_PERSON)
{
for(const auto& child : details.children)
{
stats += collectStatsRecursive(child.ref);
}
// If this is a real directory, store the aggregated totals
if(details.type == DIR_TYPE_DIR)
{
QString path = QDir::cleanPath(QString::fromUtf8(details.path.c_str()));
m_folderTotals[path] = stats;
}
}
return stats;
}
// MODIFICATION D: Check if a specific node or any of its descendants have uploads
// hasUploads for TreeStyle - Defensive Check
bool TreeStyle_RDM::hasUploads(void *ref) const
{
// CRITICAL FIX: Safety check for NULL pointers
if (ref == NULL) {
return false;
}
DirDetails details;
if (!requestDirDetails(ref, RemoteMode, details)) return false;
if (details.type == DIR_TYPE_FILE || details.type == DIR_TYPE_EXTRA_FILE) {
return rsFiles->getCumulativeUpload(details.hash) > 0;
}
if (details.type == DIR_TYPE_PERSON && details.id != rsPeers->getOwnId()) {
auto it = m_folderTotals.find("!!RS_EXTRA_FILES_ROOT!!");
return (it != m_folderTotals.end()) ? (it->second.uploads > 0) : false;
}
if (details.type == DIR_TYPE_DIR) {
QString path = QDir::cleanPath(QString::fromUtf8(details.path.c_str()));
auto it = m_folderTotals.find(path);
return (it != m_folderTotals.end()) ? (it->second.uploads > 0) : false;
}
return true;
}
void TreeStyle_RDM::update()
{
preMods() ;
// Recalculate totals before notifying view update
recalculateDirectoryTotals();
RetroshareDirModel::update();
postMods() ;
}
void TreeStyle_RDM::updateRef(const QModelIndex& indx) const
@ -586,7 +494,7 @@ void FlatStyle_RDM::update()
// MODIFICATION: Do NOT clear cache here.
// We want hasUploads() to be fast even during the re-crawl.
// We want data access to be fast even during the re-crawl.
// updateRefs will overwrite cache entries as it finds files.
// {
// RS_STACK_MUTEX(_ref_mutex);
@ -715,32 +623,10 @@ QVariant TreeStyle_RDM::sortRole(const QModelIndex& /*index*/,const DirDetails&
case REMOTEDIRMODEL_COLUMN_NAME:
return (RemoteMode)?(QString::fromUtf8(rsPeers->getPeerName(details.id).c_str())):tr("My files");
case REMOTEDIRMODEL_COLUMN_FILENB: {
SharedDirStats stats ;
if(RemoteMode)
rsFiles->getSharedDirStatistics(details.id,stats) ;
else if(details.id == rsPeers->getOwnId())
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(),stats) ;
else
{
auto it = m_folderTotals.find("!!RS_EXTRA_FILES_ROOT!!");
return (it != m_folderTotals.end()) ? (qulonglong)it->second.count : (qulonglong)0;
}
return (qulonglong) stats.total_number_of_files;
return (qulonglong) details.count;
}
case REMOTEDIRMODEL_COLUMN_SIZE: {
SharedDirStats stats ;
if(RemoteMode)
rsFiles->getSharedDirStatistics(details.id,stats) ;
else if(details.id == rsPeers->getOwnId())
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(),stats) ;
else
{
auto it = m_folderTotals.find("!!RS_EXTRA_FILES_ROOT!!");
return (it != m_folderTotals.end()) ? (qulonglong)it->second.size : (qulonglong)0;
}
return (qulonglong) stats.total_shared_size;
return (qulonglong) details.size;
}
case REMOTEDIRMODEL_COLUMN_AGE:
return details.max_mtime;
@ -784,19 +670,11 @@ QVariant TreeStyle_RDM::sortRole(const QModelIndex& /*index*/,const DirDetails&
return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_FILENB:
{
if (RemoteMode)
return (qulonglong)details.count;
auto it = m_folderTotals.find(path);
return (it != m_folderTotals.end()) ? (qulonglong)it->second.count : (qulonglong)0;
return (qulonglong)details.count;
}
case REMOTEDIRMODEL_COLUMN_SIZE:
{
if (RemoteMode)
return (qulonglong)details.size;
auto it = m_folderTotals.find(path);
return (it != m_folderTotals.end()) ? (qulonglong)it->second.size : (qulonglong)0;
return (qulonglong)details.size;
}
case REMOTEDIRMODEL_COLUMN_AGE:
return details.max_mtime;
@ -1647,44 +1525,21 @@ QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
case REMOTEDIRMODEL_COLUMN_FILENB:
{
SharedDirStats stats;
if(RemoteMode)
rsFiles->getSharedDirStatistics(details.id, stats) ;
else if(details.id == rsPeers->getOwnId())
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(), stats) ;
else {
// Specific handling for "Temporary shared files" node (Extra files root)
auto it = m_folderTotals.find("!!RS_EXTRA_FILES_ROOT!!");
uint32_t nb = (it != m_folderTotals.end()) ? it->second.count : 0;
if(nb > 1) return QString::number(nb) + " " + tr("Files");
if(nb == 1) return QString::number(nb) + " " + tr("File");
return tr("Empty");
}
if(stats.total_number_of_files > 0)
return QString::number(stats.total_number_of_files) + " " + (stats.total_number_of_files > 1 ? tr("Files") : tr("File"));
if(details.count > 0)
return QString::number(details.count) + " " + (details.count > 1 ? tr("Files") : tr("File"));
return tr("Empty");
}
break;
break;
case REMOTEDIRMODEL_COLUMN_SIZE:
{
SharedDirStats stats ;
if(RemoteMode)
rsFiles->getSharedDirStatistics(details.id,stats) ;
else if(details.id == rsPeers->getOwnId())
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(),stats) ;
else
{
auto it = m_folderTotals.find("!!RS_EXTRA_FILES_ROOT!!");
return misc::friendlyUnit((it != m_folderTotals.end()) ? it->second.size : 0);
}
if(stats.total_shared_size > 0)
return misc::friendlyUnit(stats.total_shared_size) ;
if(details.size > 0)
return misc::friendlyUnit(details.size) ;
return QString();
}
break;
break;
case REMOTEDIRMODEL_COLUMN_AGE:
{
@ -1699,17 +1554,10 @@ QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
case REMOTEDIRMODEL_COLUMN_UPLOADED:
{
if(!RemoteMode && details.id == rsPeers->getOwnId())
{
uint64_t n = rsFiles->getCumulativeUploadNum();
if(n)
return QString(misc::friendlyUnit(rsFiles->getCumulativeUploadAll()) + QString(" - %1 files").arg(n));
else
return QString("-");
}
return QString();
return (details.uploads > 0) ? misc::friendlyUnit(details.uploads) : QString();
}
break;
break;
default: return QString();
}
@ -1735,8 +1583,7 @@ QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
}
case REMOTEDIRMODEL_COLUMN_UPLOADED:
{
uint64_t x = rsFiles->getCumulativeUpload(details.hash);
return x ? misc::friendlyUnit(x) : QString();
return (details.uploads > 0) ? misc::friendlyUnit(details.uploads) : QString();
}
break;
default: return QVariant();
@ -1745,34 +1592,25 @@ QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
else if (details.type == DIR_TYPE_DIR) /* Directory */
{
QString path = QDir::cleanPath(QString::fromUtf8(details.path.c_str()));
switch(coln)
{
case REMOTEDIRMODEL_COLUMN_NAME: return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_FILENB:
{
if (RemoteMode) {
return QString::number(details.count) + " " + (details.count > 1 ? tr("Files") : tr("File"));
}
auto it = m_folderTotals.find(path);
uint32_t totalFiles = (it != m_folderTotals.end()) ? it->second.count : 0;
return QString::number(totalFiles) + " " + (totalFiles > 1 ? tr("Files") : tr("File"));
return QString::number(details.count) + " " + (details.count > 1 ? tr("Files") : tr("File"));
}
case REMOTEDIRMODEL_COLUMN_SIZE:
{
if (RemoteMode)
return misc::friendlyUnit(details.size);
auto it = m_folderTotals.find(path);
return misc::friendlyUnit((it != m_folderTotals.end()) ? it->second.size : 0);
return misc::friendlyUnit(details.size);
}
case REMOTEDIRMODEL_COLUMN_AGE: return misc::timeRelativeToNow(details.max_mtime);
case REMOTEDIRMODEL_COLUMN_FRIEND_ACCESS: return getFlagsString(details.flags);
case REMOTEDIRMODEL_COLUMN_WN_VISU_DIR: return getGroupsString(details.flags,details.parent_groups) ;
case REMOTEDIRMODEL_COLUMN_UPLOADED:
{
auto it = m_folderTotals.find(path);
uint64_t totalUpload = (it != m_folderTotals.end()) ? it->second.uploads : 0;
return totalUpload > 0 ? misc::friendlyUnit(totalUpload) : "";
return (details.uploads > 0) ? misc::friendlyUnit(details.uploads) : QString();
}
break;
default: return QVariant();
@ -1960,7 +1798,7 @@ void FlatStyle_RDM::updateRefs()
uint64_t x = rsFiles->getCumulativeUpload(details.hash);
cfd.uploadStr = x ? misc::friendlyUnit(x) : QString();
cfd.uploads = x;
cfd.hasUploads = (x > 0);
cfd.size = details.size;
cfd.mtime = details.max_mtime;
@ -2013,26 +1851,5 @@ void TreeStyle_RDM::showEmpty(const bool value)
update();
}
// hasUploads for FlatStyle - Defensive Check
bool FlatStyle_RDM::hasUploads(void *ref) const
{
if (ref == NULL) return false;
RS_STACK_MUTEX(_ref_mutex);
auto it = m_cache.find(ref);
if (it != m_cache.end())
{
return it->second.hasUploads;
}
// Fallback if not in cache (should be rare in steady state)
DirDetails details;
if (!requestDirDetails(ref, RemoteMode, details)) return false;
if (details.type == DIR_TYPE_FILE || details.type == DIR_TYPE_EXTRA_FILE) {
return rsFiles->getCumulativeUpload(details.hash) > 0;
}
return false;
}

View File

@ -81,11 +81,11 @@ class RetroshareDirModel : public QAbstractItemModel
void getFilePaths(const QModelIndexList &list, std::list<std::string> &fullpaths);
void getFilePath(const QModelIndex& index, std::string& fullpath);
void changeAgeIndicator(uint32_t indicator) { ageIndicator = indicator; }
bool isRemote() const { return RemoteMode; }
bool requestDirDetails(void *ref, bool remote,DirDetails& d) const;
// MODIFICATION A: Virtual method to check if a branch has cumulative uploads
virtual bool hasUploads(void *ref) const = 0;
virtual void update() {}
virtual void updateRef(const QModelIndex&) const =0;
@ -211,8 +211,7 @@ class TreeStyle_RDM: public RetroshareDirModel
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
// MODIFICATION B: Implementation for Tree Style
virtual bool hasUploads(void *ref) const;
private slots:
void showEmpty(const bool value);
@ -221,28 +220,9 @@ class TreeStyle_RDM: public RetroshareDirModel
QAction *_showEmptyAct;
bool _showEmpty;
// Helper to calculate total recursive statistics per directory (Files count, Size, Uploads)
void recalculateDirectoryTotals();
private:
struct FolderStats {
uint64_t size;
uint32_t count;
uint64_t uploads;
FolderStats() : size(0), count(0), uploads(0) {}
FolderStats& operator+=(const FolderStats& s) {
size += s.size;
count += s.count;
uploads += s.uploads;
return *this;
}
};
std::map<QString, FolderStats> m_folderTotals; // Key: clean path, Val: recursive stats
FolderStats collectStatsRecursive(void* ref);
protected:
mutable std::vector<int> _parentRow ; // used to store the real parent row for non empty child
@ -273,8 +253,7 @@ class FlatStyle_RDM: public RetroshareDirModel
virtual void preMods();
virtual void postMods();/* Callback from Core */
virtual void updateRef(const QModelIndex&) const {}
// MODIFICATION H: Implement hasUploads for Flat Style to fix compilation
virtual bool hasUploads(void *ref) const;
// MODIFICATION: Override data() to use internal cache for Flat View
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
@ -304,7 +283,7 @@ class FlatStyle_RDM: public RetroshareDirModel
uint64_t size;
uint32_t mtime;
uint64_t uploads;
bool hasUploads;
};
std::map<void*, CachedFileDetails> m_cache;