Skip to content

Commit 8937dae

Browse files
committed
GUI frontend completed
1 parent d5218cf commit 8937dae

File tree

13 files changed

+517
-141
lines changed

13 files changed

+517
-141
lines changed

Sources/AppGUI/Resources/example_applist.json

Lines changed: 0 additions & 14 deletions
This file was deleted.

Sources/AppGUI/Shared.cpp

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#include "Shared.hpp"
2+
3+
#include <QFileInfo>
4+
#include <QStandardPaths>
5+
#include <QJsonDocument>
6+
#include <QJsonArray>
7+
#include <QJsonObject>
8+
9+
#include <fstream>
10+
#include <iostream>
11+
#include <filesystem>
12+
#include <vector>
13+
14+
namespace fs = std::filesystem;
15+
16+
namespace SharedCode {
17+
18+
QIcon FindIcon(const QString &name) {
19+
QIcon icon = QIcon::fromTheme(name);
20+
if (!icon.isNull())
21+
return icon;
22+
23+
QStringList iconPaths = {
24+
"/usr/share/icons/hicolor/48x48/apps/" + name + ".png",
25+
"/usr/share/icons/hicolor/128x128/apps/" + name + ".png",
26+
"/usr/share/icons/hicolor/scalable/apps/" + name + ".svg",
27+
"/usr/share/pixmaps/" + name + ".png"
28+
};
29+
30+
for (const QString &iconPath: iconPaths) {
31+
if (QFileInfo::exists(iconPath))
32+
return QIcon(iconPath);
33+
}
34+
35+
return QIcon::fromTheme("application-x-executable");
36+
}
37+
38+
std::vector<Application> GetAppList() {
39+
std::vector<Application> appList;
40+
41+
QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/RunAsGPU/apps.json";
42+
QFile file(configPath);
43+
44+
if (!file.exists()) {
45+
std::ofstream _file(configPath.toStdString());
46+
if (_file.is_open() && _file.good()) {
47+
_file << "[]" << std::endl;
48+
_file.close();
49+
}
50+
return appList;
51+
}
52+
53+
if (!file.open(QIODevice::ReadOnly)) {
54+
qDebug() << "Failed to open apps.json: " << file.errorString();
55+
return appList;
56+
}
57+
58+
QByteArray jsonData = file.readAll();
59+
file.close();
60+
61+
QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData);
62+
if (!jsonDoc.isArray()) {
63+
qDebug() << "Invalid JSON format!";
64+
return appList;
65+
}
66+
67+
QJsonArray jsonArray = jsonDoc.array();
68+
for (const QJsonValue &value: jsonArray) {
69+
if (!value.isObject()) continue;
70+
71+
QJsonObject jsonObj = value.toObject();
72+
Application app{jsonObj["name"].toString(), jsonObj["desc"].toString(), jsonObj["execPath"].toString(),
73+
jsonObj["icon"].toString()};
74+
75+
appList.push_back(app);
76+
}
77+
78+
return appList;
79+
}
80+
81+
void SaveAppList(const std::vector<Application> &appList) {
82+
const char *home = getenv("HOME");
83+
if (!home) {
84+
std::cerr << "Failed to get home directory, exiting..." << std::endl;
85+
std::abort();
86+
}
87+
88+
std::string appListPath = std::string(home) + "/.config/RunAsGPU/apps.json";
89+
if (!fs::exists(fs::path(appListPath).parent_path()))
90+
fs::create_directory(fs::path(appListPath).parent_path());
91+
92+
QJsonArray jsonArr;
93+
for (const auto &app: appList) {
94+
QJsonObject obj;
95+
QString executor = app.execPath.split(' ')[0];
96+
if (executor.isEmpty()) continue;
97+
98+
if (executor.startsWith('\"'))
99+
executor = executor.mid(1, executor.length());
100+
101+
if (executor.endsWith('\"'))
102+
executor = executor.left(executor.length() - 1);
103+
104+
obj["name"] = app.name;
105+
obj["description"] = app.description;
106+
obj["execPath"] = executor;
107+
obj["icon"] = app.iconStr.isEmpty() ? QJsonValue(QJsonValue::Null) : app.iconStr;
108+
109+
jsonArr.append(obj);
110+
}
111+
112+
QJsonDocument doc(jsonArr);
113+
QString configPath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/RunAsGPU/apps.json";
114+
QFile file(configPath);
115+
116+
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
117+
qDebug() << "Failed to save apps.json:" << file.errorString();
118+
return;
119+
}
120+
121+
file.write(doc.toJson(QJsonDocument::Indented));
122+
file.close();
123+
}
124+
125+
}

