def __init__(self, name, assy, dad, members=(), editCommand=None):

        Group.__init__(self,
                       name,
                       assy,
                       dad,
                       members=members,
                       editCommand=editCommand)
        ###BUG: not all callers pass an editCommand. It would be better
        # to figure out on demand which editCommand would be appropriate.
        # [bruce 080227 comment]
        return
示例#2
0
 def __init__(self, name, assy, dad, members = (), editCommand = None):
         
     Group.__init__(self, 
                    name, 
                    assy, 
                    dad, 
                    members = members, 
                    editCommand = editCommand)
     ###BUG: not all callers pass an editCommand. It would be better
     # to figure out on demand which editCommand would be appropriate.
     # [bruce 080227 comment]
     return
    def build_struct(self, name, params, position):
        """
        Build the DNA helix based on parameters in the UI.
        
        @param name: The name to assign the node in the model tree.
        @type  name: str
        
        @param params: The list of parameters gathered from the PM.
        @type  params: tuple
        
        @param position: The position in 3d model space at which to
                         create the DNA strand. This is always 0, 0, 0.
        @type position:  position
        """
        # No error checking in build_struct, do all your error
        # checking in gather_parameters
        numberOfBases, \
        dnaForm, \
        basesPerTurn, \
        endPoint1, \
        endPoint2 = params

        if Veq(endPoint1, endPoint2):
            raise CadBug("DNA endpoints cannot be the same point.")

        if numberOfBases < 1:
            msg = redmsg("Cannot to preview/insert a DNA duplex with 0 bases.")
            self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False)
            self.dna = None  # Fixes bug 2530. Mark 2007-09-02
            return None

        if dnaForm == 'B-DNA':
            dna = B_Dna_PAM3()
        else:
            raise PluginBug("Unsupported DNA Form: " + dnaForm)

        self.dna = dna  # needed for done msg

        # Create the model tree group node.
        dnaGroup = Group(self.name, self.win.assy, self.win.assy.part.topnode)
        try:
            # Make the DNA duplex. <dnaGroup> will contain three chunks:
            #  - Strand1
            #  - Strand2
            #  - Axis
            dna.make(dnaGroup, numberOfBases, basesPerTurn, endPoint1,
                     endPoint2)

            return dnaGroup

        except (PluginBug, UserError):
            # Why do we need UserError here? Mark 2007-08-28
            rawDnaGroup.kill()
            raise PluginBug(
                "Internal error while trying to create DNA duplex.")

        pass
 def readmmp_info_opengroup_setitem(self, key, val, interp):
     """
     [extends superclass method]
     """
     #bruce 080507 refactoring (split this out of the superclass method)
     if key == ['nanotube-parameters']:
         # val includes all the parameters, separated by commas.
         n, m, type, endings = val.split(",")
         self.n = int(n)
         self.m = int(m)
         self.type = type.lstrip()
         self.endings = endings.lstrip()
         # Create the nanotube.
         from cnt.model.Nanotube import Nanotube
         self.nanotube = Nanotube()  # Returns a 5x5 CNT.
         self.nanotube.setChirality(self.n, self.m)
         self.nanotube.setType(self.type)
         self.nanotube.setEndings(self.endings)
         # The endpoints are recomputed every time it is edited.
     else:
         Group.readmmp_info_opengroup_setitem(self, key, val, interp)
     return
示例#5
0
 def readmmp_info_opengroup_setitem( self, key, val, interp ):
     """
     [extends superclass method]
     """
     #bruce 080507 refactoring (split this out of the superclass method)
     if key == ['nanotube-parameters']:
         # val includes all the parameters, separated by commas.
         n, m, type, endings = val.split(",")
         self.n = int(n)
         self.m = int(m)
         self.type = type.lstrip()
         self.endings = endings.lstrip()
         # Create the nanotube.
         from cnt.model.Nanotube import Nanotube
         self.nanotube = Nanotube() # Returns a 5x5 CNT.
         self.nanotube.setChirality(self.n, self.m)
         self.nanotube.setType(self.type)
         self.nanotube.setEndings(self.endings)
         # The endpoints are recomputed every time it is edited.
     else:
         Group.readmmp_info_opengroup_setitem( self, key, val, interp)
     return
示例#6
0
 def __init__(self, assy, name): # arg order is like Node, not like Group
     dad = None
     Group.__init__(self, name, assy, dad)
