mainwindow.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. #include <include/mainwindow.h>
  2. #include <QDateTime>
  3. #include <QDebug>
  4. #include <QLayout>
  5. #include <QString>
  6. #include <QTextEdit>
  7. #include <QTextStream>
  8. #include <headers/util.hpp>
  9. #include <vector>
  10. #include "ui_mainwindow.h"
  11. void infoMessageBox(QString text, QString title = "KYGUI") {
  12. QMessageBox box;
  13. box.setWindowTitle(title);
  14. box.setText(text);
  15. box.setButtonText(0, "Close");
  16. box.exec();
  17. }
  18. bool isSameEvent(QString event1, QString event2) {
  19. auto event_size =
  20. event1.size() > event2.size() ? event2.size() : event1.size();
  21. auto similarity_standard = event_size * 0.67;
  22. auto similarity_index = 0;
  23. for (auto i = 0; i < event_size; i++) {
  24. if (event1[i] == event2[i]) {
  25. similarity_index++;
  26. }
  27. }
  28. return similarity_index > similarity_standard;
  29. }
  30. int getLikeEventNum(QString event, QList<QString> events) {
  31. auto i = events.size() - 1;
  32. auto hits = 0;
  33. bool is_same_event = false;
  34. auto incoming_event = event.remove(0, 11);
  35. do {
  36. auto existing_event = events[i];
  37. if (is_same_event =
  38. isSameEvent(incoming_event, existing_event.remove(0, 11))) {
  39. i--;
  40. hits++;
  41. }
  42. } while (is_same_event && i > -1);
  43. return hits;
  44. }
  45. QString getTime() { return QDateTime::currentDateTime().toString("hh:mm:ss"); }
  46. /**
  47. *\mainpage The KYGUI application interface begins with the MainWindow
  48. * @brief MainWindow::MainWindow
  49. * @param argc
  50. * @param argv
  51. * @param parent
  52. */
  53. MainWindow::MainWindow(int argc, char** argv, QWidget* parent)
  54. : QMainWindow(parent),
  55. cli_argc(argc),
  56. cli_argv(argv),
  57. ui(new Ui::MainWindow),
  58. arg_ui(new ArgDialog),
  59. q_client(nullptr) {
  60. m_process_model = new QStandardItemModel(this);
  61. m_event_model = new QStandardItemModel(this);
  62. q_client = new Client(this, cli_argc, cli_argv);
  63. ui->setupUi(this);
  64. this->setWindowTitle("KYGUI");
  65. setConnectScreen();
  66. connect(ui->connect, &QPushButton::clicked, this, &MainWindow::connectClient);
  67. ui->processList->setModel(m_process_model);
  68. ui->eventList->setModel(m_event_model);
  69. }
  70. /**
  71. * @brief MainWindow::~MainWindow
  72. */
  73. MainWindow::~MainWindow() {
  74. delete q_client;
  75. delete ui;
  76. }
  77. void MainWindow::setConnectScreen(bool visible) {
  78. if (visible) {
  79. ui->startScreen->setMaximumSize(1366, 825);
  80. ui->startScreen->setMinimumSize(1366, 825);
  81. ui->connect->setMaximumSize(1366, 725);
  82. ui->connect->setMinimumSize(1366, 725);
  83. ui->kyConfig->setMaximumSize(1366, 75);
  84. ui->kyConfig->setMinimumSize(1366, 75);
  85. QFile file(QCoreApplication::applicationDirPath() + "/config/config.json");
  86. file.open(QIODevice::ReadOnly | QFile::ReadOnly);
  87. QString config_json = QString::fromUtf8(file.readAll());
  88. ui->kyConfig->setText(config_json);
  89. qDebug() << "Set config json: \n" << ui->kyConfig->toPlainText();
  90. file.close();
  91. } else {
  92. ui->connect->hide();
  93. ui->kyConfig->hide();
  94. ui->startScreen->setVisible(false);
  95. }
  96. }
  97. /**
  98. * @brief MainWindow::buttonClicked
  99. */
  100. void MainWindow::connectClient() {
  101. m_config = getConfigObject(ui->kyConfig->toPlainText());
  102. QString file_path = m_config.at("fileDirectory");
  103. if (file_path != NULL) {
  104. arg_ui->setFilePath(file_path);
  105. }
  106. setConnectScreen(false);
  107. qDebug() << "Connecting to KServer";
  108. QObject::connect(q_client, &Client::messageReceived, this,
  109. &MainWindow::updateMessages);
  110. QProgressBar* progressBar = ui->progressBar;
  111. q_client->start();
  112. for (int i = 1; i < 101; i++) {
  113. progressBar->setValue(i);
  114. }
  115. QPushButton* send_message_button =
  116. this->findChild<QPushButton*>("sendMessage");
  117. // Handle mouse
  118. QObject::connect(send_message_button, &QPushButton::clicked, this, [this]() {
  119. q_client->sendMessage(escapeMessage(ui->inputText->toPlainText()));
  120. ui->inputText->clear();
  121. });
  122. QObject::connect(
  123. ui->appList,
  124. static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged),
  125. this, [this]() {
  126. QString app_name = ui->appList->currentText();
  127. // TODO: I know, it's awful. Fix this
  128. q_client->setSelectedApp(std::vector<QString>{{app_name}});
  129. });
  130. QPushButton* disconnect_button = this->findChild<QPushButton*>("disconnect");
  131. QObject::connect(disconnect_button, &QPushButton::clicked, this,
  132. [this, progressBar]() {
  133. q_client->closeConnection();
  134. QApplication::exit(9);
  135. });
  136. QObject::connect(ui->execute, &QPushButton::clicked, this,
  137. [this]() { q_client->execute(); });
  138. QObject::connect(ui->addArgs, &QPushButton::clicked, this, [this]() {
  139. if (ui->appList->count() == 0) {
  140. QMessageBox::warning(this, tr("Args"),
  141. tr("Please connect to the KServer and retrieve a "
  142. "list of available processes."));
  143. } else {
  144. arg_ui->show();
  145. }
  146. });
  147. QObject::connect(
  148. arg_ui, &ArgDialog::uploadFiles, this,
  149. [this](QVector<KFileData> files) { q_client->sendFiles(files); });
  150. QObject::connect(
  151. arg_ui, &ArgDialog::taskRequestReady, this,
  152. [this](Task task, bool file_pending) {
  153. auto mask = q_client->getSelectedApp();
  154. if (mask > -1) {
  155. if (q_client->getAppName(mask) == "Instagram") {
  156. qDebug() << "Scheduling a task";
  157. task.args.push_back(std::to_string(mask));
  158. q_client->scheduleTask(task.args, file_pending);
  159. }
  160. }
  161. });
  162. QObject::connect(ui->tasks, &QPushButton::clicked, this, [this]() {
  163. // TODO: Change this to a complete implementation
  164. q_client->sendMessage("scheduler");
  165. });
  166. QObject::connect(ui->viewConsole, &QPushButton::clicked, this,
  167. [this]() { console_ui.show(); });
  168. QObject::connect(
  169. ui->processList, &QListView::clicked, this,
  170. [this](const QModelIndex& index) {
  171. auto process = m_processes.at(index.row());
  172. QString process_info_text =
  173. m_processes.at(index.row()).name.toUtf8() + "\n";
  174. process_info_text += "Execution requested at " +
  175. process.start.toUtf8() + "\n" +
  176. "Is currently in a state of: " +
  177. ProcessNames[process.state - 1].toUtf8();
  178. if (process.end.size() > 0 || process.id == "Scheduled task") {
  179. process_info_text += "\n\nResult: \n" + process.result;
  180. }
  181. infoMessageBox(process_info_text, "Process");
  182. });
  183. QObject::connect(ui->eventList, &QListView::clicked, this,
  184. [this](const QModelIndex& index) {
  185. auto event = m_events.at(index.row());
  186. infoMessageBox(event, "Event");
  187. });
  188. QTimer* timer = new QTimer(this);
  189. connect(timer, &QTimer::timeout, q_client, &Client::ping);
  190. timer->start(10000);
  191. }
  192. void MainWindow::handleKey() {
  193. q_client->sendMessage(ui->inputText->toPlainText());
  194. ui->inputText->clear();
  195. }
  196. QString MainWindow::parseMessage(const QString& message, StringVec v) {
  197. QString simplified_message{};
  198. if (isMessage(message.toUtf8())) {
  199. simplified_message += "Message: " + getMessage(message.toUtf8());
  200. } else if (isEvent(message.toUtf8())) {
  201. simplified_message += "Event: " + getEvent(message.toUtf8());
  202. } else if (isOperation(message.toUtf8())) {
  203. simplified_message += "Operation: ";
  204. simplified_message += getOperation(message.toUtf8()).c_str();
  205. }
  206. return simplified_message;
  207. }
  208. QStandardItem* createProcessListItem(Process process) {
  209. return new QStandardItem(
  210. QString(
  211. "%0 requested for execution. ID: %1\nStatus: %2\nTime: %3 Done: %4")
  212. .arg(process.name)
  213. .arg(process.id)
  214. .arg(ProcessNames[process.state - 1])
  215. .arg(process.start)
  216. .arg(process.end));
  217. }
  218. QStandardItem* createEventListItem(QString event) {
  219. return new QStandardItem(event);
  220. }
  221. /**
  222. * @brief MainWindow::updateMessages
  223. * @param s
  224. */
  225. void MainWindow::updateMessages(int t, const QString& message, StringVec v) {
  226. QString timestamp_prefix =
  227. QDateTime::currentDateTime().toString("hh:mm:ss") + " - ";
  228. if (t == MESSAGE_UPDATE_TYPE) {
  229. qDebug() << "Updating message area";
  230. auto simple_message = timestamp_prefix + parseMessage(message, v);
  231. ui->messages->append(simple_message);
  232. console_ui.updateText(message);
  233. } else if (t == COMMANDS_UPDATE_TYPE) {
  234. qDebug() << "Updating commands";
  235. QComboBox* app_list = ui->appList;
  236. app_list->clear();
  237. int app_index = 0;
  238. QString default_app = configValue("defaultApp", m_config);
  239. for (const auto& s : v) {
  240. app_list->addItem(s);
  241. if (s.toLower() == default_app.toLower()) {
  242. q_client->setSelectedApp(std::vector<QString>{default_app});
  243. ui->appList->setCurrentIndex(app_index);
  244. }
  245. app_index++;
  246. }
  247. if (message == "New Session") {
  248. ui->led->setState(true);
  249. arg_ui->setConfig(configValue("instagram", m_config));
  250. if (configBoolValue("schedulerMode", std::ref(m_config))) {
  251. arg_ui->show();
  252. }
  253. }
  254. } else if (t == PROCESS_REQUEST_TYPE) {
  255. qDebug() << "Updating process list";
  256. m_processes.push_back(Process{.name = v.at(1),
  257. .state = ProcessState::PENDING,
  258. .start = getTime(),
  259. .id = v.at(2)});
  260. int row = 0;
  261. for (const auto& process : m_processes) {
  262. m_process_model->setItem(row, createProcessListItem(process));
  263. row++;
  264. }
  265. } else if (t == EVENT_UPDATE_TYPE) {
  266. QString event_message{timestamp_prefix};
  267. if (!v.empty()) {
  268. // TODO: extract process result handling from here. This should handle any
  269. // event
  270. if (v.size() == 1) {
  271. event_message += message + "\n" + v.at(0);
  272. } else {
  273. event_message += message;
  274. if (message == "Process Result") {
  275. event_message += "\n";
  276. auto app_name =
  277. q_client->getAppName(std::stoi(v.at(0).toUtf8().constData()));
  278. auto process_it = std::find_if(
  279. m_processes.begin(), m_processes.end(),
  280. [v](const Process& process) { return process.id == v.at(1); });
  281. if (process_it != m_processes.end()) {
  282. updateProcessResult(v.at(1), v.at(2));
  283. } else { // new process, from scheduled task
  284. Process new_process{.name = app_name,
  285. .state = ProcessState::SUCCEEDED,
  286. .start = getTime(),
  287. .id = "Scheduled task"};
  288. if (v.count() > 2 && !v.at(2).isEmpty()) {
  289. new_process.result = v.at(2);
  290. new_process.end = new_process.start;
  291. }
  292. m_processes.push_back(new_process);
  293. m_process_model->setItem(m_process_model->rowCount(),
  294. createProcessListItem(new_process));
  295. }
  296. event_message += app_name;
  297. event_message += ": ";
  298. event_message += v.at(2);
  299. } else if (QString::compare(message, "Message Received") == 0) {
  300. event_message += "\n" + v.at(1) + ": " + v.at(2);
  301. }
  302. }
  303. } else {
  304. event_message += message;
  305. }
  306. if (m_events.size() > 1) {
  307. auto last_event = m_events[m_events.size() - 1];
  308. if (isSameEvent(message, last_event.remove(0, 11))) {
  309. m_consecutive_events++;
  310. auto count = getLikeEventNum(event_message, m_events);
  311. QString clean_event_message =
  312. event_message + " (" + QString::number(count) + ")";
  313. m_events.push_back(event_message);
  314. m_event_model->setItem(m_event_model->rowCount() - 1,
  315. createEventListItem(clean_event_message));
  316. return;
  317. }
  318. m_consecutive_events = 0;
  319. }
  320. m_events.push_back(event_message);
  321. m_event_model->setItem(m_event_model->rowCount(),
  322. createEventListItem(event_message));
  323. } else {
  324. qDebug() << "Unknown update type. Cannot update UI";
  325. }
  326. }
  327. void MainWindow::updateProcessResult(
  328. QString id, QString result) { // We need to start matching processes with a
  329. // unique identifier
  330. for (int i = m_processes.size() - 1; i >= 0; i--) {
  331. if (m_processes.at(i).id == id) {
  332. m_processes.at(i).end = getTime();
  333. m_processes.at(i).state = ProcessState::SUCCEEDED;
  334. m_processes.at(i).result = result;
  335. m_process_model->setItem(i, 0, createProcessListItem(m_processes.at(i)));
  336. return;
  337. }
  338. }
  339. // If we didn't return, it's a new process:
  340. }
  341. void MainWindow::keyPressEvent(QKeyEvent* e) {
  342. qDebug() << "Key press: " << e->key();
  343. if (e->key() == Qt::Key_0) {
  344. qDebug() << "Ok";
  345. }
  346. }