sqlshell 0.1.9__py3-none-any.whl → 0.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sqlshell might be problematic. Click here for more details.

sqlshell/menus.py ADDED
@@ -0,0 +1,171 @@
1
+ """
2
+ Menu creation and management for SQLShell application.
3
+ This module contains functions to create and manage the application's menus.
4
+ """
5
+
6
+ def create_file_menu(main_window):
7
+ """Create the File menu with project management actions.
8
+
9
+ Args:
10
+ main_window: The SQLShell main window instance
11
+
12
+ Returns:
13
+ The created File menu
14
+ """
15
+ # Create File menu
16
+ file_menu = main_window.menuBar().addMenu('&File')
17
+
18
+ # Project management actions
19
+ new_project_action = file_menu.addAction('New Project')
20
+ new_project_action.setShortcut('Ctrl+N')
21
+ new_project_action.triggered.connect(main_window.new_project)
22
+
23
+ open_project_action = file_menu.addAction('Open Project...')
24
+ open_project_action.setShortcut('Ctrl+O')
25
+ open_project_action.triggered.connect(main_window.open_project)
26
+
27
+ # Add Recent Projects submenu
28
+ main_window.recent_projects_menu = file_menu.addMenu('Recent Projects')
29
+ main_window.update_recent_projects_menu()
30
+
31
+ # Add Quick Access submenu for files
32
+ main_window.quick_access_menu = file_menu.addMenu('Quick Access Files')
33
+ main_window.update_quick_access_menu()
34
+
35
+ save_project_action = file_menu.addAction('Save Project')
36
+ save_project_action.setShortcut('Ctrl+S')
37
+ save_project_action.triggered.connect(main_window.save_project)
38
+
39
+ save_project_as_action = file_menu.addAction('Save Project As...')
40
+ save_project_as_action.setShortcut('Ctrl+Shift+S')
41
+ save_project_as_action.triggered.connect(main_window.save_project_as)
42
+
43
+ file_menu.addSeparator()
44
+
45
+ exit_action = file_menu.addAction('Exit')
46
+ exit_action.setShortcut('Ctrl+Q')
47
+ exit_action.triggered.connect(main_window.close)
48
+
49
+ return file_menu
50
+
51
+
52
+ def create_view_menu(main_window):
53
+ """Create the View menu with window management options.
54
+
55
+ Args:
56
+ main_window: The SQLShell main window instance
57
+
58
+ Returns:
59
+ The created View menu
60
+ """
61
+ # Create View menu
62
+ view_menu = main_window.menuBar().addMenu('&View')
63
+
64
+ # Maximized window option
65
+ maximize_action = view_menu.addAction('Maximize Window')
66
+ maximize_action.setShortcut('F11')
67
+ maximize_action.triggered.connect(main_window.toggle_maximize_window)
68
+
69
+ # Zoom submenu
70
+ zoom_menu = view_menu.addMenu('Zoom')
71
+
72
+ zoom_in_action = zoom_menu.addAction('Zoom In')
73
+ zoom_in_action.setShortcut('Ctrl++')
74
+ zoom_in_action.triggered.connect(lambda: main_window.change_zoom(1.1))
75
+
76
+ zoom_out_action = zoom_menu.addAction('Zoom Out')
77
+ zoom_out_action.setShortcut('Ctrl+-')
78
+ zoom_out_action.triggered.connect(lambda: main_window.change_zoom(0.9))
79
+
80
+ reset_zoom_action = zoom_menu.addAction('Reset Zoom')
81
+ reset_zoom_action.setShortcut('Ctrl+0')
82
+ reset_zoom_action.triggered.connect(lambda: main_window.reset_zoom())
83
+
84
+ return view_menu
85
+
86
+
87
+ def create_tab_menu(main_window):
88
+ """Create the Tab menu with tab management actions.
89
+
90
+ Args:
91
+ main_window: The SQLShell main window instance
92
+
93
+ Returns:
94
+ The created Tab menu
95
+ """
96
+ # Create Tab menu
97
+ tab_menu = main_window.menuBar().addMenu('&Tab')
98
+
99
+ new_tab_action = tab_menu.addAction('New Tab')
100
+ new_tab_action.setShortcut('Ctrl+T')
101
+ new_tab_action.triggered.connect(main_window.add_tab)
102
+
103
+ duplicate_tab_action = tab_menu.addAction('Duplicate Current Tab')
104
+ duplicate_tab_action.setShortcut('Ctrl+D')
105
+ duplicate_tab_action.triggered.connect(main_window.duplicate_current_tab)
106
+
107
+ rename_tab_action = tab_menu.addAction('Rename Current Tab')
108
+ rename_tab_action.setShortcut('Ctrl+R')
109
+ rename_tab_action.triggered.connect(main_window.rename_current_tab)
110
+
111
+ close_tab_action = tab_menu.addAction('Close Current Tab')
112
+ close_tab_action.setShortcut('Ctrl+W')
113
+ close_tab_action.triggered.connect(main_window.close_current_tab)
114
+
115
+ return tab_menu
116
+
117
+
118
+ def create_preferences_menu(main_window):
119
+ """Create the Preferences menu with user settings.
120
+
121
+ Args:
122
+ main_window: The SQLShell main window instance
123
+
124
+ Returns:
125
+ The created Preferences menu
126
+ """
127
+ # Create Preferences menu
128
+ preferences_menu = main_window.menuBar().addMenu('&Preferences')
129
+
130
+ # Auto-load recent project option
131
+ auto_load_action = preferences_menu.addAction('Auto-load Most Recent Project')
132
+ auto_load_action.setCheckable(True)
133
+ auto_load_action.setChecked(main_window.auto_load_recent_project)
134
+ auto_load_action.triggered.connect(lambda checked: toggle_auto_load(main_window, checked))
135
+
136
+ return preferences_menu
137
+
138
+
139
+ def toggle_auto_load(main_window, checked):
140
+ """Toggle the auto-load recent project setting.
141
+
142
+ Args:
143
+ main_window: The SQLShell main window instance
144
+ checked: Boolean indicating whether the option is checked
145
+ """
146
+ main_window.auto_load_recent_project = checked
147
+ main_window.save_recent_projects() # Save the preference
148
+ main_window.statusBar().showMessage(
149
+ f"Auto-load most recent project {'enabled' if checked else 'disabled'}",
150
+ 2000
151
+ )
152
+
153
+
154
+ def setup_menubar(main_window):
155
+ """Set up the complete menu bar for the application.
156
+
157
+ Args:
158
+ main_window: The SQLShell main window instance
159
+ """
160
+ # Create the menu bar (in case it doesn't exist)
161
+ menubar = main_window.menuBar()
162
+
163
+ # Create menus
164
+ file_menu = create_file_menu(main_window)
165
+ view_menu = create_view_menu(main_window)
166
+ tab_menu = create_tab_menu(main_window)
167
+ preferences_menu = create_preferences_menu(main_window)
168
+
169
+ # You can add more menus here in the future
170
+
171
+ return menubar
sqlshell/query_tab.py CHANGED
@@ -1,11 +1,14 @@
1
+ import os
1
2
  from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QLabel,
