mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	Use QFileSystemWatcher to reload the game list when a change is detected. (#2555)
* Added a refresh game directory option to the file menu * Make the game list watcher recursive and have it start watching from the initial load * Rework game list watcher to be thread safe * Fix code style issues
This commit is contained in:
		
							parent
							
								
									4dee08b343
								
							
						
					
					
						commit
						26823cd38b
					
				
					 2 changed files with 51 additions and 1 deletions
				
			
		|  | @ -39,6 +39,7 @@ GameList::GameList(QWidget* parent) : QWidget{parent} { | |||
| 
 | ||||
|     connect(tree_view, &QTreeView::activated, this, &GameList::ValidateEntry); | ||||
|     connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu); | ||||
|     connect(&watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); | ||||
| 
 | ||||
|     // We must register all custom types with the Qt Automoc system so that we are able to use it
 | ||||
|     // with signals/slots. In this case, QList falls under the umbrells of custom types.
 | ||||
|  | @ -103,6 +104,12 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { | |||
|     item_model->removeRows(0, item_model->rowCount()); | ||||
| 
 | ||||
|     emit ShouldCancelWorker(); | ||||
| 
 | ||||
|     auto watch_dirs = watcher.directories(); | ||||
|     if (!watch_dirs.isEmpty()) { | ||||
|         watcher.removePaths(watch_dirs); | ||||
|     } | ||||
|     UpdateWatcherList(dir_path.toStdString(), deep_scan ? 256 : 0); | ||||
|     GameListWorker* worker = new GameListWorker(dir_path, deep_scan); | ||||
| 
 | ||||
|     connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); | ||||
|  | @ -140,6 +147,45 @@ static bool HasSupportedFileExtension(const std::string& file_name) { | |||
|     return GameList::supported_file_extensions.contains(file.suffix(), Qt::CaseInsensitive); | ||||
| } | ||||
| 
 | ||||
| void GameList::RefreshGameDirectory() { | ||||
|     if (!UISettings::values.gamedir.isEmpty() && current_worker != nullptr) { | ||||
|         LOG_INFO(Frontend, "Change detected in the games directory. Reloading game list."); | ||||
|         PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  * Adds the game list folder to the QFileSystemWatcher to check for updates. | ||||
|  * | ||||
|  * The file watcher will fire off an update to the game list when a change is detected in the game | ||||
|  * list folder. | ||||
|  * | ||||
|  * Notice: This method is run on the UI thread because QFileSystemWatcher is not thread safe and | ||||
|  * this function is fast enough to not stall the UI thread. If performance is an issue, it should | ||||
|  * be moved to another thread and properly locked to prevent concurrency issues. | ||||
|  * | ||||
|  * @param dir folder to check for changes in | ||||
|  * @param recursion 0 if recursion is disabled. Any positive number passed to this will add each | ||||
|  *        directory recursively to the watcher and will update the file list if any of the folders | ||||
|  *        change. The number determines how deep the recursion should traverse. | ||||
|  */ | ||||
| void GameList::UpdateWatcherList(const std::string& dir, unsigned int recursion) { | ||||
|     const auto callback = [this, recursion](unsigned* num_entries_out, const std::string& directory, | ||||
|                                             const std::string& virtual_name) -> bool { | ||||
|         std::string physical_name = directory + DIR_SEP + virtual_name; | ||||
| 
 | ||||
|         if (FileUtil::IsDirectory(physical_name)) { | ||||
|             UpdateWatcherList(physical_name, recursion - 1); | ||||
|         } | ||||
|         return true; | ||||
|     }; | ||||
| 
 | ||||
|     watcher.addPath(QString::fromStdString(dir)); | ||||
|     if (recursion > 0) { | ||||
|         FileUtil::ForeachDirectoryEntry(nullptr, dir, callback); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { | ||||
|     const auto callback = [this, recursion](unsigned* num_entries_out, const std::string& directory, | ||||
|                                             const std::string& virtual_name) -> bool { | ||||
|  | @ -182,6 +228,6 @@ void GameListWorker::run() { | |||
| } | ||||
| 
 | ||||
| void GameListWorker::Cancel() { | ||||
|     disconnect(this, nullptr, nullptr, nullptr); | ||||
|     this->disconnect(); | ||||
|     stop_processing = true; | ||||
| } | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <QFileSystemWatcher> | ||||
| #include <QModelIndex> | ||||
| #include <QSettings> | ||||
| #include <QStandardItem> | ||||
|  | @ -46,8 +47,11 @@ private: | |||
|     void DonePopulating(); | ||||
| 
 | ||||
|     void PopupContextMenu(const QPoint& menu_location); | ||||
|     void UpdateWatcherList(const std::string& path, unsigned int recursion); | ||||
|     void RefreshGameDirectory(); | ||||
| 
 | ||||
|     QTreeView* tree_view = nullptr; | ||||
|     QStandardItemModel* item_model = nullptr; | ||||
|     GameListWorker* current_worker = nullptr; | ||||
|     QFileSystemWatcher watcher; | ||||
| }; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue