예제 #1
0
    def init ( self, parent ):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        factory = self.factory

        # Set up the adapter to use:
        self.adapter = factory.adapter
        self.sync_value(factory.adapter_name, 'adapter', 'from')

        # Create the list model and accompanying controls:
        self.model = ListStrModel(editor=self)

        self.control = QtGui.QWidget()
        layout = QtGui.QVBoxLayout(self.control)
        layout.setMargin(0)
        layout.setSpacing(0)

        if factory.title or factory.title_name:
            header_view = QtGui.QHeaderView(QtCore.Qt.Horizontal, self.control)
            header_view.setModel(self.model)
            header_view.setMaximumHeight(header_view.sizeHint().height())
            header_view.setResizeMode(QtGui.QHeaderView.Stretch)
            layout.addWidget(header_view)

        self.list_view = _ListView(self)
        layout.addWidget(self.list_view)

        # Set up the list control's event handlers:
        if factory.multi_select:
            slot = self._on_rows_selection
        else:
            slot = self._on_row_selection
        signal = 'selectionChanged(QItemSelection,QItemSelection)'
        QtCore.QObject.connect(self.list_view.selectionModel(),
                               QtCore.SIGNAL(signal), slot)

        signal = QtCore.SIGNAL('activated(QModelIndex)')
        QtCore.QObject.connect(self.list_view, signal, self._on_activate)

        signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)')
        QtCore.QObject.connect(self.list_view, signal, self._on_context_menu)

        # Initialize the editor title:
        self.title = factory.title
        self.sync_value(factory.title_name, 'title', 'from')

        # Set up the selection listener
        if factory.multi_select:
            self.sync_value(factory.selected, 'multi_selected', 'both',
                            is_list=True)
            self.sync_value(factory.selected_index, 'multi_selected_indices',
                            'both', is_list=True)
        else:
            self.sync_value(factory.selected, 'selected', 'both')
            self.sync_value(factory.selected_index, 'selected_index', 'both')

        # Synchronize other interesting traits as necessary:
        self.sync_value(factory.activated, 'activated', 'to')
        self.sync_value(factory.activated_index, 'activated_index', 'to')

        self.sync_value(factory.right_clicked, 'right_clicked', 'to')
        self.sync_value(factory.right_clicked_index, 'right_clicked_index', 'to')

        # Make sure we listen for 'items' changes as well as complete list
        # replacements:
        self.context_object.on_trait_change(
            self.update_editor, self.extended_name + '_items', dispatch='ui')

        # Create the mapping from user supplied images to QIcons:
        for image_resource in factory.images:
            self._add_image(image_resource)

        # Refresh the editor whenever the adapter changes:
        self.on_trait_change(
            self.refresh_editor, 'adapter.+update', dispatch='ui')

        # Set the list control's tooltip:
        self.set_tooltip()
