Beispiel #1
0
    def _resize_items(self):
        """ Size the splitter based on the 'width' or 'height' attributes
            of the Traits UI view elements.
        """
        use_widths = (self.orientation() == QtCore.Qt.Horizontal)

        # Get the requested size for the items.
        sizes = []
        for item in self._group.content:
            if use_widths:
                sizes.append(item.width)
            else:
                sizes.append(item.height)

        # Find out how much space is available.
        if use_widths:
            total = self.width()
        else:
            total = self.height()

        # Allocate requested space.
        avail = total
        remain = 0
        for i, sz in enumerate(sizes):
            if avail <= 0:
                break

            if sz >= 0:
                if sz >= 1:
                    sz = min(sz, avail)
                else:
                    sz *= total

                sz = int(sz)
                sizes[i] = sz
                avail -= sz
            else:
                remain += 1

        # Allocate the remainder to those parts that didn't request a width.
        if remain > 0:
            remain = int(avail / remain)

            for i, sz in enumerate(sizes):
                if sz < 0:
                    sizes[i] = remain

        # If all requested a width, allocate the remainder to the last item.
        else:
            sizes[-1] += avail

        self.setSizes(sizes)
Beispiel #2
0
    def _resize_items(self):
        """ Size the splitter based on the 'width' or 'height' attributes
            of the Traits UI view elements.
        """
        use_widths = (self.orientation() == QtCore.Qt.Horizontal)

        # Get the requested size for the items.
        sizes = []
        for item in self._group.content:
            if use_widths:
                sizes.append(item.width)
            else:
                sizes.append(item.height)

        # Find out how much space is available.
        if use_widths:
            total = self.width()
        else:
            total = self.height()

        # Allocate requested space.
        avail = total
        remain = 0
        for i, sz in enumerate(sizes):
            if avail <= 0:
                break

            if sz >= 0:
                if sz >= 1:
                    sz = min(sz, avail)
                else:
                    sz *= total

                sz = int(sz)
                sizes[i] = sz
                avail -= sz
            else:
                remain += 1

        # Allocate the remainder to those parts that didn't request a width.
        if remain > 0:
            remain = int(avail / remain)

            for i, sz in enumerate(sizes):
                if sz < 0:
                    sizes[i] = remain

        # If all requested a width, allocate the remainder to the last item.
        else:
            sizes[-1] += avail

        self.setSizes(sizes)
Beispiel #3
0
    def find(self, name, stack=None):
        """ Finds a specified ViewElement within the specified (optional) search
            context.
        """
        # Assume search starts from the beginning the of the search order:
        i = 0

        # If a stack was specified, see if there is a matching entry in the
        # stack already:
        if stack is not None:
            for ssi in stack:
                if name == ssi.id:
                    # Match found, resume search at next ViewElements object
                    # in the search order:
                    i = ssi.context + 1
                    break

        # Search for a matching name starting at the specified ViewElements
        # object in the search order:
        for j, ves in enumerate(self._get_search_order()[i:]):
            result = ves.content.get(name)
            if result is not None:
                # Match found. If there is a stack, push matching name and
                # ViewElements context onto it:
                if stack is not None:
                    stack[0:0] = [SearchStackItem(id=name, context=i + j)]

                # Return the ViewElement object that matched the name:
                return result

        # Indicate no match was found:
        return None
Beispiel #4
0
    def find ( self, name, stack = None ):
        """ Finds a specified ViewElement within the specified (optional) search
            context.
        """
        # Assume search starts from the beginning the of the search order:
        i = 0

        # If a stack was specified, see if there is a matching entry in the
        # stack already:
        if stack is not None:
            for ssi in stack:
                if name == ssi.id:
                    # Match found, resume search at next ViewElements object
                    # in the search order:
                    i = ssi.context + 1
                    break

        # Search for a matching name starting at the specified ViewElements
        # object in the search order:
        for j, ves in enumerate( self._get_search_order()[i:] ):
            result = ves.content.get( name )
            if result is not None:
                # Match found. If there is a stack, push matching name and
                # ViewElements context onto it:
                if stack is not None:
                    stack[0:0] = [ SearchStackItem( id      = name,
                                                    context = i + j ) ]

                # Return the ViewElement object that matched the name:
                return result

        # Indicate no match was found:
        return None
