diff --git a/glue/core/data_combo_helper.py b/glue/core/data_combo_helper.py index 653f2aae1..abf73238a 100644 --- a/glue/core/data_combo_helper.py +++ b/glue/core/data_combo_helper.py @@ -49,13 +49,38 @@ class ComboHelper(HubListener): The state to which the selection property belongs selection_property : :class:`~glue.external.echo.SelectionCallbackProperty` The selection property representing the combo. + none : bool or str, optional + Add an entry that means `None`. If a string, this is the display string + that will be shown for the `None` entry, otherwise an empty string is + shown. """ - def __init__(self, state, selection_property): + def __init__(self, state, selection_property, none=False): + + if isinstance(none, string_types): + self._none = True + self._none_label = none + else: + self._none = none + self._none_label = '' self._state = weakref.ref(state) self.selection_property = selection_property + @property + def none(self): + return self._none + + @none.setter + def none(self, value): + if isinstance(value, string_types): + self._none = True + self._none_label = value + else: + self._none = value + self._none_label = '' + self.refresh() + @property def state(self): """ @@ -86,6 +111,8 @@ def choices(self): def choices(self, choices): with delay_callback(self.state, self.selection_property): prop = getattr(type(self.state), self.selection_property) + if self._none: + choices = [None] + choices prop.set_choices(self.state, choices) @property @@ -100,7 +127,15 @@ def display(self): @display.setter def display(self, display): prop = getattr(type(self.state), self.selection_property) - return prop.set_display_func(self.state, display) + if self._none: + def display_wrapper(value): + if value is None: + return self._none_label + else: + return display(value) + return prop.set_display_func(self.state, display_wrapper) + else: + return prop.set_display_func(self.state, display) def _on_rename(self, msg): # If a component ID is renamed, we don't need to refresh because the @@ -160,20 +195,10 @@ def __init__(self, state, selection_property, numeric=True, categorical=True, pixel_coord=False, world_coord=False, derived=True, none=False): - super(ComponentIDComboHelper, self).__init__(state, selection_property) - - if isinstance(none, string_types): - self._none = True - self._none_label = none - else: - self._none = none - self._none_label = '' + super(ComponentIDComboHelper, self).__init__(state, selection_property, none=none) def display_func_label(cid): - if cid is None: - return self._none_label - else: - return cid.label + return cid.label self.display = display_func_label @@ -251,20 +276,6 @@ def derived(self, value): self._derived = value self.refresh() - @property - def none(self): - return self._none - - @none.setter - def none(self, value): - if isinstance(value, string_types): - self._none = True - self._none_label = value - else: - self._none = value - self._none_label = '' - self.refresh() - def append_data(self, data, refresh=True): if self._manual_data: @@ -331,9 +342,6 @@ def refresh(self, *args): choices = [] - if self._none: - choices.append(None) - for data in self._data: derived_components = [cid for cid in data.derived_components if cid.parent is data] @@ -412,11 +420,15 @@ class BaseDataComboHelper(ComboHelper): The data collection to which the datasets belong - this is needed because if a dataset is removed from the data collection, we want to remove it here. + none : bool or str, optional + Add an entry that means `None`. If a string, this is the display string + that will be shown for the `None` entry, otherwise an empty string is + shown. """ - def __init__(self, state, selection_property, data_collection=None): + def __init__(self, state, selection_property, data_collection=None, none=False): - super(BaseDataComboHelper, self).__init__(state, selection_property) + super(BaseDataComboHelper, self).__init__(state, selection_property, none=none) def display_func_label(cid): return cid.label @@ -562,10 +574,10 @@ class DataCollectionComboHelper(BaseDataComboHelper): The data collection with which to stay in sync """ - def __init__(self, state, selection_property, data_collection): + def __init__(self, state, selection_property, data_collection, none=False): super(DataCollectionComboHelper, self).__init__(state, selection_property, - data_collection=data_collection) + data_collection=data_collection, none=none) self._datasets = data_collection diff --git a/glue/dialogs/component_arithmetic/qt/component_arithmetic.py b/glue/dialogs/component_arithmetic/qt/component_arithmetic.py index 1ca692190..f50d0eff7 100644 --- a/glue/dialogs/component_arithmetic/qt/component_arithmetic.py +++ b/glue/dialogs/component_arithmetic/qt/component_arithmetic.py @@ -6,19 +6,20 @@ from qtpy import QtWidgets, QtGui from qtpy.QtCore import Qt -from glue.external.echo import SelectionCallbackProperty +from glue.external.echo import SelectionCallbackProperty, HasCallbackProperties from glue.external.echo.qt import connect_combo_selection from glue.core import ComponentID from glue.core.parse import ParsedComponentLink, ParsedCommand from glue.utils.qt import load_ui from glue.core.message import NumericalDataChangedMessage +from glue.core.data_combo_helper import DataCollectionComboHelper from glue.dialogs.component_arithmetic.qt.equation_editor import EquationEditorDialog __all__ = ['ArithmeticEditorWidget'] -class ArithmeticEditorWidget(QtWidgets.QDialog): +class ArithmeticEditorWidget(QtWidgets.QDialog, HasCallbackProperties): data = SelectionCallbackProperty() @@ -63,8 +64,8 @@ def __init__(self, data_collection=None, parent=None): self._components_other[data].append(cid) # Populate data combo - ArithmeticEditorWidget.data.set_choices(self, list(self.data_collection)) - ArithmeticEditorWidget.data.set_display_func(self, lambda x: x.label) + self._data_helper = DataCollectionComboHelper(self, 'data', data_collection, + none='Select dataset') connect_combo_selection(self, 'data', self.ui.combosel_data) self.ui.combosel_data.setCurrentIndex(0) @@ -98,11 +99,16 @@ def _update_component_lists(self, *args): self.list.blockSignals(True) + self.list.clear() + + if self.data is None: + return + mapping = {} for cid in self.data.components: mapping[cid] = cid.label - self.list.clear() + for cid in self._components_derived[self.data]: label = self._state[self.data][cid]['label'] if self._state[self.data][cid]['equation'] is None: