Skip to content
This repository was archived by the owner on Nov 7, 2024. It is now read-only.

Commit 334d314

Browse files
authored
Merge pull request #1008 from ess-dmsc/ECDC-2433_attrs_tree_view
ECDC-2433: Adding view attributes button in main window
2 parents 84a8742 + 903e0d8 commit 334d314

File tree

11 files changed

+125
-19
lines changed

11 files changed

+125
-19
lines changed

nexus_constructor/field_attrs.py

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
from functools import partial
2-
from typing import Any, Union
2+
from typing import Any, List, Union
33

44
import numpy as np
5+
from PySide6.QtCore import Signal
56
from PySide6.QtWidgets import (
67
QComboBox,
78
QDialog,
@@ -16,7 +17,8 @@
1617

1718
from nexus_constructor.array_dataset_table_widget import ArrayDatasetTableWidget
1819
from nexus_constructor.common_attrs import ARRAY, SCALAR, CommonAttrs
19-
from nexus_constructor.model.module import Dataset
20+
from nexus_constructor.model import Group
21+
from nexus_constructor.model.module import FileWriterModule
2022
from nexus_constructor.model.value_type import VALUE_TYPE_TO_NP, ValueTypes
2123
from nexus_constructor.ui_utils import validate_line_edit
2224
from nexus_constructor.validators import AttributeNameValidator, FieldValueValidator
@@ -32,9 +34,14 @@ def _get_human_readable_type(new_value: Any):
3234
elif isinstance(new_value, float):
3335
return ValueTypes.DOUBLE
3436
else:
35-
return next(
36-
key for key, value in VALUE_TYPE_TO_NP.items() if value == new_value.dtype
37-
)
37+
try:
38+
return next(
39+
key
40+
for key, value in VALUE_TYPE_TO_NP.items()
41+
if value == new_value.dtype
42+
)
43+
except AttributeError:
44+
return None
3845

3946

4047
class FieldAttrsDialog(QDialog):
@@ -49,17 +56,27 @@ def __init__(self, parent=None):
4956
self.add_button.clicked.connect(self.__add_attr)
5057
self.remove_button = QPushButton("Remove attr")
5158
self.remove_button.clicked.connect(self._remove_attrs)
59+
self.close_button = QPushButton("OK")
60+
self.close_button.clicked.connect(self.close)
5261

53-
self.layout().addWidget(self.list_widget, 0, 0, 2, 1)
62+
self.layout().addWidget(self.list_widget, 0, 0, 3, 1)
5463
self.layout().addWidget(self.add_button, 0, 1)
5564
self.layout().addWidget(self.remove_button, 1, 1)
65+
self.layout().addWidget(self.close_button, 2, 1)
5666

57-
def fill_existing_attrs(self, existing_dataset: Dataset):
67+
def fill_existing_attrs(
68+
self,
69+
existing_dataset: Union[FileWriterModule, Group],
70+
attributes_exclude: List = ATTRS_EXCLUDELIST,
71+
):
5872
for attr in existing_dataset.attributes:
59-
if attr.name not in ATTRS_EXCLUDELIST:
73+
if attr.name not in attributes_exclude:
6074
frame = FieldAttrFrame(attr)
6175
self._add_attr(existing_frame=frame)
6276

77+
def add_update_signal(self):
78+
self.close_button.clicked.connect(self.update_attributes)
79+
6380
def __add_attr(self):
6481
"""
6582
Only used for button presses. Any additional arguments from the signal are ignored.
@@ -78,6 +95,19 @@ def _remove_attrs(self):
7895
for index in self.list_widget.selectedIndexes():
7996
self.list_widget.takeItem(index.row())
8097

98+
def update_attributes(self):
99+
self.update_attributes_signal.emit(self.get_attrs())
100+
101+
def set_view_only(self, label: str, set_visibility: bool):
102+
for index in range(self.list_widget.count()):
103+
item = self.list_widget.item(index)
104+
widget = self.list_widget.itemWidget(item)
105+
widget.array_edit_button.setText(label)
106+
widget.dialog.add_row_button.setVisible(set_visibility)
107+
widget.dialog.remove_row_button.setVisible(set_visibility)
108+
widget.dialog.add_column_button.setVisible(set_visibility)
109+
widget.dialog.remove_column_button.setVisible(set_visibility)
110+
81111
def get_attrs(self):
82112
attrs_list = []
83113
for index in range(self.list_widget.count()):
@@ -103,6 +133,8 @@ def _setup_attribute_name_validator(self, frame):
103133
)
104134
)
105135

136+
update_attributes_signal = Signal(tuple)
137+
106138

107139
class FieldAttrFrame(QFrame):
108140
def __init__(self, attr=None, parent=None):
@@ -187,13 +219,12 @@ def name(self, new_name: str):
187219

188220
@property
189221
def value(self) -> Union[np.generic, np.ndarray]:
190-
191222
if self.is_scalar:
192-
if self.dtype == VALUE_TYPE_TO_NP[ValueTypes.STRING] or isinstance(
193-
self.dtype, str
194-
):
223+
if self.dtype == ValueTypes.STRING:
195224
return self.attr_value_lineedit.text()
196-
return self.dtype(VALUE_TYPE_TO_NP[self.attr_value_lineedit.text()])
225+
value = self.attr_value_lineedit.text()
226+
type_cast = VALUE_TYPE_TO_NP[self.attr_dtype_combo.currentText()]
227+
return type_cast(value) if value else ""
197228
return np.squeeze(self.dialog.model.array)
198229

199230
@value.setter
@@ -209,5 +240,8 @@ def value(self, new_value: np.ndarray):
209240
else:
210241
self.type_changed(ARRAY)
211242
self.dialog.model.array = new_value
212-
self.dialog.model.update_array_dtype(new_value.dtype)
243+
try:
244+
self.dialog.model.update_array_dtype(new_value.dtype)
245+
except AttributeError:
246+
pass
213247
self.dtype_changed(None)

nexus_constructor/json/load_from_json.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ def load_model_from_json(self, filename: str) -> bool:
199199

200200
def _load_from_json_dict(self, json_dict: Dict) -> bool:
201201
self.entry_node = self._read_json_object(json_dict[CommonKeys.CHILDREN][0])
202+
self.model.entry.attributes = self.entry_node.attributes
202203
for child in self.entry_node.children:
203204
if isinstance(child, (Dataset, Link, Group)):
204205
self.model.entry[child.name] = child
@@ -333,7 +334,6 @@ def _read_json_object(self, json_object: Dict, parent_node: Group = None):
333334
self.model.entry[nexus_object.name] = nexus_object
334335
if isinstance(nexus_object, Group):
335336
nexus_object.group_placeholder = use_placeholder
336-
337337
return nexus_object
338338

339339
def _add_object_warning(self, missing_info, parent_node):

nexus_constructor/main_window.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import json
2-
from typing import Dict, List
2+
from typing import Dict, List, Union
33
from weakref import WeakKeyDictionary
44

55
from PySide6.QtCore import Qt
@@ -13,10 +13,16 @@
1313
from ui.main_window import Ui_MainWindow
1414

1515
from .about_window import AboutWindow
16+
from .common_attrs import CommonAttrs
17+
from .field_attrs import FieldAttrsDialog
18+
from .model.attributes import Attributes
19+
from .model.module import FileWriterModule
20+
from .model.transformation import Transformation
1621

1722
NEXUS_FILE_TYPES = {"NeXus Files": ["nxs", "nex", "nx5"]}
1823
JSON_FILE_TYPES = {"JSON Files": ["json", "JSON"]}
1924
FLATBUFFER_FILE_TYPES = {"FlatBuffer Files": ["flat", "FLAT"]}
25+
ATTRIBUTES_SKIPPED_LIST = [CommonAttrs.DEPENDS_ON]
2026

2127

2228
class MainWindow(Ui_MainWindow, QMainWindow):
@@ -119,6 +125,17 @@ def show_edit_component_dialog(self):
119125
except IndexError:
120126
print("Select a valid group in the NeXus tree view before editing.")
121127

128+
def show_attributes_list_window(self):
129+
try:
130+
selected_component = (
131+
self.component_tree_view_tab.component_tree_view.selectedIndexes()[
132+
0
133+
].internalPointer()
134+
)
135+
self._show_attributes_list_window(selected_component)
136+
except IndexError:
137+
print("Select a valid group or module.")
138+
122139
def create_new_json_template(self):
123140
msg = QMessageBox.question(
124141
None,
@@ -211,6 +228,36 @@ def show_add_component_window(self, group: Group, new_group: bool):
211228
)
212229
self.add_component_window.show()
213230

231+
def _show_attributes_list_window(
232+
self, selected_object: Union[Group, FileWriterModule]
233+
):
234+
field_attrs_dialog = FieldAttrsDialog(self)
235+
field_attrs_dialog.fill_existing_attrs(selected_object, ATTRIBUTES_SKIPPED_LIST)
236+
if isinstance(selected_object, Transformation):
237+
field_attrs_dialog.setWindowTitle("Attribute Viewer")
238+
field_attrs_dialog.add_button.setVisible(False)
239+
field_attrs_dialog.remove_button.setVisible(False)
240+
field_attrs_dialog.set_view_only("View Array", False)
241+
else:
242+
field_attrs_dialog.add_update_signal()
243+
field_attrs_dialog.update_attributes_signal.connect(self._update_attributes)
244+
field_attrs_dialog.show()
245+
246+
def _update_attributes(self, edited_attributes: tuple):
247+
selected_object = (
248+
self.component_tree_view_tab.component_tree_view.selectedIndexes()[
249+
0
250+
].internalPointer()
251+
)
252+
new_attributes = Attributes()
253+
for attribute in ATTRIBUTES_SKIPPED_LIST:
254+
attribute_val = selected_object.attributes.get_attribute(attribute)
255+
if attribute_val:
256+
new_attributes.set_attribute_value(attribute, attribute_val)
257+
for name, value, attribute_type in edited_attributes:
258+
new_attributes.set_attribute_value(name, value, attribute_type)
259+
selected_object.attributes = new_attributes
260+
214261
def _update_model(self, selected_group: Group):
215262
self.component_tree_view_tab.set_up_model(self.model)
216263
component_model = self.component_tree_view_tab.component_model

nexus_constructor/model/attributes.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ def get_attribute_value(self, attribute_name: str):
3434
return _get_item(self, attribute_name).values
3535
return None
3636

37+
def get_attribute(self, attribute_name: str):
38+
if self.contains_attribute(attribute_name):
39+
return _get_item(self, attribute_name)
40+
return None
41+
3742
def contains_attribute(self, attribute_name):
3843
result = _get_item(self, attribute_name)
3944
return True if result is not None else False

nexus_constructor/module_view.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ def __init__(self, module, parent: QWidget, model: Model):
6666
self.model = model
6767
self._set_existing_items()
6868
layout.addWidget(self.field_widget)
69+
self.field_widget.attrs_button.setVisible(False)
6970
self.setLayout(layout)
7071

7172
def _set_existing_items(self):

nexus_constructor/treeview_utils.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ def set_button_states(
8888
new_translation_action: QAction,
8989
create_link_action: QAction,
9090
zoom_action: QAction,
91+
show_attrs_action: QAction,
9192
edit_component_action: QAction,
9293
):
9394
"""
@@ -98,6 +99,7 @@ def set_button_states(
9899
:param new_translation_action: The action for creating a new translation.
99100
:param create_link_action: The action for creating a link.
100101
:param zoom_action: The action for zooming on a component.
102+
:param show_attrs_action: The action for showing the attributes list.
101103
:param edit_component_action: The action for editing a component.
102104
"""
103105
selection_indices = component_tree_view.selectedIndexes()
@@ -109,6 +111,7 @@ def set_button_states(
109111
new_rotation_action,
110112
new_translation_action,
111113
zoom_action,
114+
show_attrs_action,
112115
edit_component_action,
113116
)
114117
else:
@@ -118,6 +121,10 @@ def set_button_states(
118121
allowed_transformation_action = is_transformation_action_allowed(
119122
selected_object
120123
)
124+
has_attributes = (
125+
True if not isinstance(selected_object, LinkTransformation) else False
126+
)
127+
set_enabled_and_raise(show_attrs_action, has_attributes)
121128
set_enabled_and_raise(zoom_action, selected_object_is_component)
122129
is_transform_group = False
123130
if selected_object_is_group:

nx-class-documentation/html/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ <h1>User Manual and Reference Documentation<a class="headerlink" href="#user-man
113113
</div>
114114
<hr class="docutils" />
115115
<p class="rubric">Publishing Information</p>
116-
<p>This manual built Oct 17, 2022.</p>
116+
<p>This manual built Oct 18, 2022.</p>
117117
<div class="admonition seealso">
118118
<p class="admonition-title">See also</p>
119119
<p>This document is available in these formats online:</p>

nx-class-documentation/html/searchindex.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ numpy
33
numpy-stl
44
open3d
55
pint
6-
PySide6
6+
PySide6<6.4.0
77
pytest-qt
88
xmltodict
99
ess-streaming-data-types >= 0.9.5

ui/attributes.png

11.5 KB
Loading

ui/treeview_tab.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ def __init__(self, scene_widget: InstrumentView, parent=None):
5656
self.component_tree_view.setSelectionMode(QAbstractItemView.SingleSelection)
5757

5858
self.component_tool_bar = QToolBar("Actions", self)
59+
self.component_tool_bar.setMinimumWidth(480)
5960
self.new_component_action = create_and_add_toolbar_action(
6061
"new_component.png",
6162
"Group",
@@ -92,6 +93,16 @@ def __init__(self, scene_widget: InstrumentView, parent=None):
9293
self.component_tool_bar,
9394
self,
9495
)
96+
97+
self.show_attrs_action = create_and_add_toolbar_action(
98+
"attributes.png",
99+
"Attributes",
100+
self.parent().show_attributes_list_window,
101+
self.component_tool_bar,
102+
self,
103+
)
104+
self.component_tool_bar.insertSeparator(self.show_attrs_action)
105+
95106
self.zoom_action = create_and_add_toolbar_action(
96107
"zoom.svg",
97108
"Zoom",
@@ -138,6 +149,7 @@ def _set_button_state(self):
138149
self.new_translation_action,
139150
self.create_link_action,
140151
self.zoom_action,
152+
self.show_attrs_action,
141153
self.edit_component_action,
142154
)
143155

0 commit comments

Comments
 (0)