Beispiel #5
0
    def update_editor(self):
        """ Updates the editor when the object trait changes externally to the
            editor.
        """
        self.mapper = QtCore.QSignalMapper(self.control)
        # Disconnect the editor from any control about to be destroyed:
        self._dispose_items()

        list_pane = self._list_pane
        layout = list_pane.layout()

        # Create all of the list item trait editors:
        trait_handler = self._trait_handler
        resizable = ((trait_handler.minlen != trait_handler.maxlen)
                     and self.mutable)
        item_trait = trait_handler.item_trait

        is_fake = (resizable and (len(self.value) == 0))
        if is_fake:
            self.empty_list()
        else:
            # Asking the mapper to send the sender to the callback method
            self.mapper.mapped[QtCore.QObject].connect(self.popup_menu)

        editor = self._editor
        for index, value in enumerate(self.value):
            row, column = divmod(index, self.factory.columns)

            # Account for the fact that we have <columns> number of
            # pairs
            column = column * 2

            if resizable:
                # Connecting the new button to the mapper
                control = IconButton('list_editor.png', self.mapper.map)
                # Setting the mapping and asking it to send the index of the
                # sender to the callback method
                self.mapper.setMapping(control, control)

                layout.addWidget(control, row, column)

            proxy = ListItemProxy(self.object, self.name, index, item_trait,
                                  value)
            if resizable:
                control.proxy = proxy
            peditor = editor(self.ui, proxy, 'value', self.description,
                             list_pane).set(object_name='')
            peditor.prepare(list_pane)
            pcontrol = peditor.control
            pcontrol.proxy = proxy

            if isinstance(pcontrol, QtGui.QWidget):
                layout.addWidget(pcontrol, row, column + 1)
            else:
                layout.addLayout(pcontrol, row, column + 1)

        # QScrollArea can have problems if the widget being scrolled is set too
        # early (ie. before it contains something).
        if self.control.widget() is None:
            self.control.setWidget(list_pane)
Beispiel #6
0
    def update_editor ( self ):
        """ Updates the editor when the object trait changes externally to the
            editor.
        """
        self.mapper = QtCore.QSignalMapper(self.control)
        # Disconnect the editor from any control about to be destroyed:
        self._dispose_items()

        list_pane = self._list_pane
        layout = list_pane.layout()

        # Create all of the list item trait editors:
        trait_handler = self._trait_handler
        resizable     = ((trait_handler.minlen != trait_handler.maxlen) and
                         self.mutable)
        item_trait    = trait_handler.item_trait

        is_fake = (resizable and (len( self.value ) == 0))
        if is_fake:
            self.empty_list()
        else:
            # Asking the mapper to send the sender to the callback method
            self.mapper.mapped[QtCore.QObject].connect(self.popup_menu)

        editor = self._editor
        for index, value in enumerate(self.value):
            row, column = divmod(index, self.factory.columns)

            # Account for the fact that we have <columns> number of
            # pairs
            column = column * 2

            if resizable:
                # Connecting the new button to the mapper
                control = IconButton('list_editor.png', self.mapper.map)
                # Setting the mapping and asking it to send the index of the
                # sender to the callback method
                self.mapper.setMapping(control, control)

                layout.addWidget(control, row, column)

            proxy = ListItemProxy( self.object, self.name, index, item_trait,
                                   value )
            if resizable:
                control.proxy = proxy
            peditor = editor( self.ui, proxy, 'value', self.description,
                              list_pane ).set( object_name = '' )
            peditor.prepare( list_pane )
            pcontrol = peditor.control
            pcontrol.proxy = proxy

            if isinstance(pcontrol, QtGui.QWidget):
                layout.addWidget(pcontrol, row, column+1)
            else:
                layout.addLayout(pcontrol, row, column+1)

        # QScrollArea can have problems if the widget being scrolled is set too
        # early (ie. before it contains something).
        if self.control.widget() is None:
            self.control.setWidget(list_pane)
