Windows/mainWindow.js

  1. /**
  2. * _ _
  3. * | \| |
  4. * | .` |
  5. * |_|\_|eptune
  6. *
  7. * Capstone Project 2022
  8. *
  9. * Main Window
  10. */
  11. const NodeGUI = require("@nodegui/nodegui");
  12. const NeptuneWindow = require("./NeptuneWindow");
  13. const Client = require("../Classes/Client");
  14. const Notification = require("../Classes/Notification");
  15. const { Logger } = require("./../Classes/LogMan");
  16. const ClientManager = require("../Classes/ClientManager");
  17. const NepConfig = require('../Classes/NeptuneConfig.js');
  18. const { ServiceState } = require("@homebridge/ciao");
  19. const { randomUUID } = require("node:crypto");
  20. /** @type {NepConfig} */
  21. var NeptuneConfig = global.Neptune.config;
  22. class thisTest extends NeptuneWindow {
  23. /**
  24. * Whether tooltips are enabled or not. Default no, they're a bit laggy.
  25. * @type {boolean}
  26. */
  27. enableToolTips = false;
  28. /** @type {ClientManager} */
  29. clientManager = Neptune.clientManager;
  30. /** @type {Map<string, Client>} */
  31. addedClients = new Map();
  32. /** @type {Map<string, NodeGUI.QListWidgetItem>} */
  33. clientListItems = new Map();
  34. // UI Elements
  35. // menus
  36. /** @type {NodeGUI.QMenuBar} */
  37. menuBar;
  38. // File menu
  39. /** @type {NodeGUI.QMenu} */
  40. menuFile;
  41. /** @type {NodeGUI.QAction} */
  42. actionPair_client;
  43. /** @type {NodeGUI.QMenu} */
  44. menuClient_settings;
  45. /** @type {NodeGUI.QAction} */
  46. menuClient_settings_action;
  47. // menuClient_settings_action actions:
  48. /** @type {NodeGUI.QAction} */
  49. actionRefresh_client_info;
  50. /** @type {NodeGUI.QAction} */
  51. actionSync_notifications;
  52. /** @type {NodeGUI.QAction} */
  53. actionToggleClipboardSharing;
  54. /** @type {NodeGUI.QAction} */
  55. actionSend_clipboard;
  56. /** @type {NodeGUI.QAction} */
  57. actionReceive_clipboard;
  58. /** @type {NodeGUI.QAction} */
  59. actionToggleFileSharing;
  60. /** @type {NodeGUI.QAction} */
  61. actionToggleAllowClientToUpload;
  62. /** @type {NodeGUI.QAction} */
  63. actionSend_file;
  64. /** @type {NodeGUI.QAction} */
  65. actionDelete_client;
  66. /** @type {NodeGUI.QAction} */
  67. actionSync_configuration_with_client;
  68. /** @type {NodeGUI.QAction} */
  69. actionView_connection_details;
  70. // bottom file menu
  71. /** @type {NodeGUI.QAction} */
  72. actionRefresh_device_list;
  73. /** @type {NodeGUI.QAction} */
  74. actionPreferences;
  75. /** @type {NodeGUI.QAction} */
  76. actionToggleConsoleVisibility;
  77. /** @type {NodeGUI.QAction} */
  78. actionExit;
  79. // Help menu
  80. /** @type {NodeGUI.QMenu} */
  81. menuHelp;
  82. /** @type {NodeGUI.QAction} */
  83. actionView_GitHub_page;
  84. /** @type {NodeGUI.QAction} */
  85. actionTest_notification;
  86. /** @type {NodeGUI.QAction} */
  87. actionAbout_Neptune;
  88. // devices
  89. /** @type {NodeGUI.QListWidget} */
  90. deviceList;
  91. // settings view
  92. /** @type {NodeGUI.QScrollArea} */
  93. scrollArea;
  94. // top bar client info
  95. /** @type {NodeGUI.QLabel} */
  96. lblClientName
  97. /** @type {NodeGUI.QLabel} */
  98. lblClientBatteryLevel;
  99. /** @type {NodeGUI.QCheckBox} */
  100. chkSyncNotifications;
  101. // clipboard
  102. /** @type {NodeGUI.QCheckBox} */
  103. chkSyncClipboard;
  104. /** @type {NodeGUI.QCheckBox} */
  105. chkAutoSendClipboard;
  106. /** @type {NodeGUI.QCheckBox} */
  107. chkClipboardAllowClientToGet;
  108. // file sharing
  109. /** @type {NodeGUI.QCheckBox} */
  110. chkFileSharingEnable;
  111. /** @type {NodeGUI.QCheckBox} */
  112. chkFileSharingAutoAccept;
  113. /** @type {NodeGUI.QCheckBox} */
  114. chkFileSharingNotify;
  115. /** @type {NodeGUI.QCheckBox} */
  116. chkFilesharingAllowClientToUpload;
  117. /** @type {NodeGUI.QLineEdit} */
  118. txtFileSharingSaveDirectory;
  119. /** @type {NodeGUI.QPushButton} */
  120. btnFileSharingSaveDirectoryBrowse;
  121. // Buttons
  122. /** @type {NodeGUI.QPushButton} */
  123. btnSave;
  124. /** @type {NodeGUI.QPushButton} */
  125. btnDelete;
  126. /** @type {NodeGUI.QPushButton} */
  127. btnSendFile;
  128. /** @type {NodeGUI.QPushButton} */
  129. btnSendClipboard;
  130. /** @type {NodeGUI.QPushButton} */
  131. btnReceiveClipboard;
  132. /** @type {Logger} */
  133. log;
  134. /**
  135. * Returns the selected client object
  136. * @return {Client} Current selected client in the device list on the left side
  137. */
  138. GetSelectedClient() {
  139. try {
  140. let items = this.deviceList.selectedItems();
  141. if (items.length >= 1) {
  142. /** @type {NodeGUI.QListWidgetItem} */
  143. let selectedItem = items[0];
  144. let clientName = selectedItem.text();
  145. if (this.addedClients.has(clientName))
  146. return this.addedClients.get(clientName);
  147. return undefined;
  148. }
  149. } catch (a) {
  150. this.log.error("Error grabbing selected item: " + a);
  151. }
  152. return undefined;
  153. }
  154. /**
  155. * Adds a client to the client list on the left side
  156. * @param {Client} client - Client to add
  157. */
  158. AddClientToDeviceList(client) {
  159. let listItem = new NodeGUI.QListWidgetItem();
  160. if (client.friendlyName == undefined) {
  161. client.eventEmitter.removeAllListeners('paired'); // protect against race conditions
  162. client.eventEmitter.once('paired', () => this.AddClientToDeviceList(client));
  163. this.log.debug("Attempt to add device with no friendly name. Listening for pair event...");
  164. return;
  165. }
  166. if (this.addedClients.has(client.friendlyName)) {
  167. return;
  168. }
  169. listItem.setText(client.friendlyName);
  170. if (this.enableToolTips) {
  171. if (client.isPaired)
  172. listItem.setToolTip("Paired and connected client device " + client.friendlyName);
  173. else
  174. listItem.setToolTip("Unpaired client device " + client.friendlyName);
  175. }
  176. this.addedClients.set(client.friendlyName, client);
  177. this.clientListItems.set(client.friendlyName, listItem);
  178. this.deviceList.addItem(listItem);
  179. this.log.debug("Added client to device list: " + client.friendlyName);
  180. if (this.deviceList.count() == 1) {
  181. this.deviceList.setCurrentItem(listItem);
  182. }
  183. }
  184. /**
  185. * Removes a client from the client list on the left side.
  186. * @param {string} clientName - Name of the client to remove (the text of the ListItem).
  187. */
  188. RemoveClientFromDeviceList(clientName) {
  189. if (this.clientListItems.has(clientName)) {
  190. this.deviceList.removeItemWidget(this.clientListItems.get(clientName));
  191. this.clientListItems.delete(clientName);
  192. }
  193. if (this.addedClients.has(clientName))
  194. this.addedClients.delete(clientName);
  195. // THIS IS TEMPORARY!!!
  196. this.addedClients.clear();
  197. this.clientListItems.clear();
  198. this.deviceList.clear();
  199. let clients = this.clientManager.getClients();
  200. clients.forEach((client, name) => {
  201. this.AddClientToDeviceList(client);
  202. });
  203. }
  204. receiveClipboardData() {
  205. let client = this.GetSelectedClient();
  206. if (!client.clipboardSettings.enabled)
  207. return;
  208. let clipboardData = this.GetSelectedClient().getClipboard();
  209. if (clipboardData !== undefined && typeof clipboardData === "string") {
  210. let clipboard = NodeGUI.QApplication.clipboard();
  211. clipboard.pixmap(NodeGUI.QClipboardMode.Clipboard);
  212. clipboard.setText(clipboardData);
  213. }
  214. }
  215. sendClipboardData() {
  216. try {
  217. let client = this.GetSelectedClient();
  218. if (!client.clipboardSettings.enabled)
  219. return;
  220. let clipboard = NodeGUI.QApplication.clipboard();
  221. clipboard.pixmap(NodeGUI.QClipboardMode.Clipboard);
  222. let clipboardData = clipboard.text();
  223. if (clipboardData !== undefined && typeof clipboardData === "string") {
  224. client.sendClipboard(clipboardData);
  225. }
  226. } catch (e) {}
  227. }
  228. // Enable/disable file sharing settings if file sharing is enabled/disabled
  229. updateEnableFileSharing(enabled) {
  230. let client = this.GetSelectedClient();
  231. if (client !== undefined) {
  232. client.fileSharingSettings.enabled = enabled;
  233. this.btnSendFile.setEnabled(enabled === true);
  234. this.chkFileSharingAutoAccept.setEnabled(enabled === true);
  235. this.chkFileSharingNotify.setEnabled(enabled === true);
  236. this.chkFilesharingAllowClientToUpload.setEnabled(enabled === true);
  237. //this.txtFileSharingSaveDirectory.setEnabled(enabled === true);
  238. this.btnFileSharingSaveDirectoryBrowse.setEnabled(enabled === true);
  239. this.actionToggleAllowClientToUpload.setEnabled(enabled === true);
  240. this.actionSend_file.setEnabled(enabled === true);
  241. }
  242. }
  243. // Enable/disable clipboard settings if clipboard sync is enabled/disabled
  244. updateEnableClipboardSharing(enabled) {
  245. let client = this.GetSelectedClient();
  246. if (client !== undefined) {
  247. client.clipboardSettings.enabled = enabled;
  248. this.btnSendClipboard.setEnabled(enabled === true);
  249. this.btnReceiveClipboard.setEnabled(enabled === true);
  250. this.chkAutoSendClipboard.setEnabled(enabled === true);
  251. this.chkClipboardAllowClientToGet.setEnabled(enabled === true);
  252. this.actionSend_clipboard.setEnabled(enabled === true);
  253. this.actionReceive_clipboard.setEnabled(enabled === true);
  254. }
  255. }
  256. // This is used to update all the items in the settings
  257. updateClientData() {
  258. let client = this.GetSelectedClient();
  259. if (client == undefined) {
  260. this.menuClient_settings_action.setEnabled(false);
  261. this.scrollArea.setEnabled(false);
  262. this.actionRefresh_client_info.setEnabled(false);
  263. } else {
  264. this.menuClient_settings_action.setEnabled(true);
  265. this.scrollArea.setEnabled(true);
  266. this.actionRefresh_client_info.setEnabled(true);
  267. let statusText = "offline";
  268. if (client.isConnected) {
  269. statusText = "online";
  270. }
  271. this.lblClientName.setText(client.friendlyName + " (" + statusText + ")");
  272. let batteryString = client.batteryLevel !== undefined? client.batteryLevel + "%" : "unknown%";
  273. if (client.batteryChargerType !== undefined && client.batteryChargerType !== "discharging") {
  274. batteryString = "+" + batteryString;
  275. if (client.batteryTimeRemaining !== undefined) {
  276. batteryString += " (full in ";
  277. if ((client.batteryTimeRemaining/60)>60)
  278. batteryString += Math.round(((client.batteryTimeRemaining/60/60) + Number.EPSILON) * 100) / 100 + " hours)"
  279. else
  280. batteryString += Math.round(((client.batteryTimeRemaining/60) + Number.EPSILON) * 100) / 100 + " minutes)"
  281. }
  282. }
  283. this.lblClientBatteryLevel.setText(batteryString);
  284. this.chkSyncNotifications.setChecked(client.notificationSettings.enabled === true);
  285. // clipboard
  286. this.updateEnableClipboardSharing(client.clipboardSettings.enabled);
  287. this.chkSyncClipboard.setChecked(client.clipboardSettings.enabled === true);
  288. this.actionToggleClipboardSharing.setChecked(client.clipboardSettings.enabled === true);
  289. this.chkAutoSendClipboard.setChecked(client.clipboardSettings.synchronizeClipboardToClient === true);
  290. this.chkClipboardAllowClientToGet.setChecked(client.clipboardSettings.allowClientToGet === true);
  291. // file sharing
  292. this.updateEnableFileSharing(client.fileSharingSettings.enabled);
  293. this.chkFileSharingEnable.setChecked(client.fileSharingSettings.enabled === true);
  294. this.actionToggleFileSharing.setChecked(client.fileSharingSettings.enabled === true);
  295. this.chkFileSharingAutoAccept.setChecked(client.fileSharingSettings.requireConfirmationOnClinetUploads !== true);
  296. this.chkFileSharingNotify.setChecked(client.fileSharingSettings.notifyOnClientUpload === true);
  297. this.chkFilesharingAllowClientToUpload.setChecked(client.fileSharingSettings.allowClientToUpload === true);
  298. this.actionToggleAllowClientToUpload.setChecked(client.fileSharingSettings.allowClientToUpload === true);
  299. this.txtFileSharingSaveDirectory.setText(client.fileSharingSettings.receivedFilesDirectory !== undefined? client.fileSharingSettings.receivedFilesDirectory : "");
  300. //this.txtFileSharingSaveDirectory.setEnabled(client.fileSharingSettings.enabled === true);
  301. }
  302. }
  303. saveClientData() {
  304. let client = this.GetSelectedClient();
  305. if (client == undefined) {
  306. this.menuClient_settings_action.setEnabled(false);
  307. this.scrollArea.setEnabled(false);
  308. this.actionRefresh_client_info.setEnabled(false);
  309. } else {
  310. if (client.friendlyName !== undefined)
  311. this.log.debug("Configuration saved for: " + client.friendlyName, false);
  312. this.menuClient_settings_action.setEnabled(true);
  313. this.scrollArea.setEnabled(true);
  314. this.actionRefresh_client_info.setEnabled(true);
  315. client.notificationSettings.enabled = this.chkSyncNotifications.isChecked(); //(client.notificationSettings.enabled !== false);
  316. // clipboard
  317. client.clipboardSettings.enabled = this.chkSyncClipboard.isChecked(); //(client.clipboardSettings.enabled === true);
  318. client.clipboardSettings.synchronizeClipboardToClient = this.chkAutoSendClipboard.isChecked(); //(client.clipboardSettings.synchronizeClipboardToClient === true);
  319. client.clipboardSettings.allowClientToGet = this.chkClipboardAllowClientToGet.isChecked(); //(client.clipboardSettings.allowClientToGet === true);
  320. // file sharing
  321. client.fileSharingSettings.enabled = this.chkFileSharingEnable.isChecked(); //(client.fileSharingSettings.enabled === true);
  322. client.fileSharingSettings.requireConfirmationOnClinetUploads = !this.chkFileSharingAutoAccept.isChecked(); //(client.fileSharingSettings.autoReceiveFromClient === true);
  323. client.fileSharingSettings.notifyOnClientUpload = this.chkFileSharingNotify.isChecked(); //(client.fileSharingSettings.notifyOnReceive === true);
  324. client.fileSharingSettings.allowClientToUpload = this.chkFilesharingAllowClientToUpload.isChecked(); //(client.fileSharingSettings.allowClientToUpload === true);
  325. client.fileSharingSettings.receivedFilesDirectory = this.txtFileSharingSaveDirectory.text(); //(client.fileSharingSettings.receivedFilesDirectory);
  326. client.save();
  327. client.syncConfiguration();
  328. this.updateClientData();
  329. }
  330. }
  331. clientSettingChanged() {
  332. if (!NeptuneConfig.applicationSettings.requireSaveButton) {
  333. this.saveClientData();
  334. }
  335. }
  336. constructor(arg) {
  337. super(arg);
  338. try {
  339. this.log = global.Neptune.logMan.getLogger("MainWindow");
  340. this.setWindowTitle('Neptune | Main window');
  341. this.resize(599, 522);
  342. this.setMinimumSize(425, 300);
  343. NeptuneConfig.eventEmitter.removeAllListeners('updated');
  344. NeptuneConfig.eventEmitter.on('updated', () => {
  345. if (global.Neptune.shuttingDown)
  346. return;
  347. try {
  348. this.log("Configuration updated... applying changes.");
  349. try {
  350. this.clientManager.getClients().forEach(client => {
  351. client.syncConfiguration();
  352. });
  353. } catch {}
  354. try {
  355. if (NeptuneConfig.applicationSettings.requireSaveButton) {
  356. this.btnSave.setVisible(true);
  357. this.btnSave.setEnabled(true);
  358. } else {
  359. this.btnSave.setVisible(false);
  360. this.btnSave.setEnabled(false);
  361. }
  362. } catch {}
  363. try {
  364. global.Neptune.mdnsService.updateTxt({
  365. version: global.Neptune.version.toString(),
  366. name: global.Neptune.config.friendlyName,
  367. });
  368. if (NeptuneConfig.applicationSettings.advertiseNeptune) {
  369. if (global.Neptune.mdnsService.serviceState !== ServiceState.ANNOUNCED) {
  370. global.Neptune.mdnsService.advertise().then(() => {
  371. global.Neptune.webLog.verbose("MDNS service now advertising");
  372. });
  373. }
  374. } else {
  375. if (global.Neptune.mdnsService.serviceState !== ServiceState.UNANNOUNCED) {
  376. global.Neptune.mdnsService.end().then(() => {
  377. global.Neptune.webLog.verbose("MDNS service has stopped advertising!!");
  378. });
  379. }
  380. }
  381. } catch {}
  382. } catch (e) {
  383. this.log.error("Failed to apply configuration changes. See log for more details.");
  384. this.log.error("Error: " + e, false);
  385. }
  386. });
  387. // Top bar actions
  388. // Client settings (menu)
  389. this.actionPair_client = new NodeGUI.QAction(this.MainWindow);
  390. this.actionPair_client.setObjectName("actionPair_client");
  391. this.actionPair_client.setText("Pair client");
  392. this.actionPair_client.addEventListener('triggered', () => {
  393. let tempConnectWindow = this.newChildWindow('tempConnectWindow');
  394. tempConnectWindow.show();
  395. });
  396. this.actionRefresh_client_info = new NodeGUI.QAction(this.MainWindow);
  397. this.actionRefresh_client_info.setObjectName("actionRefresh_client_info");
  398. this.actionRefresh_client_info.setText("Refresh client info");
  399. this.actionRefresh_client_info.addEventListener('triggered', () => {
  400. this.updateClientData();
  401. });
  402. this.actionSync_notifications = new NodeGUI.QAction(this.MainWindow);
  403. this.actionSync_notifications.setObjectName("actionSync_notifications");
  404. this.actionSync_notifications.setCheckable(true);
  405. this.actionSync_notifications.setChecked(true);
  406. this.actionSync_notifications.setText("Sync notifications");
  407. this.actionSync_notifications.addEventListener('triggered', (checked) => {
  408. let client = this.GetSelectedClient();
  409. if (client !== undefined) {
  410. client.notificationSettings.enabled = checked;
  411. this.chkSyncNotifications.setChecked(checked);
  412. client.save();
  413. client.syncConfiguration();
  414. this.saveClientData();
  415. }
  416. });
  417. this.actionToggleClipboardSharing = new NodeGUI.QAction(this.MainWindow);
  418. this.actionToggleClipboardSharing.setObjectName("actionToggleClipboardSharing");
  419. this.actionToggleClipboardSharing.setCheckable(true);
  420. this.actionToggleClipboardSharing.setText("Enable clipboard sharing");
  421. this.actionToggleClipboardSharing.addEventListener('triggered', (checked) => {
  422. let client = this.GetSelectedClient()
  423. if (client !== undefined) {
  424. this.updateEnableClipboardSharing(checked);
  425. if (this.chkSyncClipboard.isChecked() !== checked)
  426. this.chkSyncClipboard.setChecked(checked === true);
  427. this.saveClientData();
  428. }
  429. });
  430. this.actionSend_clipboard = new NodeGUI.QAction(this.MainWindow);
  431. this.actionSend_clipboard.setObjectName("actionSend_clipboard");
  432. this.actionSend_clipboard.setEnabled(false);
  433. this.actionSend_clipboard.setText("Send clipboard");
  434. this.actionSend_clipboard.addEventListener('triggered', () => {
  435. this.sendClipboardData();
  436. });
  437. this.actionReceive_clipboard = new NodeGUI.QAction(this.MainWindow);
  438. this.actionReceive_clipboard.setObjectName("actionReceive_clipboard");
  439. this.actionReceive_clipboard.setEnabled(false);
  440. this.actionReceive_clipboard.setText("Receive clipboard");
  441. this.actionReceive_clipboard.addEventListener('triggered', () => {
  442. this.receiveClipboardData();
  443. });
  444. this.actionToggleFileSharing = new NodeGUI.QAction(this.MainWindow);
  445. this.actionToggleFileSharing.setObjectName("actionToggleFileSharing");
  446. this.actionToggleFileSharing.setCheckable(true);
  447. this.actionToggleFileSharing.setText("Enable file sharing");
  448. this.actionToggleFileSharing.addEventListener('triggered', (checked) => {
  449. let client = this.GetSelectedClient()
  450. if (client !== undefined) {
  451. this.updateEnableFileSharing(checked);
  452. if (this.chkFileSharingEnable.isChecked() !== checked)
  453. this.chkFileSharingEnable.setChecked(checked);
  454. this.log("Saving + syncing configuration");
  455. client.save();
  456. client.syncConfiguration();
  457. }
  458. });
  459. this.actionToggleAllowClientToUpload = new NodeGUI.QAction(this.MainWindow);
  460. this.actionToggleAllowClientToUpload.setObjectName("actionToggleAllowClientToUpload");
  461. this.actionToggleAllowClientToUpload.setCheckable(true);
  462. this.actionToggleAllowClientToUpload.setEnabled(false);
  463. this.actionToggleAllowClientToUpload.setText("Allow client to upload");
  464. this.actionToggleAllowClientToUpload.addEventListener('triggered', (checked) => {
  465. let client = this.GetSelectedClient();
  466. if (client !== undefined) {
  467. client.fileSharingSettings.allowClientToUpload = checked;
  468. this.chkFilesharingAllowClientToUpload.setChecked(checked);
  469. this.log("Saving + syncing configuration");
  470. client.save();
  471. client.syncConfiguration();
  472. }
  473. });
  474. this.actionSend_file = new NodeGUI.QAction(this.MainWindow);
  475. this.actionSend_file.setObjectName("actionSend_file");
  476. this.actionSend_file.setEnabled(false);
  477. this.actionSend_file.setText("Send file");
  478. this.actionSend_file.addEventListener('triggered', () => {
  479. let client = this.GetSelectedClient();
  480. if (client !== undefined) {
  481. this.#sendFile(client);
  482. }
  483. });
  484. this.actionDelete_client = new NodeGUI.QAction(this.MainWindow);
  485. this.actionDelete_client.setObjectName("actionDelete_client");
  486. this.actionDelete_client.setText("Delete client");
  487. this.actionDelete_client.addEventListener('triggered', () => {
  488. let client = this.GetSelectedClient();
  489. if (client !== undefined) {
  490. let yesButton = new NodeGUI.QPushButton();
  491. yesButton.setText("Yes");
  492. let noButton = new NodeGUI.QPushButton();
  493. noButton.setText("No");
  494. let result = this.displayMessageBox("Delete and unpair " + (client.friendlyName === undefined? "the client" : client.friendlyName) + "?",
  495. "Are you sure you want to delete and unpair with " + (client.friendlyName === undefined? "the client" : client.friendlyName) + "?",
  496. [
  497. { button: yesButton, buttonRole: NodeGUI.ButtonRole.AcceptRole },
  498. { button: noButton, buttonRole: NodeGUI.ButtonRole.RejectRole },
  499. ]);
  500. if (result != NodeGUI.DialogCode.Accepted) { // ?
  501. this.RemoveClientFromDeviceList(client.friendlyName);
  502. client.delete();
  503. }
  504. }
  505. });
  506. this.actionSync_configuration_with_client = new NodeGUI.QAction(this.MainWindow);
  507. this.actionSync_configuration_with_client.setObjectName("actionSync_configuration_with_client");
  508. this.actionSync_configuration_with_client.setText("Sync client configuration");
  509. this.actionSync_configuration_with_client.addEventListener('triggered', () => {
  510. let selectedItem = this.GetSelectedClient();
  511. if (selectedItem !== undefined) {
  512. selectedItem.syncConfiguration();
  513. }
  514. });
  515. this.actionView_connection_details = new NodeGUI.QAction(this.MainWindow);
  516. this.actionView_connection_details.setObjectName("actionView_connection_details");
  517. this.actionView_connection_details.setText("View connection details");
  518. this.actionView_connection_details.addEventListener('triggered', () => {
  519. let selectedItem = this.GetSelectedClient();
  520. if (selectedItem !== undefined && selectedItem.isConnected) {
  521. let connectionDetails = this.newChildWindow('ConnectionDetails');
  522. connectionDetails.setClient(selectedItem);
  523. connectionDetails.show();
  524. } else if (!selectedItem.isConnected) {
  525. let okayButton = new NodeGUI.QPushButton();
  526. okayButton.setText("Okay");
  527. this.displayMessageBox("Not connected", "Device is not connected",
  528. [{ button: okayButton, buttonRole: NodeGUI.ButtonRole.AcceptRole }]);
  529. }
  530. });
  531. this.actionRefresh_device_list = new NodeGUI.QAction(this.MainWindow);
  532. this.actionRefresh_device_list.setObjectName("actionRefresh_device_list");
  533. this.actionRefresh_device_list.setText("Refresh device list");
  534. this.actionRefresh_device_list.addEventListener('triggered', () => {
  535. this.addedClients.clear();
  536. this.clientListItems.clear();
  537. this.deviceList.clear();
  538. let clients = this.clientManager.getClients();
  539. clients.forEach((client, name) => {
  540. this.AddClientToDeviceList(client);
  541. });
  542. });
  543. let preferencePageShown = false;
  544. let preferencePage = this.newChildWindow('preferencePage');
  545. preferencePage.addEventListener(NodeGUI.WidgetEventTypes.Close, () => {
  546. preferencePageShown = false;
  547. });
  548. // Generic
  549. this.actionPreferences = new NodeGUI.QAction(this.MainWindow);
  550. this.actionPreferences.setObjectName("actionPreferences");
  551. // actionPreferences.setMenuRole(QAction::PreferencesRole);
  552. this.actionPreferences.setText("Preferences");
  553. this.actionPreferences.addEventListener('triggered', () => {
  554. // Open setting window
  555. if (preferencePageShown == false) {
  556. preferencePage.show();
  557. preferencePageShown = true;
  558. } else {
  559. preferencePage.setFocus(NodeGUI.FocusReason.PopupFocusReason);
  560. }
  561. });
  562. this.actionToggleConsoleVisibility = new NodeGUI.QAction(this.MainWindow);
  563. this.actionToggleConsoleVisibility.setObjectName("actionToggleConsoleVisibility");
  564. // actionPreferences.setMenuRole(QAction::PreferencesRole);
  565. this.actionToggleConsoleVisibility.setText("Toggle console visibility");
  566. this.actionToggleConsoleVisibility.addEventListener('triggered', () => {
  567. if (global.NeptuneRunnerIPC !== undefined) {
  568. if (global.consoleVisible) {
  569. global.NeptuneRunnerIPC.sendData("hideconsolewindow", {});
  570. this.actionToggleConsoleVisibility.setText("Show console");
  571. } else {
  572. global.NeptuneRunnerIPC.sendData("showconsolewindow", {});
  573. this.actionToggleConsoleVisibility.setText("Hide console");
  574. }
  575. global.consoleVisible = !global.consoleVisible;
  576. }
  577. });
  578. this.actionExit = new NodeGUI.QAction(this.MainWindow);
  579. this.actionExit.setObjectName("actionExit");
  580. // actionExit.setMenuRole(QAction::QuitRole);
  581. this.actionExit.setText("Exit");
  582. this.actionExit.addEventListener('triggered', () => {
  583. // Prompt if unsaved?
  584. this.close();
  585. process.Shutdown();
  586. });
  587. // Help menu
  588. this.actionView_GitHub_page = new NodeGUI.QAction(this.MainWindow);
  589. this.actionView_GitHub_page.setObjectName("actionView_GitHub_page");
  590. this.actionView_GitHub_page.setText("View GitHub page");
  591. this.actionView_GitHub_page.addEventListener('triggered', () => {
  592. // Open in browser
  593. var start = (process.platform == 'darwin'? 'open': process.platform == 'win32'? 'start': 'xdg-open');
  594. require('node:child_process').exec(start + ' https://github.com/SCCapstone/Neptune');
  595. });
  596. this.actionTest_notification = new NodeGUI.QAction(this.MainWindow);
  597. this.actionTest_notification.setObjectName("actionTest_notification");
  598. this.actionTest_notification.setText("Test notifications");
  599. this.actionTest_notification.addEventListener('triggered', () => {
  600. let notification = new Notification({
  601. clientId: "Neptune",
  602. friendlyName: "MainWindow",
  603. }, {
  604. action: 'create',
  605. applicationPackage: 'com.neptune.server',
  606. applicationName: 'NeptuneServer',
  607. notificationId: 'mainwindow.testNotification',
  608. title: 'Neptune Test',
  609. type: 'text',
  610. contents: {
  611. text: 'This is a test notification. If you are seeing this, notifications are working!',
  612. subtext: "Main window",
  613. image: "data:image/jpeg;base64, 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",
  614. actions: [
  615. {
  616. "id": "btnLeft",
  617. "type": "button",
  618. "contents": "Reply"
  619. },
  620. {
  621. "id": "btnRight",
  622. "type": "button",
  623. "contents": "Button"
  624. },
  625. {
  626. "id": "textbox", // The 'name' of the action
  627. "type": "textbox", // Button OR textbox OR combobox
  628. "hintText": "Type a message...", // Unique to text box, the "hint"
  629. },
  630. {
  631. "id": "combobox", // The 'name' of the action
  632. "type": "combobox", // Button OR textbox OR combobox
  633. "choices": [ // Choices the user gets
  634. "Choice 1",
  635. "A different choice",
  636. "3rd choice!"
  637. ],
  638. }
  639. ]
  640. },
  641. onlyAlertOnce: false,
  642. priority: "default",
  643. isSilent: false,
  644. });
  645. notification.once('activate', (data) => {
  646. try {
  647. let button = "";
  648. let textbox = "";
  649. let combobox = "";
  650. if (data.actionParameters !== undefined) {
  651. if (data.actionParameters.id !== undefined) {
  652. button = Buffer.from(data.actionParameters.id, "base64").toString("utf8");
  653. }
  654. if (data.actionParameters.text !== undefined) {
  655. textbox = Buffer.from(data.actionParameters.text, "base64").toString("utf8");
  656. }
  657. if (data.actionParameters.comboBoxChoice !== undefined) {
  658. combobox = Buffer.from(data.actionParameters.comboBoxChoice, "base64").toString("utf8");
  659. }
  660. }
  661. this.displayMessageBox("Test notification activated", "The test notification was activated! Data:\n"
  662. + ((button !== "")? "Button clicked: " + button : "Notification clicked") + "\n"
  663. + ((textbox !== "")? "Entered text: " + textbox : "No text entered") + "\n"
  664. + ((combobox !== "")? "Combo box selection: " + combobox : "No combo box selection made."));
  665. } catch (e) {
  666. }
  667. });
  668. notification.once('dismissed', () => {
  669. this.displayMessageBox("Test notification dismissed", "The test notification was dismissed!");
  670. });
  671. notification.push();
  672. });
  673. this.actionAbout_Neptune = new NodeGUI.QAction(this.MainWindow);
  674. this.actionAbout_Neptune.setObjectName("actionAbout_Neptune");
  675. // actionAbout_Neptune.setMenuRole(QAction::AboutRole);
  676. this.actionAbout_Neptune.setText("About Neptune");
  677. this.actionAbout_Neptune.addEventListener('triggered', () => {
  678. let aboutWindow = this.newChildWindow('aboutWindow');
  679. aboutWindow.show();
  680. });
  681. // MenuBar
  682. this.menuBar = new NodeGUI.QMenuBar();
  683. this.menuBar.setObjectName("menuBar");
  684. this.menuBar.setGeometry(0, 0, 598, 22);
  685. this.menuFile = new NodeGUI.QMenu();
  686. this.menuFile.setObjectName("menuFile");
  687. this.menuFile.setTitle("File")
  688. this.menuClient_settings = new NodeGUI.QMenu(this.menuFile);
  689. this.menuClient_settings.setObjectName("menuClient_settings");
  690. this.menuClient_settings.setTitle("Client settings");
  691. this.menuHelp = new NodeGUI.QMenu();
  692. this.menuHelp.setObjectName("menuHelp");
  693. this.menuHelp.setTitle("Help")
  694. // client settings
  695. this.menuClient_settings.addAction(this.actionSync_notifications);
  696. this.menuClient_settings.addSeparator();
  697. this.menuClient_settings.addAction(this.actionToggleClipboardSharing);
  698. this.menuClient_settings.addAction(this.actionSend_clipboard);
  699. this.menuClient_settings.addAction(this.actionReceive_clipboard);
  700. this.menuClient_settings.addSeparator();
  701. this.menuClient_settings.addAction(this.actionToggleFileSharing);
  702. this.menuClient_settings.addAction(this.actionToggleAllowClientToUpload);
  703. this.menuClient_settings.addAction(this.actionSend_file);
  704. this.menuClient_settings.addSeparator();
  705. this.menuClient_settings.addAction(this.actionDelete_client);
  706. this.menuClient_settings.addSeparator();
  707. this.menuClient_settings.addAction(this.actionSync_configuration_with_client);
  708. this.menuClient_settings.addAction(this.actionView_connection_details);
  709. this.menuClient_settings_action = new NodeGUI.QAction();
  710. this.menuClient_settings_action.setMenu(this.menuClient_settings);
  711. this.menuClient_settings_action.setText("Client settings");
  712. // file
  713. this.menuFile.addAction(this.actionPair_client);
  714. // this.menuFile.addAction(this.actionRefresh_device_list);
  715. this.menuFile.addSeparator();
  716. this.menuFile.addAction(this.menuClient_settings_action);
  717. this.menuFile.addSeparator();
  718. this.menuFile.addAction(this.actionPreferences);
  719. this.menuFile.addAction(this.actionToggleConsoleVisibility);
  720. this.menuFile.addSeparator();
  721. this.menuFile.addAction(this.actionExit);
  722. // help
  723. this.menuHelp.addAction(this.actionView_GitHub_page);
  724. this.menuHelp.addAction(this.actionTest_notification);
  725. this.menuHelp.addSeparator();
  726. this.menuHelp.addAction(this.actionAbout_Neptune);
  727. this.menuBar.addMenu(this.menuFile);
  728. this.menuBar.addAction(this.actionRefresh_device_list);
  729. this.menuBar.addAction(this.actionRefresh_client_info);
  730. // menuBar.addMenu(this.menuClient_settings);
  731. this.menuBar.addMenu(this.menuHelp);
  732. this.setMenuBar(this.menuBar);
  733. // Window
  734. let centralwidget = new NodeGUI.QWidget(this);
  735. centralwidget.setObjectName("centralwidget");
  736. let gridLayout_3 = new NodeGUI.QGridLayout(centralwidget);
  737. gridLayout_3.setSpacing(0);
  738. gridLayout_3.setObjectName("gridLayout_3");
  739. gridLayout_3.setContentsMargins(10, 10, 10, 10);
  740. let mainLayout = new NodeGUI.QGridLayout();
  741. mainLayout.setObjectName("mainLayout");
  742. mainLayout.setHorizontalSpacing(10);
  743. mainLayout.setVerticalSpacing(0);
  744. mainLayout.setContentsMargins(0, 0, 0, 0);
  745. // Device list box (side)
  746. let leftHandContainer = new NodeGUI.QGridLayout();
  747. leftHandContainer.setObjectName("leftHandContainer");
  748. leftHandContainer.setContentsMargins(0, 0, 0, 0);
  749. this.deviceList = new NodeGUI.QListWidget(centralwidget);
  750. this.deviceList.setObjectName("deviceList");
  751. this.deviceList.setSizePolicy(NodeGUI.QSizePolicyPolicy.Fixed, NodeGUI.QSizePolicyPolicy.Expanding);
  752. this.deviceList.setMinimumSize(50, 100);
  753. this.deviceList.setMaximumSize(125, 16777215);
  754. // this.deviceList.setToolTip("Client device selector.");
  755. this.deviceList.setAutoScroll(true);
  756. this.deviceList.addEventListener('itemSelectionChanged', () => {
  757. let clients = this.clientManager.getClients();
  758. if (this.GetSelectedClient() == undefined) {
  759. clients.forEach((client, name) => {
  760. client.eventEmitter.removeAllListeners();
  761. });
  762. this.menuClient_settings_action.setEnabled(false);
  763. this.scrollArea.setEnabled(false);
  764. this.actionRefresh_client_info.setEnabled(false);
  765. this.lblClientName.setText("");
  766. this.lblClientBatteryLevel.setText("");
  767. this.updateClientData();
  768. } else {
  769. clients.forEach((client, name) => {
  770. client.eventEmitter.on('configuration_update', () => this.updateClientData());
  771. client.eventEmitter.on('connected', () => this.updateClientData());
  772. client.eventEmitter.on('websocket_connected', () => this.updateClientData());
  773. client.eventEmitter.on('websocket_disconnected', () => this.updateClientData());
  774. client.eventEmitter.on('deleted', () => this.deviceList.clearSelection());
  775. });
  776. this.updateClientData();
  777. this.menuClient_settings_action.setEnabled(true);
  778. this.scrollArea.setEnabled(true);
  779. // this.scrollArea.setFocus(NodeGUI.FocusReason.OtherFocusReason);
  780. this.actionRefresh_client_info.setEnabled(true);
  781. }
  782. })
  783. leftHandContainer.addWidget(this.deviceList, 0, 0, 1, 1);
  784. let btnPair = new NodeGUI.QPushButton(centralwidget);
  785. btnPair.setObjectName("btnPair");
  786. if (this.enableToolTips)
  787. btnPair.setToolTip("Show instructions to connect a new device.");
  788. btnPair.setText("Pair");
  789. btnPair.addEventListener('clicked', () => {
  790. let tempConnectWindow = this.newChildWindow('tempConnectWindow');
  791. tempConnectWindow.show();
  792. });
  793. leftHandContainer.addWidget(btnPair, 1, 0, 1, 1);
  794. mainLayout.addLayout(leftHandContainer, 0, 0, 1, 1);
  795. // Main contents (setting view)
  796. this.scrollArea = new NodeGUI.QScrollArea(centralwidget);
  797. this.scrollArea.setObjectName("scrollArea");
  798. this.scrollArea.setMinimumSize(125, 175);
  799. this.scrollArea.setHorizontalScrollBarPolicy(NodeGUI.ScrollBarPolicy.ScrollBarAlwaysOff);
  800. this.scrollArea.setWidgetResizable(true);
  801. let scrollAreaWidgetContents = new NodeGUI.QWidget();
  802. scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents");
  803. scrollAreaWidgetContents.setGeometry(0, 0, 440, 498);
  804. scrollAreaWidgetContents.setMinimumSize(175, 0);
  805. let gridLayout = new NodeGUI.QGridLayout(scrollAreaWidgetContents);
  806. gridLayout.setSpacing(10);
  807. gridLayout.setObjectName("gridLayout");
  808. gridLayout.setContentsMargins(0, 0, 0, 0);
  809. // Top bar
  810. let deviceInfoWidget = new NodeGUI.QWidget(scrollAreaWidgetContents);
  811. deviceInfoWidget.setObjectName("deviceInfoWidget");
  812. // QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Fixed);
  813. // sizePolicy1.setHorizontalStretch(0);
  814. // sizePolicy1.setVerticalStretch(25);
  815. // sizePolicy1.setHeightForWidth(deviceInfoWidget.sizePolicy().hasHeightForWidth());
  816. deviceInfoWidget.setSizePolicy(NodeGUI.QSizePolicyPolicy.Expanding, NodeGUI.QSizePolicyPolicy.Fixed);
  817. deviceInfoWidget.setMinimumSize(0, 25);
  818. deviceInfoWidget.setMaximumSize(16777215, 25);
  819. let horizontalLayout = new NodeGUI.QBoxLayout(NodeGUI.Direction.LeftToRight, deviceInfoWidget);
  820. horizontalLayout.setObjectName("horizontalLayout");
  821. horizontalLayout.setContentsMargins(0, 0, 0, 0);
  822. this.lblClientName = new NodeGUI.QLabel(deviceInfoWidget);
  823. this.lblClientName.setObjectName("lblClientName");
  824. this.lblClientName.setMinimumSize(100, 25);
  825. this.lblClientName.setText("");
  826. horizontalLayout.addWidget(this.lblClientName);
  827. this.lblClientBatteryLevel = new NodeGUI.QLabel(deviceInfoWidget);
  828. this.lblClientBatteryLevel.setObjectName("lblClientBatteryLevel");
  829. this.lblClientBatteryLevel.setMinimumSize(138, 25);
  830. this.lblClientBatteryLevel.setMaximumSize(138, 25);
  831. this.lblClientBatteryLevel.setText("");
  832. this.lblClientBatteryLevel.setAlignment(NodeGUI.AlignmentFlag.AlignRight | NodeGUI.AlignmentFlag.AlignVCenter);
  833. horizontalLayout.addWidget(this.lblClientBatteryLevel);
  834. gridLayout.addWidget(deviceInfoWidget, 0, 0, 1, 1);
  835. // Settings
  836. let deviceSettingsWidget = new NodeGUI.QWidget(scrollAreaWidgetContents);
  837. deviceSettingsWidget.setObjectName("deviceSettingsWidget");
  838. let gridDeviceSettings = new NodeGUI.QGridLayout(deviceSettingsWidget);
  839. gridDeviceSettings.setObjectName("gridDeviceSettings");
  840. gridDeviceSettings.setHorizontalSpacing(0);
  841. gridDeviceSettings.setVerticalSpacing(8);
  842. gridDeviceSettings.setContentsMargins(0, 0, 0, 20);
  843. let syncSettingsContainer = new NodeGUI.QWidget(deviceSettingsWidget);
  844. syncSettingsContainer.setObjectName("syncSettingsContainer");
  845. // QSizePolicy sizePolicy2(QSizePolicy::Preferred, QSizePolicy::Preferred);
  846. // sizePolicy2.setHorizontalStretch(0);
  847. // sizePolicy2.setVerticalStretch(0);
  848. // sizePolicy2.setHeightForWidth(syncSettingsContainer.sizePolicy().hasHeightForWidth());
  849. // syncSettingsContainer.setSizePolicy(sizePolicy2);
  850. let gridLayout_2 = new NodeGUI.QGridLayout(syncSettingsContainer);
  851. gridLayout_2.setObjectName("gridLayout_2");
  852. gridLayout_2.setContentsMargins(0, 0, 0, 0);
  853. let lblSyncSettings = new NodeGUI.QLabel(syncSettingsContainer);
  854. lblSyncSettings.setObjectName("lblSyncSettings");
  855. // sizePolicy.setHeightForWidth(lblSyncSettings.sizePolicy().hasHeightForWidth());
  856. lblSyncSettings.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  857. lblSyncSettings.setMinimumSize(30, 0);
  858. lblSyncSettings.setMaximumSize(16777215, 30);
  859. let font = new NodeGUI.QFont();
  860. font.setPointSize(14);
  861. font.setBold(true);
  862. font.setWeight(75);
  863. lblSyncSettings.setFont(font);
  864. if (this.enableToolTips)
  865. lblSyncSettings.setToolTip("");
  866. lblSyncSettings.setText("Sync settings");
  867. lblSyncSettings.setAlignment(NodeGUI.AlignmentFlag.AlignBottom | NodeGUI.AlignmentFlag.AlignLeft);
  868. gridLayout_2.addWidget(lblSyncSettings, 0, 0, 1, 1);
  869. let vlayCheckBoxes = new NodeGUI.QBoxLayout(NodeGUI.Direction.TopToBottom);
  870. vlayCheckBoxes.setSpacing(5);
  871. vlayCheckBoxes.setObjectName("vlayCheckBoxes");
  872. let syncSettingsNotificationsContainer = new NodeGUI.QWidget(syncSettingsContainer);
  873. syncSettingsNotificationsContainer.setObjectName("syncSettingsNotificationsContainer");
  874. // sizePolicy.setHeightForWidth(syncSettingsNotificationsContainer.sizePolicy().hasHeightForWidth());
  875. syncSettingsNotificationsContainer.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  876. let verticalLayout_3 = new NodeGUI.QBoxLayout(NodeGUI.Direction.TopToBottom, syncSettingsNotificationsContainer);
  877. verticalLayout_3.setObjectName("verticalLayout_3");
  878. verticalLayout_3.setContentsMargins(0, 0, 0, 0);
  879. this.chkSyncNotifications = new NodeGUI.QCheckBox(syncSettingsNotificationsContainer);
  880. this.chkSyncNotifications.setObjectName("chkSyncNotifications");
  881. let font1 = new NodeGUI.QFont();
  882. this.chkSyncNotifications.setFont(font1);
  883. this.chkSyncNotifications.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  884. if (this.enableToolTips)
  885. this.chkSyncNotifications.setToolTip("Receive notifications from the client device.");
  886. this.chkSyncNotifications.setText("Sync notifications");
  887. this.chkSyncNotifications.setChecked(true);
  888. this.chkSyncNotifications.addEventListener('clicked', (state) => {
  889. let client = this.GetSelectedClient();
  890. if (client !== undefined) {
  891. client.notificationSettings.enabled = (state === 2);
  892. this.actionSync_notifications.setChecked(state === 2);
  893. this.clientSettingChanged();
  894. }
  895. });
  896. verticalLayout_3.addWidget(this.chkSyncNotifications);
  897. vlayCheckBoxes.addWidget(syncSettingsNotificationsContainer);
  898. let hlineUnderNotifications = new NodeGUI.QFrame(syncSettingsContainer);
  899. hlineUnderNotifications.setObjectName("hlineUnderNotifications");
  900. hlineUnderNotifications.setFrameShape(NodeGUI.Shape.HLine);
  901. hlineUnderNotifications.setFrameShadow(NodeGUI.Shadow.Sunken);
  902. vlayCheckBoxes.addWidget(hlineUnderNotifications);
  903. let syncSettingsClipboardContainer = new NodeGUI.QWidget(syncSettingsContainer);
  904. syncSettingsClipboardContainer.setObjectName("syncSettingsClipboardContainer");
  905. //syncSettingsClipboardContainer.setEnabled(false);
  906. // sizePolicy.setHeightForWidth(syncSettingsClipboardContainer.sizePolicy().hasHeightForWidth());
  907. syncSettingsClipboardContainer.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  908. let verticalLayout_2 = new NodeGUI.QBoxLayout(NodeGUI.Direction.TopToBottom, syncSettingsClipboardContainer);
  909. verticalLayout_2.setObjectName("verticalLayout_2");
  910. verticalLayout_2.setContentsMargins(0, 0, 0, 0);
  911. this.chkSyncClipboard = new NodeGUI.QCheckBox(syncSettingsClipboardContainer);
  912. this.chkSyncClipboard.setObjectName("chkSyncClipboard");
  913. this.chkSyncClipboard.setFont(font1);
  914. this.chkSyncClipboard.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  915. if (this.enableToolTips)
  916. this.chkSyncClipboard.setToolTip("Allow syncing the clipboard between this computer and the client device.");
  917. this.chkSyncClipboard.setText("Enable sharing clipboard");
  918. this.chkSyncClipboard.addEventListener('clicked', (state) => {
  919. this.updateEnableClipboardSharing(state === 2? true : false);
  920. if (this.actionToggleClipboardSharing.isChecked() !== (state === 2))
  921. this.actionToggleClipboardSharing.setChecked(state === 2);
  922. this.clientSettingChanged();
  923. });
  924. verticalLayout_2.addWidget(this.chkSyncClipboard);
  925. this.chkAutoSendClipboard = new NodeGUI.QCheckBox(syncSettingsClipboardContainer);
  926. this.chkAutoSendClipboard.setObjectName("chkAutoSendClipboard");
  927. this.chkAutoSendClipboard.setFont(font1);
  928. this.chkAutoSendClipboard.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  929. if (this.enableToolTips)
  930. this.chkAutoSendClipboard.setToolTip("Automatically send this computer's clipboard data to the client.");
  931. this.chkAutoSendClipboard.setStyleSheet("margin-left: 25px;");
  932. this.chkAutoSendClipboard.setText("Automatically send to client");
  933. this.chkAutoSendClipboard.addEventListener('clicked', (state) => {
  934. let client = this.GetSelectedClient();
  935. if (client !== undefined) {
  936. client.clipboardSettings.synchronizeClipboardToClient = (state === 2);
  937. this.clientSettingChanged();
  938. }
  939. });
  940. verticalLayout_2.addWidget(this.chkAutoSendClipboard);
  941. this.chkClipboardAllowClientToGet = new NodeGUI.QCheckBox(syncSettingsClipboardContainer);
  942. this.chkClipboardAllowClientToGet.setObjectName("chkClipboardAllowClientToGet");
  943. this.chkClipboardAllowClientToGet.setFont(font1);
  944. this.chkClipboardAllowClientToGet.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  945. if (this.enableToolTips)
  946. this.chkClipboardAllowClientToGet.setToolTip("Allows the client to request and receive this computer's clipboard contents.");
  947. this.chkClipboardAllowClientToGet.setStyleSheet("margin-left: 25px;");
  948. this.chkClipboardAllowClientToGet.setText("Allow client to request clipboard data");
  949. this.chkClipboardAllowClientToGet.addEventListener('clicked', (state) => {
  950. let client = this.GetSelectedClient();
  951. if (client !== undefined) {
  952. client.clipboardSettings.allowClientToGet = (state === 2);
  953. this.clientSettingChanged();
  954. }
  955. });
  956. verticalLayout_2.addWidget(this.chkClipboardAllowClientToGet);
  957. vlayCheckBoxes.addWidget(syncSettingsClipboardContainer);
  958. let hlineUnderClipboard = new NodeGUI.QFrame(syncSettingsContainer);
  959. hlineUnderClipboard.setObjectName("hlineUnderClipboard");
  960. hlineUnderClipboard.setFrameShape(NodeGUI.Shape.HLine);
  961. hlineUnderClipboard.setFrameShadow(NodeGUI.Shadow.Sunken);
  962. vlayCheckBoxes.addWidget(hlineUnderClipboard);
  963. let syncSettingsFileSharingContainer = new NodeGUI.QWidget(syncSettingsContainer);
  964. syncSettingsFileSharingContainer.setObjectName("syncSettingsFileSharingContainer");
  965. //syncSettingsFileSharingContainer.setEnabled(false);
  966. // sizePolicy.setHeightForWidth(syncSettingsFileSharingContainer.sizePolicy().hasHeightForWidth());
  967. syncSettingsFileSharingContainer.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  968. let gridLayout_4 = new NodeGUI.QGridLayout(syncSettingsFileSharingContainer);
  969. gridLayout_4.setObjectName("gridLayout_4");
  970. gridLayout_4.setContentsMargins(0, 0, 0, 0);
  971. let fileSharingCheckboxes = new NodeGUI.QBoxLayout(NodeGUI.Direction.TopToBottom);
  972. fileSharingCheckboxes.setObjectName("fileSharingCheckboxes");
  973. this.chkFileSharingEnable = new NodeGUI.QCheckBox(syncSettingsFileSharingContainer);
  974. this.chkFileSharingEnable.setObjectName("chkFileSharingEnable");
  975. this.chkFileSharingEnable.setFont(font1);
  976. this.chkFileSharingEnable.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  977. if (this.enableToolTips)
  978. this.chkFileSharingEnable.setToolTip("Enable sending and receiving files for this client.");
  979. this.chkFileSharingEnable.setText("Enable file sharing");
  980. this.chkFileSharingEnable.addEventListener('clicked', (state) => {
  981. this.updateEnableFileSharing(state == 2? true : false);
  982. if (this.actionToggleFileSharing.isChecked() !== (state === 2))
  983. this.actionToggleFileSharing.setChecked(state === 2);
  984. this.clientSettingChanged();
  985. });
  986. fileSharingCheckboxes.addWidget(this.chkFileSharingEnable);
  987. this.chkFileSharingAutoAccept = new NodeGUI.QCheckBox(syncSettingsFileSharingContainer);
  988. this.chkFileSharingAutoAccept.setObjectName("chkFileSharingAutoAccept");
  989. this.chkFileSharingAutoAccept.setFont(font1);
  990. this.chkFileSharingAutoAccept.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  991. if (this.enableToolTips)
  992. this.chkFileSharingAutoAccept.setToolTip("Automatically accept incoming files from this device.");
  993. this.chkFileSharingAutoAccept.setStyleSheet("margin-left: 25px;");
  994. this.chkFileSharingAutoAccept.setText("Automatically accept incoming files");
  995. this.chkFileSharingAutoAccept.addEventListener('clicked', (state) => {
  996. let client = this.GetSelectedClient();
  997. if (client !== undefined) {
  998. client.fileSharingSettings.requireConfirmationOnClinetUploads = (state !== 2);
  999. this.clientSettingChanged();
  1000. }
  1001. });
  1002. fileSharingCheckboxes.addWidget(this.chkFileSharingAutoAccept);
  1003. this.chkFileSharingNotify = new NodeGUI.QCheckBox(syncSettingsFileSharingContainer);
  1004. this.chkFileSharingNotify.setObjectName("chkFileSharingNotify");
  1005. this.chkFileSharingNotify.setFont(font1);
  1006. this.chkFileSharingNotify.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1007. if (this.enableToolTips)
  1008. this.chkFileSharingNotify.setToolTip("Notify on incoming files for this device.");
  1009. this.chkFileSharingNotify.setStyleSheet("margin-left: 25px;");
  1010. this.chkFileSharingNotify.setText("Notify on receive");
  1011. this.chkFileSharingNotify.addEventListener('clicked', (state) => {
  1012. let client = this.GetSelectedClient();
  1013. if (client !== undefined) {
  1014. client.fileSharingSettings.notifyOnReceive = (state === 2);
  1015. this.clientSettingChanged();
  1016. }
  1017. });
  1018. fileSharingCheckboxes.addWidget(this.chkFileSharingNotify);
  1019. this.chkFilesharingAllowClientToUpload = new NodeGUI.QCheckBox(syncSettingsFileSharingContainer);
  1020. this.chkFilesharingAllowClientToUpload.setObjectName("chkFilesharingAllowClientToUpload");
  1021. this.chkFilesharingAllowClientToUpload.setFont(font1);
  1022. this.chkFilesharingAllowClientToUpload.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1023. if (this.enableToolTips)
  1024. this.chkFilesharingAllowClientToUpload.setToolTip("Allows the client to browse the files on this computer.");
  1025. this.chkFilesharingAllowClientToUpload.setStyleSheet("margin-left: 25px;");
  1026. this.chkFilesharingAllowClientToUpload.setText("Allow client to upload files.");
  1027. this.chkFilesharingAllowClientToUpload.addEventListener('clicked', (state) => {
  1028. let client = this.GetSelectedClient();
  1029. if (client !== undefined) {
  1030. client.fileSharingSettings.allowClientToUpload = (state === 2);
  1031. this.actionToggleAllowClientToUpload.setChecked(state === 2);
  1032. this.clientSettingChanged();
  1033. }
  1034. });
  1035. fileSharingCheckboxes.addWidget(this.chkFilesharingAllowClientToUpload);
  1036. gridLayout_4.addLayout(fileSharingCheckboxes, 0, 0, 1, 1);
  1037. let widget = new NodeGUI.QWidget(syncSettingsFileSharingContainer);
  1038. widget.setObjectName("widget");
  1039. // sizePolicy.setHeightForWidth(widget.sizePolicy().hasHeightForWidth());
  1040. widget.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  1041. widget.setMinimumSize(0, 0);
  1042. let gridLayout_5 = new NodeGUI.QGridLayout(widget);
  1043. gridLayout_5.setObjectName("gridLayout_5");
  1044. this.txtFileSharingSaveDirectory = new NodeGUI.QLineEdit(widget);
  1045. this.txtFileSharingSaveDirectory.setObjectName("txtFileSharingSaveDirectory");
  1046. this.txtFileSharingSaveDirectory.setEnabled(false);
  1047. let saveDirectory = "";
  1048. if (this.GetSelectedClient() !== undefined) {
  1049. let client = this.GetSelectedClient();
  1050. saveDirectory = client.getReceivedFilesDirectory();
  1051. }
  1052. this.txtFileSharingSaveDirectory.setText(saveDirectory);
  1053. if (this.enableToolTips)
  1054. this.txtFileSharingSaveDirectory.setToolTip("Directory incoming files are saved to.");
  1055. gridLayout_5.addWidget(this.txtFileSharingSaveDirectory, 1, 0, 1, 1);
  1056. this.btnFileSharingSaveDirectoryBrowse = new NodeGUI.QPushButton(widget);
  1057. this.btnFileSharingSaveDirectoryBrowse.setObjectName("btnFileSharingSaveDirectoryBrowse");
  1058. this.btnFileSharingSaveDirectoryBrowse.setFont(font1);
  1059. this.btnFileSharingSaveDirectoryBrowse.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1060. if (this.enableToolTips)
  1061. this.btnFileSharingSaveDirectoryBrowse.setToolTip("Open folder picker dialog.");
  1062. this.btnFileSharingSaveDirectoryBrowse.setText("Browse");
  1063. this.btnFileSharingSaveDirectoryBrowse.addEventListener('clicked', () => {
  1064. let client = this.GetSelectedClient();
  1065. if (client !== undefined) {
  1066. let fileDialog = new NodeGUI.QFileDialog();
  1067. fileDialog.setFileMode(NodeGUI.FileMode.Directory);
  1068. fileDialog.setWindowTitle("Select a download folder for " + (client.friendlyName !== undefined? client.friendlyName : "the client") + ".");
  1069. fileDialog.setOptions(NodeGUI.Option.ShowDirsOnly);
  1070. let acceptedOrDenied = fileDialog.exec();
  1071. if (acceptedOrDenied == NodeGUI.DialogCode.Accepted) {
  1072. let selectedFolder = fileDialog.selectedFiles()[0];
  1073. client.fileSharingSettings.receivedFilesDirectory = selectedFolder;
  1074. saveDirectory = client.getReceivedFilesDirectory(); // runs checks ?
  1075. this.txtFileSharingSaveDirectory.setText(saveDirectory);
  1076. this.clientSettingChanged();
  1077. }
  1078. }
  1079. });
  1080. gridLayout_5.addWidget(this.btnFileSharingSaveDirectoryBrowse, 1, 1, 1, 1);
  1081. let lblSaveFilesTo = new NodeGUI.QLabel(widget);
  1082. lblSaveFilesTo.setObjectName("lblSaveFilesTo");
  1083. lblSaveFilesTo.setFont(font1);
  1084. lblSaveFilesTo.setText("Save files to:");
  1085. gridLayout_5.addWidget(lblSaveFilesTo, 0, 0, 1, 1);
  1086. gridLayout_4.addWidget(widget, 1, 0, 1, 1);
  1087. vlayCheckBoxes.addWidget(syncSettingsFileSharingContainer);
  1088. gridLayout_2.addLayout(vlayCheckBoxes, 1, 0, 1, 1);
  1089. gridDeviceSettings.addWidget(syncSettingsContainer, 1, 0, 1, 1);
  1090. let bottomButtonContiner = new NodeGUI.QWidget(deviceSettingsWidget);
  1091. bottomButtonContiner.setObjectName("bottomButtonContiner");
  1092. // sizePolicy.setHeightForWidth(bottomButtonContiner.sizePolicy().hasHeightForWidth());
  1093. bottomButtonContiner.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  1094. let verticalLayout_4 = new NodeGUI.QBoxLayout(NodeGUI.Direction.TopToBottom, bottomButtonContiner);
  1095. verticalLayout_4.setSpacing(5);
  1096. verticalLayout_4.setObjectName("verticalLayout_4");
  1097. verticalLayout_4.setContentsMargins(0, 0, 0, 0);
  1098. let hlaySaveButton = new NodeGUI.QBoxLayout(NodeGUI.Direction.LeftToRight);
  1099. hlaySaveButton.setObjectName("hlaySaveButton");
  1100. this.btnSave = new NodeGUI.QPushButton(bottomButtonContiner);
  1101. this.btnSave.setObjectName("btnSave");
  1102. // QSizePolicy sizePolicy3(QSizePolicy::Fixed, QSizePolicy::Fixed);
  1103. // sizePolicy3.setHorizontalStretch(0);
  1104. // sizePolicy3.setVerticalStretch(0);
  1105. // sizePolicy3.setHeightForWidth(btnSave.sizePolicy().hasHeightForWidth());
  1106. this.btnSave.setSizePolicy(NodeGUI.QSizePolicyPolicy.Fixed, NodeGUI.QSizePolicyPolicy.Fixed);
  1107. this.btnSave.setMinimumSize(200, 30);
  1108. this.btnSave.setFont(font1);
  1109. this.btnSave.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1110. if (this.enableToolTips)
  1111. this.btnSave.setToolTip("Save client settings.");
  1112. this.btnSave.setText("Save");
  1113. this.btnSave.addEventListener('clicked', () => {
  1114. let client = this.GetSelectedClient();
  1115. if (client !== undefined) {
  1116. this.saveClientData();
  1117. }
  1118. });
  1119. hlaySaveButton.addWidget(this.btnSave);
  1120. verticalLayout_4.addLayout(hlaySaveButton);
  1121. if (!NeptuneConfig.applicationSettings.requireSaveButton) {
  1122. this.btnSave.setVisible(false);
  1123. this.btnSave.setEnabled(false);
  1124. }
  1125. let hlayDeleteButton = new NodeGUI.QBoxLayout(NodeGUI.Direction.LeftToRight);
  1126. hlayDeleteButton.setObjectName("hlayDeleteButton");
  1127. this.btnDelete = new NodeGUI.QPushButton(bottomButtonContiner);
  1128. this.btnDelete.setObjectName("btnDelete");
  1129. this.btnDelete.setSizePolicy(NodeGUI.QSizePolicyPolicy.Fixed, NodeGUI.QSizePolicyPolicy.Fixed);
  1130. this.btnDelete.setMinimumSize(200, 30);
  1131. this.btnDelete.setFont(font1);
  1132. this.btnDelete.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1133. if (this.enableToolTips)
  1134. this.btnDelete.setToolTip("Delete this client.");
  1135. this.btnDelete.setText("Delete");
  1136. this.btnDelete.addEventListener('clicked', () => {
  1137. let client = this.GetSelectedClient();
  1138. if (client !== undefined) {
  1139. let okayButton = new NodeGUI.QPushButton();
  1140. okayButton.setText("Yes");
  1141. let cancelButton = new NodeGUI.QPushButton();
  1142. cancelButton.setText("No");
  1143. let result = this.displayMessageBox("Delete and unpair " + (client.friendlyName === undefined? "the client" : client.friendlyName) + "?",
  1144. "Are you sure you want to delete and unpair with " + (client.friendlyName === undefined? "the client" : client.friendlyName) + "?",
  1145. [
  1146. { button: okayButton, buttonRole: NodeGUI.ButtonRole.AcceptRole },
  1147. { button: cancelButton, buttonRole: NodeGUI.ButtonRole.RejectRole },
  1148. ]);
  1149. if (result != NodeGUI.DialogCode.Accepted) {
  1150. this.RemoveClientFromDeviceList(client.friendlyName);
  1151. client.delete();
  1152. }
  1153. }
  1154. });
  1155. hlayDeleteButton.addWidget(this.btnDelete);
  1156. verticalLayout_4.addLayout(hlayDeleteButton);
  1157. gridDeviceSettings.addWidget(bottomButtonContiner, 3, 0, 1, 1);
  1158. let topButtonContainer = new NodeGUI.QWidget(deviceSettingsWidget);
  1159. topButtonContainer.setObjectName("topButtonContainer");
  1160. topButtonContainer.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  1161. topButtonContainer.setMinimumSize(250, 0);
  1162. let verticalLayout = new NodeGUI.QBoxLayout(NodeGUI.Direction.TopToBottom, topButtonContainer);
  1163. verticalLayout.setSpacing(5);
  1164. verticalLayout.setObjectName("verticalLayout");
  1165. verticalLayout.setContentsMargins(0, 0, 0, 0);
  1166. this.btnSendFile = new NodeGUI.QPushButton(topButtonContainer);
  1167. this.btnSendFile.setObjectName("btnSendFile");
  1168. this.btnSendFile.setMinimumSize(255, 30);
  1169. this.btnSendFile.setFont(font1);
  1170. this.btnSendFile.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1171. if (this.enableToolTips)
  1172. this.btnSendFile.setToolTip("Open the file selector dialog and send a file to the client device.");
  1173. this.btnSendFile.setText("Send file");
  1174. this.btnSendFile.setEnabled(false);
  1175. this.btnSendFile.addEventListener('clicked', () => {
  1176. let client = this.GetSelectedClient();
  1177. if (client !== undefined) {
  1178. this.#sendFile(client);
  1179. }
  1180. });
  1181. verticalLayout.addWidget(this.btnSendFile);
  1182. let hlayClipboardContainer = new NodeGUI.QWidget(topButtonContainer);
  1183. hlayClipboardContainer.setObjectName("hlayClipboardContainer");
  1184. // QSizePolicy sizePolicy4(QSizePolicy::Preferred, QSizePolicy::Fixed);
  1185. // sizePolicy4.setHorizontalStretch(0);
  1186. // sizePolicy4.setVerticalStretch(30);
  1187. // sizePolicy4.setHeightForWidth(hlayClipboardContainer.sizePolicy().hasHeightForWidth());
  1188. hlayClipboardContainer.setSizePolicy(NodeGUI.QSizePolicyPolicy.Preferred, NodeGUI.QSizePolicyPolicy.Fixed);
  1189. hlayClipboardContainer.setMinimumSize(255, 30);
  1190. hlayClipboardContainer.setMaximumSize(16777215, 30);
  1191. let horizontalLayout_3 = new NodeGUI.QBoxLayout(NodeGUI.Direction.LeftToRight, hlayClipboardContainer);
  1192. horizontalLayout_3.setSpacing(5);
  1193. horizontalLayout_3.setObjectName("horizontalLayout_3");
  1194. horizontalLayout_3.setContentsMargins(0, 0, 0, 0);
  1195. this.btnSendClipboard = new NodeGUI.QPushButton(hlayClipboardContainer);
  1196. this.btnSendClipboard.setObjectName("btnSendClipboard");
  1197. this.btnSendClipboard.setMinimumSize(115, 30);
  1198. this.btnSendClipboard.setFont(font1);
  1199. this.btnSendClipboard.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1200. if (this.enableToolTips)
  1201. this.btnSendClipboard.setToolTip("Send this computer's clipboard data to the client device.");
  1202. this.btnSendClipboard.setText("Send clipboard");
  1203. this.btnSendClipboard.setEnabled(false);
  1204. this.btnSendClipboard.addEventListener('clicked', () => {
  1205. this.sendClipboardData();
  1206. });
  1207. horizontalLayout_3.addWidget(this.btnSendClipboard);
  1208. this.btnReceiveClipboard = new NodeGUI.QPushButton(hlayClipboardContainer);
  1209. this.btnReceiveClipboard.setObjectName("btnReceiveClipboard");
  1210. this.btnReceiveClipboard.setMinimumSize(115, 30);
  1211. this.btnReceiveClipboard.setFont(font1);
  1212. this.btnReceiveClipboard.setCursor(NodeGUI.CursorShape.PointingHandCursor);
  1213. if (this.enableToolTips)
  1214. this.btnReceiveClipboard.setToolTip("Request the clipboard data from the client device.");
  1215. this.btnReceiveClipboard.setText("Receive clipboard");
  1216. this.btnReceiveClipboard.setEnabled(false);
  1217. this.btnReceiveClipboard.addEventListener('clicked', () => {
  1218. this.receiveClipboardData();
  1219. });
  1220. horizontalLayout_3.addWidget(this.btnReceiveClipboard);
  1221. verticalLayout.addWidget(hlayClipboardContainer);
  1222. gridDeviceSettings.addWidget(topButtonContainer, 0, 0, 1, 1);
  1223. gridLayout.addWidget(deviceSettingsWidget, 2, 0, 1, 1);
  1224. this.scrollArea.setWidget(scrollAreaWidgetContents);
  1225. mainLayout.addWidget(this.scrollArea, 0, 1, 1, 1);
  1226. gridLayout_3.addLayout(mainLayout, 0, 0, 1, 1);
  1227. this.setCentralWidget(centralwidget);
  1228. // add clients
  1229. try {
  1230. var removeFunction = this.RemoveClientFromDeviceList;
  1231. var addFunction = this.AddClientToDeviceList;
  1232. let clients = this.clientManager.getClients();
  1233. clients.forEach((client, name) => {
  1234. this.AddClientToDeviceList(client);
  1235. });
  1236. let maybeThis = this;
  1237. this.clientManager.addListener('added', (client) => {
  1238. if (maybeThis.isVisible()) {
  1239. console.log("ADDED")
  1240. maybeThis.AddClientToDeviceList(client);
  1241. }
  1242. });
  1243. this.clientManager.addListener('removed', (client) => {
  1244. if (maybeThis.isVisible()) {
  1245. maybeThis.RemoveClientFromDeviceList(client);
  1246. }
  1247. });
  1248. this.updateClientData();
  1249. } catch (ee) {}
  1250. } catch(e) {
  1251. console.log(e)
  1252. }
  1253. }
  1254. /**
  1255. * @typedef {object} messageboxButtons
  1256. * @property {NodeGUI.QPushButton} button
  1257. * @property {NodeGUI.ButtonRole} buttonRole
  1258. */
  1259. /**
  1260. * Displays a message box with custom buttons.
  1261. *
  1262. * @param {string} title - The title of the message box.
  1263. * @param {string} message - The message text of the message box.
  1264. * @param {messageboxButtons[]} buttons - An array of objects representing each custom button to add to the message box. Each object should contain a `button` property representing the `QPushButton` object, and an optional `buttonRole` property representing the button role (defaults to `ButtonRole.AcceptRole` if not specified).
  1265. *
  1266. * @returns {NodeGUI.DialogCode} - Whether the dialog was accepted `NodeGUI.DialogCode.Accepted` or rejected `NodeGUI.DialogCode.Rejected`.
  1267. */
  1268. displayMessageBox(title, message, buttons) {
  1269. if (!this.isVisible())
  1270. return;
  1271. const messageBox = new NodeGUI.QMessageBox();
  1272. messageBox.setWindowTitle(title);
  1273. messageBox.setText(message);
  1274. if (!global.RunningTest) // I hate this
  1275. messageBox.setWindowIcon(process.ResourceManager.ApplicationIcon);
  1276. if (process.platform == 'win32') {
  1277. try {
  1278. // This allows NeptuneRunner to fix the window's taskbar data
  1279. messageBox.addEventListener(NodeGUI.WidgetEventTypes.Show, () => {
  1280. global.NeptuneRunnerIPC.pipe.write("fixwinhwnd" + this.winId() + "");
  1281. });
  1282. } catch (_) {}
  1283. }
  1284. if (buttons === undefined) {
  1285. let okayButton = new NodeGUI.QPushButton();
  1286. okayButton.setText("Okay");
  1287. buttons = [{ button: okayButton, buttonRole: NodeGUI.ButtonRole.AcceptRole }]
  1288. }
  1289. // Add custom buttons to the message box
  1290. buttons.forEach(({ button, buttonRole }) => {
  1291. messageBox.addButton(button, buttonRole || NodeGUI.ButtonRole.AcceptRole);
  1292. button.addEventListener('clicked', () => {
  1293. messageBox.done(buttonRole || NodeGUI.ButtonRole.AcceptRole);
  1294. });
  1295. });
  1296. // Show the message box and return the result
  1297. const result = messageBox.exec();
  1298. return result;
  1299. }
  1300. /**
  1301. * Open the file dialog picker for the user to select files to send to a client.
  1302. * @param {Client} client - The client files will be sent to.
  1303. */
  1304. #sendFile(client) {
  1305. try {
  1306. let fileDialog = new NodeGUI.QFileDialog();
  1307. fileDialog.setFileMode(NodeGUI.FileMode.ExistingFiles);
  1308. fileDialog.setWindowTitle("Send a file to " + (client.friendlyName !== undefined? client.friendlyName : "the client") + ".");
  1309. fileDialog.setOptions(NodeGUI.Option.DontConfirmOverwrite);
  1310. fileDialog.setNameFilter('All files (*.*)');
  1311. let acceptedOrDenied = fileDialog.exec();
  1312. if (acceptedOrDenied == NodeGUI.DialogCode.Accepted) {
  1313. let files = fileDialog.selectedFiles();
  1314. files.forEach(filePath => {
  1315. client.sendFile(filePath);
  1316. });
  1317. }
  1318. } catch(error) {
  1319. let okayButton = new NodeGUI.QPushButton();
  1320. okayButton.setText("Okay");
  1321. this.displayMessageBox(
  1322. "Failed to send file.",
  1323. "Failed to send selected file(s) to the client.\nReason: " + error.message,
  1324. [
  1325. { button: okayButton, buttonRole: NodeGUI.ButtonRole.AcceptRole },
  1326. ]
  1327. );
  1328. }
  1329. }
  1330. }
  1331. module.exports = thisTest;