예제 #2
0
class _ListStrEditor(Editor):
    """ Traits UI editor for editing lists of strings.
    """

    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # The list view control associated with the editor:
    list_view = Any

    # The list model associated the editor:
    model = Instance(ListStrModel)

    # The title of the editor:
    title = Str

    # The current set of selected items (which one is used depends upon the
    # initial state of the editor factory 'multi_select' trait):
    selected = Any
    multi_selected = List

    # The current set of selected item indices (which one is used depends upon
    # the initial state of the editor factory 'multi_select' trait):
    selected_index = Int(-1)
    multi_selected_indices = List(Int)

    # The most recently actived item and its index.
    # Always trigger change notification.
    activated = Any(comparison_mode=NO_COMPARE)
    activated_index = Int(comparison_mode=NO_COMPARE)

    # The most recently right_clicked item and its index:
    right_clicked = Event
    right_clicked_index = Event

    # Is the list editor scrollable? This value overrides the default.
    scrollable = True

    # Should the selected item be edited after rebuilding the editor list:
    edit = Bool(False)

    # The adapter from list items to editor values:
    adapter = Instance(ListStrAdapter)

    # Dictionary mapping image names to QIcons
    images = Any({})

    # Dictionary mapping ImageResource objects to QIcons
    image_resources = Any({})

    # The current number of item currently in the list:
    item_count = Property

    # The current search string:
    search = Str

    #---------------------------------------------------------------------------
    #  Editor interface:
    #---------------------------------------------------------------------------

    def init(self, parent):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        factory = self.factory

        # Set up the adapter to use:
        self.adapter = factory.adapter
        self.sync_value(factory.adapter_name, 'adapter', 'from')

        # Create the list model and accompanying controls:
        self.model = ListStrModel(editor=self)

        self.control = QtGui.QWidget()
        layout = QtGui.QVBoxLayout(self.control)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        if factory.title or factory.title_name:
            header_view = QtGui.QHeaderView(QtCore.Qt.Horizontal, self.control)
            header_view.setModel(self.model)
            header_view.setMaximumHeight(header_view.sizeHint().height())
            header_view.setResizeMode(QtGui.QHeaderView.Stretch)
            layout.addWidget(header_view)

        self.list_view = _ListView(self)
        layout.addWidget(self.list_view)

        # Set up the list control's event handlers:
        if factory.multi_select:
            slot = self._on_rows_selection
        else:
            slot = self._on_row_selection
        signal = 'selectionChanged(QItemSelection,QItemSelection)'
        QtCore.QObject.connect(self.list_view.selectionModel(),
                               QtCore.SIGNAL(signal), slot)

        signal = QtCore.SIGNAL('activated(QModelIndex)')
        QtCore.QObject.connect(self.list_view, signal, self._on_activate)

        # Initialize the editor title:
        self.title = factory.title
        self.sync_value(factory.title_name, 'title', 'from')

        # Set up the selection listener
        if factory.multi_select:
            self.sync_value(factory.selected,
                            'multi_selected',
                            'both',
                            is_list=True)
            self.sync_value(factory.selected_index,
                            'multi_selected_indices',
                            'both',
                            is_list=True)
        else:
            self.sync_value(factory.selected, 'selected', 'both')
            self.sync_value(factory.selected_index, 'selected_index', 'both')

        # Synchronize other interesting traits as necessary:
        self.sync_value(factory.activated, 'activated', 'to')
        self.sync_value(factory.activated_index, 'activated_index', 'to')

        self.sync_value(factory.right_clicked, 'right_clicked', 'to')
        self.sync_value(factory.right_clicked_index, 'right_clicked_index',
                        'to')

        # Make sure we listen for 'items' changes as well as complete list
        # replacements:
        self.context_object.on_trait_change(self.update_editor,
                                            self.extended_name + '_items',
                                            dispatch='ui')

        # Create the mapping from user supplied images to QIcons:
        for image_resource in factory.images:
            self._add_image(image_resource)

        # Refresh the editor whenever the adapter changes:
        self.on_trait_change(self.refresh_editor,
                             'adapter.+update',
                             dispatch='ui')

        # Set the list control's tooltip:
        self.set_tooltip()

    def dispose(self):
        """ Disposes of the contents of an editor.
        """
        self.context_object.on_trait_change(self.update_editor,
                                            self.extended_name + '_items',
                                            remove=True)

        self.on_trait_change(self.refresh_editor,
                             'adapter.+update',
                             remove=True)

        super(Editor, self).dispose()

    def update_editor(self):
        """ Updates the editor when the object trait changes externally to the
            editor.
        """
        if not self._no_update:
            self.model.reset()
            # restore selection back
            if self.factory.multi_select:
                self._multi_selected_changed(self.multi_selected)
            else:
                self._selected_changed(self.selected)

    #---------------------------------------------------------------------------
    #  ListStrEditor interface:
    #---------------------------------------------------------------------------

    def refresh_editor(self):
        """ Requests that the underlying list widget to redraw itself.
        """
        self.list_view.viewport().update()

    def callx(self, func, *args, **kw):
        """ Call a function without allowing the editor to update.
        """
        old = self._no_update
        self._no_update = True
        try:
            func(*args, **kw)
        finally:
            self._no_update = old

    def setx(self, **keywords):
        """ Set one or more attributes without allowing the editor to update.
        """
        old = self._no_notify
        self._no_notify = True
        try:
            for name, value in keywords.items():
                setattr(self, name, value)
        finally:
            self._no_notify = old

    def get_image(self, image):
        """ Converts a user specified image to a QIcon.
        """
        if isinstance(image, ImageResource):
            result = self.image_resources.get(image)
            if result is not None:
                return result

            return self._add_image(image)

        return self.images.get(image)

    def is_auto_add(self, index):
        """ Returns whether or not the index is the special 'auto add' item at
            the end of the list.
        """
        return (self.factory.auto_add
                and (index >= self.adapter.len(self.object, self.name)))

    #---------------------------------------------------------------------------
    #  Private interface:
    #---------------------------------------------------------------------------

    def _add_image(self, image_resource):
        """ Adds a new image to the image map.
        """
        image = image_resource.create_icon()

        self.image_resources[image_resource] = image
        self.images[image_resource.name] = image

        return image

    #-- Property Implementations -----------------------------------------------

    def _get_item_count(self):
        return (self.model.rowCount(None) - self.factory.auto_add)

    #-- Trait Event Handlers ---------------------------------------------------

    def _selected_changed(self, selected):
        """ Handles the editor's 'selected' trait being changed.
        """
        if not self._no_update:
            try:
                selected_index = self.value.index(selected)
            except ValueError:
                pass
            else:
                self._selected_index_changed(selected_index)

    def _selected_index_changed(self, selected_index):
        """ Handles the editor's 'selected_index' trait being changed.
        """
        if not self._no_update:
            smodel = self.list_view.selectionModel()
            if selected_index == -1:
                smodel.clearSelection()
            else:
                mi = self.model.index(selected_index)
                smodel.select(mi, QtGui.QItemSelectionModel.ClearAndSelect)
                self.list_view.scrollTo(mi)

    def _multi_selected_changed(self, selected):
        """ Handles the editor's 'multi_selected' trait being changed.
        """
        if not self._no_update:
            indices = []
            for item in selected:
                try:
                    indices.append(self.value.index(item))
                except ValueError:
                    pass
            self._multi_selected_indices_changed(indices)

    def _multi_selected_items_changed(self, event):
        """ Handles the editor's 'multi_selected' trait being modified.
        """
        if not self._no_update:
            try:
                added = [self.value.index(item) for item in event.added]
                removed = [self.value.index(item) for item in event.removed]
            except ValueError:
                pass
            else:
                event = TraitListEvent(0, added, removed)
                self._multi_selected_indices_items_changed(event)

    def _multi_selected_indices_changed(self, selected_indices):
        """ Handles the editor's 'multi_selected_indices' trait being changed.
        """
        if not self._no_update:
            smodel = self.list_view.selectionModel()
            smodel.clearSelection()
            for selected_index in selected_indices:
                smodel.select(self.model.index(selected_index),
                              QtGui.QItemSelectionModel.Select)
            if selected_indices:
                self.list_view.scrollTo(self.model.index(selected_indices[-1]))

    def _multi_selected_indices_items_changed(self, event):
        """ Handles the editor's 'multi_selected_indices' trait being modified.
        """
        if not self._no_update:
            smodel = self.list_view.selectionModel()
            for selected_index in event.removed:
                smodel.select(self.model.index(selected_index),
                              QtGui.QItemSelectionModel.Deselect)
            for selected_index in event.added:
                smodel.select(self.model.index(selected_index),
                              QtGui.QItemSelectionModel.Select)

    #-- List Control Event Handlers --------------------------------------------

    def _on_activate(self, mi):
        """ Handle a cell being activated.
        """
        self.activated_index = index = mi.row()
        self.activated = self.adapter.get_item(self.object, self.name, index)

    def _on_context_menu(self, point):
        """ Handle a context menu request.
        """
        mi = self.list_view.indexAt(point)
        if mi.isValid():
            self.right_clicked_index = index = mi.row()
            self.right_clicked = self.adapter.get_item(self.object, self.name,
                                                       index)

    def _on_row_selection(self, added, removed):
        """ Handle the row selection being changed.
        """
        self._no_update = True
        try:
            indices = self.list_view.selectionModel().selectedRows()
            if len(indices):
                self.selected_index = indices[0].row()
                self.selected = self.adapter.get_item(self.object, self.name,
                                                      self.selected_index)
            else:
                self.selected_index = -1
                self.selected = None
        finally:
            self._no_update = False

    def _on_rows_selection(self, added, removed):
        """ Handle the rows selection being changed.
        """
        self._no_update = True
        try:
            indices = self.list_view.selectionModel().selectedRows()
            self.multi_selected_indices = indices = [i.row() for i in indices]
            self.multi_selected = [
                self.adapter.get_item(self.object, self.name, i)
                for i in self.multi_selected_indices
            ]
        finally:
            self._no_update = False

    def _on_context_menu(self, pos):
        menu = self.factory.menu

        index = self.list_view.indexAt(pos).row()

        if isinstance(menu, str):
            menu = getattr(self.object, menu, None)

        if isinstance(menu, collections.Callable):
            menu = menu(index)

        if menu is not None:
            qmenu = menu.create_menu(self.list_view, self)

            self._menu_context = {
                'selection': self.object,
                'object': self.object,
                'editor': self,
                'index': index,
                'info': self.ui.info,
                'handler': self.ui.handler
            }

            qmenu.exec_(self.list_view.mapToGlobal(pos))

            self._menu_context = None
