diff --git a/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.cpp b/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.cpp
index 810820b60..63a28c333 100644
--- a/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.cpp
+++ b/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.cpp
@@ -145,8 +145,7 @@ public:
void setUploadedOnly(bool val) {
if (m_uploadedOnly != val) {
m_uploadedOnly = val;
- // invalidateFilter(); // CRASH FIX: Do not invalidate incrementally.
- // The dialog calls model->update() which triggers a full Reset.
+ invalidateFilter();
}
}
@@ -229,7 +228,7 @@ SharedFilesDialog::~SharedFilesDialog()
* Constructor for the base SharedFilesDialog.
*/
SharedFilesDialog::SharedFilesDialog(bool remote_mode, QWidget *parent)
- : RsAutoUpdatePage(1000,parent), model(NULL), uploadedOnly_CB(NULL)
+ : RsAutoUpdatePage(1000,parent), model(NULL)
{
/* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this);
@@ -350,17 +349,7 @@ SharedFilesDialog::SharedFilesDialog(bool remote_mode, QWidget *parent)
LocalSharedFilesDialog::LocalSharedFilesDialog(QWidget *parent)
: SharedFilesDialog(false,parent)
{
- // Label updated to "Popular files"
- uploadedOnly_CB = new QCheckBox(tr("Popular files"), this);
-
- // Updated tooltip to be more descriptive of the "Popularity" (upload activity)
- uploadedOnly_CB->setToolTip(tr("Show only files and folders that have been successfully uploaded to other peers"));
-
- // Positioning the checkbox next to the view selector
- int cbIndex = ui.horizontalLayout_2->indexOf(ui.viewType_CB);
- ui.horizontalLayout_2->insertWidget(cbIndex + 1, uploadedOnly_CB);
-
- connect(uploadedOnly_CB, SIGNAL(toggled(bool)), this, SLOT(filterUploadedOnlyToggled(bool)));
+ connect(ui.uploadedOnly_CB, SIGNAL(toggled(bool)), this, SLOT(filterUploadedOnlyToggled(bool)));
// Ensure proper columns are visible for local sharing
ui.dirTreeView->setColumnHidden(SHARED_FILES_DIALOG_COLUMN_WN_VISU_DIR, false) ;
@@ -400,6 +389,7 @@ RemoteSharedFilesDialog::RemoteSharedFilesDialog(QWidget *parent)
//
changeCurrentViewModel(ui.viewType_CB->currentIndex()) ;
+ ui.uploadedOnly_CB->hide();
ui.addShares_PB->hide() ;
}
@@ -524,9 +514,9 @@ void SharedFilesDialog::changeCurrentViewModel(int viewTypeIndex)
proxyModel = flat_proxyModel ;
}
- if(uploadedOnly_CB) {
- if(tree_proxyModel) tree_proxyModel->setUploadedOnly(uploadedOnly_CB->isChecked());
- if(flat_proxyModel) flat_proxyModel->setUploadedOnly(uploadedOnly_CB->isChecked());
+ if(ui.uploadedOnly_CB) {
+ if(tree_proxyModel) tree_proxyModel->setUploadedOnly(ui.uploadedOnly_CB->isChecked());
+ if(flat_proxyModel) flat_proxyModel->setUploadedOnly(ui.uploadedOnly_CB->isChecked());
}
showProperColumns() ;
@@ -561,7 +551,7 @@ void SharedFilesDialog::changeCurrentViewModel(int viewTypeIndex)
FilterItems();
// MODIFICATION: Expand tree if "Uploaded Only" is active, otherwise items remain hidden in collapsed folders.
- if(viewTypeIndex==VIEW_TYPE_TREE && uploadedOnly_CB && uploadedOnly_CB->isChecked()) {
+ if(viewTypeIndex==VIEW_TYPE_TREE && ui.uploadedOnly_CB && ui.uploadedOnly_CB->isChecked()) {
expandAll();
}
}
@@ -1669,12 +1659,16 @@ void SharedFilesDialog::filterUploadedOnlyToggled(bool checked)
if (tree_proxyModel) tree_proxyModel->setUploadedOnly(checked);
if (flat_proxyModel) flat_proxyModel->setUploadedOnly(checked);
- // CRITICAL FIX: Use model->update() instead of proxy->invalidate().
- // model->update() triggers a full reset (beginResetModel), which forces
- // the Proxy to drop its dangerous mapping and rebuild it from scratch.
+ // CRITICAL PERFORMANCE FIX: DO NOT call model->update() here.
+ // model->update() triggers a full reset and re-crawl of the entire share hierarchy,
+ // which takes 30+ seconds for large shares.
+ // Instead, we rely on proxyModel->invalidateFilter() (called above) which
+ // is near-instant as it uses the existing O(1) cache.
+ /*
if (model) {
model->update();
}
+ */
if(ui.viewType_CB->currentIndex() == VIEW_TYPE_TREE) {
if (checked) expandAll();
diff --git a/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.h b/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.h
index 7d41287e6..2f99e465b 100644
--- a/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.h
+++ b/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.h
@@ -158,8 +158,7 @@ protected:
RsEventsHandlerId_t mEventHandlerId ;
- /** Checkbox to filter files with 0 upload */
- QCheckBox *uploadedOnly_CB;
+ /** Checkbox to filter files with 0 upload - now in ui.uploadedOnly_CB */
};
class LocalSharedFilesDialog : public SharedFilesDialog
diff --git a/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.ui b/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.ui
index 4c8f8c38b..e9eb8bdfb 100644
--- a/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.ui
+++ b/retroshare-gui/src/gui/FileTransfer/SharedFilesDialog.ui
@@ -236,6 +236,16 @@ border-image: url(:/images/closepressed.png)
+ -
+
+
+ Show only files and folders that have been successfully uploaded to other peers
+
+
+ Popular files
+
+
+
-
-
diff --git a/retroshare-gui/src/gui/RemoteDirModel.cpp b/retroshare-gui/src/gui/RemoteDirModel.cpp
index a17eeaef7..4cd7cca4f 100644
--- a/retroshare-gui/src/gui/RemoteDirModel.cpp
+++ b/retroshare-gui/src/gui/RemoteDirModel.cpp
@@ -58,7 +58,7 @@
#define REMOTEDIRMODEL_COLUMN_UPLOADED 6
#define REMOTEDIRMODEL_COLUMN_COUNT 7
-static const uint32_t FLAT_VIEW_MAX_REFS_PER_SECOND = 10000 ;
+static const uint32_t FLAT_VIEW_MAX_REFS_PER_SECOND = 1000 ;
static const size_t FLAT_VIEW_MAX_REFS_TABLE_SIZE = 30000 ; //
static const uint32_t FLAT_VIEW_MIN_DELAY_BETWEEN_UPDATES = 120 ; // dont rebuild ref list more than every 2 mins.
@@ -151,9 +151,7 @@ void RetroshareDirModel::treeStyle()
void TreeStyle_RDM::recalculateDirectoryTotals()
{
- m_folderUploadTotals.clear();
- m_folderFileTotals.clear();
- m_folderSizeTotals.clear();
+ m_folderTotals.clear();
// Stats are primarily calculated for local files.
// For remote files, branch stats are limited by what the core provides.
@@ -187,9 +185,7 @@ TreeStyle_RDM::FolderStats TreeStyle_RDM::collectStatsRecursive(void* ref)
// Special handling for Extra Files (virtual root)
if (details.type == DIR_TYPE_EXTRA_FILE)
{
- m_folderUploadTotals["!!RS_EXTRA_FILES_ROOT!!"] += stats.uploads;
- m_folderFileTotals["!!RS_EXTRA_FILES_ROOT!!"] += stats.count;
- m_folderSizeTotals["!!RS_EXTRA_FILES_ROOT!!"] += stats.size;
+ m_folderTotals["!!RS_EXTRA_FILES_ROOT!!"] += stats;
}
return stats;
@@ -200,21 +196,14 @@ TreeStyle_RDM::FolderStats TreeStyle_RDM::collectStatsRecursive(void* ref)
{
for(const auto& child : details.children)
{
- FolderStats childStats = collectStatsRecursive(child.ref);
-
- stats.size += childStats.size;
- stats.count += childStats.count;
- stats.uploads += childStats.uploads;
+ 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_folderUploadTotals[path] = stats.uploads;
- m_folderFileTotals[path] = stats.count;
- m_folderSizeTotals[path] = stats.size;
+ m_folderTotals[path] = stats;
}
}
@@ -238,12 +227,14 @@ bool TreeStyle_RDM::hasUploads(void *ref) const
}
if (details.type == DIR_TYPE_PERSON && details.id != rsPeers->getOwnId()) {
- return m_folderUploadTotals.value("!!RS_EXTRA_FILES_ROOT!!", 0) > 0;
+ 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()));
- return m_folderUploadTotals.value(path, 0) > 0;
+ auto it = m_folderTotals.find(path);
+ return (it != m_folderTotals.end()) ? (it->second.uploads > 0) : false;
}
return true;
@@ -251,11 +242,11 @@ bool TreeStyle_RDM::hasUploads(void *ref) const
void TreeStyle_RDM::update()
{
+ preMods() ;
// Recalculate totals before notifying view update
recalculateDirectoryTotals();
- preMods() ;
postMods() ;
}
void TreeStyle_RDM::updateRef(const QModelIndex& indx) const
@@ -588,14 +579,19 @@ void FlatStyle_RDM::update()
// Previously, this was guarded by if(_needs_update), preventing filter updates.
// if(_needs_update)
{
- if(mUpdating) return;
+ if(mUpdating)
+ {
+ }
- {
- RS_STACK_MUTEX(_ref_mutex);
- m_cache.clear();
- }
+ // MODIFICATION: Do NOT clear cache here.
+ // We want hasUploads() to be fast even during the re-crawl.
+ // updateRefs will overwrite cache entries as it finds files.
+ // {
+ // RS_STACK_MUTEX(_ref_mutex);
+ // m_cache.clear();
+ // }
preMods() ;
postMods() ;
@@ -638,21 +634,35 @@ QVariant FlatStyle_RDM::data(const QModelIndex &index, int role) const
if (!index.isValid())
return QVariant();
- if (role == Qt::DisplayRole)
+ if (role == Qt::DisplayRole || role == RetroshareDirModel::SortRole)
{
void *ref = index.internalPointer();
-
+
// Try Lock-less read first? No, use lock for safety matching updateRefs
RS_STACK_MUTEX(_ref_mutex);
- if (m_cache.contains(ref))
+ auto it = m_cache.find(ref);
+ if (it != m_cache.end())
{
- const CachedFileDetails &cfd = m_cache[ref];
- switch(index.column())
+ const CachedFileDetails &cfd = it.value();
+ if (role == Qt::DisplayRole)
{
- case REMOTEDIRMODEL_COLUMN_NAME: return cfd.name;
- case REMOTEDIRMODEL_COLUMN_SIZE: return cfd.sizeStr;
- case REMOTEDIRMODEL_COLUMN_AGE: return cfd.ageStr;
- case REMOTEDIRMODEL_COLUMN_UPLOADED: return cfd.uploadStr;
+ switch(index.column())
+ {
+ case REMOTEDIRMODEL_COLUMN_NAME: return cfd.name;
+ case REMOTEDIRMODEL_COLUMN_SIZE: return cfd.sizeStr;
+ case REMOTEDIRMODEL_COLUMN_AGE: return cfd.ageStr;
+ case REMOTEDIRMODEL_COLUMN_UPLOADED: return cfd.uploadStr;
+ }
+ }
+ else // SortRole
+ {
+ switch(index.column())
+ {
+ case REMOTEDIRMODEL_COLUMN_NAME: return cfd.name;
+ case REMOTEDIRMODEL_COLUMN_SIZE: return (qulonglong)cfd.size;
+ case REMOTEDIRMODEL_COLUMN_AGE: return (qulonglong)cfd.mtime;
+ case REMOTEDIRMODEL_COLUMN_UPLOADED: return (qulonglong)cfd.uploads;
+ }
}
}
}
@@ -702,7 +712,10 @@ QVariant TreeStyle_RDM::sortRole(const QModelIndex& /*index*/,const DirDetails&
else if(details.id == rsPeers->getOwnId())
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(),stats) ;
else
- return (qulonglong) m_folderFileTotals.value("!!RS_EXTRA_FILES_ROOT!!", 0);
+ {
+ 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;
}
@@ -713,7 +726,10 @@ QVariant TreeStyle_RDM::sortRole(const QModelIndex& /*index*/,const DirDetails&
else if(details.id == rsPeers->getOwnId())
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(),stats) ;
else
- return (qulonglong) m_folderSizeTotals.value("!!RS_EXTRA_FILES_ROOT!!", 0);
+ {
+ 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;
}
@@ -758,9 +774,15 @@ QVariant TreeStyle_RDM::sortRole(const QModelIndex& /*index*/,const DirDetails&
case REMOTEDIRMODEL_COLUMN_NAME:
return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_FILENB:
- return (qulonglong) m_folderFileTotals.value(path, 0);
+ {
+ auto it = m_folderTotals.find(path);
+ return (it != m_folderTotals.end()) ? (qulonglong)it->second.count : (qulonglong)0;
+ }
case REMOTEDIRMODEL_COLUMN_SIZE:
- return (qulonglong) m_folderSizeTotals.value(path, 0);
+ {
+ auto it = m_folderTotals.find(path);
+ return (it != m_folderTotals.end()) ? (qulonglong)it->second.size : (qulonglong)0;
+ }
case REMOTEDIRMODEL_COLUMN_AGE:
return details.max_mtime;
case REMOTEDIRMODEL_COLUMN_FRIEND_ACCESS:
@@ -1212,9 +1234,17 @@ void FlatStyle_RDM::postMods()
{
time_t now = time(NULL);
- // MODIFICATION: Removed throttling because it caused stuck model state (beginReset without endReset)
- // if(_last_update + FLAT_VIEW_MIN_DELAY_BETWEEN_UPDATES > now)
- // return ;
+ // MODIFICATION: Bypass throttle if we are in search mode (mFilteredPointers not empty)
+ // ALSO bypass if we just cleared the filter (to avoid 120s delay to show all files)
+ static bool was_filtered = false;
+ bool is_filtered = !mFilteredPointers.empty();
+ bool transition_to_unfiltered = (was_filtered && !is_filtered);
+ was_filtered = is_filtered;
+
+ if(!is_filtered && !transition_to_unfiltered && _last_update + FLAT_VIEW_MIN_DELAY_BETWEEN_UPDATES > now)
+ {
+ return ;
+ }
if(visible())
{
@@ -1521,14 +1551,12 @@ void RetroshareDirModel::getFilePaths(const QModelIndexList &list, std::list& keywords, uint32_t& found)
{
FileSearchFlags flags = RemoteMode ? RS_FILE_HINTS_REMOTE : RS_FILE_HINTS_LOCAL;
-
- std::list result_list ;
found = 0 ;
+ std::list result_list ;
if(keywords.empty())
{
mFilteredPointers.clear();
- // MODIFICATION: Call update to refresh the view when the filter is cleared
update();
return ;
}
@@ -1580,9 +1608,6 @@ void RetroshareDirModel::filterItems(const std::list& keywords, uin
}
}
- // MODIFICATION: Restore the update call.
- // This triggers beginResetModel/endResetModel which notifies the view
- // that row counts and visibility have changed.
update();
}
@@ -1614,7 +1639,8 @@ QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(), stats) ;
else {
// Specific handling for "Temporary shared files" node (Extra files root)
- uint32_t nb = m_folderFileTotals.value("!!RS_EXTRA_FILES_ROOT!!", 0);
+ 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");
@@ -1634,7 +1660,10 @@ QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
else if(details.id == rsPeers->getOwnId())
rsFiles->getSharedDirStatistics(rsPeers->getOwnId(),stats) ;
else
- return misc::friendlyUnit(m_folderSizeTotals.value("!!RS_EXTRA_FILES_ROOT!!", 0));
+ {
+ 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) ;
@@ -1706,17 +1735,22 @@ QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
case REMOTEDIRMODEL_COLUMN_NAME: return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_FILENB:
{
- uint32_t totalFiles = m_folderFileTotals.value(path, 0);
+ 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"));
}
case REMOTEDIRMODEL_COLUMN_SIZE:
- return misc::friendlyUnit(m_folderSizeTotals.value(path, 0));
+ {
+ auto it = m_folderTotals.find(path);
+ return misc::friendlyUnit((it != m_folderTotals.end()) ? it->second.size : 0);
+ }
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:
{
- uint64_t totalUpload = m_folderUploadTotals.value(path, 0);
+ auto it = m_folderTotals.find(path);
+ uint64_t totalUpload = (it != m_folderTotals.end()) ? it->second.uploads : 0;
return totalUpload > 0 ? misc::friendlyUnit(totalUpload) : "";
}
break;
@@ -1844,49 +1878,27 @@ void FlatStyle_RDM::updateRefs()
RS_STACK_MUTEX(_ref_mutex) ;
// MODIFICATION: instant search result display
- // If we have a filter active, use the filtered set directly instead of crawling.
- if (!mFilteredPointers.empty())
+ // If we have a filter active, initialize the batch stack with the results.
+ if (!mFilteredPointers.empty() && (_ref_stack.empty() || (_ref_stack.size() == 1 && _ref_stack.front() == NULL)))
{
- _ref_stack.clear(); // Stop any pending crawl
- _ref_entries.clear();
-
+ _ref_stack.clear();
+ uint32_t added = 0;
for(auto it = mFilteredPointers.begin(); it != mFilteredPointers.end(); ++it)
{
- void* ref = *it;
- DirDetails details;
- // Only add files to the flat list
- if(requestDirDetails(ref, RemoteMode, details))
+ if (*it != NULL && *it != (void*)0x1)
{
- if(details.type == DIR_TYPE_FILE || details.type == DIR_TYPE_EXTRA_FILE)
- {
- _ref_entries.push_back(ref);
-
- CachedFileDetails cfd;
- cfd.name = QString::fromUtf8(details.name.c_str());
- cfd.sizeStr = misc::friendlyUnit(details.size);
-
- if(details.type == DIR_TYPE_FILE)
- cfd.ageStr = misc::timeRelativeToNow(details.max_mtime);
- else {
- FileInfo fi;
- if (rsFiles->FileDetails(details.hash, RS_FILE_HINTS_EXTRA , fi))
- cfd.ageStr = misc::timeRelativeToNow((rstime_t)fi.age-(30 * 3600 * 24));
- }
-
- uint64_t x = rsFiles->getCumulativeUpload(details.hash);
- cfd.uploadStr = x ? misc::friendlyUnit(x) : QString();
-
- m_cache[ref] = cfd;
- }
+ _ref_stack.push_back(*it);
+ added++;
}
}
-
- _needs_update = false; // We are done
}
- else
- {
- // Standard crawling behavior (when no filter or cleared)
- while( !_ref_stack.empty() && (_ref_entries.size() <= FLAT_VIEW_MAX_REFS_TABLE_SIZE) )
+ }
+
+ {
+ RS_STACK_MUTEX(_ref_mutex) ;
+
+ // Standard batched behavior (handles both crawling and filtered results)
+ while( !_ref_stack.empty() && (_ref_entries.size() <= FLAT_VIEW_MAX_REFS_TABLE_SIZE) )
{
void *ref = _ref_stack.back() ;
#ifdef RDM_DEBUG
@@ -1896,6 +1908,16 @@ void FlatStyle_RDM::updateRefs()
DirDetails details ;
+ auto it_cache = m_cache.find(ref);
+ if (it_cache != m_cache.end())
+ {
+ _ref_entries.push_back(ref);
+ // We still need to find children if it's a directory,
+ // but only files are in m_cache.
+ // So if it's in cache, we KNOW it's a file and has no children.
+ continue;
+ }
+
if (requestDirDetails(ref, RemoteMode,details))
{
if(details.type == DIR_TYPE_FILE || details.type == DIR_TYPE_EXTRA_FILE) // only push files, not directories nor persons.
@@ -1916,14 +1938,24 @@ 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;
m_cache[ref] = cfd;
}
#ifdef RDM_DEBUG
std::cerr << "FlatStyle_RDM::postMods(): adding ref " << ref << std::endl;
#endif
- for(uint32_t i=0;i
#include
+#include