Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/artiq
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 723ef71a87b0
Choose a base ref
...
head repository: m-labs/artiq
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 108aed569e7c
Choose a head ref
  • 6 commits
  • 3 files changed
  • 1 contributor

Commits on Nov 17, 2015

  1. Copy the full SHA
    107d8f0 View commit details
  2. gui/datasets: tree view

    sbourdeauducq committed Nov 17, 2015
    Copy the full SHA
    9c5db28 View commit details
  3. gui/explorer: tree view

    sbourdeauducq committed Nov 17, 2015
    Copy the full SHA
    250ab6b View commit details
  4. Copy the full SHA
    7bebc52 View commit details
  5. Copy the full SHA
    537fa22 View commit details
  6. Copy the full SHA
    108aed5 View commit details
Showing with 207 additions and 31 deletions.
  1. +8 −12 artiq/gui/datasets.py
  2. +15 −19 artiq/gui/explorer.py
  3. +184 −0 artiq/gui/models.py
20 changes: 8 additions & 12 deletions artiq/gui/datasets.py
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@
from pyqtgraph import LayoutWidget

from artiq.tools import short_format
from artiq.gui.models import DictSyncModel
from artiq.gui.models import DictSyncTreeSepModel
from artiq.gui.displays import *

try:
@@ -20,17 +20,14 @@
logger = logging.getLogger(__name__)


class Model(DictSyncModel):
class Model(DictSyncTreeSepModel):
def __init__(self, init):
DictSyncModel.__init__(self, ["Dataset", "Persistent", "Value"], init)

def sort_key(self, k, v):
return k
DictSyncTreeSepModel.__init__(self, ".",
["Dataset", "Persistent", "Value"],
init)

def convert(self, k, v, column):
if column == 0:
return k
elif column == 1:
if column == 1:
return "Y" if v[0] else "N"
elif column == 2:
return short_format(v[1])
@@ -58,10 +55,9 @@ def __init__(self, dialog_parent, dock_area, datasets_sub):
self.search.editingFinished.connect(self._search_datasets)
grid.addWidget(self.search, 0, 0)

self.table = QtGui.QTableView()
self.table = QtGui.QTreeView()
self.table.setSelectionMode(QtGui.QAbstractItemView.NoSelection)
self.table.horizontalHeader().setResizeMode(
QtGui.QHeaderView.ResizeToContents)
self.table.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
grid.addWidget(self.table, 1, 0)

self.table_model = Model(dict())
34 changes: 15 additions & 19 deletions artiq/gui/explorer.py
Original file line number Diff line number Diff line change
@@ -6,26 +6,21 @@
from pyqtgraph import LayoutWidget

from artiq.protocols import pyon
from artiq.gui.models import DictSyncModel
from artiq.gui.models import DictSyncTreeSepModel
from artiq.gui.scan import ScanController
from artiq.gui.shortcuts import ShortcutManager


