Fix autocollapse in tree view

This commit is contained in:
jolavillette 2025-12-26 22:16:17 +01:00
parent 0495b96c00
commit a2294a9fda
2 changed files with 302 additions and 368 deletions

View file

@ -57,6 +57,31 @@
#include <set>
/**
* Helper class to block signals and show wait cursor during UI updates.
* Prevents the view from reacting to model changes while we are
* restoring the tree state.
*/
class QCursorContextBlocker
{
public:
QCursorContextBlocker(QWidget *w)
: mW(w)
{
mW->setCursor(Qt::WaitCursor);
mW->blockSignals(true);
}
~QCursorContextBlocker()
{
mW->setCursor(Qt::ArrowCursor);
mW->blockSignals(false);
}
private:
QWidget *mW ;
};
#define SHARED_FILES_DIALOG_COLUMN_NAME 0
#define SHARED_FILES_DIALOG_COLUMN_FILENB 1
#define SHARED_FILES_DIALOG_COLUMN_SIZE 2
@ -196,16 +221,16 @@ SharedFilesDialog::~SharedFilesDialog()
delete flat_model;
delete tree_proxyModel;
}
/** Constructor */
/**
* Constructor for the base SharedFilesDialog.
*/
SharedFilesDialog::SharedFilesDialog(bool remote_mode, QWidget *parent)
: RsAutoUpdatePage(1000,parent), model(NULL), uploadedOnly_CB(NULL)
{
/* Invoke the Qt Designer generated object setup routine */
ui.setupUi(this);
//connect(notify, SIGNAL(filesPreModChanged(bool)), this, SLOT(preModDirectories(bool)));
//connect(notify, SIGNAL(filesPostModChanged(bool)), this, SLOT(postModDirectories(bool)));
mEventHandlerId = 0;
rsEvents->registerEventsHandler([this](std::shared_ptr<const RsEvent> event)
@ -238,14 +263,21 @@ SharedFilesDialog::SharedFilesDialog(bool remote_mode, QWidget *parent)
connect(ui.dirTreeView, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT( spawnCustomPopupMenu( QPoint ) ) );
connect(ui.indicatorCBox, SIGNAL(currentIndexChanged(int)), this, SLOT(indicatorChanged(int)));
// Ensure the combo box items are not bold
QFont normalFont = ui.viewType_CB->font();
normalFont.setBold(false);
ui.viewType_CB->setFont(normalFont);
// Reset specific items font role to ensure no bolding from UI files
for(int i = 0; i < ui.viewType_CB->count(); ++i) {
ui.viewType_CB->setItemData(i, normalFont, Qt::FontRole);
}
tree_model = new TreeStyle_RDM(remote_mode);
flat_model = new FlatStyle_RDM(remote_mode);
connect(flat_model, SIGNAL(layoutChanged()), this, SLOT(updateDirTreeView()) );
// For filtering items we use a trick: the underlying model will use this FilterRole role to highlight selected items
// while the filterProxyModel will select them using the pre-chosen string "filtered".
tree_proxyModel = new SFDSortFilterProxyModel(tree_model, this);
tree_proxyModel->setSourceModel(tree_model);
tree_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
@ -266,15 +298,10 @@ SharedFilesDialog::SharedFilesDialog(bool remote_mode, QWidget *parent)
connect(ui.filterStartButton, SIGNAL(clicked()), this, SLOT(startFilter()));
connect(ui.filterPatternLineEdit, SIGNAL(returnPressed()), this, SLOT(startFilter()));
connect(ui.filterPatternLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(onFilterTextEdited()));
//Hidden by default, shown on onFilterTextEdited
ui.filterClearButton->hide();
ui.filterStartButton->hide();
// mFilterTimer = new RsProtectedTimer( this );
// mFilterTimer->setSingleShot( true ); // Ensure the timer will fire only once after it was started
// connect(mFilterTimer, SIGNAL(timeout()), this, SLOT(filterRegExpChanged()));
/* Set header resize modes and initial section sizes */
QHeaderView * header = ui.dirTreeView->header () ;
#if QT_VERSION < QT_VERSION_CHECK(5,11,0)
int charWidth = ui.dirTreeView->fontMetrics().width("_");
@ -286,26 +313,22 @@ SharedFilesDialog::SharedFilesDialog(bool remote_mode, QWidget *parent)
header->resizeSection ( SHARED_FILES_DIALOG_COLUMN_FILENB , charWidth*15 );
header->resizeSection ( SHARED_FILES_DIALOG_COLUMN_SIZE , charWidth*10 );
header->resizeSection ( SHARED_FILES_DIALOG_COLUMN_AGE , charWidth*6 );
// REDUCED WIDTH: Set to 4 instead of 10 to only fit icons
header->resizeSection ( SHARED_FILES_DIALOG_COLUMN_FRIEND_ACCESS, charWidth*4 );
header->resizeSection ( SHARED_FILES_DIALOG_COLUMN_WN_VISU_DIR , charWidth*20 );
header->resizeSection ( SHARED_FILES_DIALOG_COLUMN_UPLOADED , charWidth*20 );
header->setStretchLastSection(true);
/* Set Multi Selection */
ui.dirTreeView->setSelectionMode(QAbstractItemView::ExtendedSelection);
/* Hide platform specific features */
copylinkAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Copy retroshare Links to Clipboard" ), this );
connect( copylinkAct , SIGNAL( triggered() ), this, SLOT( copyLink() ) );
copylinkhtmlAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Copy retroshare Links to Clipboard (HTML)" ), this );
connect( copylinkhtmlAct , SIGNAL( triggered() ), this, SLOT( copyLinkhtml() ) );
sendlinkAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Send retroshare Links" ), this );
connect( sendlinkAct , SIGNAL( triggered() ), this, SLOT( sendLinkTo( ) ) );
copylinkAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Copy retroshare Links to Clipboard" ), this );
connect( copylinkAct , SIGNAL( triggered() ), this, SLOT( copyLink() ) );
copylinkhtmlAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Copy retroshare Links to Clipboard (HTML)" ), this );
connect( copylinkhtmlAct , SIGNAL( triggered() ), this, SLOT( copyLinkhtml() ) );
sendlinkAct = new QAction(QIcon(IMAGE_COPYLINK), tr( "Send retroshare Links" ), this );
connect( sendlinkAct , SIGNAL( triggered() ), this, SLOT( sendLinkTo( ) ) );
removeExtraFileAct = new QAction(QIcon(IMAGE_UNSHAREEXTRA), tr( "Stop sharing this file" ), this );
connect( removeExtraFileAct , SIGNAL( triggered() ), this, SLOT( removeExtraFile() ) );
removeExtraFileAct = new QAction(QIcon(IMAGE_UNSHAREEXTRA), tr( "Stop sharing this file" ), this );
connect( removeExtraFileAct , SIGNAL( triggered() ), this, SLOT( removeExtraFile() ) );
collCreateAct= new QAction(QIcon(IMAGE_COLLCREATE), tr("Create Collection..."), this) ;
connect(collCreateAct,SIGNAL(triggered()),this,SLOT(collCreate())) ;
@ -317,26 +340,25 @@ SharedFilesDialog::SharedFilesDialog(bool remote_mode, QWidget *parent)
connect(collOpenAct, SIGNAL(triggered()), this, SLOT(collOpen())) ;
}
/**
* Constructor for LocalSharedFilesDialog.
*/
LocalSharedFilesDialog::LocalSharedFilesDialog(QWidget *parent)
: SharedFilesDialog(false,parent)
{
// CREATION & POSITIONING: Box created only here and placed right of view selector
uploadedOnly_CB = new QCheckBox(tr("Uploaded only"), this);
uploadedOnly_CB->setToolTip(tr("Show only files and folders that have been uploaded"));
// Updated label to "Popular files" as requested
uploadedOnly_CB = new QCheckBox(tr("Popular files"), this);
uploadedOnly_CB->setToolTip(tr("Show only files and folders that have been uploaded by others"));
int viewTypeIdx = ui.horizontalLayout_2->indexOf(ui.viewType_CB);
ui.horizontalLayout_2->insertWidget(viewTypeIdx + 1, uploadedOnly_CB);
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)));
// Hide columns after loading the settings
ui.dirTreeView->setColumnHidden(SHARED_FILES_DIALOG_COLUMN_WN_VISU_DIR, false) ;
ui.downloadButton->hide() ;
// load settings
processSettings(true);
// Setup the current view model.
//
changeCurrentViewModel(ui.viewType_CB->currentIndex()) ;
connect(ui.addShares_PB, SIGNAL(clicked()), this, SLOT(addShares())) ;
@ -348,7 +370,6 @@ LocalSharedFilesDialog::LocalSharedFilesDialog(QWidget *parent)
connect(openfolderAct, SIGNAL(triggered()), this, SLOT(openfolder())) ;
ui.titleBarPixmap->setPixmap(FilesDefs::getPixmapFromQtResourcePath(IMAGE_MYFILES)) ;
ui.dirTreeView->setItemDelegateForColumn(SHARED_FILES_DIALOG_COLUMN_FRIEND_ACCESS,new ShareFlagsItemDelegate()) ;
}
@ -1179,41 +1200,99 @@ void SharedFilesDialog::recursRestoreExpandedItems(const QModelIndex& index, con
}
}
void SharedFilesDialog::postModDirectories(bool local)
/**
* Handles directory updates after model changes.
* Fixed to prevent autocollapse by restoring state after sorting.
*/
void SharedFilesDialog::postModDirectories(bool local)
{
if (isRemote() == local)
return;
std::set<std::string> expanded_indexes,selected_indexes,hidden_indexes;
std::set<std::string> expanded_indexes, selected_indexes, hidden_indexes;
saveExpandedPathsAndSelection(expanded_indexes,hidden_indexes,selected_indexes) ;
#ifdef DEBUG_SHARED_FILES_DIALOG
std::cerr << "Saving expanded items. " << expanded_indexes.size() << " items found" << std::endl;
#endif
// 1. Save current state
saveExpandedPathsAndSelection(expanded_indexes, hidden_indexes, selected_indexes) ;
/* Notify both models, only one is visible */
// 2. Update models
tree_model->postMods();
flat_model->postMods();
ui.dirTreeView->update() ;
if (ui.filterPatternLineEdit->text().isEmpty() == false)
FilterItems();
/** FIX: Restore selection and expansion BEFORE enabling sorting to avoid mismatch */
restoreExpandedPathsAndSelection(expanded_indexes,hidden_indexes,selected_indexes) ;
// 3. Re-enable sorting BEFORE restoring expansion to stabilize the view
ui.dirTreeView->setSortingEnabled(true);
#ifdef DEBUG_SHARED_FILES_DIALOG
std::cerr << "****** updated directories! Re-enabling sorting ******" << std::endl;
#endif
// 4. Re-apply the text filter
if (ui.filterPatternLineEdit->text().isEmpty() == false) {
FilterItems();
}
// 5. Finally restore expansion on a stable model
restoreExpandedPathsAndSelection(expanded_indexes, hidden_indexes, selected_indexes) ;
#if QT_VERSION < QT_VERSION_CHECK (6, 0, 0)
QCoreApplication::flush();
#endif
}
/**
* Applies text filtering to the current model.
* Optimized to avoid recursive model resets.
*/
void SharedFilesDialog::FilterItems()
{
#ifdef DONT_USE_SEARCH_IN_TREE_VIEW
if(proxyModel == tree_proxyModel)
return;
#endif
QString text = ui.filterPatternLineEdit->text();
if(mLastFilterText == text)
{
return ;
}
mLastFilterText = text ;
QCursorContextBlocker q(ui.dirTreeView) ;
QCoreApplication::processEvents() ;
uint32_t found = 0 ;
if(text == "")
{
model->filterItems(std::list<std::string>(), found) ;
if (tree_proxyModel) tree_proxyModel->invalidate();
if (flat_proxyModel) flat_proxyModel->invalidate();
return ;
}
if(text.length() < 3)
return ;
QStringList lst = text.split(" ", QtSkipEmptyParts) ;
std::list<std::string> keywords ;
for(auto it(lst.begin()); it != lst.end(); ++it)
keywords.push_back((*it).toStdString());
model->filterItems(keywords, found) ;
if (tree_proxyModel) tree_proxyModel->invalidate();
if (flat_proxyModel) flat_proxyModel->invalidate();
if(found > 0)
expandAll();
if(found == 0)
ui.filterPatternFrame->setToolTip(tr("No result.")) ;
else if(found > MAX_SEARCH_RESULTS)
ui.filterPatternFrame->setToolTip(tr("More than %1 results. Add more/longer search words to select less.").arg(MAX_SEARCH_RESULTS)) ;
else
ui.filterPatternFrame->setToolTip(tr("Found %1 results.").arg(found)) ;
}
class ChannelCompare
{
public:
@ -1656,90 +1735,6 @@ void SharedFilesDialog::restoreInvisibleItems()
}
#endif
class QCursorContextBlocker
{
public:
QCursorContextBlocker(QWidget *w)
: mW(w)
{
mW->setCursor(Qt::WaitCursor);
mW->blockSignals(true) ;
}
~QCursorContextBlocker()
{
mW->setCursor(Qt::ArrowCursor);
mW->blockSignals(false) ;
}
private:
QWidget *mW ;
};
void SharedFilesDialog::FilterItems()
{
#ifdef DONT_USE_SEARCH_IN_TREE_VIEW
if(proxyModel == tree_proxyModel)
return;
#endif
QString text = ui.filterPatternLineEdit->text();
if(mLastFilterText == text) // do not filter again if we already did. This is an optimization
{
#ifdef DEBUG_SHARED_FILES_DIALOG
std::cerr << "Last text is equal to text. skipping" << std::endl;
#endif
return ;
}
#ifdef DEBUG_SHARED_FILES_DIALOG
std::cerr << "New last text. Performing the filter on string \"" << text.toStdString() << "\"" << std::endl;
#endif
mLastFilterText = text ;
QCursorContextBlocker q(ui.dirTreeView) ;
QCoreApplication::processEvents() ;
std::list<DirDetails> result_list ;
uint32_t found = 0 ;
if(text == "")
{
model->filterItems(std::list<std::string>(),found) ;
model->update() ;
return ;
}
if(text.length() < 3)
return ;
//FileSearchFlags flags = isRemote()?RS_FILE_HINTS_REMOTE:RS_FILE_HINTS_LOCAL;
QStringList lst = text.split(" ",QtSkipEmptyParts) ;
std::list<std::string> keywords ;
for(auto it(lst.begin());it!=lst.end();++it)
keywords.push_back((*it).toStdString());
model->filterItems(keywords,found) ;
model->update() ;
if(found > 0)
expandAll();
if(found == 0)
ui.filterPatternFrame->setToolTip(tr("No result.")) ;
else if(found > MAX_SEARCH_RESULTS)
ui.filterPatternFrame->setToolTip(tr("More than %1 results. Add more/longer search words to select less.").arg(MAX_SEARCH_RESULTS)) ;
else
ui.filterPatternFrame->setToolTip(tr("Found %1 results.").arg(found)) ;
#ifdef DEBUG_SHARED_FILES_DIALOG
std::cerr << found << " results found by search." << std::endl;
#endif
}
void SharedFilesDialog::removeExtraFile()
{
std::list<DirDetails> files_info ;

View file

@ -544,183 +544,6 @@ QVariant RetroshareDirModel::decorationRole(const DirDetails& details,int coln)
} /* end of DecorationRole */
QVariant TreeStyle_RDM::displayRole(const DirDetails& details,int coln) const
{
/*
* Person: name, id, 0, 0;
* File : name, size, rank, (0) ts
* Dir : name, (0) count, (0) path, (0) ts
*/
if (details.type == DIR_TYPE_PERSON) /* Person */
{
switch(coln)
{
case REMOTEDIRMODEL_COLUMN_NAME: {
//SharedDirStats stats ;
QString res ;
if(RemoteMode)
res = QString::fromUtf8(rsPeers->getPeerName(details.id).c_str());
else if(details.id == rsPeers->getOwnId())
res = tr("My files");
else
res = tr("Temporary shared files");
return res ;
}
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
stats.total_number_of_files = details.children.size();
if(stats.total_number_of_files > 0)
{
if (stats.total_number_of_files > 1)
return QString::number(stats.total_number_of_files) + " " + tr("Files");
else
return QString::number(stats.total_number_of_files) + " " + tr("File");
}
return tr("Empty");
}
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
return QString();
if(stats.total_shared_size > 0)
return misc::friendlyUnit(stats.total_shared_size) ;
return QString();
}
case REMOTEDIRMODEL_COLUMN_AGE:
if(!isNewerThanEpoque(details.max_mtime))
return QString();
else if(details.id != rsPeers->getOwnId())
return QString();
else
return misc::timeRelativeToNow(details.max_mtime);
case REMOTEDIRMODEL_COLUMN_UPLOADED:
{
if(!RemoteMode && details.id == rsPeers->getOwnId()) // Totals in "My files" row
{
uint64_t n = rsFiles->getCumulativeUploadNum();
if(n)
return QString(misc::friendlyUnit(rsFiles->getCumulativeUploadAll()) + QString(" - %1 files").arg(n));
else
return QString("-");
}
}
default:
return QString() ;
}
}
else if (details.type == DIR_TYPE_FILE || details.type == DIR_TYPE_EXTRA_FILE) /* File */
{
switch(coln)
{
case REMOTEDIRMODEL_COLUMN_NAME:
return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_FILENB:
return QVariant();
case REMOTEDIRMODEL_COLUMN_SIZE:
return misc::friendlyUnit(details.size);
case REMOTEDIRMODEL_COLUMN_AGE:
{
if(details.type == DIR_TYPE_FILE)
return misc::timeRelativeToNow(details.max_mtime);
else if(details.type == DIR_TYPE_EXTRA_FILE)
{
FileInfo fi;
if (rsFiles->FileDetails(details.hash, RS_FILE_HINTS_EXTRA , fi))
return misc::timeRelativeToNow((rstime_t)fi.age-(30 * 3600 * 24)); // AFI_DEFAULT_PERIOD
return QString();
}
else
return QString();
}
case REMOTEDIRMODEL_COLUMN_FRIEND_ACCESS:
return QVariant();
case REMOTEDIRMODEL_COLUMN_WN_VISU_DIR:
return getGroupsString(details.flags,details.parent_groups) ;
case REMOTEDIRMODEL_COLUMN_UPLOADED:
{
uint64_t x = rsFiles->getCumulativeUpload(details.hash);
if(x)
return misc::friendlyUnit(x);
else
return QString();
}
default:
return tr("FILE");
}
}
else if (details.type == DIR_TYPE_DIR) /* Dir */
{
switch(coln)
{
case REMOTEDIRMODEL_COLUMN_NAME:
return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_FILENB:
if (details.children.size() > 1)
{
return QString::number(details.children.size()) + " " + tr("Files");
}
return QString::number(details.children.size()) + " " + tr("File");
case REMOTEDIRMODEL_COLUMN_SIZE:
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:
{
// New logic: Check if we have a calculated total for this directory
// Based on logs, the 'details.path' for a directory IS the full path to that directory.
// We do NOT need to append the name.
QString path = QDir::cleanPath(QString::fromUtf8(details.path.c_str()));
// Fallback / Safety: try constructed path if direct path fails (covers root vs sub-dir anomalies)
auto it = m_folderUploadTotals.find(path);
// DEBUG: Display role request
// std::cerr << "UPLOAD_DBG: Display Role for DIR. Name: " << details.name
// << " | Raw Path: " << details.path
// << " | Lookup Key: [" << path.toStdString() << "]" << std::endl;
if(it != m_folderUploadTotals.end() && it.value() > 0)
{
// std::cerr << "UPLOAD_DBG: -> FOUND! Value: " << it.value() << std::endl;
return misc::friendlyUnit(it.value());
}
return "";
}
default:
return tr("DIR");
}
}
return QVariant();
} /* end of DisplayRole */
void FlatStyle_RDM::update()
{
if(_needs_update)
@ -1619,71 +1442,187 @@ void RetroshareDirModel::getFilePaths(const QModelIndexList &list, std::list<std
#endif
}
void RetroshareDirModel::filterItems(const std::list<std::string>& keywords,uint32_t& found)
void RetroshareDirModel::filterItems(const std::list<std::string>& keywords, uint32_t& found)
{
FileSearchFlags flags = RemoteMode?RS_FILE_HINTS_REMOTE:RS_FILE_HINTS_LOCAL;
FileSearchFlags flags = RemoteMode ? RS_FILE_HINTS_REMOTE : RS_FILE_HINTS_LOCAL;
std::list<DirDetails> result_list ;
found = 0 ;
std::list<DirDetails> result_list ;
found = 0 ;
if(keywords.empty())
{
mFilteredPointers.clear();
return ;
}
else if(keywords.size() > 1)
{
RsRegularExpression::NameExpression exp(RsRegularExpression::ContainsAllStrings,keywords,true);
rsFiles->SearchBoolExp(&exp,result_list, flags) ;
}
else
rsFiles->SearchKeywords(keywords,result_list, flags) ;
if(keywords.empty())
{
mFilteredPointers.clear();
return ;
}
else if(keywords.size() > 1)
{
RsRegularExpression::NameExpression exp(RsRegularExpression::ContainsAllStrings, keywords, true);
rsFiles->SearchBoolExp(&exp, result_list, flags) ;
}
else
rsFiles->SearchKeywords(keywords, result_list, flags) ;
#ifdef RDM_SEARCH_DEBUG
std::cerr << "Found " << result_list.size() << " results" << std::endl;
#endif
if(result_list.empty())
return ;
if(result_list.empty()) // in this case we dont clear the list of filtered items, so that we can keep the old filter list
return ;
mFilteredPointers.clear();
mFilteredPointers.clear();
// Mark matching pointers and their hierarchy as visible
for(auto it(result_list.begin()); it != result_list.end(); ++it)
{
DirDetails& det(*it) ;
void *p = det.ref ;
mFilteredPointers.insert(p) ;
++found ;
#ifdef RDM_SEARCH_DEBUG
std::cerr << "Found this result: " << std::endl;
#endif
while(det.type == DIR_TYPE_FILE || det.type == DIR_TYPE_EXTRA_FILE || det.type == DIR_TYPE_DIR)
{
p = det.parent ;
if (!rsFiles->RequestDirDetails(p, det, flags))
break;
// Then show only the ones we need
for(auto it(result_list.begin());it!=result_list.end();++it)
{
DirDetails& det(*it) ;
#ifdef RDM_SEARCH_DEBUG
std::cerr << (void*)(*it).ref << " name=\"" << det.name << "\" parents: " ;
#endif
void *p = det.ref ;
mFilteredPointers.insert(p) ;
++found ;
while(det.type == DIR_TYPE_FILE || det.type == DIR_TYPE_EXTRA_FILE || det.type == DIR_TYPE_DIR)
{
p = det.parent ;
rsFiles->RequestDirDetails( p, det, flags);
#ifdef RDM_SEARCH_DEBUG
std::cerr << " " << (void*)p << "(" << (int)det.type << ")";
#endif
mFilteredPointers.insert(p) ;
}
#ifdef RDM_SEARCH_DEBUG
std::cerr << std::endl;
#endif
}
#ifdef RDM_SEARCH_DEBUG
std::cerr << mFilteredPointers.size() << " pointers in filter set." << std::endl;
#endif
mFilteredPointers.insert(p) ;
}
}
// CRITICAL: Removed update() call to prevent full model reset and collapse
}
QVariant TreeStyle_RDM::displayRole(const DirDetails& details, int coln) const
{
if (details.type == DIR_TYPE_PERSON) /* Person */
{
switch(coln)
{
case REMOTEDIRMODEL_COLUMN_NAME:
{
QString res ;
if(RemoteMode)
res = QString::fromUtf8(rsPeers->getPeerName(details.id).c_str());
else if(details.id == rsPeers->getOwnId())
res = tr("My files");
else
res = tr("Temporary shared files");
return res ;
}
break;
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
stats.total_number_of_files = details.children.size();
if(stats.total_number_of_files > 0)
{
if (stats.total_number_of_files > 1)
return QString::number(stats.total_number_of_files) + " " + tr("Files");
else
return QString::number(stats.total_number_of_files) + " " + tr("File");
}
return tr("Empty");
}
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
return QString();
if(stats.total_shared_size > 0)
return misc::friendlyUnit(stats.total_shared_size) ;
return QString();
}
break;
case REMOTEDIRMODEL_COLUMN_AGE:
{
if(!isNewerThanEpoque(details.max_mtime))
return QString();
else if(details.id != rsPeers->getOwnId())
return QString();
else
return misc::timeRelativeToNow(details.max_mtime);
}
break;
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();
}
break;
default: return QString();
}
}
else if (details.type == DIR_TYPE_FILE || details.type == DIR_TYPE_EXTRA_FILE) /* File */
{
switch(coln)
{
case REMOTEDIRMODEL_COLUMN_NAME: return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_SIZE: return misc::friendlyUnit(details.size);
case REMOTEDIRMODEL_COLUMN_AGE:
{
if(details.type == DIR_TYPE_FILE)
return misc::timeRelativeToNow(details.max_mtime);
else if(details.type == DIR_TYPE_EXTRA_FILE)
{
FileInfo fi;
if (rsFiles->FileDetails(details.hash, RS_FILE_HINTS_EXTRA , fi))
return misc::timeRelativeToNow((rstime_t)fi.age-(30 * 3600 * 24));
return QString();
}
return QString();
}
case REMOTEDIRMODEL_COLUMN_UPLOADED:
{
uint64_t x = rsFiles->getCumulativeUpload(details.hash);
return x ? misc::friendlyUnit(x) : QString();
}
break;
default: return QVariant();
}
}
else if (details.type == DIR_TYPE_DIR) /* Directory */
{
switch(coln)
{
case REMOTEDIRMODEL_COLUMN_NAME: return QString::fromUtf8(details.name.c_str());
case REMOTEDIRMODEL_COLUMN_FILENB:
return QString::number(details.children.size()) + " " + (details.children.size() > 1 ? tr("Files") : tr("File"));
case REMOTEDIRMODEL_COLUMN_SIZE: 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:
{
QString path = QDir::cleanPath(QString::fromUtf8(details.path.c_str()));
auto it = m_folderUploadTotals.find(path);
return (it != m_folderUploadTotals.end() && it.value() > 0) ? misc::friendlyUnit(it.value()) : "";
}
break;
default: return QVariant();
}
}
return QVariant();
}
/* Drag and Drop Functionality */
QMimeData * RetroshareDirModel::mimeData ( const QModelIndexList & indexes ) const