Beispiel #7
0
 def update_editor ( self ):
     """ Updates the editor when the object trait changes external to the
         editor.
     """
     ts = self._ts
     for i, value in enumerate( self.value ):
         setattr( ts, 'f%d' % i, value )
Beispiel #8
0
 def update_editor(self):
     """ Updates the editor when the object trait changes external to the
         editor.
     """
     ts = self._ts
     for i, value in enumerate(self.value):
         setattr(ts, 'f%d' % i, value)
Beispiel #9
0
 def _selected_changed(self, old, new):
     """ Activates the corresponding dock window when the 'selected' trait
     of the editor is changed.
     """
     for i, value in enumerate(self._uis):
         if new == value[1]:
             value[0].activate()
             break
     return
Beispiel #10
0
 def _selected_changed(self, old, new):
     """ Activates the corresponding dock window when the 'selected' trait
     of the editor is changed.
     """
     for i, value in enumerate(self._uis):
         if new == value[1]:
             value[0].activate()
             break
     return
Beispiel #11
0
    def dockable_tab_activated ( self, dock_control, activated ):
        """ Handles a notebook tab being activated or deactivated.
        Sets the value of the editor's selected trait to the activated
        dock_control's object.

        """
        for i, value in enumerate( self.editor._uis ):
            if dock_control is value[0] and activated:
                self.editor.selected = value[1]
                break
Beispiel #12
0
    def dockable_tab_activated(self, dock_control, activated):
        """ Handles a notebook tab being activated or deactivated.
        Sets the value of the editor's selected trait to the activated
        dock_control's object.

        """
        for i, value in enumerate(self.editor._uis):
            if dock_control is value[0] and activated:
                self.editor.selected = value[1]
                break
Beispiel #13
0
    def close_dock_control(self, dock_control, abort):
        """ Closes a DockControl.
        """
        if abort:
            return super(DockableListElement,
                         self).close_dock_control(dock_control, False)

        view_object = self.ui.context['object']
        for i, value in enumerate(self.editor._uis):
            if view_object is value[2]:
                del self.editor.value[i]

        return False
Beispiel #14
0
    def close_dock_control ( self, dock_control, abort ):
        """ Closes a DockControl.
        """
        if abort:
            return super( DockableListElement, self ).close_dock_control(
                                                           dock_control, False )

        view_object = self.ui.context[ 'object' ]
        for i, value in enumerate( self.editor._uis ):
            if view_object is value[2]:
                del self.editor.value[ i ]

        return False
Beispiel #15
0
def _fill_panel(panel, content, ui, item_handler=None):
    """Fill a page based container panel with content.
    """
    active = 0

    for index, item in enumerate(content):
        page_name = item.get_label(ui)
        if page_name == "":
            page_name = "Page %d" % index

        if isinstance(item, Group):
            if item.selected:
                active = index

            gp = _GroupPanel(item, ui, suppress_label=True)
            page = gp.control
            sub_page = gp.sub_control

            # If the result is the same type with only one page, collapse it
            # down into just the page.
            if type(sub_page) is type(panel) and sub_page.count() == 1:
                new = sub_page.widget(0)
                if isinstance(panel, QtGui.QTabWidget):
                    sub_page.removeTab(0)
                else:
                    sub_page.removeItem(0)
            elif isinstance(page, QtGui.QWidget):
                new = page
            else:
                new = QtGui.QWidget()
                new.setLayout(page)

            layout = new.layout()
            if layout is not None:
                layout.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)

        else:
            new = QtGui.QWidget()
            layout = QtGui.QVBoxLayout(new)
            layout.setContentsMargins(0, 0, 0, 0)
            item_handler(item, layout)

        # Add the content.
        if isinstance(panel, QtGui.QTabWidget):
            panel.addTab(new, page_name)
        else:
            panel.addItem(new, page_name)

    panel.setCurrentIndex(active)