2
- QPushButton, QFrame, QHeaderView, QTableWidget, QSplitter, QApplication)
3
+ QPushButton, QFrame, QHeaderView, QTableWidget, QSplitter, QApplication,
4
+ QToolButton, QMenu)
3
5
  from PyQt6.QtCore import Qt
4
6
  from PyQt6.QtGui import QIcon
5
7
 
6
8
  from sqlshell.editor import SQLEditor
7
9
  from sqlshell.syntax_highlighter import SQLSyntaxHighlighter
8
10
  from sqlshell.ui import FilterHeader
11
+ from sqlshell.styles import get_row_count_label_stylesheet
9
12
 
10
13
  class QueryTab(QWidget):
11
14
  def __init__(self, parent, results_title="RESULTS"):
@@ -52,6 +55,9 @@ class QueryTab(QWidget):
52
55
  completer.setModel(model)
53
56
  self.query_edit.set_completer(completer)
54
57
 
58
+ # Connect keyboard events for direct handling of Ctrl+Enter
59
+ self.query_edit.installEventFilter(self)
60
+
55
61
  query_layout.addWidget(self.query_edit)
56
62
 
57
63
  # Button row
@@ -98,7 +104,7 @@ class QueryTab(QWidget):
98
104
  header_layout.addStretch()
99
105
 
100
106
  self.row_count_label = QLabel("")
101
- self.row_count_label.setStyleSheet("color: #7F8C8D; font-style: italic;")
107
+ self.row_count_label.setStyleSheet(get_row_count_label_stylesheet())
102
108
  header_layout.addWidget(self.row_count_label)
103
109
 
104
110
  results_layout.addLayout(header_layout)
@@ -169,4 +175,27 @@ class QueryTab(QWidget):
169
175
  def export_to_parquet(self):
170
176
  """Export results to Parquet"""
171
177
  if hasattr(self.parent, 'export_to_parquet'):
