1// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd.
2//
3// SPDX-License-Identifier: GPL-3.0-or-later
4
5#include "recentdisplay.h"
6
7#include "displayrecentview.h"
8
9#include <QList>
10#include <QDir>
11#include <QStandardItemModel>
12#include <QListView>
13#include <QHBoxLayout>
14#include <QJsonDocument>
15
16static RecentDisplay *ins{nullptr};
17
18class DisplayProView : public DisplayRecentView
19{
20 QJsonArray projects;
21public:
22 explicit DisplayProView(QWidget *parent = nullptr)
23 : DisplayRecentView(parent)
24 {
25 load();
26 }
27
28 virtual QString title() override
29 {
30 return tr("Projects");
31 }
32
33 virtual QList<QStandardItem*> itemsFromFile() override
34 {
35 QJsonDocument doc = readRecent();
36 QJsonObject obj = doc.object();
37 QJsonArray array = obj.value(title()).toArray();
38 QList<QStandardItem*> result;
39 QStringList paths = cachedWorkspaces(projects);
40 for (auto val : array) {
41 auto elemObj = val.toObject();
42 QString language, workspace, kitName;
43 QString file = projectFile(elemObj, &kitName, &language, &workspace);
44 if (file.isEmpty() || !QFileInfo(file).exists())
45 continue;
46 auto rowItem = new QStandardItem (icon(file), file);
47 rowItem->setData(kitName, RecentDisplay::ProjectKitName);
48 rowItem->setData(language, RecentDisplay::ProjectLanguage);
49 rowItem->setData(workspace, RecentDisplay::ProjectWorkspace);
50 rowItem->setToolTip( "KitName: " + kitName + "\n" +
51 "Language: " + language + "\n" +
52 "Workspace: " + workspace );
53 if (!paths.contains(file))
54 projects << val;
55 result << rowItem;
56 }
57 return result;
58 }
59
60 virtual void load() override
61 {
62 model->appendColumn(itemsFromFile());
63 }
64
65 virtual void add(const QString &kitName,
66 const QString &language,
67 const QString &workspace)
68 {
69 model->clear(); //删除数据
70 auto paths = cachedWorkspaces(projects);
71 for (auto path : paths) {
72 if (!QFileInfo(path).exists()) {
73 removeProjectElem(projects, path);
74 }
75 }
76 if (paths.contains(workspace)) {
77 removeProjectElem(projects, workspace);
78 }
79 projects.insert(0, projectElem(kitName, language, workspace)); //置顶
80 saveToFile(projects); //保存序列
81 load(); //重新加载文件
82 }
83
84 virtual QString projectFile(const QJsonObject &elem,
85 QString *kitName = nullptr,
86 QString *language = nullptr,
87 QString *workspace = nullptr)
88 {
89 if (elem.keys().size() != 1)
90 return {};
91
92 QString file = elem.keys()[0];
93
94 if (file.isEmpty())
95 return {};
96
97 auto propertyObj = elem.value(file).toObject();
98 if (language)
99 *kitName = propertyObj["KitName"].toString();
100
101 if (language)
102 *language = propertyObj["Language"].toString();
103
104 if (workspace)
105 *workspace = propertyObj["Workspace"].toString();
106
107 return file;
108 }
109
110 virtual QJsonObject projectElem(const QString &kitName,
111 const QString &language,
112 const QString &workspace)
113 {
114 QJsonObject elem;
115 QJsonObject propertyVal;
116 propertyVal.insert("KitName", kitName);
117 propertyVal.insert("Language", language);
118 propertyVal.insert("Workspace", workspace);
119 elem.insert(workspace, QJsonValue{propertyVal});
120 return elem;
121 }
122
123 virtual QStringList cachedWorkspaces(const QJsonArray &array)
124 {
125 QStringList list;
126 for (auto val : array){
127 list += val.toObject().keys();
128 }
129 return list;
130 }
131
132 virtual void removeProjectElem(QJsonArray &array, const QString &path)
133 {
134 if (path.isEmpty())
135 return;
136
137 for (int i = 0; i < array.size(); i++) {
138 auto keys = array[i].toObject().keys();
139 if (keys.size() != 1)
140 continue;
141
142 QString currPath = keys[0];
143 if (currPath.isEmpty()) {
144 return;
145 }
146 if (currPath == path) {
147 array.removeAt(i);
148 }
149 }
150 }
151
152 virtual void saveToFile(const QJsonArray &array)
153 {
154 QJsonDocument doc = readRecent();
155 QJsonObject docObj = doc.object();
156 docObj[title()] = array;
157 doc.setObject(docObj);
158
159 QFile file(cachePath());
160 if (file.open(QFile::WriteOnly)) {
161 file.write(doc.toJson());
162 file.close();
163 }
164 }
165};
166
167class DisplayDocView : public DisplayRecentView
168{
169public:
170 explicit DisplayDocView(QWidget *parent = nullptr)
171 : DisplayRecentView(parent){
172 load();
173 }
174
175 virtual QString title() override
176 {
177 return tr("Documents");
178 }
179};
180
181class RecentDisplayPrivate
182{
183 friend class RecentDisplay;
184 QHBoxLayout *hLayout{nullptr};
185 QVBoxLayout *vLayoutDoc{nullptr};
186 QVBoxLayout *vLayoutDir{nullptr};
187 DisplayProView *proView{nullptr};
188 DisplayDocView *docView{nullptr};
189 QLabel *dirLabel{nullptr};
190 QLabel *docLabel{nullptr};
191};
192
193RecentDisplay::RecentDisplay(QWidget *parent)
194 : QWidget (parent)
195 , d(new RecentDisplayPrivate())
196{
197 d->docView = new DisplayDocView();
198 d->docView->setMinimumWidth(400);
199 d->docLabel = new QLabel(tr("Documents"));
200 d->vLayoutDoc = new QVBoxLayout();
201 d->vLayoutDoc->setMargin(40);
202 d->vLayoutDoc->addWidget(d->docLabel);
203 d->vLayoutDoc->setSpacing(20);
204 d->vLayoutDoc->addWidget(d->docView);
205 d->vLayoutDoc->setAlignment(d->proView, Qt::AlignRight);
206
207 d->proView = new DisplayProView();
208 d->proView->setMinimumWidth(400);
209 d->dirLabel = new QLabel(tr("Projects"));
210 d->vLayoutDir = new QVBoxLayout();
211 d->vLayoutDir->setMargin(40);
212 d->vLayoutDir->addWidget(d->dirLabel);
213 d->vLayoutDir->setSpacing(20);
214 d->vLayoutDir->addWidget(d->proView);
215 d->vLayoutDir->setAlignment(d->docView, Qt::AlignLeft);
216
217 d->hLayout = new QHBoxLayout();
218 d->hLayout->addStretch();
219 d->hLayout->addLayout(d->vLayoutDir);
220 d->hLayout->addLayout(d->vLayoutDoc);
221 d->hLayout->addStretch();
222 setLayout(d->hLayout);
223
224 QObject::connect(d->proView, &QListView::doubleClicked,
225 this, &RecentDisplay::doDoubleClickedProject,
226 Qt::UniqueConnection);
227
228 QObject::connect(d->docView, &QListView::doubleClicked,
229 this, &RecentDisplay::doDoubleCliekedDocument,
230 Qt::UniqueConnection);
231}
232
233RecentDisplay::~RecentDisplay()
234{
235 if (d) {
236 delete d;
237 }
238}
239
240RecentDisplay *RecentDisplay::instance()
241{
242 if (!ins)
243 ins = new RecentDisplay;
244 return ins;
245}
246
247void RecentDisplay::addDocument(const QString &filePath)
248{
249 d->docView->add(filePath);
250}
251
252void RecentDisplay::addProject(const QString &kitName,
253 const QString &language,
254 const QString &workspace)
255{
256 d->proView->add(kitName, language, workspace);
257}
258
259void RecentDisplay::doDoubleClickedProject(const QModelIndex &index)
260{
261 QString filePath = index.data(Qt::DisplayRole).toString();
262 QString kitName = index.data(ProjectKitName).toString();
263 QString language = index.data(ProjectLanguage).toString();
264 QString workspace = index.data(ProjectWorkspace).toString();
265 // "kitName", "language", "workspace"
266 project.openProject(kitName, language, workspace);
267 RecentDisplay::addProject(kitName, language, workspace);
268}
269
270void RecentDisplay::doDoubleCliekedDocument(const QModelIndex &index)
271{
272 QString filePath = index.data(Qt::DisplayRole).toString();
273 RecentDisplay::addDocument(filePath);
274 editor.openFile(filePath);
275}
276
277