forked from M-Labs/artiq
gui: support multiple log docks
This commit is contained in:
parent
fa89e165b2
commit
3cbd7c4c13
|
@ -53,6 +53,7 @@ class MainWindow(QtGui.QMainWindow):
|
|||
|
||||
|
||||
def main():
|
||||
# initialize application
|
||||
args = get_argparser().parse_args()
|
||||
init_logger(args)
|
||||
|
||||
|
@ -60,7 +61,9 @@ def main():
|
|||
loop = QEventLoop(app)
|
||||
asyncio.set_event_loop(loop)
|
||||
atexit.register(loop.close)
|
||||
smgr = state.StateManager(args.db_file)
|
||||
|
||||
# create connections to master
|
||||
rpc_clients = dict()
|
||||
for target in "schedule", "repository", "dataset_db":
|
||||
client = AsyncioClient()
|
||||
|
@ -80,8 +83,7 @@ def main():
|
|||
atexit_register_coroutine(subscriber.close)
|
||||
sub_clients[notifier_name] = subscriber
|
||||
|
||||
smgr = state.StateManager(args.db_file)
|
||||
|
||||
# initialize main window
|
||||
win = MainWindow(app, args.server)
|
||||
area = dockarea.DockArea()
|
||||
smgr.register(area)
|
||||
|
@ -91,6 +93,7 @@ def main():
|
|||
status_bar.showMessage("Connected to {}".format(args.server))
|
||||
win.setStatusBar(status_bar)
|
||||
|
||||
# create UI components
|
||||
d_explorer = explorer.ExplorerDock(win, status_bar,
|
||||
sub_clients["explist"],
|
||||
sub_clients["schedule"],
|
||||
|
@ -106,6 +109,16 @@ def main():
|
|||
loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify))
|
||||
atexit_register_coroutine(d_ttl_dds.stop)
|
||||
|
||||
d_schedule = schedule.ScheduleDock(
|
||||
status_bar, rpc_clients["schedule"], sub_clients["schedule"])
|
||||
|
||||
logmgr = log.LogDockManager(area, sub_clients["log"])
|
||||
smgr.register(logmgr)
|
||||
|
||||
d_console = console.ConsoleDock(sub_clients["datasets"],
|
||||
rpc_clients["dataset_db"])
|
||||
|
||||
# lay out docks
|
||||
if os.name != "nt":
|
||||
area.addDock(d_ttl_dds.dds_dock, "top")
|
||||
area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock)
|
||||
|
@ -113,23 +126,20 @@ def main():
|
|||
else:
|
||||
area.addDock(d_datasets, "top")
|
||||
area.addDock(d_explorer, "above", d_datasets)
|
||||
|
||||
d_schedule = schedule.ScheduleDock(
|
||||
status_bar, rpc_clients["schedule"], sub_clients["schedule"])
|
||||
|
||||
d_log = log.LogDock(sub_clients["log"])
|
||||
smgr.register(d_log)
|
||||
|
||||
d_console = console.ConsoleDock(sub_clients["datasets"],
|
||||
rpc_clients["dataset_db"])
|
||||
|
||||
area.addDock(d_console, "bottom")
|
||||
area.addDock(d_log, "above", d_console)
|
||||
area.addDock(d_schedule, "above", d_log)
|
||||
area.addDock(d_schedule, "above", d_console)
|
||||
|
||||
# load/initialize state
|
||||
smgr.load()
|
||||
smgr.start()
|
||||
atexit_register_coroutine(smgr.stop)
|
||||
|
||||
# create first log dock if not already in state
|
||||
d_log0 = logmgr.first_log_dock()
|
||||
if d_log0 is not None:
|
||||
area.addDock(d_log0, "right", d_explorer)
|
||||
|
||||
# run
|
||||
win.show()
|
||||
loop.run_until_complete(win.exit_request.wait())
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import asyncio
|
||||
import logging
|
||||
import time
|
||||
from functools import partial
|
||||
|
||||
from quamash import QtGui, QtCore
|
||||
from pyqtgraph import dockarea, LayoutWidget
|
||||
|
@ -151,8 +152,8 @@ class _LogFilterProxyModel(QSortFilterProxyModel):
|
|||
|
||||
|
||||
class LogDock(dockarea.Dock):
|
||||
def __init__(self, log_sub):
|
||||
dockarea.Dock.__init__(self, "Log", size=(1000, 300))
|
||||
def __init__(self, manager, name, log_sub):
|
||||
dockarea.Dock.__init__(self, name, label="Log", size=(1000, 300))
|
||||
|
||||
grid = LayoutWidget()
|
||||
self.addWidget(grid)
|
||||
|
@ -180,6 +181,13 @@ class LogDock(dockarea.Dock):
|
|||
self.log.setTextElideMode(QtCore.Qt.ElideNone)
|
||||
grid.addWidget(self.log, 1, 0, colspan=4)
|
||||
self.scroll_at_bottom = False
|
||||
self.scroll_value = 0
|
||||
|
||||
self.log.setContextMenuPolicy(QtCore.Qt.ActionsContextMenu)
|
||||
newlog_action = QtGui.QAction("Create new log dock", self.log)
|
||||
# note the lambda, the default parameter is overriden otherwise
|
||||
newlog_action.triggered.connect(lambda: manager.create_new_dock())
|
||||
self.log.addAction(newlog_action)
|
||||
|
||||
log_sub.add_setmodel_callback(self.set_model)
|
||||
|
||||
|
@ -228,7 +236,10 @@ class LogDock(dockarea.Dock):
|
|||
self.table_model_filter.rowsRemoved.connect(self.rows_removed)
|
||||
|
||||
def save_state(self):
|
||||
return {"min_level_idx": self.filter_level.currentIndex()}
|
||||
return {
|
||||
"min_level_idx": self.filter_level.currentIndex(),
|
||||
"freetext_filter": self.filter_freetext.text()
|
||||
}
|
||||
|
||||
def restore_state(self, state):
|
||||
try:
|
||||
|
@ -237,3 +248,64 @@ class LogDock(dockarea.Dock):
|
|||
pass
|
||||
else:
|
||||
self.filter_level.setCurrentIndex(idx)
|
||||
|
||||
try:
|
||||
freetext = state["freetext_filter"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
self.filter_freetext.setText(freetext)
|
||||
# Note that editingFinished is not emitted when calling setText,
|
||||
# (unlike currentIndexChanged) so we need to call the callback
|
||||
# manually here, unlike for the combobox.
|
||||
self.filter_freetext_changed()
|
||||
|
||||
|
||||
class LogDockManager:
|
||||
def __init__(self, dock_area, log_sub):
|
||||
self.dock_area = dock_area
|
||||
self.log_sub = log_sub
|
||||
self.docks = dict()
|
||||
|
||||
def create_new_dock(self, add_to_area=True):
|
||||
n = 0
|
||||
name = "log0"
|
||||
while name in self.docks:
|
||||
n += 1
|
||||
name = "log" + str(n)
|
||||
|
||||
dock = LogDock(self, name, self.log_sub)
|
||||
self.docks[name] = dock
|
||||
if add_to_area:
|
||||
self.dock_area.addDock(dock)
|
||||
self.dock_area.floatDock(dock)
|
||||
dock.sigClosed.connect(partial(self.on_dock_closed, name))
|
||||
self.update_closable()
|
||||
return dock
|
||||
|
||||
def on_dock_closed(self, name):
|
||||
del self.docks[name]
|
||||
self.update_closable()
|
||||
|
||||
def update_closable(self):
|
||||
closable = len(self.docks) > 1
|
||||
for dock in self.docks.values():
|
||||
dock.setClosable(closable)
|
||||
|
||||
def save_state(self):
|
||||
return {name: dock.save_state() for name, dock in self.docks.items()}
|
||||
|
||||
def restore_state(self, state):
|
||||
if self.docks:
|
||||
raise NotImplementedError
|
||||
for name, dock_state in state.items():
|
||||
dock = LogDock(self, name, self.log_sub)
|
||||
dock.restore_state(dock_state)
|
||||
self.dock_area.addDock(dock)
|
||||
self.docks[name] = dock
|
||||
|
||||
def first_log_dock(self):
|
||||
if self.docks:
|
||||
return None
|
||||
dock = self.create_new_dock(False)
|
||||
return dock
|
||||
|
|
Loading…
Reference in New Issue