示例#7
0
    def drop_on(self, drag_type, nodes):  ###@@@ needs a big cleanup
        # todo: also return description of what we did (for statusbar text)
        # [bruce 080303 comment]
        """
        After a "drag and drop" of type 'move' or 'copy' (according to
        drag_type), perform the drop of the given list of nodes
        onto self.node. The list always contains the original nodes --
        for drag_type == 'copy', this method should make the copies itself.

        Exactly how to do this depends on whether self.node is a leaf or group;
        subclasses of Node can override this to change the UI behavior.
        (As of 050307, only the Clipboard overrides this. Update 071025:
        that's now done by an 'if' statement in the following method,
        which calls self.node.drop_on_should_autogroup, which is what
        the Clipboard overrides.)

        @return: list of new nodes made by this operation, which is [] if it
                 didn't make any (making them is normal for copy, but can also
                 happen in some cases for move)
        @rtype: list of nodes
        """
        will_drop_inside = self.node.MT_DND_can_drop_inside()
        # if true, nodes or their copies will become new children of self.node;
        # if false, they will become new siblings. [revised, bruce 080317]
        autogroup_at_top = will_drop_inside and \
                           self.node.drop_on_should_autogroup(drag_type, nodes)
        drop_onto_Group_at_top = pref_drop_onto_Group_puts_nodes_at_top(
        )  #bruce 080414
        if autogroup_at_top:
            #bruce 050203/080303:
            # nodes dropped onto the clipboard come from one
            # "physical space" (Part) and ought to stay that way by default;
            # user can drag them one-at-a-time if desired. (In theory this
            #  autogrouping need only be done for the subsets of them which
            #  are bonded; for now that's too hard -- maybe not for long,
            #  similar to bug 371. But this simpler behavior might be better
            #  anyway.)
            if drag_type == 'move':
                name = self.node.assy.name_autogrouped_nodes_for_clipboard(
                    nodes, howmade=drag_type)
                new = Group(name, self.node.assy, None)
                for node in nodes[:]:  #bruce 050216 don't reverse the order, it's already correct
                    node.unpick(
                    )  #bruce 050216; don't know if needed or matters; 050307 moved from after to before moveto
                    node.moveto(
                        new
                    )  ####@@@@ guess, same as in super.drop_on (move here, regardless of drag_type? no, not correct!)
                nodes = [new]  # a new length-1 list of nodes
                env.history.message(
                    "(fyi: Grouped some nodes to keep them in one clipboard item)"
                )  ###e improve text
            else:
                # the above implem is wrong for copy, so we handle it differently below,
                # when autogroup_at_top and drag_type != 'move'
                pass
            pass
        #e rewrite to use copy_nodes (nim)? (also rewrite the assy methods? not for alpha)

        res = [
        ]  #bruce 050203: return any new nodes this creates (toplevel nodes only, for copied groups)

        #bruce 050216: order is correct if you're dropping on a group, but (for the ops used below)
        # wrong if you're dropping on a node. This needs a big cleanup, but for now, use this kluge
        # [revised to fix bug 2403 (most likely, this never worked as intended for copy until now), bruce 070525]:

        if not will_drop_inside:
            # drops on nodes which act like leaf nodes are placed after them,
            # when done by the methods named in the following flags,
            # so to drop several nodes in a row and preserve order,
            # drop them in reverse order -- but *when* we reverse them
            # (as well as which method we use) depends on whether we're
            # doing move or copy, so these flags are used in the right
            # place below.
            ##            reverse_moveto = True

            reverse_addmember = True  # for either addchild or addsibling
            pass
        else:
            # will_drop_inside is True
            #
            # drops on groups which accept drops inside themselves
            # go at the end of their members,
            # when done by those methods, so *don't* reverse node order --
            # UNLESS drop_onto_Group_at_top is set, which means, we put nodes dropped
            # on groups at the beginning of their members list.
            # REVIEW: are there any other things that need to be changed for that? ###

            ## assert not debug_pref_DND_drop_at_start_of_groups()
            ##            reverse_moveto = drop_onto_Group_at_top

            reverse_addmember = drop_onto_Group_at_top

            #bruce 060203 removing this, to implement one aspect of NFR 932:
            ## self.node.open = True # open groups which have nodes dropped on them [bruce 050528 new feature]
            pass

        if drag_type == 'move':
            # TODO: this code is now the same as the end of the copy case;
            # after the release, clean this up by moving the common code
            # outside of (after) this move/copy 'if' statement.
            # [bruce 080414 comment]

            if reverse_addmember:  # [bruce 080414 post-rc0 code cleanup: reverse_moveto -> reverse_addmember]
                nodes = nodes[::-1]
            for node in nodes[:]:
                ## node.moveto(self.node)
                if will_drop_inside:
                    self.node.addchild(node, top=drop_onto_Group_at_top)
                else:
                    self.node.addsibling(node, before=False)
                continue
            pass

        else:
            #bruce 050527 [revised 071025] this uses copied_nodes_for_DND,
            # new code to "copy anything". That code is preliminary
            # (probably not enough history messages, or maybe sometimes
            # too many). It would be better to create the Copier object
            # (done in that subr?) earlier, when the drag is started,
            # for various reasons mentioned elsewhere.
            # update 071025: autogroup_at_top is now set at start of this method
            ## autogroup_at_top = isinstance(self.node, ClipboardShelfGroup)
            #####@@@@@ kluge! replace with per-group variable or func.
            #e or perhaps better, a per-group method to process the nodes list, eg to do the grouping
            # as the comment in copied_nodes_for_DND or its subr suggests.

            nodes = copied_nodes_for_DND(nodes,
                                         autogroup_at_top=autogroup_at_top)
            # Note: this ignores order within input list of nodes, using only their MT order
            # to affect the order of copied nodes which it returns. [bruce 070525 comment]
            if not nodes:  # might be None
                return res  # return copied nodes [bruce 080414 post-rc0 code cleanup: [] -> res]

            res.extend(nodes)

            # note: the following code is the same in the move/copy cases;
            # see above for more about this.
            if reverse_addmember:
                nodes = nodes[::-1]
                # note: if autogroup_at_top makes len(nodes) == 1, this has no effect,
                # but it's harmless then, and logically best to do it whenever using
                # addmember on list elements.
            for node in nodes[:]:
                # node is a "copied node" [bruce 080414 post-rc0 code cleanup: renamed nc -> node]
                ## self.node.addmember(node) # self.node is sometimes a Group,
                ##     # so this does need to be addmember (not addchild or addsibling)
                if will_drop_inside:
                    self.node.addchild(node, top=drop_onto_Group_at_top)
                else:
                    self.node.addsibling(node, before=False)
                continue
            pass

        self.node.assy.update_parts(
        )  #e could be optimized to scan only what's needed (same for most other calls of update_parts)

        return res
    def build_struct(self, name, params, position):
        """
        Build the DNA helix based on parameters in the UI.
        
        @param name: The name to assign the node in the model tree.
        @type  name: str
        
        @param params: The list of parameters gathered from the PM.
        @type  params: tuple
        
        @param position: The position in 3d model space at which to
                         create the DNA strand. This is always 0, 0, 0.
        @type position:  position
        """
        # No error checking in build_struct, do all your error
        # checking in gather_parameters
        theSequence, \
        dnaModel, \
        dnaType, \
        basesPerTurn, \
        chunkOption, \
        endpoint1, \
        endpoint2 = params
        
        if Veq(endpoint1, endpoint2):
            raise CadBug("Dna endpoints cannot be the same point.")
            return
        
        if len(theSequence) < 1:
            msg = redmsg("Enter a strand sequence to preview/insert DNA")
            self.MessageGroupBox.insertHtmlMessage(msg, setAsDefault=False)
            self.dna = None # Fixes bug 2530. Mark 2007-09-02
            return None

        if dnaModel == 'PAM3':
            dna = B_Dna_PAM3()
        else:
            dna = B_Dna_PAM5()
        
        self.dna = dna  # needed for done msg
        
        # Create the model tree group node. 
        rawDnaGroup = Group(self.name, 
                            self.win.assy,
                            self.win.assy.part.topnode)
        try:
            # Make the DNA duplex. <rawDnaGroup> returns a different 
            # grouping arrangement for atomistic vs. PAM5. This 'issue'
            # is resolved when we regroup the atoms into strand chunks
            # below.
            dna.make(rawDnaGroup, theSequence, basesPerTurn)
             
            self._orientRawDnaGroup(rawDnaGroup, endpoint1, endpoint2)
        
            # Now group the DNA atoms based on the grouping option selected
            # (i.e. "Strand chunks" or "Single Chunk").
            dnaGroup = self._makePAMStrandAndAxisChunks(rawDnaGroup)
            
            if chunkOption == 'Single chunk':
                return self._makeDuplexChunk(dnaGroup)
            
            return dnaGroup
        
        except (PluginBug, UserError):
            # Why do we need UserError here? Mark 2007-08-28
            rawDnaGroup.kill()
            raise PluginBug("Internal error while trying to create DNA duplex.")
            return None
