Skip to content

Commit

Permalink
Merge pull request #80 from tangkong/enh_coll_builder
Browse files Browse the repository at this point in the history
ENH: add FilterComboBox, CollectionBuilderPage
  • Loading branch information
tangkong authored Sep 19, 2024
2 parents c1685a0 + abbf9d2 commit bcd8ff2
Show file tree
Hide file tree
Showing 8 changed files with 670 additions and 18 deletions.
23 changes: 23 additions & 0 deletions docs/source/upcoming_release_notes/80-enh_coll_builder.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
80 enh_coll_builder
###################

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

Features
--------
- Adds CollectionBuilderPage, which can add/remove PVs/Collections
- Adds FilterComboBox, for filtering through options

Bugfixes
--------
- N/A

Maintenance
-----------
- N/A

Contributors
------------
- tangkong
35 changes: 33 additions & 2 deletions superscore/tests/test_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
from pytestqt.qtbot import QtBot

from superscore.client import Client
from superscore.model import Collection
from superscore.model import Collection, Parameter
from superscore.widgets.page.collection_builder import CollectionBuilderPage
from superscore.widgets.page.entry import CollectionPage
from superscore.widgets.page.search import SearchPage

Expand All @@ -24,7 +25,19 @@ def search_page(qtbot: QtBot, sample_client: Client):
return page


@pytest.mark.parametrize('page', ["collection_page", "search_page"])
@pytest.fixture(scope="function")
def collection_builder_page(qtbot: QtBot, sample_client: Client):
page = CollectionBuilderPage(client=sample_client)
qtbot.addWidget(page)
yield page
page.pv_model.stop_polling()
qtbot.waitUntil(lambda: page.pv_model._poll_thread.isFinished())


@pytest.mark.parametrize(
'page',
["collection_page", "search_page", "collection_builder_page"]
)
def test_page_smoke(page: str, request: pytest.FixtureRequest):
"""smoke test, just create each page and see if they fail"""
print(type(request.getfixturevalue(page)))
Expand Down Expand Up @@ -55,3 +68,21 @@ def test_apply_filter(search_page: SearchPage):
search_page.name_line_edit.setText('collection 1')
search_page.apply_filter_button.clicked.emit()
assert search_page.results_table_view.model().rowCount() == 1


def test_coll_builder_add(collection_builder_page: CollectionBuilderPage):
page = collection_builder_page

page.pv_line_edit.setText("THIS:PV")
page.add_pvs_button.clicked.emit()

assert len(page.data.children) == 1
assert "THIS:PV" in page.data.children[0].pv_name
assert isinstance(page.data.children[0], Parameter)
assert page.pv_model.rowCount() == 1

page.coll_combo_box.setCurrentIndex(0)
added_collection = page._coll_options[0]
page.add_collection_button.clicked.emit()
assert added_collection is page.data.children[1]
assert page.coll_model.rowCount() == 1
207 changes: 207 additions & 0 deletions superscore/ui/collection_builder_page.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>924</width>
<height>660</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QWidget" name="meta_placeholder" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QSplitter" name="splitter_2">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QTreeView" name="tree_view">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
<widget class="QSplitter" name="splitter">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>3</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QTableView" name="sub_pv_table_view"/>
<widget class="QTableView" name="sub_coll_table_view"/>
<widget class="QTabWidget" name="add_tab_widget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="pv_add_widget">
<attribute name="title">
<string>add PV</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="pv_name_label">
<property name="text">
<string>PV name: </string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="pv_line_edit">
<property name="placeholderText">
<string>PV:TO:ADD, PV2:TO:ADD</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_5">
<item>
<widget class="QLabel" name="rbv_name_label">
<property name="text">
<string>Readback PV name:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="rbv_line_edit">
<property name="placeholderText">
<string>OPTIONAL:PV_RBV, OPTIONAL2:PV_RBV</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Preferred</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QPushButton" name="add_pvs_button">
<property name="text">
<string>Add PV(s)</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_6">
<item>
<widget class="QCheckBox" name="ro_checkbox">
<property name="text">
<string>Read Only</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QWidget" name="coll_add_widget">
<attribute name="title">
<string>add Collection</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Collection Name</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="coll_combo_box_placeholder">
<property name="placeholderText">
<string>Filtered Collections</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="add_collection_button">
<property name="text">
<string>Add Collection</string>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="save_button">
<property name="text">
<string>Save Collection</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>
22 changes: 14 additions & 8 deletions superscore/ui/main_window.ui
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="">
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="search_hayout">
Expand Down Expand Up @@ -85,15 +85,21 @@
<x>0</x>
<y>0</y>
<width>800</width>
<height>20</height>
<height>37</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<widget class="QMenu" name="menu_new">
<property name="title">
<string>New</string>
</property>
<addaction name="action_new_coll"/>
</widget>
<addaction name="separator"/>
<addaction name="action_open"/>
<addaction name="menu_new"/>
</widget>
<widget class="QMenu" name="menuDebug">
<property name="title">
Expand All @@ -120,11 +126,6 @@
<string>Open File</string>
</property>
</action>
<action name="action_open">
<property name="text">
<string>Open</string>
</property>
</action>
<action name="action_save_as">
<property name="text">
<string>Save As...</string>
Expand Down Expand Up @@ -170,6 +171,11 @@
<string>Welcome Tab</string>
</property>
</action>
<action name="action_new_coll">
<property name="text">
<string>Collection</string>
</property>
</action>
</widget>
<resources/>
<connections/>
Expand Down
55 changes: 55 additions & 0 deletions superscore/widgets/enhanced.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
"""
Enhanced widgets. Widgets that subclass standard qt widgets and add functionality
"""
from qtpy import QtCore, QtWidgets


class FilterComboBox(QtWidgets.QComboBox):
"""
ComboBox with the LineEdit enabled with autocomplete and option filtering
Adapted from https://stackoverflow.com/a/50639066
"""
def __init__(self, parent=None):
super().__init__(parent)

self.setFocusPolicy(QtCore.Qt.StrongFocus)
self.setEditable(True)

# add a filter model to filter matching items
self.filter_model = QtCore.QSortFilterProxyModel(self)
self.filter_model.setFilterCaseSensitivity(QtCore.Qt.CaseInsensitive)
self.filter_model.setSourceModel(self.model())

# add a completer, which uses the filter model
self.setCompleter(QtWidgets.QCompleter(self.filter_model, self))
# always show all (filtered) completions
self.completer().setCompletionMode(QtWidgets.QCompleter.UnfilteredPopupCompletion)

# connect signals
self.lineEdit().textEdited.connect(self.filter_model.setFilterFixedString)
self.completer().activated.connect(self.on_completer_activated)

def on_completer_activated(self, text):
"""
on selection of an item from the completer, select the corresponding item
"""
if text:
index = self.findText(text)
self.setCurrentIndex(index)
self.activated[str].emit(self.itemText(index))

def setModel(self, model):
"""
on model change, update the models of the filter and completer as well
"""
super().setModel(model)
self.filter_model.setSourceModel(model)
self.completer().setModel(self.filter_model)

def setModelColumn(self, column):
"""
on model column change, update the model column of the filter and completer
"""
self.completer().setCompletionColumn(column)
self.filter_model.setFilterKeyColumn(column)
super().setModelColumn(column)
Loading

0 comments on commit bcd8ff2

Please sign in to comment.