예제 #3
0
class _ListStrEditor(Editor):
    """ Traits UI editor for editing lists of strings.
    """

    #---------------------------------------------------------------------------
    #  Trait definitions:
    #---------------------------------------------------------------------------

    # The list view control associated with the editor:
    list_view = Any

    # The list model associated the editor:
    model = Instance(ListStrModel)

    # The title of the editor:
    title = Str

    # The current set of selected items (which one is used depends upon the
    # initial state of the editor factory 'multi_select' trait):
    selected = Any
    multi_selected = List

    # The current set of selected item indices (which one is used depends upon
    # the initial state of the editor factory 'multi_select' trait):
    selected_index = Int(-1)
    multi_selected_indices = List(Int)

    # The most recently actived item and its index:
    activated = Any
    activated_index = Int

    # The most recently right_clicked item and its index:
    right_clicked = Event
    right_clicked_index = Event

    # Is the list editor scrollable? This value overrides the default.
    scrollable = True

    # Should the selected item be edited after rebuilding the editor list:
    edit = Bool(False)

    # The adapter from list items to editor values:
    adapter = Instance( ListStrAdapter )

    # Dictionary mapping image names to QIcons
    images = Any({})

    # Dictionary mapping ImageResource objects to QIcons
    image_resources = Any({})

    # The current number of item currently in the list:
    item_count = Property

    # The current search string:
    search = Str

    #---------------------------------------------------------------------------
    #  Editor interface:
    #---------------------------------------------------------------------------

    def init ( self, parent ):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        factory = self.factory

        # Set up the adapter to use:
        self.adapter = factory.adapter
        self.sync_value(factory.adapter_name, 'adapter', 'from')

        # Create the list model and accompanying controls:
        self.model = ListStrModel(editor=self)

        self.control = QtGui.QWidget()
        layout = QtGui.QVBoxLayout(self.control)
        layout.setMargin(0)
        layout.setSpacing(0)

        if factory.title or factory.title_name:
            header_view = QtGui.QHeaderView(QtCore.Qt.Horizontal, self.control)
            header_view.setModel(self.model)
            header_view.setMaximumHeight(header_view.sizeHint().height())
            header_view.setResizeMode(QtGui.QHeaderView.Stretch)
            layout.addWidget(header_view)

        self.list_view = _ListView(self)
        layout.addWidget(self.list_view)

        # Set up the list control's event handlers:
        if factory.multi_select:
            slot = self._on_rows_selection
        else:
            slot = self._on_row_selection
        signal = 'selectionChanged(QItemSelection,QItemSelection)'
        QtCore.QObject.connect(self.list_view.selectionModel(),
                               QtCore.SIGNAL(signal), slot)

        signal = QtCore.SIGNAL('activated(QModelIndex)')
        QtCore.QObject.connect(self.list_view, signal, self._on_activate)

        signal = QtCore.SIGNAL('customContextMenuRequested(QPoint)')
        QtCore.QObject.connect(self.list_view, signal, self._on_context_menu)

        # Initialize the editor title:
        self.title = factory.title
        self.sync_value(factory.title_name, 'title', 'from')

        # Set up the selection listener
        if factory.multi_select:
            self.sync_value(factory.selected, 'multi_selected', 'both',
                            is_list=True)
            self.sync_value(factory.selected_index, 'multi_selected_indices',
                            'both', is_list=True)
        else:
            self.sync_value(factory.selected, 'selected', 'both')
            self.sync_value(factory.selected_index, 'selected_index', 'both')

        # Synchronize other interesting traits as necessary:
        self.sync_value(factory.activated, 'activated', 'to')
        self.sync_value(factory.activated_index, 'activated_index', 'to')

        self.sync_value(factory.right_clicked, 'right_clicked', 'to')
        self.sync_value(factory.right_clicked_index, 'right_clicked_index', 'to')

        # Make sure we listen for 'items' changes as well as complete list
        # replacements:
        self.context_object.on_trait_change(
            self.update_editor, self.extended_name + '_items', dispatch='ui')

        # Create the mapping from user supplied images to QIcons:
        for image_resource in factory.images:
            self._add_image(image_resource)

        # Refresh the editor whenever the adapter changes:
        self.on_trait_change(
            self.refresh_editor, 'adapter.+update', dispatch='ui')

        # Set the list control's tooltip:
        self.set_tooltip()

    def dispose(self):
        """ Disposes of the contents of an editor.
        """
        self.context_object.on_trait_change(
            self.update_editor, self.extended_name + '_items', remove=True)

        self.on_trait_change(
            self.refresh_editor, 'adapter.+update', remove=True)

    def update_editor(self):
        """ Updates the editor when the object trait changes externally to the
            editor.
        """
        if not self._no_update:
            self.model.reset()

    #---------------------------------------------------------------------------
    #  ListStrEditor interface:
    #---------------------------------------------------------------------------

    def refresh_editor(self):
        """ Requests that the underlying list widget to redraw itself.
        """
        self.list_view.viewport().update()

    def callx(self, func, *args, **kw):
        """ Call a function without allowing the editor to update.
        """
        old = self._no_update
        self._no_update = True
        try:
            func(*args, **kw)
        finally:
            self._no_update = old

    def setx(self, **keywords):
        """ Set one or more attributes without allowing the editor to update.
        """
        old = self._no_notify
        self._no_notify = True
        try:
            for name, value in keywords.items():
                setattr(self, name, value)
        finally:
            self._no_notify = old

    def get_image(self, image):
        """ Converts a user specified image to a QIcon.
        """
        if isinstance(image, ImageResource):
            result = self.image_resources.get(image)
            if result is not None:
                return result

            return self._add_image(image)

        return self.images.get(image)

    def is_auto_add(self, index):
        """ Returns whether or not the index is the special 'auto add' item at
            the end of the list.
        """
        return (self.factory.auto_add and
                (index >= self.adapter.len(self.object, self.name)))

    #---------------------------------------------------------------------------
    #  Private interface:
    #---------------------------------------------------------------------------

    def _add_image(self, image_resource):
        """ Adds a new image to the image map.
        """
        image = image_resource.create_icon()

        self.image_resources[image_resource] = image
        self.images[image_resource.name] = image

        return image

    #-- Property Implementations -----------------------------------------------

    def _get_item_count ( self ):
        return (self.model.rowCount(None) - self.factory.auto_add)

    #-- Trait Event Handlers ---------------------------------------------------

    def _selected_changed(self, selected):
        """ Handles the editor's 'selected' trait being changed.
        """
        if not self._no_update:
            try:
                selected_index = self.value.index(selected)
            except ValueError:
                pass
            else:
                self._selected_index_changed(selected_index)

    def _selected_index_changed(self, selected_index):
        """ Handles the editor's 'selected_index' trait being changed.
        """
        if not self._no_update:
            smodel = self.list_view.selectionModel()
            if selected_index == -1:
                smodel.clearSelection()
            else:
                mi = self.model.index(selected_index)
                smodel.select(mi, QtGui.QItemSelectionModel.ClearAndSelect)
                self.list_view.scrollTo(mi)

    def _multi_selected_changed(self, selected):
        """ Handles the editor's 'multi_selected' trait being changed.
        """
        if not self._no_update:
            try:
                indices = [ self.value.index(item) for item in selected ]
            except ValueError:
                pass
            else:
                self._multi_selected_indices_changed(indices)

    def _multi_selected_items_changed(self, event):
        """ Handles the editor's 'multi_selected' trait being modified.
        """
        if not self._no_update:
            try:
                added = [ values.index(item) for item in event.added ]
                removed = [ values.index(item) for item in event.removed ]
            except ValueError:
                pass
            else:
                event = TraitListEvent(0, added, removed)
                self._multi_selected_indices_items_changed(event)

    def _multi_selected_indices_changed(self, selected_indices):
        """ Handles the editor's 'multi_selected_indices' trait being changed.
        """
        if not self._no_update:
            smodel = self.list_view.selectionModel()
            smodel.clearSelection()
            for selected_index in selected_indices:
                smodel.select(self.model.index(selected_index),
                              QtGui.QItemSelectionModel.Select)
            if selected_indices:
                self.list_view.scrollTo(self.model.index(selected_indices[-1]))

    def _multi_selected_indices_items_changed(self, event):
        """ Handles the editor's 'multi_selected_indices' trait being modified.
        """
        if not self._no_update:
            smodel = self.list_view.selectionModel()
            for selected_index in event.removed:
                smodel.select(self.model.index(selected_index),
                              QtGui.QItemSelectionModel.Deselect)
            for selected_index in event.added:
                smodel.select(self.model.index(selected_index),
                              QtGui.QItemSelectionModel.Select)

    #-- List Control Event Handlers --------------------------------------------

    def _on_activate(self, mi):
        """ Handle a cell being activated.
        """
        self.activated_index = index = mi.row()
        self.activated = self.adapter.get_item(self.object, self.name, index)

    def _on_context_menu(self, point):
        """ Handle a context menu request.
        """
        mi = self.list_view.indexAt(point)
        self.right_clicked_index = index = mi.row()
        self.right_clicked = self.adapter.get_item(self.object, self.name,
                                                   index)

    def _on_row_selection(self, added, removed):
        """ Handle the row selection being changed.
        """
        self._no_update = True
        try:
            indices = self.list_view.selectionModel().selectedRows()
            if len(indices):
                self.selected_index = indices[0].row()
                self.selected = self.adapter.get_item(self.object, self.name,
                                                      self.selected_index)
            else:
                self.selected_index = -1
                self.selected = None
        finally:
            self._no_update = False

    def _on_rows_selection(self, added, removed):
        """ Handle the rows selection being changed.
        """
        self._no_update = True
        try:
            indices = self.list_view.selectionModel().selectedRows()
            self.multi_selected_indices = indices = [ i.row() for i in indices ]
            self.multi_selected = [ self.adapter.get_item(self.object,
                                                          self.name, i)
                                    for i in self.multi_selected_indices ]
        finally:
            self._no_update = False
