77from typing import Optional
88
99from PyQt6 .QtCore import QSettings , Qt
10- from PyQt6 .QtGui import QAction , QCloseEvent
10+ from PyQt6 .QtGui import QAction , QCloseEvent , QFontDatabase , QKeySequence , QShortcut
1111from PyQt6 .QtWidgets import (
1212 QApplication ,
1313 QFileDialog ,
3232from .database import DatabaseError , DatabaseService , QueryResult
3333from .resources import load_icon
3434from .sql_highlighter import SqlHighlighter
35+ from .theme import SETTINGS_GROUP , Theme , apply_theme , load_theme_preference , save_theme_preference
3536
3637
3738MAX_RECENT_FILES = 5
@@ -47,8 +48,9 @@ def __init__(self) -> None:
4748 self .setWindowIcon (load_icon ())
4849
4950 self .database_service = DatabaseService ()
50- self .settings = QSettings ("SQLiteViewer" , "App" )
51+ self .settings = QSettings (* SETTINGS_GROUP )
5152 self .query_result : Optional [QueryResult ] = None
53+ self .current_theme = load_theme_preference ()
5254
5355 self .table_list = QListWidget ()
5456 self .table_list .itemSelectionChanged .connect (self ._on_table_selected )
@@ -64,8 +66,16 @@ def __init__(self) -> None:
6466
6567 self .query_editor = QPlainTextEdit ()
6668 self .query_editor .setPlaceholderText ("Write a SQL statement…" )
67- self .query_editor .setTabStopDistance (4 * self .query_editor .fontMetrics ().horizontalAdvance (' ' ))
68- SqlHighlighter (self .query_editor .document ())
69+ self .highlighter = SqlHighlighter (self .query_editor .document ())
70+ self .highlighter .set_color_scheme (self .current_theme )
71+
72+ fixed_font = QFontDatabase .systemFont (QFontDatabase .SystemFont .FixedFont )
73+ fixed_font .setPointSize (11 )
74+ self .query_editor .setFont (fixed_font )
75+ self .schema_view .setFont (fixed_font )
76+ tab_stop = 4 * self .query_editor .fontMetrics ().horizontalAdvance (" " )
77+ self .query_editor .setTabStopDistance (tab_stop )
78+ self .schema_view .setTabStopDistance (tab_stop )
6979
7080 self .query_result_view = QTableView ()
7181 self .query_result_view .setSelectionBehavior (QTableView .SelectionBehavior .SelectRows )
@@ -117,11 +127,12 @@ def _build_ui(self) -> None:
117127 query_layout .addWidget (self .query_editor )
118128
119129 button_bar = QHBoxLayout ()
120- run_button = QPushButton ("Run Query" )
121- run_button .clicked .connect (self ._run_query )
130+ self .run_button = QPushButton ("Run Query" )
131+ self .run_button .setToolTip ("Execute SQL (Ctrl+Enter)" )
132+ self .run_button .clicked .connect (self ._run_query )
122133 export_button = QPushButton ("Export Results" )
123134 export_button .clicked .connect (self ._export_results )
124- button_bar .addWidget (run_button )
135+ button_bar .addWidget (self . run_button )
125136 button_bar .addWidget (export_button )
126137 button_bar .addStretch (1 )
127138 query_layout .addLayout (button_bar )
@@ -159,16 +170,46 @@ def _build_menus(self) -> None:
159170 exit_action .triggered .connect (QApplication .instance ().quit )
160171 file_menu .addAction (exit_action )
161172
173+ view_menu = menubar .addMenu ("&View" )
174+
175+ self .toggle_dark_mode_action = QAction ("Toggle Dark Mode" , self )
176+ self .toggle_dark_mode_action .setShortcut ("Ctrl+D" )
177+ self .toggle_dark_mode_action .setCheckable (True )
178+ self .toggle_dark_mode_action .setChecked (self .current_theme == Theme .DARK )
179+ self .toggle_dark_mode_action .toggled .connect (self ._toggle_dark_mode )
180+ view_menu .addAction (self .toggle_dark_mode_action )
181+
182+ refresh_action = QAction ("Refresh Tables" , self )
183+ refresh_action .setShortcut ("Ctrl+R" )
184+ refresh_action .triggered .connect (self ._refresh_tables )
185+ view_menu .addAction (refresh_action )
186+
162187 help_menu = menubar .addMenu ("&Help" )
163188 about_action = QAction ("About" , self )
164189 about_action .triggered .connect (self ._show_about_dialog )
165190 help_menu .addAction (about_action )
166191
192+ self ._install_shortcuts ()
193+
194+ def _install_shortcuts (self ) -> None :
195+ for shortcut_key in ("Ctrl+Return" , "Ctrl+Enter" , "F5" ):
196+ shortcut = QShortcut (QKeySequence (shortcut_key ), self .query_editor )
197+ shortcut .activated .connect (self ._run_query )
198+
167199 def _open_dialog (self ) -> None :
168200 path , _ = QFileDialog .getOpenFileName (self , "Open SQLite Database" , str (Path .home ()), "SQLite Database (*.db *.sqlite *.sqlite3);;All Files (*)" )
169201 if path :
170202 self .open_database (path )
171203
204+ def _toggle_dark_mode (self , checked : bool ) -> None :
205+ self ._set_theme (Theme .DARK if checked else Theme .LIGHT )
206+
207+ def _set_theme (self , theme : Theme ) -> None :
208+ self .current_theme = theme
209+ apply_theme (theme )
210+ save_theme_preference (theme )
211+ self .highlighter .set_color_scheme (theme )
212+
172213 def open_database (self , path : str ) -> None :
173214 try :
174215 self .database_service .open (path )
0 commit comments