forked from M-Labs/artiq
1
0
Fork 0

gui: support multiple log docks

This commit is contained in:
Sebastien Bourdeauducq 2015-11-12 01:13:57 +08:00
parent fa89e165b2
commit 3cbd7c4c13
2 changed files with 99 additions and 17 deletions

View File

@ -53,6 +53,7 @@ class MainWindow(QtGui.QMainWindow):
def main(): def main():
# initialize application
args = get_argparser().parse_args() args = get_argparser().parse_args()
init_logger(args) init_logger(args)
@ -60,7 +61,9 @@ def main():
loop = QEventLoop(app) loop = QEventLoop(app)
asyncio.set_event_loop(loop) asyncio.set_event_loop(loop)
atexit.register(loop.close) atexit.register(loop.close)
smgr = state.StateManager(args.db_file)
# create connections to master
rpc_clients = dict() rpc_clients = dict()
for target in "schedule", "repository", "dataset_db": for target in "schedule", "repository", "dataset_db":
client = AsyncioClient() client = AsyncioClient()
@ -80,8 +83,7 @@ def main():
atexit_register_coroutine(subscriber.close) atexit_register_coroutine(subscriber.close)
sub_clients[notifier_name] = subscriber sub_clients[notifier_name] = subscriber
smgr = state.StateManager(args.db_file) # initialize main window
win = MainWindow(app, args.server) win = MainWindow(app, args.server)
area = dockarea.DockArea() area = dockarea.DockArea()
smgr.register(area) smgr.register(area)
@ -91,6 +93,7 @@ def main():
status_bar.showMessage("Connected to {}".format(args.server)) status_bar.showMessage("Connected to {}".format(args.server))
win.setStatusBar(status_bar) win.setStatusBar(status_bar)
# create UI components
d_explorer = explorer.ExplorerDock(win, status_bar, d_explorer = explorer.ExplorerDock(win, status_bar,
sub_clients["explist"], sub_clients["explist"],
sub_clients["schedule"], sub_clients["schedule"],
@ -106,6 +109,16 @@ def main():
loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify)) loop.run_until_complete(d_ttl_dds.start(args.server, args.port_notify))
atexit_register_coroutine(d_ttl_dds.stop) 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": if os.name != "nt":
area.addDock(d_ttl_dds.dds_dock, "top") area.addDock(d_ttl_dds.dds_dock, "top")
area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock) area.addDock(d_ttl_dds.ttl_dock, "above", d_ttl_dds.dds_dock)
@ -113,23 +126,20 @@ def main():
else: else:
area.addDock(d_datasets, "top") area.addDock(d_datasets, "top")
area.addDock(d_explorer, "above", d_datasets) 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_console, "bottom")
area.addDock(d_log, "above", d_console) area.addDock(d_schedule, "above", d_console)
area.addDock(d_schedule, "above", d_log)
# load/initialize state
smgr.load() smgr.load()
smgr.start() smgr.start()
atexit_register_coroutine(smgr.stop) 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() win.show()
loop.run_until_complete(win.exit_request.wait()) loop.run_until_complete(win.exit_request.wait())

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
import logging import logging
import time import time
from functools import partial
from quamash import QtGui, QtCore from quamash import QtGui, QtCore
from pyqtgraph import dockarea, LayoutWidget from pyqtgraph import dockarea, LayoutWidget
@ -151,8 +152,8 @@ class _LogFilterProxyModel(QSortFilterProxyModel):
class LogDock(dockarea.Dock): class LogDock(dockarea.Dock):
def __init__(self, log_sub): def __init__(self, manager, name, log_sub):
dockarea.Dock.__init__(self, "Log", size=(1000, 300)) dockarea.Dock.__init__(self, name, label="Log", size=(1000, 300))
grid = LayoutWidget() grid = LayoutWidget()
self.addWidget(grid) self.addWidget(grid)
@ -180,6 +181,13 @@ class LogDock(dockarea.Dock):
self.log.setTextElideMode(QtCore.Qt.ElideNone) self.log.setTextElideMode(QtCore.Qt.ElideNone)
grid.addWidget(self.log, 1, 0, colspan=4) grid.addWidget(self.log, 1, 0, colspan=4)
self.scroll_at_bottom = False 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) 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) self.table_model_filter.rowsRemoved.connect(self.rows_removed)
def save_state(self): 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): def restore_state(self, state):
try: try:
@ -237,3 +248,64 @@ class LogDock(dockarea.Dock):
pass pass
else: else:
self.filter_level.setCurrentIndex(idx) 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