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():
# 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())

View File

@ -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