1 #ifndef REMOTEMODEL_H
2 #define REMOTEMODEL_H
3 
4 #include <QAbstractItemModel>
5 #include <QUrl>
6 
7 #include <json.hpp>
8 
9 // List of fields stored in the JSON data
10 enum RemoteModelColumns
11 {
12     RemoteModelColumnName,
13     RemoteModelColumnType,
14     RemoteModelColumnUrl,
15     RemoteModelColumnCommitId,
16     RemoteModelColumnSize,
17     RemoteModelColumnLastModified,
18     RemoteModelColumnDefaultBranch,
19     RemoteModelColumnLicence,
20     RemoteModelColumnOneLineDescription,
21     RemoteModelColumnPublic,
22     RemoteModelColumnRepoModified,
23     RemoteModelColumnSha256,
24 
25     RemoteModelColumnCount
26 };
27 
28 class RemoteModelItem
29 {
30 public:
31     explicit RemoteModelItem(RemoteModelItem* parent = nullptr);
32     ~RemoteModelItem();
33 
34     QVariant value(RemoteModelColumns column) const;
35     void setValue(RemoteModelColumns column, QVariant value);
36 
37     bool fetchedDirectoryList() const;
38     void setFetchedDirectoryList(bool fetched);
39 
40     void appendChild(RemoteModelItem* item);
41     RemoteModelItem* child(int row) const;
42     RemoteModelItem* parent() const;
43     int childCount() const;
44     int row() const;
45 
46     // This function assumes the JSON value it's getting passed is an array ("[{...}, {...}, {...}, ...]"). It returns a list of model items, one
47     // per array entry and each with the specified parent set.
48     static std::vector<RemoteModelItem*> loadArray(const nlohmann::json& array, RemoteModelItem* parent = nullptr);
49 
50 private:
51     // These are just the fields from the json objects returned by the dbhub.io server
52     QVariant m_values[RemoteModelColumnCount];
53 
54     // Child items and parent item
55     std::vector<RemoteModelItem*> m_children;
56     RemoteModelItem* m_parent;
57 
58     // Indicates whether we already tried fetching a directory listing for this item. This serves two purposes:
59     // 1) When having an empty directory this allows us to remove the expandable flag for this item.
60     // 2) Between sending a network request and getting the reply this flag is already set, avoiding a second or third request being sent in the meantime.
61     bool m_fetchedDirectoryList;
62 };
63 
64 class RemoteModel : public QAbstractItemModel
65 {
66     Q_OBJECT
67 
68 public:
69     explicit RemoteModel(QObject* parent);
70     ~RemoteModel() override;
71 
72     void setNewRootDir(const QString& url, const QString& cert);
73     void refresh();
74 
75     QModelIndex index(int row, int column,const QModelIndex& parent = QModelIndex()) const override;
76     QModelIndex parent(const QModelIndex& index) const override;
77 
78     QVariant data(const QModelIndex& index, int role) const override;
79     QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
80 
81     int rowCount(const QModelIndex& parent = QModelIndex()) const override;
82     int columnCount(const QModelIndex& parent = QModelIndex()) const override;
83     bool hasChildren(const QModelIndex& parent) const override;
84 
85     bool canFetchMore(const QModelIndex& parent) const override;
86     void fetchMore(const QModelIndex& parent) override;
87 
88     // This helper function takes a model index and returns the according model item. An invalid model index is used to indicate the
89     // root item, so if the index is invalid the root item is returned. This means that if you need to check for actual invalid indices
90     // this needs to be done prior to calling this function.
91     const RemoteModelItem* modelIndexToItem(const QModelIndex& idx) const;
92 
93     // Returns the current client certificate
94     const QString& currentClientCertificate() const;
95 
96 signals:
97     // This signal is emitted whenever a directory listing has been received and parsed
98     void directoryListingParsed(QModelIndex parent);
99 
100 private slots:
101     // This is called whenever a network reply containing a directory listing arrives
102     void parseDirectoryListing(const QString& text, QModelIndex parent);
103 
104 private:
105     // The header list is a list of column titles
106     const std::vector<QString> headerList;
107 
108     // Pointer to the root item. This contains all the actual item data.
109     RemoteModelItem* rootItem;
110 
111     // This stores the currently used network identity so it can be used for further requests, e.g. for
112     // lazy population.
113     QUrl currentRootDirectory;
114     QString currentClientCert;
115     QString currentUserName;
116 };
117 
118 #endif
119