Beispiel #16
0
def _fill_panel(panel, content, ui, item_handler=None):
    """Fill a page based container panel with content.
    """
    active = 0

    for index, item in enumerate(content):
        page_name = item.get_label(ui)
        if page_name == "":
           page_name = "Page %d" % index

        if isinstance(item, Group):
            if item.selected:
                active = index

            gp = _GroupPanel(item, ui, suppress_label=True)
            page = gp.control
            sub_page = gp.sub_control

            # If the result is the same type with only one page, collapse it
            # down into just the page.
            if type(sub_page) is type(panel) and sub_page.count() == 1:
                new = sub_page.widget(0)
                if isinstance(panel, QtGui.QTabWidget):
                    sub_page.removeTab(0)
                else:
                    sub_page.removeItem(0)
            elif isinstance(page, QtGui.QWidget):
                new = page
            else:
                new = QtGui.QWidget()
                new.setLayout(page)

            layout = new.layout()
            if layout is not None:
                layout.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)

        else:
            new = QtGui.QWidget()
            layout = QtGui.QVBoxLayout(new)
            layout.setContentsMargins(0, 0, 0, 0)
            item_handler(item, layout)

        # Add the content.
        if isinstance(panel, QtGui.QTabWidget):
            panel.addTab(new, page_name)
        else:
            panel.addItem(new, page_name)

    panel.setCurrentIndex(active)
Beispiel #17
0
 def merge_undo ( self, undo_item ):
     """ Merges two undo items if possible.
     """
     # Discard undo items that are identical to us. This is to eliminate
     # the same undo item being created by multiple listeners monitoring the
     # same list for changes:
     if (isinstance( undo_item, self.__class__ )        and
        (self.object is undo_item.object)               and
        (self.name  == undo_item.name)                  and
        (self.index == undo_item.index)):
         added   = undo_item.added
         removed = undo_item.removed
         if ((len( self.added )   == len( added )) and
             (len( self.removed ) == len( removed ))):
             for i, item in enumerate( self.added ):
                 if item is not added[i]:
                     break
             else:
                 for i, item in enumerate( self.removed ):
                     if item is not removed[i]:
                         break
                 else:
                     return True
     return False
Beispiel #18
0
 def merge_undo(self, undo_item):
     """ Merges two undo items if possible.
     """
     # Discard undo items that are identical to us. This is to eliminate
     # the same undo item being created by multiple listeners monitoring the
     # same list for changes:
     if (isinstance(undo_item, self.__class__)
             and (self.object is undo_item.object)
             and (self.name == undo_item.name)
             and (self.index == undo_item.index)):
         added = undo_item.added
         removed = undo_item.removed
         if ((len(self.added) == len(added))
                 and (len(self.removed) == len(removed))):
             for i, item in enumerate(self.added):
                 if item is not added[i]:
                     break
             else:
                 for i, item in enumerate(self.removed):
                     if item is not removed[i]:
                         break
                 else:
                     return True
     return False
