polish: row numbers, ping indicator, frozen column, keyboard nav

- ResultsPanel: _RowNumberProxy keeps vertical header numbers sequential
  in visual order (sort-stable); both views get a 48 px wide row-number header
- MainWindow: _PingWorker pings each active connection every 30 s via
  test_connection(); status dot (green/red) shown in status bar with tooltip
- TableViewer: 📌 toggle freezes first column using dual-view overlay
  (_frozen_view child widget) with synced scroll, row heights, and resize
  event-filter; column 0 is hidden in the main view while frozen
- RowDialog: OK set as default button; first field focused on open
- ConnectionDialog: OK set as default; Enter in password field submits

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-21 17:37:50 -04:00
co-authored by Claude Sonnet 4.6
parent b7e7411c1b
commit 6cff9557b3
5 changed files with 191 additions and 9 deletions
+10 -1
View File
@@ -19,6 +19,14 @@ from PyQt6.QtGui import QColor, QFont
from app.models.result_table_model import ResultTableModel
class _RowNumberProxy(QSortFilterProxyModel):
"""Proxy that shows sequential visual-order row numbers in the vertical header."""
def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
if orientation == Qt.Orientation.Vertical and role == Qt.ItemDataRole.DisplayRole:
return str(section + 1)
return super().headerData(section, orientation, role)
class ResultsPanel(QWidget):
status_message = pyqtSignal(str)
@@ -86,7 +94,7 @@ class ResultsPanel(QWidget):
def _make_table_tab(self, cols: list, rows: list) -> tuple:
model = ResultTableModel()
model.set_data(cols, rows)
proxy = QSortFilterProxyModel()
proxy = _RowNumberProxy()
proxy.setSourceModel(model)
table = QTableView()
@@ -99,6 +107,7 @@ class ResultsPanel(QWidget):
QHeaderView.ResizeMode.Interactive)
table.horizontalHeader().setStretchLastSection(True)
table.verticalHeader().setDefaultSectionSize(24)
table.verticalHeader().setFixedWidth(48)
table.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
table.customContextMenuRequested.connect(
lambda pos, t=table, p=proxy, m=model: