diff --git a/dcoraid/gui/upload/widget_schema.py b/dcoraid/gui/upload/widget_schema.py index bdbe78e..3203b6f 100644 --- a/dcoraid/gui/upload/widget_schema.py +++ b/dcoraid/gui/upload/widget_schema.py @@ -1,6 +1,6 @@ from PyQt5 import QtCore, QtWidgets -from .widget_supplement_item import RSSItem, RSSTagsItem +from .widget_supplement_item import RSSItem, RSSTagsItem, TitleItem #: These items displayed differently to the user and may populate other keys @@ -66,29 +66,50 @@ def get_current_schema(self): schema[sec][key] = widget.get_value() return schema + @QtCore.pyqtSlot(str, str, object, bool) + def on_hide_show_items(self, section, key, value, enabled): + """Send a value_changed signal to all widgets + + ...so they can decide whether they are visible or not. + """ + for sec in self.schema_widgets: + for item in self.schema_widgets[sec]: + item.on_schema_key_toggled(section, key, value, enabled) + for label in self.schema_title_widgets: + label.on_schema_key_toggled(section, key, value, enabled) + def populate_schema(self, schema_dict): """Create all widgets corresponding to the schema Omits any :const:`HIDDEN_ITEMS` and creates special widgets for :const:`MAGIC_ITEMS`. """ + self.schema_title_widgets = [] for sec in schema_dict: widget_list = [] - label = QtWidgets.QLabel(sec.capitalize()) + label = TitleItem(schema_dict[sec].get("requires", {}), + schema_dict[sec]["name"]) + self.schema_title_widgets.append(label) self.verticalLayout.addWidget(label) for item in schema_dict[sec]["items"]: key = item["key"] + # Update item requirements with section requirements + if "requires" not in item: + item["requires"] = schema_dict[sec].get("requires", {}) if sec in MAGIC_ITEMS and key in MAGIC_ITEMS[sec]: # is a special widget (e.g. tags) - wrss = MAGIC_ITEMS[sec][key]["widget"](item, self) + wrss = MAGIC_ITEMS[sec][key]["widget"](item, + section=sec, + parent=self) elif sec in HIDDEN_ITEMS and key in HIDDEN_ITEMS[sec]: # should not be displayed continue else: - wrss = RSSItem(item, self) + wrss = RSSItem(item, section=sec, parent=self) self.verticalLayout.addWidget(wrss) widget_list.append(wrss) wrss.value_changed.connect(self.schema_changed) + wrss.value_changed.connect(self.on_hide_show_items) self.schema_widgets[sec] = widget_list def set_schema(self, schema_dict): @@ -114,3 +135,15 @@ def set_schema(self, schema_dict): value = schema_dict[sec][key] wrss.set_value(value) self.blockSignals(False) + self.update_visible_widgets() + + def update_visible_widgets(self): + """Cause all schema data widgets to emit their values + + This effectively updates the visibility of all schema + widgets (including titles). + """ + # Force all updates + for sec in self.schema_widgets: + for widget in self.schema_widgets[sec]: + widget.emit_value() diff --git a/dcoraid/gui/upload/widget_supplement_item.py b/dcoraid/gui/upload/widget_supplement_item.py index e1eda82..a0b0399 100644 --- a/dcoraid/gui/upload/widget_supplement_item.py +++ b/dcoraid/gui/upload/widget_supplement_item.py @@ -3,16 +3,89 @@ from PyQt5 import uic, QtCore, QtWidgets -class RSSTagsItem(QtWidgets.QWidget): - value_changed = QtCore.pyqtSignal() +class TitleItem(QtWidgets.QWidget): + def __init__(self, requires, title, *args, **kwargs): + """A schema widget for the section titles - def __init__(self, rss_dict, *args, **kwargs): + Parameters + ---------- + requires: dict + Requirements dictionary + title: str + Section title + """ + super(TitleItem, self).__init__(*args, **kwargs) + + self.verticalLayout = QtWidgets.QVBoxLayout(self) + self.verticalLayout.setContentsMargins(0, 0, 0, 0) + + self.label = QtWidgets.QLabel("{}".format(title)) + self.verticalLayout.addWidget(self.label) + + self.requires = requires + + @QtCore.pyqtSlot(str, str, object, bool) + def on_schema_key_toggled(self, section, key, value, enabled): + """Hide or show this widget based on self.requires""" + if not self.requires: + self.setVisible(True) + elif section in self.requires and key in self.requires[section]: + if value in self.requires[section][key]: + self.setVisible(enabled) + else: + self.setVisible(False) + + +class RSSItemBase(QtWidgets.QWidget): + value_changed = QtCore.pyqtSignal(str, str, object, bool) + + def __init__(self, rss_dict, section, *args, **kwargs): + super(RSSItemBase, self).__init__(*args, **kwargs) + self.rss_dict = rss_dict + self.section = section + self.key = rss_dict["key"] + self.requires = rss_dict.get("requires", {}) + + def emit_value(self): + """Emit `value_changed` with current data""" + self.value_changed.emit(self.section, self.key, self.get_value(), + self.checkBox.isChecked()) + + @QtCore.pyqtSlot() + def on_value_changed(self): + """Activate checkbox and call `emit_value`""" + if self.sender() == self.checkBox and not self.checkBox.isChecked(): + # Do not check the checkBox again if the user unchecks it + pass + else: + self.check(True) + self.emit_value() + + @QtCore.pyqtSlot(str, str, object, bool) + def on_schema_key_toggled(self, section, key, value, enabled): + """Hide or show this widget based on self.rss_dict["requires"]""" + if not self.requires: + visible = True + elif section in self.requires and key in self.requires[section]: + if value in self.requires[section][key]: + visible = enabled + else: + visible = False + else: + visible = self.isVisible() + self.setVisible(visible) + if not visible: + # uncheck the widget if it is hidden + self.checkBox.setChecked(False) + + +class RSSTagsItem(RSSItemBase): + def __init__(self, *args, **kwargs): """Represents an item in the supplementary resource schema""" super(RSSTagsItem, self).__init__(*args, **kwargs) path_ui = pkg_resources.resource_filename( "dcoraid.gui.upload", "widget_supplement_tags.ui") uic.loadUi(path_ui, self) - self.rss_dict = rss_dict self.tableWidget.setRowCount(3) self.on_assert_row_count() @@ -79,27 +152,14 @@ def on_assert_row_count(self): self.tableWidget.setItem(ii, jj, QtWidgets.QTableWidgetItem()) - @QtCore.pyqtSlot() - def on_value_changed(self): - """Activate checkbox and emit value_changed signal""" - if self.sender() == self.checkBox and not self.checkBox.isChecked(): - # Do not check the checkBox again if the user unchecks it - pass - else: - self.check(True) - self.value_changed.emit() - -class RSSItem(QtWidgets.QWidget): - value_changed = QtCore.pyqtSignal() - - def __init__(self, rss_dict, *args, **kwargs): +class RSSItem(RSSItemBase): + def __init__(self, *args, **kwargs): """Represents an item in the supplementary resource schema""" super(RSSItem, self).__init__(*args, **kwargs) path_ui = pkg_resources.resource_filename( "dcoraid.gui.upload", "widget_supplement_item.ui") uic.loadUi(path_ui, self) - self.rss_dict = rss_dict self.apply_schema() # signals @@ -196,16 +256,6 @@ def get_data_widget(self, retval=False): else: return widget - @QtCore.pyqtSlot() - def on_value_changed(self): - """Activate checkbox and emit value_changed signal""" - if self.sender() == self.checkBox and not self.checkBox.isChecked(): - # Do not check the checkBox again if the user unchecks it - pass - else: - self.check(True) - self.value_changed.emit() - def show_only_data_widget(self): """Convenience function that hides all but the data widget""" widget = self.get_data_widget()