Beispiel #19
0
    def update_editor ( self ):
        """ Updates the editor when the object trait changes externally to the
            editor.
        """
        # Disconnect the editor from any control about to be destroyed:
        self._dispose_items()

        list_pane = self._list_pane
        layout = list_pane.layout()

        # Create all of the list item trait editors:
        trait_handler = self._trait_handler
        resizable     = ((trait_handler.minlen != trait_handler.maxlen) and
                         self.mutable)
        item_trait    = trait_handler.item_trait

        is_fake = (resizable and (len( self.value ) == 0))
        if is_fake:
           self.empty_list()

        editor = self._editor
        # FIXME: Add support for more than one column.
        for index, value in enumerate(self.value):
            if resizable:
                control = IconButton('list_editor.png', self.popup_menu)
                layout.addWidget(control, index, 0)

            proxy = ListItemProxy( self.object, self.name, index, item_trait,
                                   value )
            if resizable:
                control.proxy = proxy
            peditor = editor( self.ui, proxy, 'value', self.description,
                              list_pane ).set( object_name = '' )
            peditor.prepare( list_pane )
            pcontrol = peditor.control
            pcontrol.proxy = proxy

            if isinstance(pcontrol, QtGui.QWidget):
                layout.addWidget(pcontrol, index, 1)
            else:
                layout.addLayout(pcontrol, index, 1)

        # QScrollArea can have problems if the widget being scrolled is set too
        # early (ie. before it contains something).
        if self.control.widget() is None:
            self.control.setWidget(list_pane)
Beispiel #20
0
    def update_page_name ( self, object, name, old, new ):
        """ Handles the trait defining a particular page's name being changed.
        """
        for i, value in enumerate(self._uis):
            page, ui, _, _ = value
            if object is ui.info.object:
                name = None
                handler = getattr(self.ui.handler,
                        '%s_%s_page_name' % (self.object_name, self.name),
                        None)

                if handler is not None:
                    name = handler(self.ui.info, object)

                if name is None:
                    name = str(xgetattr(object, self.factory.page_name[1:], '???'))
                self.control.setTabText(self.control.indexOf(page), name)
                break
Beispiel #21
0
    def update_page_name ( self, object, name, old, new ):
        """ Handles the trait defining a particular page's name being changed.
        """
        for i, value in enumerate(self._uis):
            page, ui, _, _ = value
            if object is ui.info.object:
                name = None
                handler = getattr(self.ui.handler,
                        '%s_%s_page_name' % (self.object_name, self.name),
                        None)

                if handler is not None:
                    name = handler(self.ui.info, object)

                if name is None:
                    name = str(xgetattr(object, self.factory.page_name[1:], '???'))
                self.control.setTabText(self.control.indexOf(page), name)
                break
Beispiel #22
0
    def replace_include ( self, view_elements ):
        """ Replaces any items that have an **id** attribute with an Include
        object with the same ID value, and puts the object with the ID
        into the specified ViewElements object.

        Parameters
        ----------
        view_elements : ViewElements object
            A set of Group, Item, and Include objects
        """
        for i, item in enumerate( self.content ):
            if item.is_includable():
                id = item.id
                if id in view_elements.content:
                    raise TraitError, \
                          "Duplicate definition for view element '%s'" % id
                self.content[ i ] = Include( id )
                view_elements.content[ id ] = item
            item.replace_include( view_elements )
Beispiel #23
0
    def replace_include(self, view_elements):
        """ Replaces any items that have an **id** attribute with an Include
        object with the same ID value, and puts the object with the ID
        into the specified ViewElements object.

        Parameters
        ----------
        view_elements : ViewElements object
            A set of Group, Item, and Include objects
        """
        for i, item in enumerate(self.content):
            if item.is_includable():
                id = item.id
                if id in view_elements.content:
                    raise TraitError, \
                          "Duplicate definition for view element '%s'" % id
                self.content[i] = Include(id)
                view_elements.content[id] = item
            item.replace_include(view_elements)
Beispiel #24
0
    def update_page_name ( self ):
        """ Handles the trait defining a particular page's name being changed.
        """
        changed = False
        for i, value in enumerate( self._uis ):
            dock_control, user_object, view_object, monitoring = value
            if dock_control.control is not None:
                name    = None
                handler = getattr( self.ui.handler, '%s_%s_page_name' %
                                   ( self.object_name, self.name ), None )
                if handler is not None:
                    name = handler( self.ui.info, user_object )

                if name is None:
                    name = unicode( xgetattr( view_object,
                                          self.factory.page_name[1:], u'???' ) )

                changed |= (dock_control.name != name)
                dock_control.name = name

        if changed:
            self.update_layout()
