sqlshell 0.1.8__py3-none-any.whl → 0.1.9__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/__init__.py +1 -1
- sqlshell/db/__init__.py +5 -0
- sqlshell/db/database_manager.py +691 -0
- sqlshell/editor.py +546 -45
- sqlshell/main.py +1472 -889
- sqlshell/query_tab.py +172 -0
- sqlshell/resources/create_icon.py +106 -28
- sqlshell/resources/create_splash.py +41 -11
- sqlshell/resources/icon.png +0 -0
- sqlshell/resources/logo_large.png +0 -0
- sqlshell/resources/logo_medium.png +0 -0
- sqlshell/resources/logo_small.png +0 -0
- sqlshell/setup.py +1 -1
- sqlshell/splash_screen.py +276 -48
- sqlshell/ui/__init__.py +6 -0
- sqlshell/ui/bar_chart_delegate.py +49 -0
- sqlshell/ui/filter_header.py +403 -0
- {sqlshell-0.1.8.dist-info → sqlshell-0.1.9.dist-info}/METADATA +8 -6
- sqlshell-0.1.9.dist-info/RECORD +31 -0
- {sqlshell-0.1.8.dist-info → sqlshell-0.1.9.dist-info}/WHEEL +1 -1
- sqlshell-0.1.8.dist-info/RECORD +0 -21
- {sqlshell-0.1.8.dist-info → sqlshell-0.1.9.dist-info}/entry_points.txt +0 -0
- {sqlshell-0.1.8.dist-info → sqlshell-0.1.9.dist-info}/top_level.txt +0 -0
sqlshell/splash_screen.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from PyQt6.QtWidgets import QWidget, QLabel, QVBoxLayout
|
|
2
2
|
from PyQt6.QtCore import Qt, QTimer, QPropertyAnimation, QEasingCurve, QPoint, QRect, pyqtProperty
|
|
3
|
-
from PyQt6.QtGui import QPainter, QColor, QFont, QMovie, QPainterPath, QLinearGradient
|
|
3
|
+
from PyQt6.QtGui import QPainter, QColor, QFont, QMovie, QPainterPath, QLinearGradient, QPixmap
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
6
|
class AnimatedSplashScreen(QWidget):
|
|
@@ -11,6 +11,7 @@ class AnimatedSplashScreen(QWidget):
|
|
|
11
11
|
self._opacity = 0.0
|
|
12
12
|
self._progress = 0.0
|
|
13
13
|
self.next_widget = None
|
|
14
|
+
self.use_fallback = False
|
|
14
15
|
|
|
15
16
|
# Set up the window properties
|
|
16
17
|
self.setWindowFlags(
|
|
@@ -34,30 +35,32 @@ class AnimatedSplashScreen(QWidget):
|
|
|
34
35
|
(screen_geometry.height() - self.height()) // 2
|
|
35
36
|
)
|
|
36
37
|
|
|
38
|
+
# Create movie label first (background)
|
|
39
|
+
self.movie_label = QLabel(self)
|
|
40
|
+
self.movie_label.setGeometry(0, 0, self.width(), self.height())
|
|
41
|
+
|
|
42
|
+
# Create overlay for fade effect (between movie and content)
|
|
43
|
+
self.overlay = QLabel(self)
|
|
44
|
+
self.overlay.setStyleSheet("background-color: rgba(0, 0, 0, 0);")
|
|
45
|
+
self.overlay.setGeometry(0, 0, self.width(), self.height())
|
|
46
|
+
|
|
47
|
+
# Create text label for animated text
|
|
48
|
+
self.text_label = QLabel(self)
|
|
49
|
+
self.text_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
50
|
+
self.text_label.setStyleSheet("color: rgba(255, 255, 255, 0); background: transparent;")
|
|
51
|
+
self.text_label.setGeometry(0, 0, self.width(), self.height())
|
|
52
|
+
|
|
37
53
|
# Create layout
|
|
38
54
|
layout = QVBoxLayout(self)
|
|
39
|
-
layout.setContentsMargins(20,
|
|
55
|
+
layout.setContentsMargins(20, 140, 20, 20) # Increased top margin to accommodate title bar and logo
|
|
40
56
|
layout.setSpacing(10)
|
|
41
57
|
|
|
42
|
-
# Create background container for the
|
|
58
|
+
# Create background container for the subtitle
|
|
43
59
|
self.content_container = QWidget(self)
|
|
60
|
+
self.content_container.setStyleSheet("background: transparent;")
|
|
44
61
|
content_layout = QVBoxLayout(self.content_container)
|
|
45
|
-
content_layout.setContentsMargins(20,
|
|
46
|
-
content_layout.setSpacing(
|
|
47
|
-
|
|
48
|
-
# Create title label
|
|
49
|
-
self.title_label = QLabel("SQLShell", self.content_container)
|
|
50
|
-
self.title_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
51
|
-
self.title_label.setStyleSheet("""
|
|
52
|
-
QLabel {
|
|
53
|
-
color: #3498DB;
|
|
54
|
-
font-size: 32px;
|
|
55
|
-
font-weight: bold;
|
|
56
|
-
font-family: 'Segoe UI', Arial, sans-serif;
|
|
57
|
-
background: transparent;
|
|
58
|
-
}
|
|
59
|
-
""")
|
|
60
|
-
content_layout.addWidget(self.title_label)
|
|
62
|
+
content_layout.setContentsMargins(20, 5, 20, 20)
|
|
63
|
+
content_layout.setSpacing(5)
|
|
61
64
|
|
|
62
65
|
# Create subtitle label
|
|
63
66
|
self.subtitle_label = QLabel("Loading...", self.content_container)
|
|
@@ -75,36 +78,81 @@ class AnimatedSplashScreen(QWidget):
|
|
|
75
78
|
# Add content container to main layout
|
|
76
79
|
layout.addWidget(self.content_container)
|
|
77
80
|
|
|
78
|
-
# Create movie label (background)
|
|
79
|
-
self.movie_label = QLabel(self)
|
|
80
|
-
self.movie_label.setGeometry(0, 0, self.width(), self.height())
|
|
81
|
-
self.movie_label.lower() # Put it at the back
|
|
82
|
-
|
|
83
|
-
# Create overlay for fade effect (between movie and content)
|
|
84
|
-
self.overlay = QLabel(self)
|
|
85
|
-
self.overlay.setStyleSheet("background-color: rgba(0, 0, 0, 0);")
|
|
86
|
-
self.overlay.setGeometry(0, 0, self.width(), self.height())
|
|
87
|
-
self.overlay.lower() # Put it behind the content but above the movie
|
|
88
|
-
|
|
89
|
-
# Create text label for animated text
|
|
90
|
-
self.text_label = QLabel(self)
|
|
91
|
-
self.text_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
92
|
-
self.text_label.setStyleSheet("color: rgba(255, 255, 255, 0); background: transparent;")
|
|
93
|
-
self.text_label.setGeometry(0, 0, self.width(), self.height())
|
|
94
|
-
self.text_label.lower() # Put it behind the content
|
|
95
|
-
|
|
96
81
|
# Create progress bar (always on top)
|
|
97
82
|
self.progress_bar = QLabel(self)
|
|
98
83
|
self.progress_bar.setFixedHeight(4)
|
|
99
84
|
self.progress_bar.setStyleSheet("background-color: #3498DB; border-radius: 2px;")
|
|
100
85
|
self.progress_bar.move(100, self.height() - 40)
|
|
101
86
|
self.progress_bar.setFixedWidth(0)
|
|
102
|
-
|
|
87
|
+
|
|
88
|
+
# Create a top overlay widget that will always be on top
|
|
89
|
+
self.top_overlay = QWidget(self)
|
|
90
|
+
self.top_overlay.setGeometry(0, 0, self.width(), 130) # Covers title and logo area
|
|
91
|
+
self.top_overlay.setStyleSheet("background: transparent;")
|
|
92
|
+
|
|
93
|
+
# Now create the top title and logo elements on the overlay
|
|
94
|
+
|
|
95
|
+
# Create title bar at the very top
|
|
96
|
+
self.title_bar = QLabel(self.top_overlay)
|
|
97
|
+
self.title_bar.setText("SQL Shell") # Set the text
|
|
98
|
+
self.title_bar.setFixedSize(self.width(), 50)
|
|
99
|
+
self.title_bar.move(0, 0)
|
|
100
|
+
self.title_bar.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
101
|
+
self.title_bar.setStyleSheet("""
|
|
102
|
+
QLabel {
|
|
103
|
+
color: white;
|
|
104
|
+
font-size: 28px;
|
|
105
|
+
font-weight: bold;
|
|
106
|
+
font-family: 'Segoe UI', Arial, sans-serif;
|
|
107
|
+
background-color: rgba(52, 152, 219, 0.9);
|
|
108
|
+
border-bottom: 2px solid #2980B9;
|
|
109
|
+
border-top-left-radius: 10px;
|
|
110
|
+
border-top-right-radius: 10px;
|
|
111
|
+
}
|
|
112
|
+
""")
|
|
113
|
+
|
|
114
|
+
# Create a dedicated logo container right below the title bar
|
|
115
|
+
self.logo_container = QLabel(self.top_overlay)
|
|
116
|
+
self.logo_container.setFixedSize(self.width(), 80)
|
|
117
|
+
self.logo_container.move(0, 50) # Position right below title bar
|
|
118
|
+
self.logo_container.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
|
119
|
+
self.logo_container.setStyleSheet("background: rgba(255, 255, 255, 0.8); border: 0px;")
|
|
120
|
+
|
|
121
|
+
# Try to load logo directly here
|
|
122
|
+
logo_path = os.path.join(os.path.dirname(__file__), "resources", "logo_medium.png")
|
|
123
|
+
if os.path.exists(logo_path):
|
|
124
|
+
logo_pixmap = QPixmap(logo_path)
|
|
125
|
+
# Scale logo to appropriate size
|
|
126
|
+
scaled_logo = logo_pixmap.scaledToWidth(200, Qt.TransformationMode.SmoothTransformation)
|
|
127
|
+
self.logo_container.setPixmap(scaled_logo)
|
|
128
|
+
print(f"Logo loaded with size: {scaled_logo.width()}x{scaled_logo.height()}")
|
|
129
|
+
print(f"Logo container geometry: {self.logo_container.geometry()}")
|
|
130
|
+
else:
|
|
131
|
+
print(f"Logo not found at path: {logo_path}")
|
|
132
|
+
# Try the small logo as fallback
|
|
133
|
+
logo_path = os.path.join(os.path.dirname(__file__), "resources", "logo_small.png")
|
|
134
|
+
if os.path.exists(logo_path):
|
|
135
|
+
logo_pixmap = QPixmap(logo_path)
|
|
136
|
+
scaled_logo = logo_pixmap.scaledToWidth(150, Qt.TransformationMode.SmoothTransformation)
|
|
137
|
+
self.logo_container.setPixmap(scaled_logo)
|
|
138
|
+
print(f"Fallback logo loaded with size: {scaled_logo.width()}x{scaled_logo.height()}")
|
|
139
|
+
print(f"Logo container geometry: {self.logo_container.geometry()}")
|
|
103
140
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
self.
|
|
107
|
-
|
|
141
|
+
print(f"Title bar geometry: {self.title_bar.geometry()}")
|
|
142
|
+
print(f"Title bar text: {self.title_bar.text()}")
|
|
143
|
+
print(f"Top overlay geometry: {self.top_overlay.geometry()}")
|
|
144
|
+
|
|
145
|
+
# Set appropriate z-order of elements
|
|
146
|
+
self.movie_label.lower() # Background at the very back
|
|
147
|
+
self.overlay.raise_() # Overlay above background
|
|
148
|
+
self.text_label.raise_() # Text above overlay
|
|
149
|
+
self.content_container.raise_() # Content above text
|
|
150
|
+
self.progress_bar.raise_() # Progress bar on top
|
|
151
|
+
self.top_overlay.raise_() # Top overlay with title and logo at the very top
|
|
152
|
+
|
|
153
|
+
# Set up the loading animation - do it immediately in init
|
|
154
|
+
self.movie = None # Initialize to None for safety
|
|
155
|
+
self.load_animation()
|
|
108
156
|
|
|
109
157
|
# Set up fade animation
|
|
110
158
|
self.fade_anim = QPropertyAnimation(self, b"opacity")
|
|
@@ -120,12 +168,151 @@ class AnimatedSplashScreen(QWidget):
|
|
|
120
168
|
self.progress_anim.setEndValue(1.0)
|
|
121
169
|
self.progress_anim.setEasingCurve(QEasingCurve.Type.InOutQuad)
|
|
122
170
|
|
|
171
|
+
# Create a dedicated timer to ensure title and logo always stay on top
|
|
172
|
+
self.z_order_timer = QTimer(self)
|
|
173
|
+
self.z_order_timer.timeout.connect(self.ensure_top_elements_visible)
|
|
174
|
+
self.z_order_timer.start(50) # Check every 50ms
|
|
175
|
+
|
|
123
176
|
# Start animations after everything is initialized
|
|
124
177
|
QTimer.singleShot(100, self.start_animations) # Small delay to ensure everything is ready
|
|
125
178
|
|
|
179
|
+
def load_animation(self):
|
|
180
|
+
"""Load the splash screen animation"""
|
|
181
|
+
# Check multiple potential paths for the splash screen GIF
|
|
182
|
+
possible_paths = [
|
|
183
|
+
os.path.join(os.path.dirname(__file__), "resources", "splash_screen.gif"),
|
|
184
|
+
os.path.join(os.path.dirname(os.path.dirname(__file__)), "resources", "splash_screen.gif"),
|
|
185
|
+
os.path.join(os.path.dirname(__file__), "splash_screen.gif"),
|
|
186
|
+
os.path.abspath("sqlshell/resources/splash_screen.gif"),
|
|
187
|
+
os.path.abspath("resources/splash_screen.gif")
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
# Try each possible path
|
|
191
|
+
for path in possible_paths:
|
|
192
|
+
if os.path.exists(path):
|
|
193
|
+
print(f"Loading splash screen animation from: {path}")
|
|
194
|
+
try:
|
|
195
|
+
self.movie = QMovie(path)
|
|
196
|
+
self.movie.setCacheMode(QMovie.CacheMode.CacheAll) # Cache all frames for smoother playback
|
|
197
|
+
self.movie.setScaledSize(self.size())
|
|
198
|
+
|
|
199
|
+
# Connect frameChanged signal to update the label
|
|
200
|
+
self.movie.frameChanged.connect(self.update_frame)
|
|
201
|
+
|
|
202
|
+
# Ensure the movie label is visible but below other elements
|
|
203
|
+
self.movie_label.lower()
|
|
204
|
+
self.movie_label.setStyleSheet("background: transparent;")
|
|
205
|
+
|
|
206
|
+
# Set the movie to the label
|
|
207
|
+
self.movie_label.setMovie(self.movie)
|
|
208
|
+
|
|
209
|
+
# Test if the movie is valid
|
|
210
|
+
if self.movie.isValid():
|
|
211
|
+
print(f"Successfully loaded animation with {self.movie.frameCount()} frames")
|
|
212
|
+
self.use_fallback = False
|
|
213
|
+
|
|
214
|
+
# Create a timer to ensure animation updates
|
|
215
|
+
self.animation_timer = QTimer(self)
|
|
216
|
+
self.animation_timer.timeout.connect(self.update_animation)
|
|
217
|
+
self.animation_timer.start(50) # Update every 50ms
|
|
218
|
+
|
|
219
|
+
# Force our top overlay to be visible
|
|
220
|
+
self.top_overlay.raise_()
|
|
221
|
+
|
|
222
|
+
return
|
|
223
|
+
else:
|
|
224
|
+
print(f"Warning: Animation file at {path} is not valid")
|
|
225
|
+
self.use_fallback = True
|
|
226
|
+
except Exception as e:
|
|
227
|
+
print(f"Error loading animation from {path}: {e}")
|
|
228
|
+
|
|
229
|
+
# If we get here, no valid animation was found
|
|
230
|
+
print("No valid animation found, using fallback static splash screen")
|
|
231
|
+
self.use_fallback = True
|
|
232
|
+
|
|
233
|
+
def update_frame(self):
|
|
234
|
+
"""Handle frame changed in the animation"""
|
|
235
|
+
# Make sure the movie label is refreshed and visible
|
|
236
|
+
self.movie_label.update()
|
|
237
|
+
self.movie_label.show()
|
|
238
|
+
|
|
239
|
+
# Always ensure title and logo stay on top
|
|
240
|
+
self.title_bar.raise_()
|
|
241
|
+
self.logo_container.raise_()
|
|
242
|
+
|
|
243
|
+
def update_animation(self):
|
|
244
|
+
"""Ensure animation keeps running"""
|
|
245
|
+
if self.movie and not self.use_fallback:
|
|
246
|
+
# Check if movie is running
|
|
247
|
+
if self.movie.state() != QMovie.MovieState.Running:
|
|
248
|
+
self.movie.start()
|
|
249
|
+
|
|
250
|
+
# Force update of the movie label
|
|
251
|
+
self.movie_label.update()
|
|
252
|
+
|
|
253
|
+
# Always ensure title and logo stay on top
|
|
254
|
+
self.title_bar.raise_()
|
|
255
|
+
self.logo_container.raise_()
|
|
256
|
+
|
|
257
|
+
def paintEvent(self, event):
|
|
258
|
+
"""Custom paint event to draw a fallback splash screen if needed"""
|
|
259
|
+
if self.use_fallback:
|
|
260
|
+
painter = QPainter(self)
|
|
261
|
+
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
|
|
262
|
+
|
|
263
|
+
# Draw rounded rectangle background
|
|
264
|
+
gradient = QLinearGradient(0, 0, 0, self.height())
|
|
265
|
+
gradient.setColorAt(0, QColor(44, 62, 80)) # Dark blue-gray
|
|
266
|
+
gradient.setColorAt(1, QColor(52, 152, 219)) # Bright blue
|
|
267
|
+
|
|
268
|
+
painter.setBrush(gradient)
|
|
269
|
+
painter.setPen(Qt.PenStyle.NoPen)
|
|
270
|
+
painter.drawRoundedRect(0, 0, self.width(), self.height(), 10, 10)
|
|
271
|
+
|
|
272
|
+
# Draw title bar at the top
|
|
273
|
+
title_rect = QRect(0, 0, self.width(), 50)
|
|
274
|
+
painter.setBrush(QColor(52, 152, 219)) # Bright blue
|
|
275
|
+
painter.drawRect(title_rect)
|
|
276
|
+
|
|
277
|
+
# Draw title text
|
|
278
|
+
painter.setPen(QColor(255, 255, 255))
|
|
279
|
+
font = QFont("Segoe UI", 24)
|
|
280
|
+
font.setBold(True)
|
|
281
|
+
painter.setFont(font)
|
|
282
|
+
painter.drawText(title_rect, Qt.AlignmentFlag.AlignCenter, "SQL Shell")
|
|
283
|
+
|
|
284
|
+
# Try to draw logo
|
|
285
|
+
logo_path = os.path.join(os.path.dirname(__file__), "resources", "logo_small.png")
|
|
286
|
+
if os.path.exists(logo_path):
|
|
287
|
+
logo_pixmap = QPixmap(logo_path)
|
|
288
|
+
scaled_logo = logo_pixmap.scaledToHeight(70, Qt.TransformationMode.SmoothTransformation)
|
|
289
|
+
logo_x = (self.width() - scaled_logo.width()) // 2
|
|
290
|
+
painter.drawPixmap(logo_x, 60, scaled_logo)
|
|
291
|
+
|
|
292
|
+
# Draw progress bar
|
|
293
|
+
if hasattr(self, '_progress'):
|
|
294
|
+
progress_width = int(200 * self._progress)
|
|
295
|
+
progress_rect = QRect(100, self.height() - 40, progress_width, 4)
|
|
296
|
+
painter.setBrush(QColor(26, 188, 156)) # Teal
|
|
297
|
+
painter.drawRoundedRect(progress_rect, 2, 2)
|
|
298
|
+
|
|
299
|
+
super().paintEvent(event)
|
|
300
|
+
|
|
126
301
|
def start_animations(self):
|
|
127
302
|
"""Start all animations"""
|
|
128
|
-
|
|
303
|
+
# Try to start the movie if we have one
|
|
304
|
+
if self.movie and not self.use_fallback:
|
|
305
|
+
self.movie.start()
|
|
306
|
+
|
|
307
|
+
# Check if movie is running after attempt to start
|
|
308
|
+
if not self.movie.state() == QMovie.MovieState.Running:
|
|
309
|
+
print("Warning: Could not start the animation")
|
|
310
|
+
self.use_fallback = True
|
|
311
|
+
else:
|
|
312
|
+
# Ensure the movie label is visible and updated
|
|
313
|
+
self.movie_label.show()
|
|
314
|
+
self.movie_label.update()
|
|
315
|
+
|
|
129
316
|
self.fade_anim.start()
|
|
130
317
|
self.progress_anim.start()
|
|
131
318
|
self.progress_anim.finished.connect(self._on_animation_finished)
|
|
@@ -156,8 +343,16 @@ class AnimatedSplashScreen(QWidget):
|
|
|
156
343
|
def progress(self, value):
|
|
157
344
|
self._progress = value
|
|
158
345
|
# Update progress bar width
|
|
159
|
-
self
|
|
346
|
+
if hasattr(self, 'progress_bar'):
|
|
347
|
+
self.progress_bar.setFixedWidth(int(200 * value))
|
|
348
|
+
# Force repaint if using fallback
|
|
349
|
+
if self.use_fallback:
|
|
350
|
+
self.update()
|
|
160
351
|
|
|
352
|
+
def ensure_top_elements_visible(self):
|
|
353
|
+
"""Ensure title bar and logo container are always on top"""
|
|
354
|
+
self.top_overlay.raise_()
|
|
355
|
+
|
|
161
356
|
def _on_animation_finished(self):
|
|
162
357
|
"""Handle animation completion"""
|
|
163
358
|
if self.next_widget:
|
|
@@ -165,13 +360,46 @@ class AnimatedSplashScreen(QWidget):
|
|
|
165
360
|
|
|
166
361
|
def _finish_splash(self):
|
|
167
362
|
"""Clean up and show the main window"""
|
|
168
|
-
|
|
169
|
-
self.
|
|
170
|
-
|
|
363
|
+
# Stop the animation timer if it exists
|
|
364
|
+
if hasattr(self, 'animation_timer') and self.animation_timer:
|
|
365
|
+
self.animation_timer.stop()
|
|
366
|
+
|
|
367
|
+
# Stop the z-order timer
|
|
368
|
+
if hasattr(self, 'z_order_timer'):
|
|
369
|
+
self.z_order_timer.stop()
|
|
370
|
+
|
|
371
|
+
if self.movie:
|
|
372
|
+
self.movie.stop()
|
|
373
|
+
if self.fade_anim:
|
|
374
|
+
self.fade_anim.stop()
|
|
375
|
+
if self.progress_anim:
|
|
376
|
+
self.progress_anim.stop()
|
|
171
377
|
self.close()
|
|
172
378
|
if self.next_widget:
|
|
173
379
|
self.next_widget.show()
|
|
174
380
|
|
|
175
381
|
def finish(self, widget):
|
|
176
382
|
"""Store the widget to show after animation completes"""
|
|
177
|
-
self.next_widget = widget
|
|
383
|
+
self.next_widget = widget
|
|
384
|
+
|
|
385
|
+
# On Windows, we need to explicitly trigger the finish process
|
|
386
|
+
# instead of waiting for the animation to complete
|
|
387
|
+
|
|
388
|
+
# First forcibly stop all animations
|
|
389
|
+
if hasattr(self, 'animation_timer') and self.animation_timer:
|
|
390
|
+
self.animation_timer.stop()
|
|
391
|
+
|
|
392
|
+
# Stop the z-order timer
|
|
393
|
+
if hasattr(self, 'z_order_timer'):
|
|
394
|
+
self.z_order_timer.stop()
|
|
395
|
+
|
|
396
|
+
if self.movie:
|
|
397
|
+
self.movie.stop()
|
|
398
|
+
if self.fade_anim:
|
|
399
|
+
self.fade_anim.stop()
|
|
400
|
+
if self.progress_anim:
|
|
401
|
+
self.progress_anim.stop()
|
|
402
|
+
|
|
403
|
+
# Close the splash screen and show the main window directly
|
|
404
|
+
# Use a very short timer to allow the event loop to process
|
|
405
|
+
QTimer.singleShot(50, self._finish_splash)
|
sqlshell/ui/__init__.py
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
from PyQt6.QtWidgets import QStyledItemDelegate
|
|
2
|
+
from PyQt6.QtCore import Qt, QRect
|
|
3
|
+
from PyQt6.QtGui import QColor
|
|
4
|
+
|
|
5
|
+
class BarChartDelegate(QStyledItemDelegate):
|
|
6
|
+
def __init__(self, parent=None):
|
|
7
|
+
super().__init__(parent)
|
|
8
|
+
self.min_val = 0
|
|
9
|
+
self.max_val = 1
|
|
10
|
+
self.bar_color = QColor("#3498DB")
|
|
11
|
+
|
|
12
|
+
def set_range(self, min_val, max_val):
|
|
13
|
+
self.min_val = min_val
|
|
14
|
+
self.max_val = max_val
|
|
15
|
+
|
|
16
|
+
def paint(self, painter, option, index):
|
|
17
|
+
# Draw the default background
|
|
18
|
+
super().paint(painter, option, index)
|
|
19
|
+
|
|
20
|
+
try:
|
|
21
|
+
text = index.data()
|
|
22
|
+
value = float(text.replace(',', ''))
|
|
23
|
+
|
|
24
|
+
# Calculate normalized value
|
|
25
|
+
range_val = self.max_val - self.min_val if self.max_val != self.min_val else 1
|
|
26
|
+
normalized = (value - self.min_val) / range_val
|
|
27
|
+
|
|
28
|
+
# Define bar dimensions
|
|
29
|
+
bar_height = 16
|
|
30
|
+
max_bar_width = 100
|
|
31
|
+
bar_width = max(5, int(max_bar_width * normalized))
|
|
32
|
+
|
|
33
|
+
# Calculate positions
|
|
34
|
+
text_width = option.fontMetrics.horizontalAdvance(text) + 10
|
|
35
|
+
bar_x = option.rect.left() + text_width + 10
|
|
36
|
+
bar_y = option.rect.center().y() - bar_height // 2
|
|
37
|
+
|
|
38
|
+
# Draw the bar
|
|
39
|
+
bar_rect = QRect(bar_x, bar_y, bar_width, bar_height)
|
|
40
|
+
painter.fillRect(bar_rect, self.bar_color)
|
|
41
|
+
|
|
42
|
+
# Draw the text
|
|
43
|
+
text_rect = QRect(option.rect.left() + 4, option.rect.top(),
|
|
44
|
+
text_width, option.rect.height())
|
|
45
|
+
painter.drawText(text_rect, Qt.AlignmentFlag.AlignLeft | Qt.AlignmentFlag.AlignVCenter, text)
|
|
46
|
+
|
|
47
|
+
except (ValueError, AttributeError):
|
|
48
|
+
# If not a number, just draw the text
|
|
49
|
+
super().paint(painter, option, index)
|