class Model(DictSyncModel):
class Model(DictSyncTreeSepModel):
def __init__(self, init):
DictSyncModel.__init__(self,
self.explorer = None
DictSyncTreeSepModel.__init__(self,
"/",
["Experiment"],
init)
self.explorer = None

def sort_key(self, k, v):
return k

def convert(self, k, v, column):
return k

def __setitem__(self, k, v):
DictSyncModel.__setitem__(self, k, v)
DictSyncTreeSepModel.__setitem__(self, k, v)
if self.explorer is not None:
if k == self.explorer.selected_key:
self.explorer.update_selection(k, k)
@@ -232,7 +227,9 @@ def __init__(self, main_window, status_bar,
grid = LayoutWidget()
self.splitter.addWidget(grid)

self.el = QtGui.QListView()
self.el = QtGui.QTreeView()
self.el.setHeaderHidden(True)
self.el.setSelectionBehavior(QtGui.QAbstractItemView.SelectItems)
self.el.selectionChanged = self._selection_changed
self.selected_key = None
grid.addWidget(self.el, 0, 0, colspan=4)
@@ -310,10 +307,10 @@ def set_model(self, model):
self.el.setModel(model)

def update_selection(self, selected, deselected):
if deselected:
if deselected is not None:
self.argeditor_states[deselected] = self.argeditor.save_state()

if selected:
if selected is not None:
expinfo = self.explist_model.backing_store[selected]
self.argeditor.set_arguments(expinfo["arguments"])
if selected in self.argeditor_states:
@@ -324,8 +321,7 @@ def update_selection(self, selected, deselected):
def _sel_to_key(self, selection):
selection = selection.indexes()
if selection:
row = selection[0].row()
return self.explist_model.row_to_key[row]
return self.explist_model.index_to_key(selection[0])
else:
return None

@@ -336,9 +332,9 @@ def _selection_changed(self, selected, deselected):
def save_state(self):
idx = self.el.selectedIndexes()
if idx:
row = idx[0].row()
key = self.explist_model.row_to_key[row]
self.argeditor_states[key] = self.argeditor.save_state()
key = self.explist_model.index_to_key(idx[0])
if key is not None:
self.argeditor_states[key] = self.argeditor.save_state()
return {
"argeditor": self.argeditor_states,
"shortcuts": self.shortcuts.save_state()
184 changes: 184 additions & 0 deletions artiq/gui/models.py
Original file line number Diff line number Diff line change
@@ -180,3 +180,187 @@ def append(self, v):

def convert(self, v, column):
raise NotImplementedError


# An item is a node if it has children, a leaf if it does not.
# There can be a node and a leaf with the same name and different
# rows, e.g. foo/bar and foo.
class _DictSyncTreeSepItem:
def __init__(self, parent, row, name):
self.parent = parent
self.row = row
self.name = name
self.children_by_row = []
self.children_nodes_by_name = dict()
self.children_leaves_by_name = dict()

def __repr__(self):
return ("<DictSyncTreeSepItem {}, row={}, nchildren={}>"
.format(self.name, self.row, len(self.children_by_row)))


def _bisect_item(a, name):
lo = 0
hi = len(a)
while lo < hi:
mid = (lo + hi)//2
if name < a[mid].name:
hi = mid
else:
lo = mid + 1
return lo


class DictSyncTreeSepModel(QtCore.QAbstractItemModel):
def __init__(self, separator, headers, init):
QtCore.QAbstractItemModel.__init__(self)

self.separator = separator
self.headers = headers

self.backing_store = dict()
self.children_by_row = []
self.children_nodes_by_name = dict()
self.children_leaves_by_name = dict()

for k, v in init.items():
self[k] = v

def rowCount(self, parent):
if parent.isValid():
item = parent.internalPointer()
return len(item.children_by_row)
else:
return len(self.children_by_row)

def columnCount(self, parent):
return len(self.headers)

def headerData(self, col, orientation, role):
if (orientation == QtCore.Qt.Horizontal
and role == QtCore.Qt.DisplayRole):
return self.headers[col]
return None

def index(self, row, column, parent):
if parent.isValid():
parent_item = parent.internalPointer()
return self.createIndex(row, column,
parent_item.children_by_row[row])
else:
return self.createIndex(row, column,
self.children_by_row[row])

def _index_item(self, item):
if item is self:
return QtCore.QModelIndex()
else:
return self.createIndex(item.row, 0, item)

def parent(self, index):
if index.isValid():
return self._index_item(index.internalPointer().parent)
else:
return QtCore.QModelIndex()

def _add_item(self, parent, name, leaf):
if leaf:
name_dict = parent.children_leaves_by_name
else:
name_dict = parent.children_nodes_by_name

if name in name_dict:
return name_dict[name]
row = _bisect_item(parent.children_by_row, name)
item = _DictSyncTreeSepItem(parent, row, name)

self.beginInsertRows(self._index_item(parent), row, row)
parent.children_by_row.insert(row, item)
for next_item in parent.children_by_row[row+1:]:
next_item.row += 1
name_dict[name] = item
self.endInsertRows()

return item

def __setitem__(self, k, v):
*node_names, leaf_name = k.split(self.separator)
if k in self.backing_store:
parent = self
for node_name in node_names:
parent = parent.children_nodes_by_name[node_name]
item = parent.children_leaves_by_name[leaf_name]
index0 = self.createIndex(item.row, 0, item)
index1 = self.createIndex(item.row, len(self.headers)-1, item)
self.backing_store[k] = v
self.dataChanged.emit(index0, index1)
else:
self.backing_store[k] = v
parent = self
for node_name in node_names:
parent = self._add_item(parent, node_name, False)
self._add_item(parent, leaf_name, True)

def _del_item(self, parent, path):
if len(path) == 1:
# leaf
name = path[0]
item = parent.children_leaves_by_name[name]
row = item.row
self.beginRemoveRows(self._index_item(parent), row, row)
del parent.children_leaves_by_name[name]
del parent.children_by_row[row]
for next_item in parent.children_by_row[row:]:
next_item.row -= 1
self.endRemoveRows()
else:
# node
name, *rest = path
item = parent.children_nodes_by_name[name]
self._del_item(item, rest)
if not item.children_by_row:
row = item.row
self.beginRemoveRows(self._index_item(parent), row, row)
del parent.children_nodes_by_name[name]
del parent.children_by_row[row]
for next_item in parent.children_by_row[row:]:
next_item.row -= 1
self.endRemoveRows()

def __delitem__(self, k):
self._del_item(self, k.split(self.separator))
del self.backing_store[k]

def __getitem__(self, k):
def update():
self[k] = self.backing_store[k]
return _SyncSubstruct(update, self.backing_store[k])

def index_to_key(self, index):
item = index.internalPointer()
if item.children_by_row:
return None
key = item.name
item = item.parent
while item is not self:
key = item.name + self.separator + key
item = item.parent
return key

def data(self, index, role):
if not index.isValid() or role != QtCore.Qt.DisplayRole:
return None
else:
column = index.column()
if column == 0:
return index.internalPointer().name
else:
key = self.index_to_key(index)
if key is None:
return None
else:
return self.convert(key, self.backing_store[key],
column)

def convert(self, k, v, column):
raise NotImplementedError