Beispiel #25
0
    def update_page_name ( self ):
        """ Handles the trait defining a particular page's name being changed.
        """
        changed = False
        for i, value in enumerate( self._uis ):
            dock_control, user_object, view_object, monitoring = value
            if dock_control.control is not None:
                name    = None
                handler = getattr( self.ui.handler, '%s_%s_page_name' %
                                   ( self.object_name, self.name ), None )
                if handler is not None:
                    name = handler( self.ui.info, user_object )

                if name is None:
                    name = unicode( xgetattr( view_object,
                                          self.factory.page_name[1:], u'???' ) )

                changed |= (dock_control.name != name)
                dock_control.name = name

        if changed:
            self.update_layout()
Beispiel #26
0
def _fill_panel(panel, content, ui, item_handler=None):
    """Fill a page based container panel with content.
    """
    active = 0

    for index, item in enumerate(content):
        page_name = item.get_label(ui)
        if page_name == "":
            page_name = "Page %d" % index

        if isinstance(item, Group):
            if item.selected:
                active = index

            gp = _GroupPanel(item, ui, suppress_label=True)
            page = gp.control
            sub_page = gp.sub_control

            # If the result is a TabSheet type with only one page, collapse it
            # down into just the page.
            if (isinstance(sub_page, TabSheet)
                    and sub_page.getComponentCount() == 1):
                sub_page = sub_page.getTab(0).getComponent()
            else:
                new = page
        else:
            new = VerticalLayout()
            new.setMargin(False)
            item_handler(item, new)

        # Add the content.
        if isinstance(panel, TabSheet):
            panel.addTab(new, page_name)
        else:
            panel.addComponent(new, page_name)

    panel.setSelectedTab(panel.getTab(active))
Beispiel #27
0
    def __init__ ( self, editor ):
        """ Initializes the object.
        """
        factory = editor.factory
        types   = factory.types
        labels  = factory.labels
        editors = factory.editors
        cols    = factory.cols

        # Save the reference to the editor:
        self.editor = editor

        # Get the tuple we are mirroring:
        object = editor.value

        # For each tuple field, add a trait with the appropriate trait
        # definition and default value:
        content     = []
        self.fields = len( object )
        len_labels  = len( labels )
        len_editors = len( editors )

        if types is None:
            type = editor.value_trait.handler
            if isinstance( type, Tuple ):
                types = type.types

        if not isinstance( types, SequenceTypes ):
            types = [ types ]

        len_types = len( types )
        if len_types == 0:
            types     = [ Any ]
            len_types = 1

        for i, value in enumerate( object ):
            type = types[ i % len_types ]

            auto_set = enter_set = None
            if isinstance(type, TraitType):
                auto_set = type.auto_set
                enter_set = type.enter_set
            if auto_set is None:
                auto_set = editor.factory.auto_set
            if enter_set is None:
                enter_set = editor.factory.enter_set

            label = ''
            if i < len_labels:
                label = labels[i]

            field_editor = None
            if i < len_editors:
                field_editor = editors[i]

            name = 'f%d' % i
            self.add_trait( name, type( value, event = 'field',
                                               auto_set = auto_set,
                                               enter_set = enter_set ) )
            item = Item( name = name, label = label, editor = field_editor )
            if cols <= 1:
                content.append( item )
            else:
                if (i % cols) == 0:
                    group = Group( orientation = 'horizontal' )
                    content.append( group )

                group.content.append( item )

        self.view = View( Group( show_labels = (len_labels != 0), *content ) )