Sources/AppGUI/SharedData/IconFinder.hpp

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#ifndef RUNASGPU_SHARED_HPP
2+
#define RUNASGPU_SHARED_HPP
3+
4+
#include <QIcon>
5+
#include <QString>
6+
7+
#include "../UI/Model/AppListModel.hpp"
8+
9+
namespace SharedCode {
10+
11+
QIcon FindIcon(const QString &iconName);
12+
13+
std::vector<Application> GetAppList();
14+
15+
void SaveAppList(const std::vector<Application> &appList);
16+
17+
}
18+
19+
#endif //RUNASGPU_SHARED_HPP

Sources/AppGUI/UI/AppRemoval.cpp

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#include "AppRemoval.hpp"
2+
#include "Model/AppListDelegate.hpp"
3+
4+
#include <Shared.hpp>
5+
#include <iostream>
6+
7+
std::vector<Application> Ui::appsForRemoval;
8+
9+
AppListModel *modelAppList0;
10+
AppListDelegate *delegateAppList0;
11+
12+
std::vector<QString> rSelectedApps;
13+
std::vector<Application> rFilteredApps, rApps;
14+
15+
void Ui_AppRemovalDialog::performLogic() const {
16+
self->setFixedSize(self->size());
17+
18+
modelAppList0 = new AppListModel(appListView);
19+
delegateAppList0 = new AppListDelegate(appListView);
20+
21+
self->setFixedSize(self->size());
22+
23+
appListView->setModel(modelAppList0);
24+
appListView->setItemDelegate(delegateAppList0);
25+
appListView->setViewMode(QListView::ListMode);
26+
appListView->setUniformItemSizes(true);
27+
appListView->setSpacing(5);
28+
appListView->setSelectionMode(QAbstractItemView::MultiSelection);
29+
appListView->setEditTriggers(QAbstractItemView::NoEditTriggers);
30+
appListView->setFocusPolicy(Qt::StrongFocus);
31+
32+
rApps = SharedCode::GetAppList();
33+
for (const auto &app: rApps)
34+
modelAppList0->addItem(app);
35+
36+
QObject::connect(filterBox, &QLineEdit::textChanged, self, [&](const QString &text) {
37+
QItemSelectionModel *selectionModel = appListView->selectionModel();
38+
39+
rFilteredApps.clear();
40+
for (const auto &app: rApps) {
41+
if (app.name.contains(text, Qt::CaseInsensitive))
42+
rFilteredApps.push_back(app);
43+
}
44+
45+
modelAppList0->clear();
46+
for (const auto &app: rFilteredApps)
47+
modelAppList0->addItem(app);
48+
49+
// restore selections
50+
for (int i = 0; i < modelAppList0->rowCount(); i++) {
51+
QModelIndex index = modelAppList0->index(i, 0);
52+
QString appName = modelAppList0->data(index, Qt::DisplayRole).toString();
53+
if (std::find(rSelectedApps.begin(), rSelectedApps.end(), appName) != rSelectedApps.end())
54+
selectionModel->select(index, QItemSelectionModel::Select);
55+
}
56+
});
57+
58+
QObject::connect(appListView->selectionModel(), &QItemSelectionModel::selectionChanged, self,
59+
[&](const QItemSelection &selected, const QItemSelection &deselected) {
60+
for (const QModelIndex &index: selected.indexes()) {
61+
QString selectedName = modelAppList0->data(index, Qt::DisplayRole).toString();
62+
63+
auto it = std::find_if(rSelectedApps.begin(), rSelectedApps.end(),
64+
[&](const QString &appName) {
65+
return appName == selectedName;
66+
});
67+
68+
if (it == rSelectedApps.end()) {
69+
auto appIt = std::find_if(rApps.begin(), rApps.end(), [&](const Application &app) {
70+
return app.name == selectedName;
71+
});
72+
73+
if (appIt != rApps.end())
74+
rSelectedApps.push_back(selectedName);
75+
}
76+
}
77+
78+
for (const QModelIndex &index: deselected.indexes()) {
79+
QString deselectedName = modelAppList0->data(index, Qt::DisplayRole).toString();
80+
81+
rSelectedApps.erase(std::remove_if(rSelectedApps.begin(), rSelectedApps.end(),
82+
[&](const QString &appName) {
83+
return appName == deselectedName;
84+
}), rSelectedApps.end());
85+
}
86+
});
87+
88+
QObject::connect(buttonBox, &QDialogButtonBox::clicked, self, [&](QAbstractButton *button) {
89+
if (buttonBox->standardButton(button) != QDialogButtonBox::Apply)
90+
return;
91+
92+
Ui::appsForRemoval.clear();
93+
94+
for (const QString &index: rSelectedApps) {
95+
auto it = std::find_if(rApps.begin(), rApps.end(), [&](const Application &app) {
96+
return app.name == index;
97+
});
98+
99+
if (it != rApps.end()) {
100+
Ui::appsForRemoval.push_back(*it);
101+
}
102+
}
103+
104+
appListView->selectionModel()->clearSelection();
105+
self->accept();
106+
});
107+
108+
QObject::connect(buttonBox, &QDialogButtonBox::rejected, self, [&]() {
109+
self->reject();
110+
});
111+
}

