dashboard: Allow moving/hiding of Schedule view columns

This is very handy to make good use of screen real estate, as
e.g. file path and Git revision are often not as important to
judge the state of the system at a glance – particularly, as
the schedule entries can then fit on a single line each.
This commit is contained in:
David Nadlinger 2024-09-05 16:35:17 +01:00 committed by Sébastien Bourdeauducq
parent 4e654011c3
commit 6a7926ddeb
2 changed files with 57 additions and 3 deletions

View File

@ -6,6 +6,7 @@ import logging
from PyQt6 import QtCore, QtWidgets, QtGui
from artiq.gui.models import DictSyncModel
from artiq.gui.tools import SelectableColumnTableView
from artiq.tools import elide
@ -66,7 +67,7 @@ class ScheduleDock(QtWidgets.QDockWidget):
self.schedule_ctl = schedule_ctl
self.table = QtWidgets.QTableView()
self.table = SelectableColumnTableView()
self.table.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
self.table.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.SingleSelection)
self.table.verticalHeader().setSectionResizeMode(
@ -104,6 +105,9 @@ class ScheduleDock(QtWidgets.QDockWidget):
h.resizeSection(6, 20 * cw)
h.resizeSection(7, 20 * cw)
# Allow user to reorder or disable columns.
h.setSectionsMovable(True)
def set_model(self, model):
self.table_model = model
self.table.setModel(self.table_model)
@ -154,4 +158,9 @@ class ScheduleDock(QtWidgets.QDockWidget):
return bytes(self.table.horizontalHeader().saveState())
def restore_state(self, state):
self.table.horizontalHeader().restoreState(QtCore.QByteArray(state))
h = self.table.horizontalHeader()
h.restoreState(QtCore.QByteArray(state))
# The state includes the sectionsMovable property, so set it again to be able to
# deal with pre-existing save files from when we used not to enable it.
h.setSectionsMovable(True)

View File

@ -1,7 +1,7 @@
import asyncio
import logging
from PyQt6 import QtCore, QtWidgets
from PyQt6 import QtCore, QtGui, QtWidgets
class DoubleClickLineEdit(QtWidgets.QLineEdit):
@ -88,6 +88,51 @@ class LayoutWidget(QtWidgets.QWidget):
self.layout.addWidget(item, row, col, rowspan, colspan)
class SelectableColumnTableView(QtWidgets.QTableView):
"""A QTableView packaged up with a header row context menu that allows users to
show/hide columns using checkable entries.
By default, all columns are shown. If only one shown column remains, the entry is
disabled to prevent a situation where no columns are shown, which might be confusing
to the user.
Qt considers whether columns are shown to be part of the header state, i.e. it is
included in saveState()/restoreState().
"""
def __init__(self):
super().__init__()
self.horizontalHeader().setContextMenuPolicy(
QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
self.horizontalHeader().customContextMenuRequested.connect(
self.show_header_context_menu)
def show_header_context_menu(self, pos):
menu = QtWidgets.QMenu(self)
num_columns_total = self.model().columnCount()
num_columns_shown = sum(
(not self.isColumnHidden(i)) for i in range(num_columns_total))
for i in range(num_columns_total):
name = self.model().headerData(i, QtCore.Qt.Orientation.Horizontal)
action = QtGui.QAction(name, self)
action.setCheckable(True)
is_currently_hidden = self.isColumnHidden(i)
action.setChecked(not is_currently_hidden)
if not is_currently_hidden:
if num_columns_shown == 1:
# Don't allow hiding of the last visible column.
action.setEnabled(False)
action.triggered.connect(
lambda checked, i=i: self.setColumnHidden(i, not checked))
menu.addAction(action)
menu.exec(self.horizontalHeader().mapToGlobal(pos))
async def get_open_file_name(parent, caption, dir, filter):
"""like QtWidgets.QFileDialog.getOpenFileName(), but a coroutine"""
dialog = QtWidgets.QFileDialog(parent, caption, dir, filter)