feat: multi-result tabs, column statistics, and Ctrl+W close tab

- ResultsPanel rewritten: single queries show one result as before;
  scripts with multiple statements show each result in a named sub-tab
  (e.g. "Result 2 (1,234)") with the tab bar auto-shown/hidden
- EditorTab._on_script_done now calls show_script_results() instead of
  overwriting the panel on each statement
- ColumnStatsDialog: right-click any column header in TableViewer to see
  total rows, null count, distinct values, min, max, and avg (async,
  gracefully skips avg for non-numeric columns)
- TableViewer header context menu also adds "Resize to fit" shortcuts
- Ctrl+W closes the current workspace tab (View menu)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 17:10:35 -04:00
co-authored by Claude Sonnet 4.6
parent 771c92b7b6
commit 9f0891755e
5 changed files with 334 additions and 81 deletions
+34
View File
@@ -399,6 +399,11 @@ class TableViewer(QWidget):
Qt.ContextMenuPolicy.CustomContextMenu)
self._table_view.customContextMenuRequested.connect(self._context_menu)
self._table_view.doubleClicked.connect(self._on_double_click)
# Column header context menu
hdr = self._table_view.horizontalHeader()
hdr.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
hdr.customContextMenuRequested.connect(self._header_context_menu)
# Track selection to enable/disable Edit/Delete buttons.
# Use both signals: clicked covers mouse, selectionChanged covers keyboard.
self._table_view.clicked.connect(self._on_cell_click)
@@ -629,6 +634,35 @@ class TableViewer(QWidget):
self._copy_selected_as_insert)
menu.exec(self._table_view.viewport().mapToGlobal(pos))
def _header_context_menu(self, pos):
hdr = self._table_view.horizontalHeader()
col_idx = hdr.logicalIndexAt(pos)
if col_idx < 0 or col_idx >= len(self._model.column_names()):
return
col_name = self._model.column_names()[col_idx]
menu = QMenu(self)
menu.addAction(
f"📊 Statistics: {col_name}",
lambda: self._show_column_stats(col_name),
)
menu.addSeparator()
menu.addAction(
"⟺ Resize to fit",
lambda: self._table_view.resizeColumnToContents(col_idx),
)
menu.addAction(
"⟺ Resize all to fit",
self._table_view.resizeColumnsToContents,
)
menu.exec(hdr.mapToGlobal(pos))
def _show_column_stats(self, col_name: str):
from app.ui.column_stats_dialog import ColumnStatsDialog
dlg = ColumnStatsDialog(
self._driver, self._database, self._table, col_name, parent=self
)
dlg.exec()
# ── Double-click: edit ────────────────────────────────────────────────────
def _on_double_click(self, index: QModelIndex):