class SimpleEditor ( EditorWithList, IValueChangeListener ): """ Simple style of editor for checklists, which displays a combo box. """ #--------------------------------------------------------------------------- # Trait definitions: #--------------------------------------------------------------------------- # Checklist item names names = List( Unicode ) # Checklist item values values = List #--------------------------------------------------------------------------- # Finishes initializing the editor by creating the underlying toolkit # widget: #--------------------------------------------------------------------------- def init ( self, parent ): """ Finishes initializing the editor by creating the underlying toolkit widget. """ self.create_control( parent ) super( SimpleEditor, self ).init( parent ) self.set_tooltip() #--------------------------------------------------------------------------- # Creates the initial editor control: #--------------------------------------------------------------------------- def create_control ( self, parent ): """ Creates the initial editor control. """ self.control = ComboBox() self.control.setMultiSelect(False) self.control.setNullSelectionAllowed(True) self.control.setImmediate(True) self.control.addListener(self, IValueChangeListener) #--------------------------------------------------------------------------- # Handles the list of legal check list values being updated: #--------------------------------------------------------------------------- def list_updated ( self, values ): """ Handles updates to the list of legal checklist values. """ sv = self.string_value if (len( values ) > 0) and isinstance( values[0], basestring ): values = [ ( x, sv( x, capitalize ) ) for x in values ] self.values = valid_values = [ x[0] for x in values ] self.names = [ x[1] for x in values ] # Make sure the current value is still legal: modified = False cur_value = parse_value( self.value ) for i in range( len( cur_value ) - 1, -1, -1 ): if cur_value[i] not in valid_values: try: del cur_value[i] modified = True except TypeError: logger.warn('Unable to remove non-current value [%s] from ' 'values %s', cur_value[i], values) if modified: if isinstance( self.value, basestring ): cur_value = ','.join( cur_value ) self.value = cur_value self.rebuild_editor() #--------------------------------------------------------------------------- # Rebuilds the editor after its definition is modified: #--------------------------------------------------------------------------- def rebuild_editor ( self ): """ Rebuilds the editor after its definition is modified. """ control = self.control c = IndexedContainer() for name in self.names: c.addItem(name) control.setContainerDataSource(c) self.update_editor() #--------------------------------------------------------------------------- # Handles the user selecting a new value from the combo box: #--------------------------------------------------------------------------- def valueChange(self, event): v = str(event.getProperty()) self.update_object(v) def update_object ( self, text ): """ Handles the user selecting a new value from the combo box. """ if unicode(text) in self.names: value = self.values[self.names.index(unicode(text))] if not isinstance(self.value, basestring): value = [value] elif not isinstance(self.value, basestring): value = [] else: value = '' self.value = value #--------------------------------------------------------------------------- # Updates the editor when the object trait changes external to the editor: #--------------------------------------------------------------------------- def update_editor ( self ): """ Updates the editor when the object trait changes externally to the editor. """ try: self.control.select( parse_value(self.value)[0] ) except: pass
class MuntjacComboBox(MuntjacControl, AbstractTkComboBox): """ A Muntjac implementation of ComboBox. Use a combo box to select a single item from a collection of items. """ #-------------------------------------------------------------------------- # Setup methods #-------------------------------------------------------------------------- def create(self, parent): """ Creates a QComboBox. """ self.widget = ComboBox() self.widget.setImmediate(True) parent.addComponent(self.widget) def initialize(self): """ Intializes the widget with the attributes of this instance. """ super(MuntjacComboBox, self).initialize() shell = self.shell_obj self.set_items(shell.labels) self.set_selection(shell.index) def bind(self): """ Connects the event handlers for the combo box. """ super(MuntjacComboBox, self).bind() self.widget.currentIndexChanged.connect(self.on_selected) #-------------------------------------------------------------------------- # Implementation #-------------------------------------------------------------------------- def shell_index_changed(self, index): """ The change handler for the 'index' attribute on the shell object. """ self.set_selection(index) def shell_labels_changed(self, labels): """ The change handler for the 'labels' attribute on the shell object. """ self.set_items(labels) def on_selected(self): """ The event handler for a combo box selection event. """ if not guard.guarded(self, 'updating'): shell = self.shell_obj curr_index = self._selected_index() shell.index = curr_index # Only fire the selected event if we have a valid selection if curr_index != -1: shell.selected = shell.value def set_items(self, str_items): """ Sets the items in the combo box. """ # We need to avoid a feedback loop when updating the items in # the combo box. Qt will emit index changed signals when the # items are updated. But, the shell object has already computed # the proper index for the new items, so we use that to update # the index of the control after updating the items. The flag # is read by the on_selected handler to ignore updates during # this process. with guard(self, 'updating'): widget = self.widget widget.removeAllItems() for item in str_items: widget.addItem(item) ids = widget.getItemIds() widget.select(ids[self.shell_obj.index]) def set_selection(self, index): """ Sets the value in the combo box, or resets the combo box if the value is not in the list of items. """ # We need to avoid a feedback loop when updating the selection # in the combo box. Qt will emit index changed signals when the # selectino is updated. But, the shell object has already computed # the proper index for the new selection so we don't need to feed # back while doing this. with guard(self, 'updating'): ids = self.widget.getItemIds() self.widget.select(ids[index]) #-------------------------------------------------------------------------- # Helper Methods #-------------------------------------------------------------------------- def _selected_index(self): widget = self.widget ids = widget.getItemIds() val = widget.getValue() if val in ids: curr_index = ids.index(val) else: curr_index = -1 return curr_index