172
- self.parent.export_to_parquet()
178
+ self.parent.export_to_parquet()
179
+
180
+ def eventFilter(self, obj, event):
181
+ """Event filter to intercept Ctrl+Enter and send it to the main window"""
182
+ from PyQt6.QtCore import QEvent, Qt
183
+
184
+ # Check if it's a key press event
185
+ if event.type() == QEvent.Type.KeyPress:
186
+ # Check for Ctrl+Enter specifically
187
+ if (event.key() == Qt.Key.Key_Return and
188
+ event.modifiers() & Qt.KeyboardModifier.ControlModifier):
189
+
190
+ # Hide any autocomplete popup if it's visible
191
+ if hasattr(obj, 'completer') and obj.completer and obj.completer.popup().isVisible():
192
+ obj.completer.popup().hide()
193
+
194
+ # Execute the query via the parent (main window)
195
+ if hasattr(self.parent, 'execute_query'):
196
+ self.parent.execute_query()
197
+ # Mark event as handled
198
+ return True
199
+
200
+ # Default - let the event propagate normally
201
+ return super().eventFilter(obj, event)
sqlshell/styles.py ADDED
@@ -0,0 +1,257 @@
1
+ def get_application_stylesheet(colors):
2
+ """Generate the application's stylesheet using the provided color scheme.
3
+
4
+ Args:
5
+ colors: A dictionary containing color definitions for the application
6
+
7
+ Returns:
8
+ A string containing the complete Qt stylesheet
9
+ """
10
+ return f"""
11
+ QMainWindow {{
12
+ background-color: {colors['background']};
13
+ }}
14
+
15
+ QWidget {{
16
+ color: {colors['text']};
17
+ font-family: 'Segoe UI', 'Arial', sans-serif;
18
+ }}
19
+
20
+ QLabel {{
21
+ font-size: 13px;
22
+ padding: 2px;
23
+ }}
24
+
25
+ QLabel#header_label {{
26
+ font-size: 16px;
27
+ font-weight: bold;
28
+ color: {colors['primary']};
29
+ padding: 8px 0;
30
+ }}
31
+
32
+ QPushButton {{
33
+ background-color: {colors['secondary']};
34
+ color: white;
35
+ border: none;
36
+ border-radius: 4px;
37
+ padding: 8px 16px;
38
+ font-weight: bold;
39
+ font-size: 13px;
40
+ min-height: 30px;
41
+ }}
42
+
43
+ QPushButton:hover {{
44
+ background-color: #2980B9;
45
+ }}
46
+
47
+ QPushButton:pressed {{
48
+ background-color: #1F618D;
49
+ }}
50
+
51
+ QPushButton#primary_button {{
52
+ background-color: {colors['accent']};
53
+ }}
54
+
55
+ QPushButton#primary_button:hover {{
56
+ background-color: #16A085;
57
+ }}
58
+
59
+ QPushButton#primary_button:pressed {{
60
+ background-color: #0E6655;
61
+ }}
62
+
63
+ QPushButton#danger_button {{
64
+ background-color: {colors['error']};
65
+ }}
66
+
67
+ QPushButton#danger_button:hover {{
68
+ background-color: #CB4335;
69
+ }}
70
+
71
+ QToolButton {{
72
+ background-color: transparent;
73
+ border: none;
74
+ border-radius: 4px;
75
+ padding: 4px;
76
+ }}
77
+
78
+ QToolButton:hover {{
79
+ background-color: rgba(52, 152, 219, 0.2);
80
+ }}
81
+
82
+ QFrame#sidebar {{
83
+ background-color: {colors['primary']};
84
+ border-radius: 0px;
85
+ }}
86
+
87
+ QFrame#content_panel {{
88
+ background-color: white;
89
+ border-radius: 8px;
90
+ border: 1px solid {colors['border']};
91
+ }}
92
+
93
+ QListWidget {{
94
+ background-color: white;
95
+ border-radius: 4px;
96
+ border: 1px solid {colors['border']};
97
+ padding: 4px;
98
+ outline: none;
99
+ }}
100
+
101
+ QListWidget::item {{
102
+ padding: 8px;
103
+ border-radius: 4px;
104
+ }}
105
+
106
+ QListWidget::item:selected {{
107
+ background-color: {colors['secondary']};
108
+ color: white;
109
+ }}
110
+
111
+ QListWidget::item:hover:!selected {{
112
+ background-color: #E3F2FD;
113
+ }}
114
+
115
+ QTableWidget {{
116
+ background-color: white;
117
+ alternate-background-color: #F8F9FA;
118
+ border-radius: 4px;
119
+ border: 1px solid {colors['border']};
120
+ gridline-color: #E0E0E0;
121
+ outline: none;
122
+ }}
123
+
124
+ QTableWidget::item {{
125
+ padding: 4px;
126
+ }}
127
+
128
+ QTableWidget::item:selected {{
129
+ background-color: rgba(52, 152, 219, 0.2);
130
+ color: {colors['text']};
131
+ }}
132
+
133
+ QHeaderView::section {{
134
+ background-color: {colors['primary']};
135
+ color: white;
136
+ padding: 8px;
137
+ border: none;
138
+ font-weight: bold;
139
+ }}
140
+
141
+ QSplitter::handle {{
142
+ background-color: {colors['border']};
143
+ }}
144
+
145
+ QStatusBar {{
146
+ background-color: {colors['primary']};
147
+ color: white;
148
+ padding: 8px;
149
+ }}
150
+
151
+ QTabWidget::pane {{
152
+ border: 1px solid {colors['border']};
153
+ border-radius: 4px;
154
+ top: -1px;
155
+ background-color: white;
156
+ }}
157
+
158
+ QTabBar::tab {{
159
+ background-color: {colors['light_bg']};
160
+ color: {colors['text']};
161
+ border: 1px solid {colors['border']};
162
+ border-bottom: none;
163
+ border-top-left-radius: 4px;
164
+ border-top-right-radius: 4px;
165
+ padding: 8px 12px;
166
+ margin-right: 2px;
167
+ min-width: 80px;
168
+ }}
169
+
170
+ QTabBar::tab:selected {{
171
+ background-color: white;
172
+ border-bottom: 1px solid white;
173
+ }}
174
+
175
+ QTabBar::tab:hover:!selected {{
176
+ background-color: #E3F2FD;
177
+ }}
178
+
179
+ QTabBar::close-button {{
180
+ image: url(close.png);
181
+ subcontrol-position: right;
182
+ }}
183
+
184
+ QTabBar::close-button:hover {{
185
+ background-color: rgba(255, 0, 0, 0.2);
186
+ border-radius: 2px;
187
+ }}
188
+
189
+ QPlainTextEdit, QTextEdit {{
190
+ background-color: white;
191
+ border-radius: 4px;
192
+ border: 1px solid {colors['border']};
193
+ padding: 8px;
194
+ selection-background-color: #BBDEFB;
195
+ selection-color: {colors['text']};
196
+ font-family: 'Consolas', 'Courier New', monospace;
197
+ font-size: 14px;
198
+ }}
199
+ """
200
+
201
+ def get_tab_corner_stylesheet():
202
+ """Get the stylesheet for the tab corner widget with the + button"""
203
+ return """
204
+ QToolButton {
205
+ background-color: transparent;
206
+ border: none;
207
+ border-radius: 4px;
208
+ padding: 4px;
209
+ font-weight: bold;
210
+ font-size: 16px;
211
+ color: #3498DB;
212
+ }
213
+ QToolButton:hover {
214
+ background-color: rgba(52, 152, 219, 0.2);
215
+ }
216
+ QToolButton:pressed {
217
+ background-color: rgba(52, 152, 219, 0.4);
218
+ }
219
+ """
220
+
221
+ def get_context_menu_stylesheet():
222
+ """Get the stylesheet for context menus"""
223
+ return """
224
+ QMenu {
225
+ background-color: white;
226
+ border: 1px solid #BDC3C7;
227
+ padding: 5px;
228
+ }
229
+ QMenu::item {
230
+ padding: 5px 20px;
231
+ }
232
+ QMenu::item:selected {
233
+ background-color: #3498DB;
234
+ color: white;
235
+ }
236
+ QMenu::separator {
237
+ height: 1px;
238
+ background-color: #BDC3C7;
239
+ margin: 5px 15px;
240
+ }
241
+ """
242
+
243
+ def get_header_label_stylesheet():
244
+ """Get the stylesheet for header labels"""
245
+ return "color: white; font-weight: bold; font-size: 14px;"
246
+
247
+ def get_db_info_label_stylesheet():
248
+ """Get the stylesheet for database info label"""
249
+ return "color: rgba(255, 255, 255, 0.8); padding: 8px 0; font-size: 13px;"
250
+
251
+ def get_tables_header_stylesheet():
252
+ """Get the stylesheet for tables header"""
253
+ return "color: white; font-weight: bold; font-size: 14px; margin-top: 8px;"
254
+
255
+ def get_row_count_label_stylesheet():
256
+ """Get the stylesheet for row count label"""
257
+ return "color: #7F8C8D; font-size: 12px; font-style: italic; padding: 8px 0;"