示例#9
0
 def cm_new_clipboard_item(self):  #bruce 050505
     name = self.assy.name_autogrouped_nodes_for_clipboard(
         [])  # will this end up being the part name too? not sure... ###k
     self.assy.shelf.addchild(Group(name, self.assy, None))
     self.assy.update_parts()
     self.mt_update()
示例#10
0
    def cm_group(
        self
    ):  # bruce 050126 adding comments and changing behavior; 050420 permitting exactly one subtree
        """
        put the selected subtrees (one or more than one) into a new Group (and update)
        """
        ##e I wonder if option/alt/middleButton should be like a "force" or "power" flag
        # for cmenus; in this case, it would let this work even for a single element,
        # making a 1-item group. That idea can wait. [bruce 050126]
        #bruce 050420 making this work inside clipboard items too
        # TEST if assy.part updated in time ####@@@@ -- no, change to selgroup!
        self.deselect_partly_picked_whole_nodes()
        sg = self.assy.current_selgroup()
        node = sg.hindmost()  # smallest nodetree containing all picked nodes
        if not node:
            env.history.message(
                "nothing selected to Group")  # should never happen
            return
        if node.picked:
            #bruce 050420: permit this case whenever possible (formation of 1-item group);
            # cmenu constructor should disable or leave out the menu command when desired.
            if node != sg:
                assert node.dad  # in fact, it'll be part of the same sg subtree (perhaps equal to sg)
                node = node.dad
                assert not node.picked
                # fall through -- general case below can handle this.
            else:
                # the picked item is the topnode of a selection group.
                # If it's the main part, we could make a new group inside it
                # containing all its children (0 or more). This can't happen yet
                # so I'll be lazy and save it for later.
                assert node != self.assy.tree
                # Otherwise it's a clipboard item. Let the Part take care of it
                # since it needs to patch up its topnode, choose the right name,
                # preserve its view attributes, etc.
                assert node.part.topnode == node
                newtop = node.part.create_new_toplevel_group()
                env.history.message(
                    "made new group %s" % newtop.name
                )  ###k see if this looks ok with autogenerated name
                self.mt_update()
                return
        # (above 'if' might change node and then fall through to here)
        # node is an unpicked Group inside (or equal to) sg;
        # more than one of its children (or exactly one if we fell through from the node.picked case above)
        # are either picked or contain something picked (but maybe none of them are directly picked).
        # We'll make a new Group inside node, just before the first child containing
        # anything picked, and move all picked subtrees into it (preserving their order;
        # but losing their structure in terms of unpicked groups that contain some of them).
        ###e what do we do with the picked state of things we move? worry about the invariant! ####@@@@

        # make a new Group (inside node, same assy)
        ###e future: require all assys the same, or, do this once per topnode or assy-node.
        # for now: this will have bugs when done across topnodes!
        # so the caller doesn't let that happen, for now. [050126]
        new = Group(gensym("Group", node.assy), node.assy,
                    node)  # was self.assy
        assert not new.picked

        # put it where we want it -- before the first node member-tree with anything picked in it
        for m in node.members:
            if m.haspicked():
                assert m != new
                ## node.delmember(new) #e (addsibling ought to do this for us...) [now it does]
                m.addsibling(new, before=True)
                break  # (this always happens, since something was picked under node)
        node.apply2picked(lambda (x): x.moveto(new))
        # this will have skipped new before moving anything picked into it!
        # even so, I'd feel better if it unpicked them before moving them...
        # but I guess it doesn't. for now, just see if it works this way... seems to work.
        # ... later [050316], it evidently does unpick them, or maybe delmember does.
        msg = fix_plurals(
            "grouped %d item(s) into " % len(new.members)) + "%s" % new.name
        env.history.message(msg)

        # now, should we pick the new group so that glpane picked state has not changed?
        # or not, and then make sure to redraw as well? hmm...
        # - possibility 1: try picking the group, then see if anyone complains.
        # Caveat: future changes might cause glpane redraw to occur anyway, defeating the speed-purpose of this...
        # and as a UI feature I'm not sure what's better.
        # - possibility 2: don't pick it, do update glpane. This is consistent with Ungroup (for now)
        # and most other commands, so I'll do it.
        #
        # BTW, the prior code didn't pick the group
        # and orginally didn't unpick the members but now does, so it had a bug (failure to update
        # glpane to show new picked state), whose bug number I forget, which this should fix.
        # [bruce 050316]
        ## new.pick() # this will emit an undesirable history message... fix that?
        self.win.glpane.gl_update(
        )  #k needed? (e.g. for selection change? not sure.)
        self.mt_update()
        return