From a0759dd92329696a37706b0cc210003f2d3d6823 Mon Sep 17 00:00:00 2001 From: Debanjum Singh Solanky Date: Sat, 13 Aug 2022 01:39:46 +0300 Subject: [PATCH] Convert Configure Screen into the Main Application Window - What - Convert the config screen into the main application window with configuration as just one of the functionality it provides - Rename config screen to main window to match new designation - Why - System Tray isn't available everywhere (e.g Linux) - This requires moving functionality into a normal window for cross-compat --- .../{configure_screen.py => main_window.py} | 47 +++++++++++-------- src/interface/desktop/system_tray.py | 4 +- src/main.py | 12 ++--- 3 files changed, 35 insertions(+), 28 deletions(-) rename src/interface/desktop/{configure_screen.py => main_window.py} (91%) diff --git a/src/interface/desktop/configure_screen.py b/src/interface/desktop/main_window.py similarity index 91% rename from src/interface/desktop/configure_screen.py rename to src/interface/desktop/main_window.py index b39f2216..c67f1c92 100644 --- a/src/interface/desktop/configure_screen.py +++ b/src/interface/desktop/main_window.py @@ -18,7 +18,7 @@ from src.utils.config import SearchType, ProcessorType from src.utils.helpers import merge_dicts, resolve_absolute_path -class ConfigureScreen(QtWidgets.QDialog): +class MainWindow(QtWidgets.QMainWindow): """Create Window to Configure Khoj Allow user to 1. Configure content types to search @@ -26,8 +26,8 @@ class ConfigureScreen(QtWidgets.QDialog): 3. Save the configuration to khoj.yml """ - def __init__(self, config_file: Path, parent=None): - super(ConfigureScreen, self).__init__(parent=parent) + def __init__(self, config_file: Path): + super(MainWindow, self).__init__() self.config_file = config_file # Load config from existing config, if exists, else load from default config @@ -45,24 +45,31 @@ class ConfigureScreen(QtWidgets.QDialog): self.setFixedWidth(600) # Initialize Configure Window Layout - layout = QtWidgets.QVBoxLayout() - self.setLayout(layout) + self.layout = QtWidgets.QVBoxLayout() # Add Settings Panels for each Search Type to Configure Window Layout self.search_settings_panels = [] for search_type in SearchType: current_content_config = self.current_config['content-type'].get(search_type, {}) - self.search_settings_panels += [self.add_settings_panel(current_content_config, search_type, layout)] + self.search_settings_panels += [self.add_settings_panel(current_content_config, search_type)] # Add Conversation Processor Panel to Configure Screen self.processor_settings_panels = [] conversation_type = ProcessorType.Conversation current_conversation_config = self.current_config['processor'].get(conversation_type, {}) - self.processor_settings_panels += [self.add_processor_panel(current_conversation_config, conversation_type, layout)] + self.processor_settings_panels += [self.add_processor_panel(current_conversation_config, conversation_type)] - self.add_action_panel(layout) + # Add Action Buttons Panel + self.add_action_panel() - def add_settings_panel(self, current_content_config: dict, search_type: SearchType, parent_layout: QtWidgets.QLayout): + # Set the central widget of the Window. Widget will expand + # to take up all the space in the window by default. + self.config_window = QtWidgets.QWidget() + self.config_window.setLayout(self.layout) + self.setCentralWidget(self.config_window) + + + def add_settings_panel(self, current_content_config: dict, search_type: SearchType): "Add Settings Panel for specified Search Type. Toggle Editable Search Types" # Get current files from config for given search type if search_type == SearchType.Image: @@ -87,11 +94,11 @@ class ConfigureScreen(QtWidgets.QDialog): # Add setting widgets for given search type to panel search_type_layout.addWidget(enable_search_type) search_type_layout.addWidget(input_files) - parent_layout.addWidget(search_type_settings) + self.layout.addWidget(search_type_settings) return search_type_settings - def add_processor_panel(self, current_conversation_config: dict, processor_type: ProcessorType, parent_layout: QtWidgets.QLayout): + def add_processor_panel(self, current_conversation_config: dict, processor_type: ProcessorType): "Add Conversation Processor Panel" # Get current settings from config for given processor type current_openai_api_key = current_conversation_config.get('openai-api-key', None) @@ -111,11 +118,11 @@ class ConfigureScreen(QtWidgets.QDialog): # Add setting widgets for given processor type to panel processor_type_layout.addWidget(enable_conversation) processor_type_layout.addWidget(input_field) - parent_layout.addWidget(processor_type_settings) + self.layout.addWidget(processor_type_settings) return processor_type_settings - def add_action_panel(self, parent_layout: QtWidgets.QLayout): + def add_action_panel(self): "Add Action Panel" # Button to Save Settings action_bar = QtWidgets.QWidget() @@ -127,7 +134,7 @@ class ConfigureScreen(QtWidgets.QDialog): action_bar_layout.addWidget(self.configure_button) action_bar_layout.addWidget(self.search_button) - parent_layout.addWidget(action_bar) + self.layout.addWidget(action_bar) def get_default_config(self, search_type:SearchType=None, processor_type:ProcessorType=None): "Get default config" @@ -139,13 +146,13 @@ class ConfigureScreen(QtWidgets.QDialog): else: return config - def add_error_message(self, message: str, parent_layout: QtWidgets.QLayout): + def add_error_message(self, message: str): "Add Error Message to Configure Screen" error_message = QtWidgets.QLabel() error_message.setWordWrap(True) error_message.setText(message) error_message.setStyleSheet("color: red") - parent_layout.addWidget(error_message) + self.layout.addWidget(error_message) def update_search_settings(self): "Update config with search settings from UI" @@ -190,14 +197,14 @@ class ConfigureScreen(QtWidgets.QDialog): yaml_utils.parse_config_from_string(self.new_config) except Exception as e: print(f"Error validating config: {e}") - self.add_error_message(f"Error validating config: {e}", self.layout()) + self.add_error_message(f"Error validating config: {e}") return False else: # Remove error message if present - for i in range(self.layout().count()): - current_widget = self.layout().itemAt(i).widget() + for i in range(self.layout.count()): + current_widget = self.layout.itemAt(i).widget() if isinstance(current_widget, QtWidgets.QLabel) and current_widget.text().startswith("Error validating config:"): - self.layout().removeWidget(current_widget) + self.layout.removeWidget(current_widget) current_widget.deleteLater() # Save the config to app config file diff --git a/src/interface/desktop/system_tray.py b/src/interface/desktop/system_tray.py index 5d53787b..39d257e8 100644 --- a/src/interface/desktop/system_tray.py +++ b/src/interface/desktop/system_tray.py @@ -8,7 +8,7 @@ from PyQt6 import QtGui, QtWidgets from src.utils import constants -def create_system_tray(gui: QtWidgets.QApplication, configure_screen: QtWidgets.QDialog): +def create_system_tray(gui: QtWidgets.QApplication, main_window: QtWidgets.QMainWindow): """Create System Tray with Menu. Menu contain options to 1. Open Search Page on the Web Interface 2. Open App Configuration Screen @@ -25,7 +25,7 @@ def create_system_tray(gui: QtWidgets.QApplication, configure_screen: QtWidgets. menu = QtWidgets.QMenu() menu_actions = [ ('Search', lambda: webbrowser.open('http://localhost:8000/')), - ('Configure', configure_screen.show), + ('Configure', main_window.show), ('Quit', gui.quit), ] diff --git a/src/main.py b/src/main.py index 435330da..45c00e77 100644 --- a/src/main.py +++ b/src/main.py @@ -15,7 +15,7 @@ from src.configure import configure_server from src.router import router from src.utils import constants, state from src.utils.cli import cli -from src.interface.desktop.configure_screen import ConfigureScreen +from src.interface.desktop.main_window import MainWindow from src.interface.desktop.system_tray import create_system_tray @@ -38,24 +38,24 @@ def run(): else: # Setup GUI gui = QtWidgets.QApplication([]) - configure_screen = ConfigureScreen(args.config_file) + main_window = MainWindow(args.config_file) # System tray is only available on Windows, MacOS. # On Linux (Gnome) the System tray is not supported. - # Since only the Configure Window is available + # Since only the Main Window is available # Quitting it should quit the application if system() in ['Windows', 'Darwin']: gui.setQuitOnLastWindowClosed(False) - tray = create_system_tray(gui, configure_screen) + tray = create_system_tray(gui, main_window) tray.show() # Setup Server configure_server(args, required=False) server = ServerThread(app, args.host, args.port, args.socket) - # Show Configure Screen on Linux (etc.) or First Run Experience + # Show Main Window on First Run Experience or if on Linux if args.config is None or system() not in ['Windows', 'Darwin']: - configure_screen.show() + main_window.show() # Setup Signal Handlers signal.signal(signal.SIGINT, sigint_handler)