Sources/AppGUI/UI/AppRemoval.hpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
#ifndef AppRemoval_HPP
2+
#define AppRemoval_HPP
3+
4+
#include "Model/AppListModel.hpp"
5+
6+
#include <QtCore/QVariant>
7+
#include <QtWidgets/QAbstractButton>
8+
#include <QtWidgets/QApplication>
9+
#include <QtWidgets/QDialog>
10+
#include <QtWidgets/QDialogButtonBox>
11+
#include <QtWidgets/QLabel>
12+
#include <QtWidgets/QLineEdit>
13+
#include <QtWidgets/QListView>
14+
15+
QT_BEGIN_NAMESPACE
16+
17+
class Ui_AppRemovalDialog {
18+
public:
19+
QDialog *self;
20+
QDialogButtonBox *buttonBox;
21+
QLabel *labelFilter;
22+
QLineEdit *filterBox;
23+
QListView *appListView;
24+
25+
void setupUi(QDialog *AppRemovalDialog) {
26+
if (AppRemovalDialog->objectName().isEmpty())
27+
AppRemovalDialog->setObjectName("AppRemovalDialog");
28+
AppRemovalDialog->resize(491, 377);
29+
self = AppRemovalDialog;
30+
buttonBox = new QDialogButtonBox(AppRemovalDialog);
31+
buttonBox->setObjectName("buttonBox");
32+
buttonBox->setGeometry(QRect(140, 330, 341, 32));
33+
buttonBox->setOrientation(Qt::Orientation::Horizontal);
34+
buttonBox->setStandardButtons(
35+
QDialogButtonBox::StandardButton::Apply | QDialogButtonBox::StandardButton::Close);
36+
labelFilter = new QLabel(AppRemovalDialog);
37+
labelFilter->setObjectName("labelFilter");
38+
labelFilter->setGeometry(QRect(10, 285, 41, 18));
39+
filterBox = new QLineEdit(AppRemovalDialog);
40+
filterBox->setObjectName("filterBox");
41+
filterBox->setGeometry(QRect(60, 280, 421, 32));
42+
appListView = new QListView(AppRemovalDialog);
43+
appListView->setObjectName("appListView");
44+
appListView->setGeometry(QRect(10, 10, 471, 261));
45+
46+
retranslateUi(AppRemovalDialog);
47+
48+
QMetaObject::connectSlotsByName(AppRemovalDialog);
49+
performLogic();
50+
} // setupUi
51+
52+
void retranslateUi(QDialog *AppRemovalDialog) {
53+
AppRemovalDialog->setWindowTitle(QCoreApplication::translate("AppRemovalDialog", "Remove Apps", nullptr));
54+
labelFilter->setText(QCoreApplication::translate("AppRemovalDialog", "Filter:", nullptr));
55+
filterBox->setPlaceholderText(QCoreApplication::translate("AppRemovalDialog", "Application Name", nullptr));
56+
} // retranslateUi
57+
58+
void performLogic() const;
59+
60+
};
61+
62+
namespace Ui {
63+
64+
extern std::vector<Application> appsForRemoval;
65+
66+
class AppRemovalDialog : public Ui_AppRemovalDialog {
67+
};
68+
} // namespace Ui
69+
70+
QT_END_NAMESPACE
71+
72+
#endif // AppRemoval_HPP

0 commit comments

Comments
 (0)