diff --git a/CompuRacer_Core/src/command_processor.py b/CompuRacer_Core/src/command_processor.py index b9932f3..7242b81 100644 --- a/CompuRacer_Core/src/command_processor.py +++ b/CompuRacer_Core/src/command_processor.py @@ -16,12 +16,12 @@ import src.utils as utils -from src.maingui import MainGUI +from src.connectgui import ConnectGUI -from PyQt5.QtCore import QThread, QObject, pyqtSignal +from PyQt5.QtCore import QThread, pyqtSignal from PyQt5.QtWidgets import QApplication -__version__ = "v1" +__version__ = "v1.1.0" class GuiThread(QThread): start_gui_signal = pyqtSignal() @@ -140,7 +140,7 @@ def gui_interpreter(self, state): self.print_formatted("Starting GUI " + __version__ + "..", utils.QType.INFORMATION) app = QApplication([]) - MainGUI.show_requests_gui(self.racer, app, state, self) + ConnectGUI.show_requests_gui(self.racer, app, state, self) def command_interpreter(self): self.welcome_function(self.welcome_function_class) diff --git a/CompuRacer_Core/src/compu_racer_core.py b/CompuRacer_Core/src/compu_racer_core.py index 623543a..ade5591 100644 --- a/CompuRacer_Core/src/compu_racer_core.py +++ b/CompuRacer_Core/src/compu_racer_core.py @@ -523,7 +523,7 @@ def add_commands_batches(self): arg_spec_opt=[("Index of the batch", int, "* the current batch *"), ("Print result summary", bool, True)] ) - self.command_processor.add_command(["add bs", "add batch"], self.comm_batches_create_new_static, + self.command_processor.add_command(["add bs", "add batch"], self.comm_batches_create_new, "Creates a new batch by name and sets it as current batch (must be unique)", self, arg_spec=[("Name of the batch", str)], @@ -624,7 +624,7 @@ def add_commands_current_batch(self): "Sets the current batch send timout (default 20 seconds).", self, arg_spec_opt=[("send timeout >= 1", int, 20)] ) - self.command_processor.add_command(["add"], self.comm_curr_add_static, + self.command_processor.add_command(["add"], self.comm_curr_add, "Adds a request to the current batch by ID, wait_time, parallel and sequential duplicates", self, arg_spec=[("Request ID", str)], @@ -895,19 +895,19 @@ def comm_requests_remove(self, request_id_first=None, request_id_last=None, ask_ self.print_formatted(f"Removal of all requests cancelled.", utils.QType.INFORMATION) return elif request_id_last is not None: - # remove a range of requests if not ask_confirmation or self.command_processor.accept_yes_no( f"Are you sure you want to remove requests with id between and including {request_id_first} and {request_id_last}?", utils.QType.WARNING): + # remove a range of requests for i, request_id in enumerate(copy.deepcopy(list(self.state['requests'].keys()))): if request_id_first <= request_id <= request_id_last: if self.rem_request(self, request_id, False) == -1: failed_requests.append(request_id) else: success_requests.append(request_id) - else: - self.print_formatted(f"Removal of range of requests cancelled.", utils.QType.INFORMATION) - return + else: + self.print_formatted(f"Removal of range of requests cancelled.", utils.QType.INFORMATION) + return else: # remove one request if self.rem_request(self, request_id_first, True) == -1: @@ -1059,15 +1059,9 @@ def add_request(self, a_request, used_from_interface=False, print_information=Tr self.rem_batch_by_name(self, self.immediate_batch_name, True) if self.immediate_batch_name not in self.state['batches']: # create new immediate batch - if self.cli_check: - return self.comm_batches_create_new_static(self, self.immediate_batch_name, False, - not used_from_interface, - allow_redirects, sync_last_byte, send_timeout) - else: - return self.comm_batches_create_new(self, self.immediate_batch_name, False, - not used_from_interface, - allow_redirects, sync_last_byte, send_timeout) - + return self.comm_batches_create_new(self, self.immediate_batch_name, False, + not used_from_interface, + allow_redirects, sync_last_byte, send_timeout) immediate_batch = self.state['batches'][self.immediate_batch_name] try: immediate_batch.add(req_id, 0, par, seq, False) @@ -1112,7 +1106,7 @@ def request_used_in(self, request_id): return used_in @staticmethod # do not add requests to this list in any other way - def rem_request(self, request_id, ask_confirmation=False): + def rem_request(self, request_id, ask_confirmation=True): with self.requests_list_lock: if request_id not in self.state['requests']: self.print_formatted(f"Cannot remove request:\n\t" @@ -1126,28 +1120,16 @@ def rem_request(self, request_id, ask_confirmation=False): f"The request with id '{request_id}' is (also) used by the immediate batch!", utils.QType.ERROR) return -1 - if not ask_confirmation: + if self.cli_check: self.print_formatted(f"The request with id '{request_id}' is used by batches: " f"{used_in}. It must be removed individually.", utils.QType.ERROR) return -1 - # remove request from the batches - if not self.command_processor.accept_yes_no(f"The request with id '{request_id}' is used by batches: " - f"{used_in}, continue?\n\tIt will be removed from these batches and their results are cleared!!", - utils.QType.WARNING): - return -1 - # remove request from the batches for batch_name in used_in: self.state['batches'][batch_name].remove(request_id) ask_confirmation = False - - if not ask_confirmation or self.command_processor.accept_yes_no( - f"Are you sure you want to remove the request with id '{request_id}'?", - utils.QType.WARNING): - self.__change_state('requests', sub_search=request_id, do_delete=True) - self.print_formatted(f"Request with id '{request_id}' is removed", utils.QType.INFORMATION) - else: - self.print_formatted(f"Removal of request cancelled.", utils.QType.INFORMATION) + self.__change_state('requests', sub_search=request_id, do_delete=True) + self.print_formatted(f"Request with id '{request_id}' is removed", utils.QType.INFORMATION) # --------------------------------------------------------------------------------------------------- # # ------------------------------------- Batch command functions ------------------------------------- # @@ -1163,9 +1145,6 @@ def get_batch_result_formatting(): re.compile(r"'status_code': 4.."): utils.QType.RED, re.compile(r"'status_code': 5.."): utils.QType.BLUE} - def gui_send_batches(self): - self.comm_batches_send(self) - @staticmethod def comm_batches_send(self, index=None, print_results=True, immediate_allowed=False): name = self.batch_index_to_name(self, index) @@ -1221,10 +1200,7 @@ def comm_batches_set_current(self, index, immediate_allowed=False): name = self.batch_index_to_name(self, index) if name == -1: return -1 - if self.cli_check: - return self.set_curr_batch_by_name_static(self, name, immediate_allowed) - else: - return self.set_curr_batch_by_name(self, name, immediate_allowed) + return self.set_curr_batch_by_name(self, name, immediate_allowed) @staticmethod def add_prefix(self, name): @@ -1234,7 +1210,7 @@ def add_prefix(self, name): return self.state['project_name'] + name @staticmethod - def comm_batches_create_new_static(self, name, set_current_batch=True, immediate_allowed=False, + def comm_batches_create_new(self, name, set_current_batch=True, immediate_allowed=False, allow_redirects=False, sync_last_byte=False, send_timeout=20): if name != self.immediate_batch_name: name = self.add_prefix(self, name) @@ -1249,10 +1225,7 @@ def comm_batches_create_new_static(self, name, set_current_batch=True, immediate self.print_formatted(f"Created a new batch:", utils.QType.INFORMATION) self.print_formatted(new_batch.get_summary(), utils.QType.BLUE) if set_current_batch: - return self.set_curr_batch_by_name_static(self, name) - - def gui_create_new_batch(self, name): - self.comm_batches_create_new_static(self, name) + return self.set_curr_batch_by_name(self, name) @staticmethod def comm_batches_get_project(self): @@ -1474,14 +1447,6 @@ def batch_index_to_name(self, index, indices=None): return indices[index] @staticmethod - def set_curr_batch_by_name_static(self, name, immediate_allowed=False): - if not immediate_allowed and name == self.immediate_batch_name: - self.print_formatted(f"Not allowed to set immediate batch as current batch from interface!", - utils.QType.ERROR) - return -1 - self.__change_state('current_batch', name) - self.print_formatted(f"Set current batch to batch with name '{name}'.", utils.QType.INFORMATION) - def set_curr_batch_by_name(self, name, immediate_allowed=False): if not immediate_allowed and name == self.immediate_batch_name: self.print_formatted(f"Not allowed to set immediate batch as current batch from interface!", @@ -1798,7 +1763,7 @@ def comm_curr_compare_groups(self, group_nr_1, group_nr_2, request_id=None): # NOTE: it does not overwrite an item with the same id & wait_time. @staticmethod - def comm_curr_add_static(self, request_id, wait_time=0, dup_par=1, dup_seq=1): + def comm_curr_add(self, request_id, wait_time=0, dup_par=1, dup_seq=1): """ Adds the request with this wait time and the parallel and sequential values to the current batch :param self: reference to the CompuRacer @@ -1829,37 +1794,6 @@ def comm_curr_add_static(self, request_id, wait_time=0, dup_par=1, dup_seq=1): f"{curr_batch.get_info(request_id, wait_time)}", utils.QType.INFORMATION) - def comm_curr_add(self, state, request_id, wait_time=0, dup_par=1, dup_seq=1): - """ - Adds the request with this wait time and the parallel and sequential values to the current batch - :param self: reference to the CompuRacer - :param request_id: the id of the request - :param wait_time: the wait time of the request before sending it - :param dup_par: the parallel duplication - :param dup_seq: the parallel sequential - :return: 0 on success and -1 on error - :return: - """ - if request_id not in state['requests']: - self.print_formatted( - f"Cannot add a request to current batch: The request with id '{request_id}' is not in the request list!", - utils.QType.ERROR) - return -1 - if not state['current_batch']: - self.print_formatted( - f"Cannot add a request to current batch: There is no current batch! First, select a current batch.", - utils.QType.ERROR) - return -1 - curr_batch = self.state['batches'][self.state['current_batch']] - try: - curr_batch.add(request_id, wait_time, dup_par, dup_seq, False) - except Exception as e: - self.print_formatted(f"Cannot add a request to current batch:\n\t{e}", utils.QType.ERROR) - return -1 - self.print_formatted(f"The request was added to the current batch:\n" - f"{curr_batch.get_info(request_id, wait_time)}", - utils.QType.INFORMATION) - # NOTE: it does not overwrite an item with the same id & wait_time. @staticmethod def comm_curr_update(self, request_id, wait_time=0, dup_par=1, dup_seq=1): @@ -1965,21 +1899,23 @@ def comm_curr_remove(self, request_id=None, wait_time=None): self.print_formatted(f"Cannot remove a request from current batch: The current batch is empty!", utils.QType.ERROR) return -1 - if request_id is None: - # remove all items from the batch - question = "Are you sure you want to remove all requests from the current batch?" - elif wait_time is None: - # remove all items with a certain ID from the batch - question = f"Are you sure you want to remove all requests with id '{request_id}' from the current batch?" - else: - # remove a specific item with a certain ID and wait_time from the batch - question = f"Are you sure you want to remove the request with id '{request_id}' and wait_time '{wait_time}' from the current batch?" - if self.command_processor.accept_yes_no(question, utils.QType.WARNING): - num_removed = curr_batch.remove(request_id, wait_time) - self.print_formatted(f"All matching requests are removed from the current batch.\nNumber: {num_removed}", - utils.QType.INFORMATION) - else: - self.print_formatted(f"Removal of current batch requests cancelled.", utils.QType.INFORMATION) + if self.cli_check: + if request_id is None: + # remove all items from the batch + question = "Are you sure you want to remove all requests from the current batch?" + elif wait_time is None: + # remove all items with a certain ID from the batch + question = f"Are you sure you want to remove all requests with id '{request_id}' from the current batch?" + else: + # remove a specific item with a certain ID and wait_time from the batch + question = f"Are you sure you want to remove the request with id '{request_id}' and wait_time '{wait_time}' from the current batch?" + if self.command_processor.accept_yes_no(question, utils.QType.WARNING): + num_removed = curr_batch.remove(request_id, wait_time) + self.print_formatted(f"All matching requests are removed from the current batch.\nNumber: {num_removed}", + utils.QType.INFORMATION) + num_removed = curr_batch.remove(request_id, wait_time) + self.print_formatted(f"All matching requests are removed from the current batch.\nNumber: {num_removed}", + utils.QType.INFORMATION) # ------------------------------------------------------------------------------------------------- # # ------------------------------------- Main helper functions ------------------------------------- # diff --git a/CompuRacer_Core/src/maingui.py b/CompuRacer_Core/src/connectgui.py similarity index 63% rename from CompuRacer_Core/src/maingui.py rename to CompuRacer_Core/src/connectgui.py index 0b12967..d5b69c1 100644 --- a/CompuRacer_Core/src/maingui.py +++ b/CompuRacer_Core/src/connectgui.py @@ -1,10 +1,10 @@ import os import sys -from src.gui import RequestsGUI +from src.gui import MainGUI -class MainGUI: +class ConnectGUI: def __init__(self, racer): super().__init__() self.racer = racer @@ -12,7 +12,7 @@ def __init__(self, racer): self.show_requests_gui(racer) def show_requests_gui(racer, app, state, cmdprocessor): - requests_gui = RequestsGUI(racer, state, cmdprocessor) + main_gui = MainGUI(racer, state, cmdprocessor) - requests_gui.show() + main_gui.show() sys.exit(app.exec_()) diff --git a/CompuRacer_Core/src/gui.py b/CompuRacer_Core/src/gui.py index b139db3..0b29612 100644 --- a/CompuRacer_Core/src/gui.py +++ b/CompuRacer_Core/src/gui.py @@ -1,13 +1,13 @@ import json import os -import sys +from typing import List, Any from PyQt5.QtCore import Qt, QTimer -from PyQt5.QtWidgets import QPushButton, QSystemTrayIcon, QMenu, QAction, QMainWindow, QVBoxLayout, QLabel, QTableWidget, QTableWidgetItem, QTabWidget, QWidget, QMessageBox, QLineEdit, QHBoxLayout, QApplication -from PyQt5.QtGui import QIcon +from PyQt5.QtWidgets import QPushButton, QMainWindow, QVBoxLayout, QLabel, QTableWidget, QTableWidgetItem, QTabWidget, QWidget, QMessageBox, QLineEdit, QHBoxLayout, QApplication, QHeaderView, QTableView +from PyQt5.QtGui import QStandardItem, QStandardItemModel -def load_json_batches(directory) -> [str]: +def load_json_batches(directory) -> List[Any]: file_names = [] for filename in os.listdir(directory): if filename.endswith(".json"): @@ -18,20 +18,28 @@ def load_json_batches(directory) -> [str]: return file_names -class RequestsGUI(QMainWindow): - def __init__(self, racer, state, cmdprocessor): +class MainGUI(QMainWindow): + def __init__(self, racer, state, command_processor) -> None: super().__init__() + self.request_window = None + self.update_json_timer = None + self.general_window = None self.batch_window = None self.current_batch = None self.data_requests = None self.table_widget = None + self.table_widget_requests = None + self.table_widget_batches = None + self.file_names = None + self.directory = None - self.command_processor = cmdprocessor + self.command_processor = command_processor self.racer = racer self.state = state self.batch_buttons = [] + self.request_buttons = [] self.load_json_requests() @@ -41,6 +49,9 @@ def init_ui(self) -> None: self.showFullScreen() self.setWindowTitle("CompuRacer GUI") + self.directory = "state/batches" + self.file_names = load_json_batches(self.directory) + tabs = QTabWidget() general_tab = QWidget() logs_tab = QWidget() @@ -51,6 +62,7 @@ def init_ui(self) -> None: vbox_general = QVBoxLayout() vbox_logs = QVBoxLayout() + # --- Create and load in GUI --- # self.create_request_widget(vbox_general, general_tab) self.create_batch_widget(vbox_general, general_tab) self.create_logs_widget(vbox_logs, logs_tab) @@ -62,42 +74,38 @@ def init_ui(self) -> None: def create_request_widget(self, vbox, requests_tab) -> None: vbox.addWidget(QLabel("Requests Information")) - self.table_widget = QTableWidget(len(self.data_requests["requests"]), 6) - self.table_widget.setColumnWidth(0, 30) - self.table_widget.setColumnWidth(1, 400) - self.table_widget.setColumnWidth(3, 200) - self.table_widget.setColumnWidth(4, 100) - self.table_widget.setHorizontalHeaderLabels(["ID", "URL", "Method", "Timestamp", "Host", "Add To Batch"]) - vbox.addWidget(self.table_widget) - - self.load_requests(vbox) + # --- Creating Table --- # + self.table_widget_requests = QTableWidget() + self.table_widget_requests.setColumnCount(8) + self.table_widget_requests.setColumnWidth(0, 20) + self.table_widget_requests.setColumnWidth(1, 500) + self.table_widget_requests.setColumnWidth(3, 200) + self.table_widget_requests.setHorizontalHeaderLabels(["ID", "URL", "Method", "Timestamp", "Host", "Add To Batch", "Open", "Remove"]) + vbox.addWidget(self.table_widget_requests) requests_tab.setLayout(vbox) + self.table_widget_requests.show() + + self.load_requests() return None def create_batch_widget(self, vbox, batches_tab) -> None: vbox.addWidget(QLabel("Batches Information")) - directory = "state/batches" - file_names = load_json_batches(directory) - - self.table_widget = QTableWidget(len(file_names), 6) - self.table_widget.setColumnWidth(0, 400) - self.table_widget.setHorizontalHeaderLabels(["Name", "Allow Redirects", "Sync Last Byte", "Send Timeout", "Set Current Batch", "Open Batch"]) - vbox.addWidget(self.table_widget) - - # clear the table widget before loading new batches - self.table_widget.clearContents() - self.table_widget.setRowCount(0) - - current_batch = self.data_requests["current_batch"] + # --- Creating table --- # + self.table_widget_batches = QTableWidget() + self.table_widget_batches.setColumnCount(6) + self.table_widget_batches.setColumnWidth(0, 400) + self.table_widget_batches.setHorizontalHeaderLabels(["Name", "Allow Redirects", "Sync Last Byte", "Send Timeout", "Set Current Batch", "Open Batch"]) + vbox.addWidget(self.table_widget_batches) # --- Add new batch --- # add_batch_field = QLineEdit() add_batch_field_button = QPushButton("Add Batch", self) add_batch_field_button.clicked.connect(lambda _, input_field=add_batch_field: self.create_new_batch(input_field)) + # --- Create add batch button and field --- # hbox = QHBoxLayout() hbox.addWidget(add_batch_field) hbox.addWidget(add_batch_field_button) @@ -108,16 +116,19 @@ def create_batch_widget(self, vbox, batches_tab) -> None: quit_button.clicked.connect(QApplication.quit) vbox.addWidget(quit_button) - self.load_batches(file_names, directory, vbox, current_batch) - - self.update_json_timer = QTimer() - self.update_json_timer.timeout.connect(self.reload_json) - self.update_json_timer.start(5000) + self.load_batches() batches_tab.setLayout(vbox) return None + def update_json(self) -> None: + self.save_data() + self.load_requests() + self.load_batches() + + return None + def create_logs_widget(self, vbox, logs_tab) -> None: vbox.addWidget(QLabel("Logs")) @@ -127,7 +138,9 @@ def create_logs_widget(self, vbox, logs_tab) -> None: self.table_widget.setHorizontalHeaderLabels(["Commands"]) vbox.addWidget(self.table_widget) - vbox.addWidget(QPushButton("Save", self, clicked=self.save_data)) + save_button = QPushButton("Save") + save_button.clicked.connect(self.save_data) + vbox.addWidget(save_button) self.load_logs() @@ -135,36 +148,80 @@ def create_logs_widget(self, vbox, logs_tab) -> None: return None - def load_requests(self, vbox) -> None: - for idx, request in enumerate(self.data_requests["requests"]): - # --- Insert row number {forloopnumber} --- # - row = self.table_widget.rowCount() - self.table_widget.insertRow(row) + def create_requests_button_widget(self, request, row) -> None: + add_request_button = QPushButton("Add", self) + window_button = QPushButton("Open", self) + remove_button = QPushButton("Remove", self) + + add_request_button.clicked.connect(lambda _, request_id=str(request): self.add_request_to_batch(request_id)) + window_button.clicked.connect(lambda _, request_id=request: self.new_request_window(request_id)) + remove_button.clicked.connect(lambda _, request_id=str(request): self.remove_request(request_id)) + + self.request_buttons.append((add_request_button, window_button, remove_button)) + + self.table_widget_requests.setCellWidget(row, 5, add_request_button) + self.table_widget_requests.setCellWidget(row, 6, window_button) + self.table_widget_requests.setCellWidget(row, 7, remove_button) + + return None + + def load_requests(self) -> None: + self.load_json_requests() + + rows_to_delete = [] - # --- Create Button --- # - add_request_button = QPushButton("Add", self) - add_request_button.clicked.connect(lambda _, request_id=str(request): self.add_request_to_batch(request_id)) + for row in range(self.table_widget_requests.rowCount()): + request_id = self.table_widget_requests.item(row, 0).text() + if request_id not in self.data_requests["requests"]: + rows_to_delete.append(row) - # --- Insert data into row --- # - self.table_widget.setItem(row, 0, QTableWidgetItem(str(request))) - self.table_widget.setItem(row, 1, QTableWidgetItem(str(self.data_requests["requests"][request]["url"]))) - self.table_widget.setItem(row, 2, QTableWidgetItem(str(self.data_requests["requests"][request]["method"]))) - self.table_widget.setItem(row, 3, QTableWidgetItem(str(self.data_requests["requests"][request]["timestamp"]))) - headers = self.data_requests["requests"][request].get("headers", {}) - host = headers.get("Host", "") - self.table_widget.setItem(row, 4, QTableWidgetItem(str(host))) - self.table_widget.setCellWidget(row, 5, add_request_button) + for row in reversed(rows_to_delete): + self.table_widget_requests.removeRow(row) - self.remove_empty_rows() + for request_id, request_data in self.data_requests["requests"].items(): + existing_row = None + for row in range(self.table_widget_requests.rowCount()): + if self.table_widget_requests.item(row, 0).text() == request_id: + existing_row = row + break + + if existing_row is not None: + self.table_widget_requests.setItem(existing_row, 1, QTableWidgetItem(str(request_data["url"]))) + self.table_widget_requests.setItem(existing_row, 2, QTableWidgetItem(str(request_data["method"]))) + self.table_widget_requests.setItem(existing_row, 3, QTableWidgetItem(str(request_data["timestamp"]))) + headers = request_data.get("headers", {}) + host = headers.get("Host", "") + self.table_widget_requests.setItem(existing_row, 4, QTableWidgetItem(str(host))) + else: + row = self.table_widget_requests.rowCount() + self.table_widget_requests.insertRow(row) + self.table_widget_requests.setItem(row, 0, QTableWidgetItem(str(request_id))) + self.table_widget_requests.setItem(row, 1, QTableWidgetItem(str(request_data["url"]))) + self.table_widget_requests.setItem(row, 2, QTableWidgetItem(str(request_data["method"]))) + self.table_widget_requests.setItem(row, 3, QTableWidgetItem(str(request_data["timestamp"]))) + headers = request_data.get("headers", {}) + host = headers.get("Host", "") + self.table_widget_requests.setItem(row, 4, QTableWidgetItem(str(host))) + + self.create_requests_button_widget(request_id, row) return None - def load_batches(self, file_names, directory, vbox, current_batch) -> callable([]): + def load_batches(self) -> callable([]): + self.directory = "state/batches" + self.file_names = load_json_batches(self.directory) + self.batch_buttons.clear() + current_batch = self.data_requests["current_batch"] + + # remove existing rows + for row in reversed(range(self.table_widget_batches.rowCount())): + self.table_widget_batches.removeRow(row) + def load_table(): - for idx, name in enumerate(file_names): - # --- Create commandbuttons --- # + for idx, name in enumerate(self.file_names): + # --- Create command-buttons --- # current_button = QPushButton("Set Current", self) window_button = QPushButton("Open", self) @@ -174,28 +231,27 @@ def load_table(): self.batch_buttons.append((current_button, window_button)) # --- Insert row number {forloopnumber} --- # - row = self.table_widget.rowCount() - self.table_widget.insertRow(row) - self.table_widget.setItem(row, 0, QTableWidgetItem(str(name))) - self.table_widget.setCellWidget(row, 4, current_button) - self.table_widget.setCellWidget(row, 5, window_button) + row = self.table_widget_batches.rowCount() + self.table_widget_batches.insertRow(row) + self.table_widget_batches.setItem(row, 0, QTableWidgetItem(str(name))) + self.table_widget_batches.setCellWidget(row, 4, current_button) + self.table_widget_batches.setCellWidget(row, 5, window_button) self.check_current_batch(name, row, current_button, window_button, current_batch) - data = self.get_json_data(directory, name) + data = self.get_json_data(name) for col, col_name in enumerate(["Allow Redirects", "Sync Last Byte", "Send Timeout"]): value = data.get(col_name.lower().replace(" ", "_")) - self.table_widget.setItem(row, col + 1, QTableWidgetItem(str(value))) + self.table_widget_batches.setItem(row, col + 1, QTableWidgetItem(str(value))) if name == current_batch: - item = self.table_widget.item(row, col + 1) + item = self.table_widget_batches.item(row, col + 1) if item is not None: item.setBackground(Qt.gray) - self.remove_empty_rows() - load_table() + return load_table def load_logs(self) -> None: @@ -204,170 +260,175 @@ def load_logs(self) -> None: self.table_widget.insertRow(row) self.table_widget.setItem(row, 0, QTableWidgetItem(str(command))) - self.remove_empty_rows() return None - def add_request_to_batch(self, request_id): - self.showNotification("RequestID " + request_id + " has been added to active Batch!") + def add_request_to_batch(self, request_id) -> None: + self.racer.comm_curr_add(self.racer, request_id) + + self.update_json() - self.racer.comm_curr_add(self.state, request_id) + return None - def get_json_data(self, directory, name): - with open(os.path.join(directory, name + ".json"), "r") as file: + def get_json_data(self, name) -> dict: + with open(os.path.join(self.directory, name + ".json"), "r") as file: data = json.load(file) return data - def check_current_batch(self, name, row, current_button, window_button, current_batch): + def check_current_batch(self, name, row, button1, button2, current_batch) -> None: if name == current_batch: - for col in range(self.table_widget.columnCount()): - item = self.table_widget.item(row, col) + for col in range(self.table_widget_batches.columnCount()): + item = self.table_widget_batches.item(row, col) if item is not None: item.setBackground(Qt.gray) - current_button.setEnabled(False) - window_button.setEnabled(True) + button1.setEnabled(False) + button2.setEnabled(True) else: - window_button.setEnabled(False) + button2.setEnabled(False) if name == "Imm": - current_button.setEnabled(False) - window_button.setEnabled(False) - - def remove_empty_rows(self) -> None: - for row in range(self.table_widget.rowCount() - 1, -1, -1): - empty = True - for col in range(self.table_widget.columnCount()): - item = self.table_widget.item(row, col) - if item is not None and not item.text().strip() == "": - empty = False - break - if empty: - self.table_widget.removeRow(row) + button1.setEnabled(False) + button2.setEnabled(False) return None def load_json_requests(self) -> None: with open('state/state.json', 'r') as f: self.data_requests = json.load(f) + return None def save_data(self) -> None: - self.racer.comm_general_save(True) - return None + self.racer.comm_general_save() - def reload_json(self): - if self.isActiveWindow(): - self.save_data() - self.update_json_timer.stop() - self.hide() - self.general_window = RequestsGUI(self.racer, self.state, self.command_processor) # Create a new window - self.general_window.show() - self.deleteLater() + return None def set_current_batch(self, batch_name) -> None: - self.racer.set_curr_batch_by_name(batch_name) + self.racer.set_curr_batch_by_name(self.racer, batch_name) self.current_batch = batch_name - self.showNotification("Set current batch to " + batch_name) + + self.update_json() + return None - def new_batch_window(self, batch_name): + def remove_request(self, request_id) -> None: + self.racer.comm_requests_remove(self.racer, request_id, None, False) + + self.update_json() + + return None + + def new_batch_window(self, batch_name) -> None: self.save_data() self.update_json_timer.stop() self.batch_window = BatchWindow(batch_name, self.racer, self.state, self.command_processor) self.batch_window.show() self.hide() - def create_new_batch(self, batch_name): - batch_name = batch_name.text() - - self.racer.gui_create_new_batch(batch_name) + return None - self.showNotification("Added New Batch " + batch_name + ". Add a request to your batch so you can open your batch") + def new_request_window(self, request_id) -> None: + self.save_data() + self.update_json_timer.stop() + self.request_window = RequestWindow(request_id, self.racer, self.state, self.command_processor) + self.request_window.show() + self.hide() - def showNotification(self, notiText): - messageBox = QMessageBox() - messageBox.setIcon(QMessageBox.Information) - messageBox.setText(notiText) + return None - messageBox.setGeometry(0, 0, 500, 50) + def create_new_batch(self, batch_name) -> None: + batch_name = batch_name.text() + self.racer.comm_batches_create_new(self.racer, batch_name) - timer = QTimer() - timer.setSingleShot(True) - timer.timeout.connect(messageBox.close) - timer.start(5000) + self.update_json() - messageBox.exec() + return None class BatchWindow(QMainWindow): - def __init__(self, batch_name, racer, state, command_processor): + def __init__(self, batch_name, racer, state, command_processor) -> None: super().__init__() self.showFullScreen() + self.setWindowTitle("Batch: " + batch_name) + self.update_json_timer = None self.general_window = None self.table_widget = None - self.batch_requests = [] self.racer = racer self.batch_name = batch_name self.state = state self.command_processor = command_processor - self.setWindowTitle("Batch: " + batch_name) + self.batch_requests = [] self.init_ui() - def init_ui(self): + def init_ui(self) -> None: vbox = QVBoxLayout() batch_tab = QWidget() batch_tab.setLayout(vbox) - batch_tab.layout().addWidget(self.table_widget) tabs = QTabWidget() - tabs.addTab(batch_tab, "Batch") vbox.addStretch() - vbox.addWidget(QPushButton("Send Batch", self, clicked=self.send_batch), alignment=Qt.AlignBottom) - vbox.addWidget(QPushButton("Go Back", self, clicked=self.go_back), alignment=Qt.AlignBottom) - vbox.addWidget(QPushButton("Quit", self, clicked=QApplication.quit)) - + self.add_button_widget(vbox) self.setCentralWidget(tabs) - self.create_requests_widget(vbox) - vbox.insertWidget(0, self.table_widget) - self.update_json_timer = QTimer() - self.update_json_timer.timeout.connect(lambda: self.reload_json()) - self.update_json_timer.start(10000) + vbox.insertWidget(0, self.table_widget) - def send_batch(self): - self.save_data() - self.update_json_timer.stop() - self.racer.gui_send_batches() + return None - def create_requests_widget(self, vbox): + def create_requests_widget(self, vbox) -> None: self.table_widget = QTableWidget() vbox.addWidget(QLabel("")) - self.table_widget.setColumnCount(4) - self.table_widget.setHorizontalHeaderLabels(["ID", "URL", "Method", "Host"]) + self.table_widget.setColumnCount(5) + self.table_widget.setHorizontalHeaderLabels(["ID", "URL", "Method", "Host", "Remove"]) self.add_request_table() + return None + + def load_json(self, filepath) -> List[Any]: + with open(filepath, 'r') as file: + data = json.load(file) + + return data + + def add_button_widget(self, vbox) -> None: + send_batch_button = QPushButton("Send Batch") + go_back_button = QPushButton("Go Back") + quit_button = QPushButton("Quit") + + send_batch_button.clicked.connect(self.send_batch) + go_back_button.clicked.connect(self.go_back) + quit_button.clicked.connect(QApplication.quit) + + vbox.addWidget(send_batch_button, alignment=Qt.AlignBottom) + vbox.addWidget(go_back_button, alignment=Qt.AlignBottom) + vbox.addWidget(quit_button, alignment=Qt.AlignBottom) + + return None + def add_request_table(self) -> None: items = self.load_json("state/batches/" + self.batch_name + ".json")["items"] requests = self.load_json("state/state.json")["requests"] - self.table_widget = QTableWidget(len(items), 4, self) - self.table_widget.setHorizontalHeaderLabels(["ID", "Method", "URL", "Host"]) + self.table_widget = QTableWidget(len(items), 5, self) + self.table_widget.setHorizontalHeaderLabels(["ID", "Method", "URL", "Host", "Remove"]) self.table_widget.setColumnWidth(0, 50) self.table_widget.setColumnWidth(1, 50) self.table_widget.setColumnWidth(2, 300) self.table_widget.setColumnWidth(3, 100) + self.table_widget.setColumnWidth(4, 100) + + remove_button = QPushButton("Remove", self) self.table_widget.verticalHeader().hide() @@ -383,14 +444,22 @@ def add_request_table(self) -> None: self.table_widget.setItem(i, 1, QTableWidgetItem(method)) self.table_widget.setItem(i, 2, QTableWidgetItem(url)) self.table_widget.setItem(i, 3, QTableWidgetItem(host)) + self.table_widget.setCellWidget(i, 4, remove_button) - def load_json(self, filepath): - with open(filepath, 'r') as file: - data = json.load(file) - return data + remove_button.clicked.connect(lambda _, request_id=str(request_id): self.remove_request(request_id)) + self.racer.print_formatted("Dit is een test voor request : " + request_id) + + return None + + def send_batch(self) -> None: + self.save_data() + self.update_json_timer.stop() + self.racer.comm_batches_send(self.racer) + + return None def go_back(self) -> None: - self.general_window = RequestsGUI(self.racer, self.state, self.command_processor) + self.general_window = MainGUI(self.racer, self.state, self.command_processor) self.general_window.show() self.hide() @@ -398,27 +467,122 @@ def go_back(self) -> None: def save_data(self) -> None: self.racer.comm_general_save(True) + + return None + + def remove_request(self, request_id) -> None: + self.racer.comm_curr_remove(self.racer, request_id) + return None - def reload_json(self): - if self.isActiveWindow(): - self.save_data() - self.update_json_timer.stop() - self.hide() - self.general_window = BatchWindow(self.batch_name, self.racer, self.state, self.command_processor) # Create a new window - self.general_window.show() - self.deleteLater() - def showNotification(self, notiText): - messageBox = QMessageBox() - messageBox.setIcon(QMessageBox.Information) - messageBox.setText(notiText) +class RequestWindow(QMainWindow): + def __init__(self, request_id, racer, state, command_processor): + super().__init__() - messageBox.setGeometry(0, 0, 500, 50) + self.request_id = request_id + self.racer = racer + self.state = state + self.command_processor = command_processor - timer = QTimer() - timer.setSingleShot(True) - timer.timeout.connect(messageBox.close) - timer.start(5000) + self.general_window = None + self.update_json_timer = None + + self.table_widget = QWidget() + + self.init_ui() - messageBox.exec() \ No newline at end of file + def init_ui(self): + vbox = QVBoxLayout() + + request_tab = QWidget() + request_tab.setLayout(vbox) + request_tab.layout().addWidget(self.table_widget) + + tabs = QTabWidget() + tabs.addTab(request_tab, "Request") + + vbox.addStretch() + + self.add_button_widget(vbox) + self.setCentralWidget(tabs) + self.load_request() + + vbox.insertWidget(0, self.table_widget) + + def load_request(self) -> None: + requests_data = self.load_json("state/state.json")["requests"] + request_data = requests_data.get(str(self.request_id)) + + if not request_data: + return + + # --- Ready the data --- # + body = request_data.get("body", "") + headers = request_data.get("headers", {}) + method = request_data.get("method", "") + timestamp = request_data.get("timestamp", "") + url = request_data.get("url", "") + request_id = request_data.get("id", "") + + # --- Create model and add headers --- # + model = QStandardItemModel() + model.setHorizontalHeaderLabels(["Field", "Value"]) + + # --- Insert data into rows --- # + model.appendRow([QStandardItem("Request ID"), QStandardItem(str(request_id))]) + model.appendRow([QStandardItem("URL"), QStandardItem(url)]) + model.appendRow([QStandardItem("Method"), QStandardItem(method)]) + model.appendRow([QStandardItem("Timestamp"), QStandardItem(str(timestamp))]) + model.appendRow([QStandardItem("Body"), QStandardItem(body)]) + for key, value in headers.items(): + model.appendRow([QStandardItem(key), QStandardItem(value)]) + + table_view = QTableView() + table_view.setModel(model) + + table_view.horizontalHeader().setStretchLastSection(True) + table_view.verticalHeader().setVisible(False) + table_view.setShowGrid(True) + table_view.setEditTriggers(QTableView.NoEditTriggers) + + # Set grid color to background color + table_view.setStyleSheet( + "QTableView::item {border-bottom: 1px solid black;} QTableView {background-color: white;}") + table_view.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents) + table_view.setColumnWidth(0, 300) + + self.table_widget = table_view + self.layout().addWidget(self.table_widget) + + return None + + def add_button_widget(self, vbox) -> None: + quit_button = QPushButton("Quit") + go_back_button = QPushButton("Go Back") + + quit_button.clicked.connect(QApplication.quit) + go_back_button.clicked.connect(self.go_back) + + vbox.addWidget(quit_button, alignment=Qt.AlignBottom) + vbox.addWidget(go_back_button, alignment=Qt.AlignBottom) + + return None + + def load_json(self, filepath): + with open(filepath, 'r') as file: + data = json.load(file) + + return data + + def go_back(self) -> None: + self.general_window = MainGUI(self.racer, self.state, self.command_processor) + self.general_window.show() + self.deleteLater() + + return None + + def save_data(self) -> None: + self.racer.comm_general_save(True) + + return None