예제 #4
0
    def init(self, parent):
        """ Finishes initializing the editor by creating the underlying toolkit
            widget.
        """
        factory = self.factory

        # Set up the adapter to use:
        self.adapter = factory.adapter
        self.sync_value(factory.adapter_name, 'adapter', 'from')

        # Create the list model and accompanying controls:
        self.model = ListStrModel(editor=self)

        self.control = QtGui.QWidget()
        layout = QtGui.QVBoxLayout(self.control)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        if factory.title or factory.title_name:
            header_view = QtGui.QHeaderView(QtCore.Qt.Horizontal, self.control)
            header_view.setModel(self.model)
            header_view.setMaximumHeight(header_view.sizeHint().height())
            header_view.setResizeMode(QtGui.QHeaderView.Stretch)
            layout.addWidget(header_view)

        self.list_view = _ListView(self)
        layout.addWidget(self.list_view)

        # Set up the list control's event handlers:
        if factory.multi_select:
            slot = self._on_rows_selection
        else:
            slot = self._on_row_selection
        signal = 'selectionChanged(QItemSelection,QItemSelection)'
        QtCore.QObject.connect(self.list_view.selectionModel(),
                               QtCore.SIGNAL(signal), slot)

        signal = QtCore.SIGNAL('activated(QModelIndex)')
        QtCore.QObject.connect(self.list_view, signal, self._on_activate)

        # Initialize the editor title:
        self.title = factory.title
        self.sync_value(factory.title_name, 'title', 'from')

        # Set up the selection listener
        if factory.multi_select:
            self.sync_value(factory.selected,
                            'multi_selected',
                            'both',
                            is_list=True)
            self.sync_value(factory.selected_index,
                            'multi_selected_indices',
                            'both',
                            is_list=True)
        else:
            self.sync_value(factory.selected, 'selected', 'both')
            self.sync_value(factory.selected_index, 'selected_index', 'both')

        # Synchronize other interesting traits as necessary:
        self.sync_value(factory.activated, 'activated', 'to')
        self.sync_value(factory.activated_index, 'activated_index', 'to')

        self.sync_value(factory.right_clicked, 'right_clicked', 'to')
        self.sync_value(factory.right_clicked_index, 'right_clicked_index',
                        'to')

        # Make sure we listen for 'items' changes as well as complete list
        # replacements:
        self.context_object.on_trait_change(self.update_editor,
                                            self.extended_name + '_items',
                                            dispatch='ui')

        # Create the mapping from user supplied images to QIcons:
        for image_resource in factory.images:
            self._add_image(image_resource)

        # Refresh the editor whenever the adapter changes:
        self.on_trait_change(self.refresh_editor,
                             'adapter.+update',
                             dispatch='ui')

        # Set the list control's tooltip:
        self.set_tooltip()