diff --git a/retroshare-gui/src/gui/common/FriendListModel.cpp b/retroshare-gui/src/gui/common/FriendListModel.cpp index 4f0babc4c..5418b8e10 100644 --- a/retroshare-gui/src/gui/common/FriendListModel.cpp +++ b/retroshare-gui/src/gui/common/FriendListModel.cpp @@ -726,30 +726,33 @@ QVariant RsFriendListModel::displayRole(const EntryIndex& e, int col) const case COLUMN_THREAD_IP: case COLUMN_THREAD_LAST_CONTACT: { - if(!isProfileExpanded(e)) + // BUG FIX: Removed 'if(!isProfileExpanded(e))' to keep the last contact and IP + // visible even when the profile is expanded (e.g. during search filtering). + const HierarchicalProfileInformation *hn = getProfileInfo(e); + + if(!hn) return QVariant(); + + QDateTime most_recent_time = DateTime::DateTimeFromTime_t(0); + QString most_recent_ip("---"); + + // We aggregate the most recent contact info from all child nodes/locations + for(uint32_t i=0;ichild_node_indices.size();++i) { - const HierarchicalProfileInformation *hn = getProfileInfo(e); + const HierarchicalNodeInformation& node = mLocations[hn->child_node_indices[i]]; + auto node_time = DateTime::DateTimeFromTime_t(node.node_info.lastConnect); - QDateTime most_recent_time = DateTime::DateTimeFromTime_t(0); - QString most_recent_ip("---"); - - for(uint32_t i=0;ichild_node_indices.size();++i) + if(most_recent_time < node_time) { - const HierarchicalNodeInformation& node = mLocations[hn->child_node_indices[i]]; - auto node_time = DateTime::DateTimeFromTime_t(node.node_info.lastConnect); - - if(most_recent_time < node_time) - { - most_recent_time = node_time; - most_recent_ip = (node.node_info.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(node.node_info) : QString("---"); - } + most_recent_time = node_time; + most_recent_ip = (node.node_info.state & RS_PEER_STATE_CONNECTED) ? StatusDefs::connectStateIpString(node.node_info) : QString("---"); } - - if(col == COLUMN_THREAD_LAST_CONTACT) return QVariant(most_recent_time); - if(col == COLUMN_THREAD_IP) return QVariant(most_recent_ip); } - }// Fall-through + if(col == COLUMN_THREAD_LAST_CONTACT) return QVariant(most_recent_time); + if(col == COLUMN_THREAD_IP) return QVariant(most_recent_ip); + + return QVariant(); + } default: return QVariant(); } @@ -994,49 +997,47 @@ QVariant RsFriendListModel::decorationRole(const EntryIndex& entry,int col) cons } case ENTRY_TYPE_PROFILE: { - if(!isProfileExpanded(entry)) - { - QPixmap sslAvatar; - bool foundAvatar = false; - const HierarchicalProfileInformation *hn = getProfileInfo(entry); - RsStatusValue status = RsStatusValue::RS_STATUS_OFFLINE; - const HierarchicalNodeInformation *bestNodeInformation = NULL; + // BUG FIX: Removed 'if(!isProfileExpanded(entry))' to keep the icon visible + // even when the profile is expanded (e.g. during search filtering). + + QPixmap sslAvatar; + bool foundAvatar = false; + const HierarchicalProfileInformation *hn = getProfileInfo(entry); + RsStatusValue status = RsStatusValue::RS_STATUS_OFFLINE; + const HierarchicalNodeInformation *bestNodeInformation = NULL; - if (mDisplayStatusIcon) { - bestNodeInformation = getBestNodeInformation(hn, &status); - if (bestNodeInformation) { - if (AvatarDefs::getAvatarFromSslId(RsPeerId(bestNodeInformation->node_info.id.toStdString()), sslAvatar, "")) { - /* Use avatar from best node */ - foundAvatar = true; - } - } - } + if (mDisplayStatusIcon) { + bestNodeInformation = getBestNodeInformation(hn, &status); + if (bestNodeInformation) { + if (AvatarDefs::getAvatarFromSslId(RsPeerId(bestNodeInformation->node_info.id.toStdString()), sslAvatar, "")) { + /* Use avatar from best node */ + foundAvatar = true; + } + } + } - if (!foundAvatar) { - /* Use first available avatar */ - for(uint32_t i=0;ichild_node_indices.size();++i) { - if(AvatarDefs::getAvatarFromSslId(RsPeerId(mLocations[hn->child_node_indices[i]].node_info.id.toStdString()), sslAvatar, "")) { - foundAvatar = true; - break; - } - } - } + if (!foundAvatar) { + /* Use first available avatar */ + for(uint32_t i=0;ichild_node_indices.size();++i) { + if(AvatarDefs::getAvatarFromSslId(RsPeerId(mLocations[hn->child_node_indices[i]].node_info.id.toStdString()), sslAvatar, "")) { + foundAvatar = true; + break; + } + } + } - if (!foundAvatar || sslAvatar.isNull()) { - sslAvatar = FilesDefs::getPixmapFromQtResourcePath(AVATAR_DEFAULT_IMAGE); - } + if (!foundAvatar || sslAvatar.isNull()) { + sslAvatar = FilesDefs::getPixmapFromQtResourcePath(AVATAR_DEFAULT_IMAGE); + } - if (mDisplayStatusIcon) { - if (bestNodeInformation) { - QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(StatusDefs::imageStatus(status)); - return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon))); - } - } + if (mDisplayStatusIcon) { + if (bestNodeInformation) { + QPixmap sslOverlayIcon = FilesDefs::getPixmapFromQtResourcePath(StatusDefs::imageStatus(status)); + return QVariant(QIcon(createAvatar(sslAvatar, sslOverlayIcon))); + } + } - return QVariant(QIcon(sslAvatar)); - } - - return QVariant(); + return QVariant(QIcon(sslAvatar)); } case ENTRY_TYPE_NODE: diff --git a/retroshare-gui/src/gui/common/NewFriendList.cpp b/retroshare-gui/src/gui/common/NewFriendList.cpp index 492b089b0..a164830d8 100644 --- a/retroshare-gui/src/gui/common/NewFriendList.cpp +++ b/retroshare-gui/src/gui/common/NewFriendList.cpp @@ -1153,63 +1153,57 @@ void NewFriendList::removeGroup() void NewFriendList::applyWhileKeepingTree(std::function predicate) { + // 1. Store the current vertical scroll position to prevent the list from jumping + int scrollValue = ui->peerTreeWidget->verticalScrollBar()->value(); + std::set expanded_indexes; QString selected; + // 2. Save the current state of the tree (which groups are open and what is selected) saveExpandedPathsAndSelection(expanded_indexes, selected); -#ifdef DEBUG_NEW_FRIEND_LIST - std::cerr << "After collecting selection, selected paths is: \"" << selected.toStdString() << "\", " ; - std::cerr << "expanded paths are: " << std::endl; - for(auto path:expanded_indexes) - std::cerr << " \"" << path.toStdString() << "\"" << std::endl; - std::cerr << "Current sort column is: " << mLastSortColumn << " and order is " << mLastSortOrder << std::endl; -#endif + // 3. Clear selection and block signals to avoid UI flicker during updates whileBlocking(ui->peerTreeWidget)->clearSelection(); - // This is a hack to avoid crashes on windows while calling endInsertRows(). I'm not sure wether these crashes are - // due to a Qt bug, or a misuse of the proxy model on my side. Anyway, this solves them for good. - // As a side effect we need to save/restore hidden columns because setSourceModel() resets this setting. - - // save hidden columns and sizes + // 4. Save current column visibility and widths + // Detaching the model resets these settings, so we must back them up std::vector col_visible(RsFriendListModel::COLUMN_THREAD_NB_COLUMNS); std::vector col_sizes(RsFriendListModel::COLUMN_THREAD_NB_COLUMNS); - for(int i=0;ipeerTreeWidget->isColumnHidden(i); col_sizes[i] = ui->peerTreeWidget->columnWidth(i); } -#ifdef DEBUG_NEW_FRIEND_LIST - std::cerr << "Applying predicate..." << std::endl; -#endif + // 5. Detach the model from the view + // This "hack" prevents crashes on some platforms (like Windows) during deep data updates mProxyModel->setSourceModel(nullptr); + // 6. Execute the actual data update (the predicate) predicate(); + // 7. Reattach the model and restore expanded items/selection QModelIndex selected_index; mProxyModel->setSourceModel(mModel); - restoreExpandedPathsAndSelection(expanded_indexes,selected,selected_index); + restoreExpandedPathsAndSelection(expanded_indexes, selected, selected_index); - // restore hidden columns - for(uint32_t i=0;ipeerTreeWidget->setColumnHidden(i,!col_visible[i]); - ui->peerTreeWidget->setColumnWidth(i,col_sizes[i]); + ui->peerTreeWidget->setColumnHidden(i, !col_visible[i]); + ui->peerTreeWidget->setColumnWidth(i, col_sizes[i]); } - // restore sorting - // sortColumn(mLastSortColumn,mLastSortOrder); -#ifdef DEBUG_NEW_FRIEND_LIST - std::cerr << "Sorting again with sort column: " << mLastSortColumn << " and order " << mLastSortOrder << std::endl; -#endif + // 9. Re-apply the current sorting to the list mProxyModel->setSortingEnabled(true); - mProxyModel->sort(mLastSortColumn,mLastSortOrder); + mProxyModel->sort(mLastSortColumn, mLastSortOrder); mProxyModel->setSortingEnabled(false); - if(selected_index.isValid()) - ui->peerTreeWidget->scrollTo(selected_index); + // 10. CRITICAL FIX: Restore the exact scroll position + // We use setValue() instead of scrollTo() to ensure the view stays exactly where it was, + // even if a friend connects/disconnects outside of the visible area. + ui->peerTreeWidget->verticalScrollBar()->setValue(scrollValue); } void NewFriendList::sortColumn(int col,Qt::SortOrder so) diff --git a/retroshare-gui/src/gui/common/NewFriendList.h b/retroshare-gui/src/gui/common/NewFriendList.h index 0f3b9dda3..a2f7c2a24 100644 --- a/retroshare-gui/src/gui/common/NewFriendList.h +++ b/retroshare-gui/src/gui/common/NewFriendList.h @@ -30,6 +30,7 @@ #include "FriendListModel.h" #include "retroshare/rsstatus.h" #include "util/FontSizeHandler.h" +#include namespace Ui { class NewFriendList; diff --git a/retroshare-gui/src/gui/common/RsCollectionDialog.cpp b/retroshare-gui/src/gui/common/RsCollectionDialog.cpp index 97464645a..8352597b4 100644 --- a/retroshare-gui/src/gui/common/RsCollectionDialog.cpp +++ b/retroshare-gui/src/gui/common/RsCollectionDialog.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #define COLUMN_FILE 0 #define COLUMN_FILEPATH 1 @@ -54,12 +55,12 @@ #define ROLE_FILEC Qt::UserRole + 6 #define ROLE_SELFILEC Qt::UserRole + 7 -#define MAX_FILE_ADDED_BEFORE_ASK 500 //Number of file added in Recursive mode before asking to continue +#define MAX_FILE_ADDED_BEFORE_ASK 500 //Number of files added in Recursive mode before asking to continue #define IMAGE_SEARCH ":/icons/svg/magnifying-glass.svg" /** - * @brief The FSMSortFilterProxyModel class sort directory before file. + * @brief The FSMSortFilterProxyModel class sorts directories before files. */ class FSMSortFilterProxyModel : public QSortFilterProxyModel { @@ -97,21 +98,20 @@ protected: return asc; - /*If sorting by Size (Take real size, not Display one 10<2)*/ + /*If sorting by Size (Take real size, not Display string)*/ if ((sortColumn()==1) && (!leftFileInfo.isDir() && !rightFileInfo.isDir())) { if (leftFileInfo.size() < rightFileInfo.size()) return true; if (leftFileInfo.size() > rightFileInfo.size()) return false; } - /*If sorting by Date Modified (Take real date, not Display one 01-10-2014<02-01-1980)*/ + /*If sorting by Date Modified (Take real date, not Display string)*/ if (sortColumn()==3) { if (leftFileInfo.lastModified() < rightFileInfo.lastModified()) return true; if (leftFileInfo.lastModified() > rightFileInfo.lastModified()) return false; } - //Columns found here:https://qt.gitorious.org/qt/qt/source/9e8abb63ba4609887d988ee15ba6daee0b01380e:src/gui/dialogs/qfilesystemmodel.cpp return QSortFilterProxyModel::lessThan(left, right); } @@ -121,11 +121,10 @@ protected: /** * @brief RsCollectionDialog::RsCollectionDialog * @param collectionFileName: Filename of RSCollection saved - * @param creation: Open dialog as RsColl Creation or RsColl DownLoad - * @param readOnly: Open dialog for RsColl as ReadOnly + * @param mode: Open dialog as RsColl Creation or RsColl DownLoad */ RsCollectionDialog::RsCollectionDialog(const QString& collectionFileName, RsCollectionDialogMode mode) - : _mode(mode) + : _mode(mode), _dirModel(nullptr), _tree_proxyModel(nullptr), _selectionProxy(nullptr) { RsCollection::RsCollectionErrorCode err_code; mCollection = new RsCollection(collectionFileName,err_code); @@ -140,11 +139,12 @@ RsCollectionDialog::RsCollectionDialog(const QString& collectionFileName, RsColl } RsCollectionDialog::RsCollectionDialog(const RsCollection& coll, RsCollectionDialogMode mode) - : _mode(mode) + : _mode(mode), _dirModel(nullptr), _tree_proxyModel(nullptr), _selectionProxy(nullptr) { mCollection = new RsCollection(coll); init(QString()); } + void RsCollectionDialog::init(const QString& collectionFileName) { ui.setupUi(this) ; @@ -209,21 +209,32 @@ void RsCollectionDialog::init(const QString& collectionFileName) connect(ui._download_PB, SIGNAL(clicked()), this, SLOT(download())); connect(ui._hashBox, SIGNAL(fileHashingFinished(QList)), this, SLOT(fileHashingFinished(QList))); - // 3 Initialize List - _dirModel = new QFileSystemModel(this); - _dirModel->setRootPath("/"); - _dirModel->setFilter(QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot); - _dirLoaded = false; - connect(_dirModel, SIGNAL(directoryLoaded(QString)), this, SLOT(directoryLoaded(QString))); + // 3 Initialize Local System List ONLY in EDIT mode + if (_mode == EDIT) + { + _dirModel = new QFileSystemModel(this); + _dirModel->setRootPath(QDir::homePath()); + _dirModel->setFilter(QDir::AllEntries | QDir::NoSymLinks | QDir::NoDotAndDotDot); + _dirLoaded = false; + connect(_dirModel, SIGNAL(directoryLoaded(QString)), this, SLOT(directoryLoaded(QString))); - _tree_proxyModel = new FSMSortFilterProxyModel(this); - _tree_proxyModel->setSourceModel(_dirModel); - _tree_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); - _tree_proxyModel->setSortRole(Qt::DisplayRole); + _tree_proxyModel = new FSMSortFilterProxyModel(this); + _tree_proxyModel->setSourceModel(_dirModel); + _tree_proxyModel->setSortCaseSensitivity(Qt::CaseInsensitive); + _tree_proxyModel->setSortRole(Qt::DisplayRole); - ui._systemFileTW->setModel(_tree_proxyModel); - //Selection Setup - _selectionProxy = ui._systemFileTW->selectionModel(); + ui._systemFileTW->setModel(_tree_proxyModel); + _selectionProxy = ui._systemFileTW->selectionModel(); + + ui._systemFileTW->installEventFilter(this); + } + else + { + _dirModel = nullptr; + _tree_proxyModel = nullptr; + _selectionProxy = nullptr; + _dirLoaded = true; + } // 4 Restore Configuration // load settings @@ -236,8 +247,6 @@ void RsCollectionDialog::init(const QString& collectionFileName) ui._treeViewFrame->setVisible(_mode == EDIT); ui._download_PB->setVisible(_mode == DOWNLOAD); - ui._systemFileTW->installEventFilter(this); - // 6 Add HashBox setAcceptDrops(true); ui._hashBox->setDropWidget(this); @@ -306,7 +315,7 @@ void RsCollectionDialog::processSettings(bool bLoad) // load settings if(_mode == EDIT){ - // Load windows geometrie + // Load windows geometry restoreGeometry(Settings->value("WindowGeometrie_CM").toByteArray()); // Load splitters state ui._mainSplitter->restoreState(Settings->value("MainSplitterState_CM").toByteArray()); @@ -316,7 +325,7 @@ void RsCollectionDialog::processSettings(bool bLoad) // Load file entries header configuration ui._fileEntriesTW->header()->restoreState(Settings->value("FileEntriesHeader_CM").toByteArray()); } else { - // Load windows geometrie + // Load windows geometry restoreGeometry(Settings->value("WindowGeometrie").toByteArray()); // Load splitters state ui._mainSplitter->restoreState(Settings->value("MainSplitterState").toByteArray()); @@ -328,7 +337,7 @@ void RsCollectionDialog::processSettings(bool bLoad) } } else { if(_mode == EDIT){ - // Save windows geometrie + // Save windows geometry Settings->setValue("WindowGeometrie_CM",saveGeometry()); // Save splitters state Settings->setValue("MainSplitterState_CM", ui._mainSplitter->saveState()); @@ -338,7 +347,7 @@ void RsCollectionDialog::processSettings(bool bLoad) // Save file entries header configuration Settings->setValue("FileEntriesHeader_CM", ui._fileEntriesTW->header()->saveState()); } else { - // Save windows geometrie + // Save windows geometry Settings->setValue("WindowGeometrie",saveGeometry()); // Save splitter state Settings->setValue("MainSplitterState", ui._mainSplitter->saveState()); @@ -359,6 +368,8 @@ void RsCollectionDialog::processSettings(bool bLoad) */ void RsCollectionDialog::directoryLoaded(QString dirLoaded) { + if(!_dirModel) return; + if(!_dirLoaded) { @@ -545,13 +556,15 @@ static void recursBuildFileTree(const QString& path,RsFileTree& tree,RsFileTree: } /** * @brief RsCollectionDialog::addRecursive: Add Selected item to RSCollection - * -Add File seperatly if parent folder not selected - * -Add File in folder if selected - * -Get root folder the selected one + * -Add File seperatly if parent folder not selected + * -Add File in folder if selected + * -Get root folder the selected one * @param recursive: If true, add all selected directory childrens */ void RsCollectionDialog::addSelection(bool recursive) { + if(!_dirModel) return; + QMap dirToAdd; QModelIndexList milSelectionList = ui._systemFileTW->selectionModel()->selectedIndexes(); @@ -599,7 +612,6 @@ void RsCollectionDialog::addSelection(bool recursive) void RsCollectionDialog::remove() { QMap dirToRemove; - int count=0;//to not scan all items on list .count() QModelIndexList milSelectionList = ui._fileEntriesTW->selectionModel()->selectedIndexes(); @@ -654,7 +666,7 @@ void RsCollectionDialog::makeDir() /** * @brief RsCollectionDialog::fileHashingFinished: Connected to ui._hashBox.fileHashingFinished - * Add finished File to collection in respective directory + * Add finished File to collection in respective directory * @param hashedFiles: List of the file finished */ void RsCollectionDialog::fileHashingFinished(QList hashedFiles) @@ -772,10 +784,15 @@ void RsCollectionDialog::download() continue; if(mb.clickedButton() == btnCorrectAll) + { auto_correct = true; - } + } - std::cerr << "Requesting file " << corrected_name << " to directory " << path << std::endl; + if(mb.clickedButton() == btnCorrect) + { + auto_correct = false; // logic placeholder + } + } rsFiles->FileRequest(corrected_name,f.hash,f.size,path,RS_FILE_REQ_ANONYMOUS_ROUTING,std::list()); } @@ -801,12 +818,12 @@ void RsCollectionDialog::save() close(); } -bool RsCollectionDialog::editExistingCollection(const QString& fileName, bool showError /* = true*/) +bool RsCollectionDialog::editExistingCollection(const QString& fileName, bool /*showError*/) { return RsCollectionDialog(fileName,EDIT).exec(); } -bool RsCollectionDialog::openExistingCollection(const QString& fileName, bool showError /* = true*/) +bool RsCollectionDialog::openExistingCollection(const QString& fileName, bool /*showError*/) { return RsCollectionDialog(fileName,DOWNLOAD).exec(); } @@ -845,6 +862,11 @@ bool RsCollectionDialog::openNewCollection(const RsFileTree& tree) if (mb.clickedButton()==btnCancel) return false; + + if (mb.clickedButton()==btnOwerWrite) + { + // Proceed to overwrite + } } if(!collection.save(fileName)) @@ -852,4 +874,3 @@ bool RsCollectionDialog::openNewCollection(const RsFileTree& tree) return RsCollectionDialog(fileName,EDIT).exec(); } - diff --git a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp index a6c729862..d3c1f6613 100644 --- a/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp +++ b/retroshare-gui/src/gui/statistics/GxsTransportStatistics.cpp @@ -33,6 +33,7 @@ #include #include #include +#include // Required for thread safety check #include #include @@ -452,42 +453,35 @@ void GxsTransportStatistics::loadGroupStats(const RsGxsGroupId& groupId) } #endif - void GxsTransportStatistics::loadGroups() { - mStateHelper->setLoading(GXSTRANS_GROUP_META, true); + mStateHelper->setLoading(GXSTRANS_GROUP_META, true); - RsThread::async([this]() - { - // 1 - get message data from p3GxsForums + /* Perform the statistics retrieval in a background thread to avoid UI lag */ + RsThread::async([this]() + { + /* Temporary storage for statistics retrieved from the GXS transport service */ + auto stats = new std::map(); -#ifdef DEBUG_FORUMS - std::cerr << "Retrieving post data for post " << mThreadId << std::endl; -#endif - auto stats = new std::map(); - - if(!rsGxsTrans->getGroupStatistics(*stats)) - { - RS_ERR("Cannot retrieve group statistics in GxsTransportStatistics"); + if(!rsGxsTrans->getGroupStatistics(*stats)) + { + RS_ERR("Cannot retrieve group statistics in GxsTransportStatistics"); delete stats; - return; - } + return; + } - RsQThreadUtils::postToObject( [stats, this]() - { - /* Here it goes any code you want to be executed on the Qt Gui - * thread, for example to update the data model with new information - * after a blocking call to RetroShare API complete */ - - // TODO: consider making mGroupStats an unique_ptr to avoid copying - mGroupStats = *stats; - updateContent(); - mStateHelper->setLoading(GXSTRANS_GROUP_META, false); + /* Switch back to the GUI thread to update the display components */ + RsQThreadUtils::postToObject([stats, this]() + { + /* Update the local cache and refresh the tree widgets. + * Since StatisticsWindow is no longer destroyed on close, + * 'this' is guaranteed to be valid here. */ + mGroupStats = *stats; + updateContent(); + mStateHelper->setLoading(GXSTRANS_GROUP_META, false); delete stats; - }, this ); - + }, this); }); } - diff --git a/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp b/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp index 684fdc69d..a277ddb90 100644 --- a/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp +++ b/retroshare-gui/src/gui/statistics/StatisticsWindow.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -73,8 +74,14 @@ void StatisticsWindow::showYourself() mInstance = new StatisticsWindow(); } + /* Ensure the window is visible and restored if minimized */ + if (mInstance->isMinimized()) { + mInstance->showNormal(); + } + mInstance->show(); - mInstance->activateWindow(); + mInstance->raise(); /* Bring to front */ + mInstance->activateWindow(); /* Give focus */ } StatisticsWindow* StatisticsWindow::getInstance() @@ -91,23 +98,25 @@ void StatisticsWindow::releaseInstance() /********************************************** STATIC WINDOW *************************************/ - - StatisticsWindow::StatisticsWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::StatisticsWindow) { ui->setupUi(this); - Settings->loadWidgetInformation(this); - + Settings->loadWidgetInformation(this); + + // Ensure the window is NOT destroyed on close to preserve temporal curves + // and avoid async race conditions. + this->setAttribute(Qt::WA_DeleteOnClose, false); + initStackedPage(); connect(ui->stackPages, SIGNAL(currentChanged(int)), this, SLOT(setNewPage(int))); ui->stackPages->setCurrentIndex(0); - int toolSize = Settings->getToolButtonSize(); - ui->toolBar->setToolButtonStyle(Settings->getToolButtonStyle()); - ui->toolBar->setIconSize(QSize(toolSize,toolSize)); - setWindowTitle("RetroShare Statistics - " + MainWindow::getInstance()->get_nameAndLocation()); + int toolSize = Settings->getToolButtonSize(); + ui->toolBar->setToolButtonStyle(Settings->getToolButtonStyle()); + ui->toolBar->setIconSize(QSize(toolSize,toolSize)); + setWindowTitle("RetroShare Statistics - " + MainWindow::getInstance()->get_nameAndLocation()); } StatisticsWindow::~StatisticsWindow() @@ -228,3 +237,15 @@ void StatisticsWindow::setNewPage(int page) ui->stackPages->setCurrentIndex(page); } } + +void StatisticsWindow::keyPressEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Escape) { + // Just call close(), which will hide the window without destroying + // the static instance or resetting statistics data. + this->close(); + } else { + QMainWindow::keyPressEvent(event); + } +} + diff --git a/retroshare-gui/src/gui/statistics/StatisticsWindow.h b/retroshare-gui/src/gui/statistics/StatisticsWindow.h index 2450812d7..47635377f 100644 --- a/retroshare-gui/src/gui/statistics/StatisticsWindow.h +++ b/retroshare-gui/src/gui/statistics/StatisticsWindow.h @@ -66,7 +66,8 @@ public slots: protected: void changeEvent(QEvent *e); - void closeEvent (QCloseEvent * event); + void closeEvent (QCloseEvent * event); + void keyPressEvent(QKeyEvent *event) override; private: void initStackedPage();