1 // Copyright 2015 Dolphin Emulator Project
2 // Licensed under GPLv2+
3 // Refer to the license.txt file included.
4 
5 #pragma once
6 
7 #include <memory>
8 #include <string>
9 
10 #include <QFileSystemWatcher>
11 #include <QMap>
12 #include <QSet>
13 #include <QString>
14 #include <QVector>
15 
16 #include "Common/Event.h"
17 #include "Common/WorkQueueThread.h"
18 #include "UICommon/GameFileCache.h"
19 
20 namespace UICommon
21 {
22 class GameFile;
23 }
24 
25 // Watches directories and loads GameFiles in a separate thread.
26 // To use this, just add directories using AddDirectory, and listen for the
27 // GameLoaded and GameRemoved signals.
28 class GameTracker final : public QFileSystemWatcher
29 {
30   Q_OBJECT
31 
32 public:
33   explicit GameTracker(QObject* parent = nullptr);
34 
35   // A GameTracker won't emit any signals until this function has been called.
36   // Before you call this function, make sure to call AddDirectory for all
37   // directories you want to track, otherwise games will briefly disappear
38   // until you call AddDirectory and the GameTracker finishes scanning the file system.
39   void Start();
40 
41   void AddDirectory(const QString& dir);
42   void RemoveDirectory(const QString& dir);
43   void RefreshAll();
44   void PurgeCache();
45 
46 signals:
47   void GameLoaded(const std::shared_ptr<const UICommon::GameFile>& game);
48   void GameUpdated(const std::shared_ptr<const UICommon::GameFile>& game);
49   void GameRemoved(const std::string& path);
50 
51 private:
52   void LoadCache();
53   void StartInternal();
54   void UpdateDirectory(const QString& dir);
55   void UpdateFile(const QString& path);
56   void AddDirectoryInternal(const QString& dir);
57   void RemoveDirectoryInternal(const QString& dir);
58   void UpdateDirectoryInternal(const QString& dir);
59   void UpdateFileInternal(const QString& path);
60   QSet<QString> FindMissingFiles(const QString& dir);
61   void LoadGame(const QString& path);
62 
63   bool AddPath(const QString& path);
64   bool RemovePath(const QString& path);
65 
66   enum class CommandType
67   {
68     LoadCache,
69     Start,
70     AddDirectory,
71     RemoveDirectory,
72     UpdateDirectory,
73     UpdateFile,
74     UpdateMetadata,
75     PurgeCache,
76     BeginRefresh,
77     EndRefresh,
78   };
79 
80   struct Command
81   {
82     CommandType type;
83     QString path;
84   };
85 
86   // game path -> directories that track it
87   QMap<QString, QSet<QString>> m_tracked_files;
88   QVector<QString> m_tracked_paths;
89   Common::WorkQueueThread<Command> m_load_thread;
90   UICommon::GameFileCache m_cache;
91   Common::Event m_cache_loaded_event;
92   Common::Event m_initial_games_emitted_event;
93   bool m_initial_games_emitted = false;
94   bool m_started = false;
95   // Count of currently running refresh jobs
96   u32 m_busy_count = 0;
97 };
98 
99 Q_DECLARE_METATYPE(std::shared_ptr<const UICommon::GameFile>)
100 Q_DECLARE_METATYPE(std::string)
101