Beispiel #28
0
    def merge_undo(self, undo_item):
        """ Merges two undo items if possible.
        """
        # Undo items are potentially mergeable only if they are of the same
        # class and refer to the same object trait, so check that first:
        if (isinstance(undo_item, self.__class__)
                and (self.object is undo_item.object)
                and (self.name == undo_item.name)):
            v1 = self.new_value
            v2 = undo_item.new_value
            t1 = type(v1)
            if t1 is type(v2):

                if isinstance(t1, basestring):
                    # Merge two undo items if they have new values which are
                    # strings which only differ by one character (corresponding
                    # to a single character insertion, deletion or replacement
                    # operation in a text editor):
                    n1 = len(v1)
                    n2 = len(v2)
                    n = min(n1, n2)
                    i = 0
                    while (i < n) and (v1[i] == v2[i]):
                        i += 1
                    if v1[i + (n2 <= n1):] == v2[i + (n2 >= n1):]:
                        self.new_value = v2
                        return True

                elif isSequenceType(v1):
                    # Merge sequence types only if a single element has changed
                    # from the 'original' value, and the element type is a
                    # simple Python type:
                    v1 = self.old_value
                    if isSequenceType(v1):
                        # Note: wxColour says it's a sequence type, but it
                        # doesn't support 'len', so we handle the exception
                        # just in case other classes have similar behavior:
                        try:
                            if len(v1) == len(v2):
                                diffs = 0
                                for i, item in enumerate(v1):
                                    titem = type(item)
                                    item2 = v2[i]
                                    if ((titem not in SimpleTypes)
                                            or (titem is not type(item2))
                                            or (item != item2)):
                                        diffs += 1
                                        if diffs >= 2:
                                            return False
                                if diffs == 0:
                                    return False
                                self.new_value = v2
                                return True
                        except:
                            pass

                elif t1 in NumericTypes:
                    # Always merge simple numeric trait changes:
                    self.new_value = v2
                    return True
        return False
Beispiel #29
0
    def __init__(self, editor):
        """ Initializes the object.
        """
        factory = editor.factory
        types = factory.types
        labels = factory.labels
        editors = factory.editors
        cols = factory.cols

        # Save the reference to the editor:
        self.editor = editor

        # Get the tuple we are mirroring:
        object = editor.value

        # For each tuple field, add a trait with the appropriate trait
        # definition and default value:
        content = []
        self.fields = len(object)
        len_labels = len(labels)
        len_editors = len(editors)

        if types is None:
            type = editor.value_trait.handler
            if isinstance(type, Tuple):
                types = type.types

        if not isinstance(types, SequenceTypes):
            types = [types]

        len_types = len(types)
        if len_types == 0:
            types = [Any]
            len_types = 1

        for i, value in enumerate(object):
            type = types[i % len_types]

            auto_set = enter_set = None
            if isinstance(type, TraitType):
                auto_set = type.auto_set
                enter_set = type.enter_set
            if auto_set is None:
                auto_set = editor.factory.auto_set
            if enter_set is None:
                enter_set = editor.factory.enter_set

            label = ''
            if i < len_labels:
                label = labels[i]

            field_editor = None
            if i < len_editors:
                field_editor = editors[i]

            name = 'f%d' % i
            self.add_trait(
                name,
                type(value,
                     event='field',
                     auto_set=auto_set,
                     enter_set=enter_set))
            item = Item(name=name, label=label, editor=field_editor)
            if cols <= 1:
                content.append(item)
            else:
                if (i % cols) == 0:
                    group = Group(orientation='horizontal')
                    content.append(group)

                group.content.append(item)

        self.view = View(Group(show_labels=(len_labels != 0), *content))
