def __init__(self): super().__init__() self.other_data_context_was_added = Signal(BaseViewModel) self.other_data_context_was_removed = Signal(BaseViewModel) self.data_context_container = DataContexts() self._other_data_contexts = None self.other_data_contexts = ObservableList()
class BaseViewModel(object): """ This is the base view model class to be implemented by all data context classes """ name = 'data_context' def __init__(self): self.property_changed = Signal(str) def notify_change(self, name): """ Send notification that a variable has been changed that the binding enabled widgets can update accordingly :param name: variable name """ self.property_changed.emit(name) def save_configuration(self): """ This method can be overwritten to enable the automatic saving of the data-context data when it is used inside a modular application. NOTE: There is now save system in place, this method will just by called once the application terminates """ pass
class BindingEnabledWidget(object): """ This class is not a visual widget but enables a widget that inherits it along with a Qt widget to do data binding. """ data_context_changed = Signal(BaseViewModel) data_context_removed = Signal(BaseViewModel) @property def data_context(self): """ Gets the data context of this frame """ return self._data_context @data_context.setter def data_context(self, value): """ Sets the data context of this frame """ # alert that the old data context will be removed self.data_context_removed.emit(self._data_context) self._data_context = value self.bindings.destroy( ) # destroy the bindings manager to remove any previous binding relationships self.bindings = BindingManager( self._data_context) # create a new bindings manager # alert listeners that the data context of this frame was changed self.data_context_changed.emit(self._data_context) def __init__(self): self._data_context = None self.bindings = BindingManager(None) def __del__(self): self.bindings.destroy()
def __init__(self): self._data_context = None self.data_context_changed = Signal(BaseViewModel) self.data_context_removed = Signal(BaseViewModel) self.bindings = BindingManager(None)
class ExperimentOverviewViewModel(BaseContextAwareViewModel): """ This is the data-context for the experiment frame. It stores the data-contexts of single experiment boxes. """ name = 'experiments' add_experiment_request = Signal(bool) @property def experiment_folder(self): """ Gets the path of the folder where the python scripts containing experiments are """ return self._experiment_folder @experiment_folder.setter def experiment_folder(self, value): """ Sets the path of the folder where the python scripts containing experiments are :param value: path """ self._experiment_folder = value for experiment in self.experiments: experiment.experiment_folder = value def __init__(self, experiment_folder=None): super().__init__() self.experiments = ObservableList( ) # list that contains the experiment data-contexts self.experiments.item_added.connect( self._experiment_added_) # listen for experiments which are added self._experiment_folder = experiment_folder # member for storing the experiment folder path self.other_data_contexts.item_added.connect( self._data_contexts_changed_ ) # listen for data contexts that appear in the application self.other_data_contexts.item_removed.connect( self._data_contexts_changed_ ) # listen for data contexts that disappear from the application def add_experiment(self, cannot_be_removed=False): """ Add experiment box :param cannot_be_removed: If set to true no remove button will be added """ self.add_experiment_request.emit(cannot_be_removed) def save_configuration(self): """ Save experiment configuration """ experiment_list = list() for experiment in self.experiments: experiment_data = {'experiment_name': experiment.experiment_name} experiment_list.append(experiment_data) data = { 'experiments': experiment_list, 'experiment_folder': self.experiment_folder } with open(EXPERIMENT_CONFIG, 'w') as file: file.write(json.dumps(data)) def load_configuration(self): """ Load experiment configuration """ if os.path.isfile(EXPERIMENT_CONFIG): with open(EXPERIMENT_CONFIG, 'r') as file: data = json.loads(file.read()) self.experiment_folder = data['experiment_folder'] while len(self.experiments) < len(data['experiments']): self.add_experiment( cannot_be_removed=len(self.experiments) == 0) for i in range(len(self.experiments)): experiment_name = data['experiments'][i]['experiment_name'] if experiment_name in self.experiments[ i].available_experiments: index = self.experiments[ i].available_experiments.index(experiment_name) self.experiments[i].selected_experiment = index def change_experiment_folder(self): """ Opens a dialog to select a new folder to look for experiment python scripts :return: """ path = QFileDialog.getExistingDirectory( None, "Select folder containing experiment scripts") if path != '': self.experiment_folder = path def _data_contexts_changed_(self, vm): """ Callback for handling changes in the available other data contexts. This method updates the experiments that they can access these contexts :param vm: data context that caused the signal """ for experiment in self.experiments: experiment.other_data_contexts = self.other_data_contexts def _experiment_added_(self, experiment: BaseContextAwareViewModel): """ Callback for handling an experiment being added :param experiment: experiment which was added """ experiment.other_data_contexts = self.other_data_contexts # make other data contexts available to newly added experiment
class BaseContextAwareViewModel(BaseViewModel): """ Context aware view models have the ability that they can access other view models which are present in the application. This enables the context aware view model to control other view models. Important: This only works if the control is embedded in the lab master main window which handles the dependency injection! """ other_data_context_was_added = Signal(BaseViewModel) other_data_context_was_removed = Signal(BaseViewModel) @property def other_data_contexts(self): """ Gets all the available data contexts """ return self._other_data_contexts @other_data_contexts.setter def other_data_contexts(self, value: ObservableList): """ Sets the data contexts of other view models. Makes view models available """ if type(self._other_data_contexts) == ObservableList: # check if old data context list is observable # de-register change events self._other_data_contexts.item_added.disconnect(self._other_data_context_added_) self._other_data_contexts.item_removed.disconnect(self._other_data_context_removed_) if type(value) == ObservableList: # check if new data context list is observable # register change events self._other_data_contexts = value self._other_data_contexts.item_added.connect(self._other_data_context_added_) self._other_data_contexts.item_removed.connect(self._other_data_context_removed_) # add existing data contexts for data_context in self._other_data_contexts: self._other_data_context_added_(data_context) def __init__(self): super().__init__() self.data_context_container = DataContexts() self._other_data_contexts = None self.other_data_contexts = ObservableList() def _count_instances_(self, data_context): """ Counts how many view models of this type are present :param data_context: view model :return: view model count """ count = 0 for dc in self._other_data_contexts: if is_non_strict_type(type(dc), type(data_context)): count += 1 return count def _other_data_context_added_(self, data_context): """ Callback for handling newly added view model :param data_context: newly added view model """ count = self._count_instances_(data_context) data_context_name = str(data_context).replace(' ', '') if hasattr(data_context, 'name'): data_context_name = getattr(data_context, 'name').replace(' ', '') if count > 1: data_context_name += str(count) self.data_context_container.__dict__[data_context_name] = data_context self.other_data_context_was_added.emit(data_context) def _other_data_context_removed_(self, data_context): """ Callback for handling the removal of a view model :param data_context: view model that has been removed """ remove_key = None for key in self.data_context_container.__dict__: if self.data_context_container.__dict__[key] == data_context: remove_key = key break if remove_key is not None: del self.data_context_container.__dict__[remove_key] self.other_data_context_was_removed.emit(data_context)
def __init__(self): self.property_changed = Signal(str)