Skip to content

Commit

Permalink
Merge pull request #107 from tangkong/mnt_upstream_tree_view
Browse files Browse the repository at this point in the history
MNT: move context menu functionality upstream into `RootTreeView`
  • Loading branch information
tangkong authored Dec 3, 2024
2 parents 3c3bc18 + 05da191 commit 557b55f
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 63 deletions.
22 changes: 22 additions & 0 deletions docs/source/upcoming_release_notes/107-mnt_upstream_tree_view.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
107 mnt_upstream_tree_view
##########################

API Breaks
----------
- N/A

Features
--------
- N/A

Bugfixes
--------
- Fills the top-level entry whenever RootTree model is created, to ensure at least first level of children display

Maintenance
-----------
- Adds common RootTreeView which holds the RootTree model. Upstreams standard settings and context menu support

Contributors
------------
- tangkong
1 change: 1 addition & 0 deletions superscore/backends/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

class TestBackend(_Backend):
"""Backend that manipulates Entries in-memory, for testing purposes."""
__test__ = False # Tell pytest this isn't a test case
_entry_cache: Dict[UUID, Entry] = {}

def __init__(self, data: Optional[List[Entry]] = None):
Expand Down
58 changes: 45 additions & 13 deletions superscore/tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
from superscore.backends.test import TestBackend
from superscore.client import Client
from superscore.control_layers import EpicsData
from superscore.model import Collection, Parameter, Severity, Status
from superscore.model import Collection, Parameter, Root, Severity, Status
from superscore.tests.conftest import nest_depth
from superscore.widgets.views import (CustRoles, LivePVHeader,
from superscore.widgets.views import (CustRoles, EntryItem, LivePVHeader,
LivePVTableModel, LivePVTableView,
NestableTableView, RootTree)
NestableTableView, RootTree,
RootTreeView)


@pytest.fixture(scope='function')
Expand Down Expand Up @@ -242,24 +243,55 @@ def test_fill_uuids_entry_item(linac_backend: TestBackend, qtbot: QtBot):
nested_coll.swap_to_uuids()
assert all(isinstance(c, UUID) for c in nested_coll.children)

tree_model = RootTree(base_entry=nested_coll, client=client)
# hack: make all of linac_backend flat
for entry in linac_backend._entry_cache.values():
entry.swap_to_uuids()

tree_model = RootTree(base_entry=nested_coll, client=client)
original_depth = nest_depth(tree_model.root_item)
assert original_depth == 1
# default fill depth is 2, so children and their children get EntryItems
assert original_depth == 2

# fill just the first child
# fill depth can depend on how the backend returns data. Backend may not
# be lazy, so we assert only child1's children have EntryItems
root_item = tree_model.root_item
child1 = root_item.child(0)
assert child1.childCount() == 0
assert child1.child(0).childCount() == 0
child1.fill_uuids(client)
assert child1.childCount() > 0
assert root_item.child(1).childCount() == 0
assert root_item.child(2).childCount() == 0
assert child1.child(0).childCount() > 0
assert root_item.child(1).child(0).childCount() == 0
assert root_item.child(2).child(0).childCount() == 0

# filling the root item fills its children, which held uuids before
# filling only occurs if direct children are UUIDs, does nothing here
# since it was originally filled by RootTree
root_item.fill_uuids(client)
assert root_item.child(0).childCount() > 0
assert root_item.child(1).childCount() > 0
assert root_item.child(2).childCount() > 0
assert root_item.child(0).child(0).childCount() > 0
assert root_item.child(1).child(0).childCount() == 0
assert root_item.child(2).child(0).childCount() == 0


def test_roottree_setup(sample_database: Root):
tree_model = RootTree(base_entry=sample_database)
root_index = tree_model.index_from_item(tree_model.root_item)
# Check that the entire tree was created
assert tree_model.rowCount(root_index) == 4
assert tree_model.root_item.child(3).childCount() == 3


def test_root_tree_view_setup_init_args(sample_client: Client):
tree_view = RootTreeView(
client=sample_client,
entry=sample_client.backend.root
)
assert isinstance(tree_view.model().root_item, EntryItem)
assert isinstance(tree_view.model(), RootTree)


def test_root_tree_view_setup_post_init(sample_client: Client):
tree_view = RootTreeView()
tree_view.client = sample_client
tree_view.set_data(sample_client.backend.root)

assert isinstance(tree_view.model().root_item, EntryItem)
assert isinstance(tree_view.model(), RootTree)
11 changes: 1 addition & 10 deletions superscore/tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,8 @@
import pytest
from pytestqt.qtbot import QtBot

from superscore.model import Collection, Root
from superscore.model import Collection
from superscore.widgets.core import DataWidget
from superscore.widgets.views import RootTree


@pytest.mark.parametrize(
Expand Down Expand Up @@ -39,11 +38,3 @@ def test_collection_datawidget_bridge(

qtbot.addWidget(widget1)
qtbot.addWidget(widget2)


def test_roottree_setup(sample_database: Root):
tree_model = RootTree(base_entry=sample_database)
root_index = tree_model.index_from_item(tree_model.root_item)
# Check that the entire tree was created
assert tree_model.rowCount(root_index) == 4
assert tree_model.root_item.child(3).childCount() == 3
4 changes: 2 additions & 2 deletions superscore/tests/test_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ def count_visible_items(tree_view):
return count


def test_main_window(qtbot: QtBot, mock_client: Client):
def test_main_window(qtbot: QtBot, sample_client: Client):
"""Pass if main window opens successfully"""
window = Window(client=mock_client)
window = Window(client=sample_client)
qtbot.addWidget(window)


Expand Down
7 changes: 6 additions & 1 deletion superscore/ui/collection_builder_page.ui
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="tree_view">
<widget class="RootTreeView" name="tree_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
Expand Down Expand Up @@ -213,6 +213,11 @@
<extends>QTableView</extends>
<header>superscore.widgets.views</header>
</customwidget>
<customwidget>
<class>RootTreeView</class>
<extends>QTreeView</extends>
<header>superscore.widgets.views</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down
11 changes: 9 additions & 2 deletions superscore/ui/main_window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
</layout>
</item>
<item>
<widget class="QTreeView" name="tree_view">
<widget class="RootTreeView" name="tree_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
Expand Down Expand Up @@ -85,7 +85,7 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>37</height>
<height>20</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
Expand Down Expand Up @@ -177,6 +177,13 @@
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>RootTreeView</class>
<extends>QTreeView</extends>
<header>superscore.widgets.views</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
7 changes: 6 additions & 1 deletion superscore/ui/nestable_page.ui
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="tree_view">
<widget class="RootTreeView" name="tree_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
Expand Down Expand Up @@ -85,6 +85,11 @@
<extends>QTableView</extends>
<header>superscore.widgets.views</header>
</customwidget>
<customwidget>
<class>RootTreeView</class>
<extends>QTreeView</extends>
<header>superscore.widgets.views</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
Expand Down
11 changes: 7 additions & 4 deletions superscore/widgets/page/collection_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from superscore.widgets.manip_helpers import insert_widget
from superscore.widgets.views import (BaseTableEntryModel, LivePVHeader,
LivePVTableView, NestableTableView,
RootTree)
RootTree, RootTreeView)

logger = logging.getLogger(__name__)

Expand All @@ -24,7 +24,7 @@ class CollectionBuilderPage(Display, DataWidget):
meta_placeholder: QtWidgets.QWidget
meta_widget: NameDescTagsWidget

tree_view: QtWidgets.QTreeView
tree_view: RootTreeView

sub_coll_table_view: NestableTableView
sub_pv_table_view: LivePVTableView
Expand Down Expand Up @@ -88,8 +88,11 @@ def setup_ui(self):
self.sub_coll_table_view.client = self.client
self.sub_coll_table_view.set_data(self.data)

self.tree_model = RootTree(base_entry=self.data, client=self.client)
self.tree_view.setModel(self.tree_model)
self.tree_view.client = self.client
self.tree_view.set_data(self.data)
self.tree_view.open_page_slot = self.open_page_slot
self.tree_model: RootTree = self.tree_view.model()

self.sub_coll_table_view.data_updated.connect(self.tree_model.refresh_tree)
self.sub_pv_table_view.data_updated.connect(self.tree_model.refresh_tree)

Expand Down
10 changes: 6 additions & 4 deletions superscore/widgets/page/entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
match_line_edit_text_width)
from superscore.widgets.thread_helpers import BusyCursorThread
from superscore.widgets.views import (LivePVTableView, NestableTableView,
RootTree, edit_widget_from_epics_data)
RootTreeView,
edit_widget_from_epics_data)

logger = logging.getLogger(__name__)

Expand All @@ -29,7 +30,7 @@ class NestablePage(Display, DataWidget):

meta_placeholder: QtWidgets.QWidget
meta_widget: NameDescTagsWidget
tree_view: QtWidgets.QTreeView
tree_view: RootTreeView
sub_coll_table_view: NestableTableView
sub_pv_table_view: LivePVTableView

Expand Down Expand Up @@ -58,8 +59,9 @@ def setup_ui(self):
insert_widget(self.meta_widget, self.meta_placeholder)

# show tree view
self.model = RootTree(base_entry=self.data, client=self.client)
self.tree_view.setModel(self.model)
self.tree_view.client = self.client
self.tree_view.set_data(self.data)
self.tree_view.open_page_slot = self.open_page_slot

self.sub_pv_table_view.client = self.client
self.sub_pv_table_view.set_data(self.data)
Expand Down
Loading

0 comments on commit 557b55f

Please sign in to comment.