Beispiel #30
0
def create_notebook_for_items(content, ui, parent, group, item_handler=None, is_dock_window=False):
    """ Creates a notebook and adds a list of groups or items to it as separate
        pages.
    """
    if is_dock_window:
        nb = parent
    else:
        dw = DockWindow(parent, handler=ui.handler, handler_args=(ui.info,), id=ui.id)
        if group is not None:
            dw.theme = group.dock_theme
        nb = dw.control
    pages = []
    count = 0
    has_theme = (group is not None) and (group.group_theme is not None)

    # Create a notebook page for each group or item in the content:
    active = 0
    for index, item in enumerate(content):
        if isinstance(item, Group):
            # Create the group as a nested DockWindow item:
            if item.selected:
                active = index
            sg_sizer, resizable, contents = fill_panel_for_group(nb, item, ui, suppress_label=True, is_dock_window=True)

            # If the result is a region (i.e. notebook) with only one page,
            # collapse it down into just the contents of the region:
            if isinstance(contents, DockRegion) and (len(contents.contents) == 1):
                contents = contents.contents[0]

            # Add the content to the notebook as a new page:
            pages.append(contents)
        else:
            # Create the new page as a simple DockControl containing the
            # specified set of controls:
            page_name = item.get_label(ui)
            count += 1
            if page_name == "":
                page_name = "Page %d" % count

            sizer = wx.BoxSizer(wx.VERTICAL)
            if has_theme:
                image_panel, image_sizer = add_image_panel(nb, group)
                panel = image_panel.control
                image_sizer.Add(sizer, 1, wx.EXPAND)
            else:
                panel = TraitsUIPanel(nb, -1)
                panel.SetSizer(sizer)

            pages.append(
                DockControl(
                    name=page_name,
                    image=item.image,
                    id=item.get_id(),
                    style=item.dock,
                    dockable=DockableViewElement(ui=ui, element=item),
                    export=item.export,
                    control=panel,
                )
            )
            item_handler(item, panel, sizer)
            panel.GetSizer().Fit(panel)

    region = DockRegion(contents=pages, active=active)

    # If the caller is a DockWindow, return the region as the result:
    if is_dock_window:
        return region

    nb.SetSizer(DockSizer(contents=DockSection(contents=[region])))

    # Return the notebook as the result:
    return nb
Beispiel #31
0
    def merge_undo ( self, undo_item ):
        """ Merges two undo items if possible.
        """
        # Undo items are potentially mergeable only if they are of the same
        # class and refer to the same object trait, so check that first:
        if (isinstance( undo_item, self.__class__ ) and
           (self.object is undo_item.object) and
           (self.name == undo_item.name)):
            v1 = self.new_value
            v2 = undo_item.new_value
            t1 = type( v1 )
            if t1 is type( v2 ):

                if isinstance(t1, basestring):
                    # Merge two undo items if they have new values which are
                    # strings which only differ by one character (corresponding
                    # to a single character insertion, deletion or replacement
                    # operation in a text editor):
                    n1 = len( v1 )
                    n2 = len( v2 )
                    n  = min( n1, n2 )
                    i  = 0
                    while (i < n) and (v1[i] == v2[i]):
                        i += 1
                    if v1[i + (n2 <= n1):] == v2[i + (n2 >= n1):]:
                        self.new_value = v2
                        return True

                elif isSequenceType( v1 ):
                    # Merge sequence types only if a single element has changed
                    # from the 'original' value, and the element type is a
                    # simple Python type:
                    v1 = self.old_value
                    if isSequenceType( v1 ):
                        # Note: wxColour says it's a sequence type, but it
                        # doesn't support 'len', so we handle the exception
                        # just in case other classes have similar behavior:
                        try:
                            if len( v1 ) == len( v2 ):
                                diffs = 0
                                for i, item in enumerate( v1 ):
                                    titem = type( item )
                                    item2 = v2[i]
                                    if ((titem not in SimpleTypes)   or
                                        (titem is not type( item2 )) or
                                        (item != item2)):
                                        diffs += 1
                                        if diffs >= 2:
                                            return False
                                if diffs == 0:
                                    return False
                                self.new_value = v2
                                return True
                        except:
                            pass

                elif t1 in NumericTypes:
                    # Always merge simple numeric trait changes:
                    self.new_value = v2
                    return True
        return False