def makeGridPlane(self): cmd = greenmsg("Grid Plane: ") atoms = self.assy.selatoms_list() if not atoms: msg = "You must select 3 or more atoms to create a Grid Plane." env.history.message(cmd + redmsg(msg)) return # Make sure only one atom is selected. if len(atoms) < 3: msg = "To create a Grid Plane, at least 3 atoms must be selected." env.history.message(cmd + redmsg(msg)) return from model.jigs_planes import GridPlane m = GridPlane(self.assy, atoms) m.edit() if m.cancelled: # User hit 'Cancel' button in the jig dialog. env.history.message(cmd + "Cancelled") return self.unpickall_in_GLPane() self.place_new_jig(m) #After placing the jig, remove the atom list from the jig. m.atoms = [] env.history.message(cmd + "Grid Plane created") self.assy.w.win_update() return
def makethermo(self): """ Attaches a thermometer to the single atom selected. """ cmd = greenmsg("Thermometer: ") atoms = self.assy.selatoms_list() if not atoms: msg = "You must select an atom on the chunk you want to " \ "associate with a Thermometer." env.history.message(cmd + redmsg(msg)) return # Make sure only one atom is selected. if len(atoms) != 1: msg = "To create a Thermometer, only one atom may be selected." env.history.message(cmd + redmsg(msg)) return m = Thermo(self.assy, atoms) self.unpickall_in_GLPane() self.place_new_jig(m) env.history.message(cmd + "Thermometer created") self.assy.w.win_update()
def editMakeCheckpoint(win): """ This is called from MWsemantics.editMakeCheckpoint, which is documented as: "Slot for making a checkpoint (only available when Automatic Checkpointing is disabled)." """ env.history.message(greenmsg("Make Checkpoint")) # do it try: #REVIEW: Should make sure this is correct with or without # auto-checkpointing enabled, and leaves that setting unchanged. # (This is not urgent, since in present UI it can't be called # except when auto-checkpointing is disabled.) um = win.assy.undo_manager if um: um.make_manual_checkpoint() # no msg needed, was emitted above: ## env.history.message(greenmsg("Make Checkpoint")) pass else: # this should never happen msg = "Make Checkpoint: error, no undo_manager" env.history.message(redmsg(msg)) except: print_compact_traceback("exception caught in editMakeCheckpoint: ") msg = "Internal error in Make Checkpoint. " \ "Undo/Redo might be unsafe until a new file is opened." env.history.message(redmsg(msg)) #e that wording assumes we can't open more than one file at a time... return
def run(self): """ Execute a rosetta simulation """ if not self.part.molecules: # Nothing in the part to simulate. msg = redmsg("Nothing to simulate.") env.history.message(self.cmdname + ": " + msg) self.win.rosettaSetupAction.setChecked(0) return #check if at least one protein chunk is present on the NE-1 window, #otherwise there's no point calling the simulator proteinExists, chunk = checkIfProteinChunkInPart(self.part) if not proteinExists: msg = redmsg("No protein to simulate.") env.history.message(self.cmdname + ": " + msg) self.win.rosettaSetupAction.setChecked(0) return # iff it's the current mode. previous_movie = self.assy.current_movie self.movie = None r = self.makeSimMovie( ) # will store self.movie as the one it made, or leave it as None if cancelled self.win.rosettaSetupAction.setChecked(0) return
def print_energy(self): r, final_energy_str = get_energy_from_gms_outfile(self.outputfile) if r == 1: # GAMESS terminated abnormally. if final_energy_str: env.history.message( redmsg( final_energy_str + " Check if you have set the right Gamess executable file. Usually it's called gamess.??.x or ??gamess.exe." )) return msg = "Final energy value not found. The output file is located at: " + self.outputfile env.history.message(redmsg(msg)) elif r == 2: # The output file not exist msg = "The output file %s doesn't exist. The reason is either that Gamess didn't run or the output file has been deleted. " % self.outputfile env.history.message(redmsg(msg)) else: # Final energy was found. gmstr = self.gms_parms_info() msg = "GAMESS finished. The output file is located at: " + self.outputfile env.history.message(msg) msg = "Parameters: " + gmstr + ". The final energy is: " + final_energy_str + " Hartree." env.history.message(msg)
def editMakeCheckpoint(win): """ This is called from MWsemantics.editMakeCheckpoint, which is documented as: "Slot for making a checkpoint (only available when Automatic Checkpointing is disabled)." """ env.history.message( greenmsg("Make Checkpoint")) # do it try: #REVIEW: Should make sure this is correct with or without # auto-checkpointing enabled, and leaves that setting unchanged. # (This is not urgent, since in present UI it can't be called # except when auto-checkpointing is disabled.) um = win.assy.undo_manager if um: um.make_manual_checkpoint() # no msg needed, was emitted above: ## env.history.message(greenmsg("Make Checkpoint")) pass else: # this should never happen msg = "Make Checkpoint: error, no undo_manager" env.history.message(redmsg(msg)) except: print_compact_traceback("exception caught in editMakeCheckpoint: ") msg = "Internal error in Make Checkpoint. " \ "Undo/Redo might be unsafe until a new file is opened." env.history.message(redmsg(msg)) #e that wording assumes we can't open more than one file at a time... return
def print_energy(self): r, final_energy_str = get_energy_from_gms_outfile(self.outputfile) if r == 1: # GAMESS terminated abnormally. if final_energy_str: env.history.message( redmsg( final_energy_str + " Check if you have set the right Gamess executable file. Usually it's called gamess.??.x or ??gamess.exe." ) ) return msg = "Final energy value not found. The output file is located at: " + self.outputfile env.history.message(redmsg(msg)) elif r == 2: # The output file not exist msg = ( "The output file %s doesn't exist. The reason is either that Gamess didn't run or the output file has been deleted. " % self.outputfile ) env.history.message(redmsg(msg)) else: # Final energy was found. gmstr = self.gms_parms_info() msg = "GAMESS finished. The output file is located at: " + self.outputfile env.history.message(msg) msg = "Parameters: " + gmstr + ". The final energy is: " + final_energy_str + " Hartree." env.history.message(msg)
def makegamess(self): """ Makes a GAMESS jig from the selected chunks or atoms. """ # [mark 2007-05-07 modified docstring] if sys.platform == "win32": gms_str = "PC GAMESS" else: gms_str = "GAMESS" cmd = greenmsg(gms_str + ": ") atoms = [] # Get a list of atoms from the selected chunks or atoms. atoms = self.assy.selected_atoms_list( include_atoms_in_selected_chunks=True) if not atoms: msg = "At least one atom must be selected to create a " + \ gms_str + " jig." env.history.message(cmd + redmsg(msg)) return # Make sure that no more than 200 atoms are selected. nsa = len(atoms) if nsa > 200: msg = str(nsa) + " atoms selected. The limit is 200." env.history.message(cmd + redmsg(msg)) return # Bug 742. Mark 050731. if nsa > 50: ret = QMessageBox.warning( self.assy.w, "Too many atoms?", gms_str + " jigs with more than 50 atoms may take an\n" "excessively long time to compute (days or weeks).\n" "Are you sure you want to continue?", "&Continue", "Cancel", "", 0, 1) if ret == 1: # Cancel return from analysis.GAMESS.jig_Gamess import Gamess m = Gamess(self.assy, atoms) m.edit() #bruce 050701 split edit method out of the constructor, so the # dialog doesn't show up when the jig is read from an mmp file if m.cancelled: # User hit 'Cancel' button in the jig dialog. env.history.message(cmd + "Cancelled") return self.unpickall_in_GLPane() self.place_new_jig(m) env.history.message(cmd + gms_str + " jig created") self.assy.w.win_update()
def makegamess(self): """ Makes a GAMESS jig from the selected chunks or atoms. """ # [mark 2007-05-07 modified docstring] if sys.platform == "win32": gms_str = "PC GAMESS" else: gms_str = "GAMESS" cmd = greenmsg(gms_str + ": ") atoms = [] # Get a list of atoms from the selected chunks or atoms. atoms = self.assy.selected_atoms_list( include_atoms_in_selected_chunks = True) if not atoms: msg = "At least one atom must be selected to create a " + \ gms_str + " jig." env.history.message(cmd + redmsg(msg)) return # Make sure that no more than 200 atoms are selected. nsa = len(atoms) if nsa > 200: msg = str(nsa) + " atoms selected. The limit is 200." env.history.message(cmd + redmsg(msg)) return # Bug 742. Mark 050731. if nsa > 50: ret = QMessageBox.warning( self.assy.w, "Too many atoms?", gms_str + " jigs with more than 50 atoms may take an\n" "excessively long time to compute (days or weeks).\n" "Are you sure you want to continue?", "&Continue", "Cancel", "", 0, 1 ) if ret == 1: # Cancel return from analysis.GAMESS.jig_Gamess import Gamess m = Gamess(self.assy, atoms) m.edit() #bruce 050701 split edit method out of the constructor, so the # dialog doesn't show up when the jig is read from an mmp file if m.cancelled: # User hit 'Cancel' button in the jig dialog. env.history.message(cmd + "Cancelled") return self.unpickall_in_GLPane() self.place_new_jig(m) env.history.message(cmd + gms_str + " jig created") self.assy.w.win_update()
def Mirror(self): """ Mirror the selected chunk(s) about a selected grid plane. """ cmd = greenmsg("Mirror: ") #ninad060814 this is necessary to fix a bug. Otherwise program will #crash if you try to mirror when the top node of the part #(main part of clipboard) is selected if self.topnode.picked: self.topnode.unpick_top() self.mirrorJigs = self.getQualifiedMirrorJigs() jigCounter = len(self.mirrorJigs) if jigCounter < 1: msg1 = "No mirror plane selected." msg2 = " Please select a Reference Plane or a Grid Plane first." msg = redmsg(msg1 + msg2) instr1 = "(If it doesn't exist, create it using" instr2 = "<b>Insert > Reference Geometry menu </b> )" instruction = instr1 + instr2 env.history.message(cmd + msg + instruction) return elif jigCounter > 1: msg = redmsg( "More than one plane selected. Please select only one plane and try again" ) env.history.message(cmd + msg) return for j in self.mirrorJigs: j.unpick() copiedObject = self.o.assy.part.copy_sel_in_same_part() # ninad060812 Get the axis vector of the Grid Plane. Then you need to #rotate the inverted chunk by pi around this axis vector self.mirrorAxis = self.mirrorJigs[0].getaxis() if isinstance(copiedObject, Chunk): copiedObject.name = copiedObject.name + "-Mirror" self._mirrorChunk(copiedObject) return elif isinstance(copiedObject, Group): copiedObject.name = "Mirrored Items" def mirrorChild(obj): if isinstance(obj, Chunk): self._mirrorChunk(obj) elif isinstance(obj, Jig): self._mirrorJig(obj) copiedObject.apply2all(mirrorChild) return
def _update_UI_do_updates(self): """ Overrides superclass method. @see: Command_PropertyManager._update_UI_do_updates() """ self.proteinChunk1 = None self.proteinChunk2 = None self.comparePushButton.setEnabled(False) self.hidePushButton.setEnabled(False) selectedProteinList = self.win.assy.getSelectedProteinChunks() if len(selectedProteinList) == 0: self.structure1LineEdit.setText("") self.structure2LineEdit.setText("") msg = "Select two structures of the same length in the graphics area, "\ "then click the <b>Compare</b> button to compare them." elif len(selectedProteinList) == 1: self.proteinChunk1 = selectedProteinList[0] aa1_count = " (%d)" % self.proteinChunk1.protein.count_amino_acids() self.structure1LineEdit.setText(self.proteinChunk1.name + aa1_count) self.structure2LineEdit.setText("") msg = "Select one more structure in the graphics area that is the same "\ "length as <b>" + self.proteinChunk1.name + "</b>. "\ "Then click the <b>Compare</b> button to compare them." elif len(selectedProteinList) == 2: self.proteinChunk1 = selectedProteinList[0] aa1_count = " (%d)" % self.proteinChunk1.protein.count_amino_acids() self.structure1LineEdit.setText(self.proteinChunk1.name + aa1_count) self.proteinChunk2 = selectedProteinList[1] aa2_count = " (%d)" % self.proteinChunk2.protein.count_amino_acids() self.structure2LineEdit.setText(self.proteinChunk2.name + aa2_count) if aa1_count == aa2_count: self.comparePushButton.setEnabled(True) self.hidePushButton.setEnabled(True) msg = "Click the <b>Compare</b> button to compare the two selected structures." else: msg = "<b>%s</b> and <b>%s</b> are not the same length." % \ (self.proteinChunk1.name, self.proteinChunk2.name) msg = redmsg(msg) else: self.structure1LineEdit.setText("") self.structure2LineEdit.setText("") msg = redmsg("Too many proteins selected.") self.updateMessage(msg) env.history.redmsg(msg) return
def simPlot(assy): # moved here from MWsemantics method, bruce 050327 """Opens the "Make Graphs" dialog (and waits until it's dismissed), for the current movie if there is one, otherwise for a previously saved dpb file with the same name as the current part, if one can be found. Returns the dialog, after it's dismissed (probably useless), or None if no dialog was shown. """ #bruce 050326 inferred docstring from code, then revised to fit my recent changes # to assy.current_movie, but didn't yet try to look for alternate dpb file names # when the current part is not the main part. (I'm sure that we'll soon have a wholly # different scheme for letting the user look around for preexisting related files to use, # like movie files applicable to the current part.) # I did reorder the code, and removed the check on the current part having atoms # (since plotting from an old file shouldn't require movie to be valid for current part). # This method should be moved into some other file. if assy.current_movie and assy.current_movie.filename: return PlotTool(assy, assy.current_movie.filename) else: msg = redmsg("There is no current movie file loaded.") env.history.message(cmd + msg) return None # wware 060317, bug 1484 if assy.filename: return PlotTool(assy, assy.filename) # no valid current movie, look for saved one with same name as assy msg = redmsg("No simulation has been run yet.") env.history.message(cmd + msg) if assy.filename: if assy.part is not assy.tree.part: msg = redmsg( "Warning: Looking for saved movie for main part, not for displayed clipboard item." ) env.history.message(cmd + msg) mfile = assy.filename[:-4] + ".dpb" movie = find_saved_movie(assy, mfile) # just checks existence, not validity for current part or main part if movie: #e should we set this as current_movie? I don't see a good reason to do that, # user can open it if they want to. But I'll do it if we don't have one yet. if not assy.current_movie: assy.current_movie = movie #e should we switch to the part for which this movie was made? # No current way to tell how to do that, and this might be done even if it's not valid # for any loaded Part. So let's not... tho we might presume (from filename choice we used) # it was valid for Main Part. Maybe print warning for clip item, and for not valid? #e msg = "Using previously saved movie for this part." env.history.message(cmd + msg) return PlotTool(assy, movie) else: msg = redmsg("Can't find previously saved movie for this part.") env.history.message(cmd + msg) return
def simPlot(assy): # moved here from MWsemantics method, bruce 050327 """Opens the "Make Graphs" dialog (and waits until it's dismissed), for the current movie if there is one, otherwise for a previously saved dpb file with the same name as the current part, if one can be found. Returns the dialog, after it's dismissed (probably useless), or None if no dialog was shown. """ #bruce 050326 inferred docstring from code, then revised to fit my recent changes # to assy.current_movie, but didn't yet try to look for alternate dpb file names # when the current part is not the main part. (I'm sure that we'll soon have a wholly # different scheme for letting the user look around for preexisting related files to use, # like movie files applicable to the current part.) # I did reorder the code, and removed the check on the current part having atoms # (since plotting from an old file shouldn't require movie to be valid for current part). # This method should be moved into some other file. if assy.current_movie and assy.current_movie.filename: return PlotTool(assy, assy.current_movie.filename) else: msg = redmsg("There is no current movie file loaded.") env.history.message(cmd + msg) return None # wware 060317, bug 1484 if assy.filename: return PlotTool(assy, assy.filename) # no valid current movie, look for saved one with same name as assy msg = redmsg("No simulation has been run yet.") env.history.message(cmd + msg) if assy.filename: if assy.part is not assy.tree.part: msg = redmsg("Warning: Looking for saved movie for main part, not for displayed clipboard item.") env.history.message(cmd + msg) mfile = assy.filename[:-4] + ".dpb" movie = find_saved_movie( assy, mfile) # just checks existence, not validity for current part or main part if movie: #e should we set this as current_movie? I don't see a good reason to do that, # user can open it if they want to. But I'll do it if we don't have one yet. if not assy.current_movie: assy.current_movie = movie #e should we switch to the part for which this movie was made? # No current way to tell how to do that, and this might be done even if it's not valid # for any loaded Part. So let's not... tho we might presume (from filename choice we used) # it was valid for Main Part. Maybe print warning for clip item, and for not valid? #e msg = "Using previously saved movie for this part." env.history.message(cmd + msg) return PlotTool(assy, movie) else: msg = redmsg("Can't find previously saved movie for this part.") env.history.message(cmd + msg) return
def Mirror(self): """ Mirror the selected chunk(s) about a selected grid plane. """ cmd = greenmsg("Mirror: ") #ninad060814 this is necessary to fix a bug. Otherwise program will #crash if you try to mirror when the top node of the part #(main part of clipboard) is selected if self.topnode.picked: self.topnode.unpick_top() self.mirrorJigs = self.getQualifiedMirrorJigs() jigCounter = len(self.mirrorJigs) if jigCounter < 1: msg1 = "No mirror plane selected." msg2 = " Please select a Reference Plane or a Grid Plane first." msg = redmsg(msg1+msg2) instr1 = "(If it doesn't exist, create it using" instr2 = "<b>Insert > Reference Geometry menu </b> )" instruction = instr1 + instr2 env.history.message(cmd + msg + instruction) return elif jigCounter >1: msg = redmsg("More than one plane selected. Please select only one plane and try again") env.history.message(cmd + msg ) return for j in self.mirrorJigs: j.unpick() copiedObject = self.o.assy.part.copy_sel_in_same_part() # ninad060812 Get the axis vector of the Grid Plane. Then you need to #rotate the inverted chunk by pi around this axis vector self.mirrorAxis = self.mirrorJigs[0].getaxis() if isinstance(copiedObject, Chunk): copiedObject.name = copiedObject.name + "-Mirror" self._mirrorChunk(copiedObject) return elif isinstance(copiedObject, Group): copiedObject.name = "Mirrored Items" def mirrorChild(obj): if isinstance(obj, Chunk): self._mirrorChunk(obj) elif isinstance(obj, Jig): self._mirrorJig(obj) copiedObject.apply2all(mirrorChild) return
def makeChunkFromSelectedAtoms(self): """ Create a new chunk from the selected atoms. """ # ninad 070411 moved the original method out of 'merge' method to # facilitate implementation of 'Create New Chunk # from selected atoms' feature cmd = greenmsg("Create New Chunk: ") if not self.selatoms: msg1 = "Create New Chunk: " msg2 = redmsg("Select some atoms first to create a new chunk") env.history.message(msg1 + msg2) return # ninad070411 : Following checks if the selected molecules # belong to more than one chunk. If they don't (i.e. if they are a part of # a sinle chunk, it returns from the method with proper histry msg molList = [] for atm in self.selatoms.values(): if not len(molList) > 1: mol = atm.molecule if mol not in molList: molList.append(mol) if len(molList) < 2: msg1 = "Create New Chunk: " msg2 = redmsg( "Not created as the selected atoms are part of the \ same chunk." ) env.history.message(msg1 + msg2) return # bruce 060329 new feature: work on atoms too (put all selected atoms into a new chunk) self.ensure_toplevel_group() # avoid bug for part containing just one chunk, all atoms selected numol = Chunk(self.assy, gensym("Chunk", self.assy)) natoms = len(self.selatoms) for a in self.selatoms.values(): # leave the moved atoms picked, so still visible a.hopmol(numol) self.addmol(numol) # e should we add it in the same groups (and just after the chunks) which these atoms used to belong to? # could use similar scheme to placing jigs... msg = fix_plurals( "made chunk from %d atom(s)" % natoms ) # len(numol.atoms) would count bondpoints, this doesn't msg = msg.replace("chunk", numol.name) env.history.message(cmd + msg) self.w.win_update()
def makeChunkFromSelectedAtoms(self): """ Create a new chunk from the selected atoms. """ #ninad 070411 moved the original method out of 'merge' method to #facilitate implementation of 'Create New Chunk #from selected atoms' feature cmd = greenmsg("Create New Chunk: ") if not self.selatoms: msg1 = "Create New Chunk: " msg2 = redmsg('Select some atoms first to create a new chunk') env.history.message(msg1 + msg2) return #ninad070411 : Following checks if the selected molecules #belong to more than one chunk. If they don't (i.e. if they are a part of # a sinle chunk, it returns from the method with proper histry msg molList = [] for atm in self.selatoms.values(): if not len(molList) > 1: mol = atm.molecule if mol not in molList: molList.append(mol) if len(molList) < 2: msg1 = "Create New Chunk: " msg2 = redmsg('Not created as the selected atoms are part of the \ same chunk.') env.history.message(msg1 + msg2) return #bruce 060329 new feature: work on atoms too (put all selected atoms into a new chunk) self.ensure_toplevel_group( ) # avoid bug for part containing just one chunk, all atoms selected numol = Chunk(self.assy, gensym("Chunk", self.assy)) natoms = len(self.selatoms) for a in self.selatoms.values(): # leave the moved atoms picked, so still visible a.hopmol(numol) self.addmol(numol) #e should we add it in the same groups (and just after the chunks) which these atoms used to belong to? # could use similar scheme to placing jigs... msg = fix_plurals( "made chunk from %d atom(s)" % natoms) # len(numol.atoms) would count bondpoints, this doesn't msg = msg.replace('chunk', numol.name) env.history.message(cmd + msg) self.w.win_update()
def placePlaneOffsetToAnother(self): """ Orient the plane such that it is parallel to a selected plane , with an offset. """ cmd = self.editCommand.cmd jigList = self.win.assy.getSelectedJigs() if jigList: planeList = [] for j in jigList: if isinstance(j, Plane) and (j is not self): planeList.append(j) #First, clear all the direction arrow drawings if any in #the existing Plane objectes in the part if not self.assy.part.topnode.members: msg = redmsg("Select a different plane first to place the" " current plane offset to it") env.history.message(cmd + msg) return for p in self.assy.part.topnode.members: if isinstance(p, Plane): if p.directionArrow: p.directionArrow.setDrawRequested(False) if len(planeList) == 1: self.offsetParentGeometry = planeList[0] self.offsetParentGeometry.directionArrow.setDrawRequested(True) if self.offsetParentGeometry.directionArrow.flipDirection: offset = 2 * norm(self.offsetParentGeometry.getaxis()) else: offset = -2 * norm(self.offsetParentGeometry.getaxis()) self.center = self.offsetParentGeometry.center + offset self.quat = Q(self.offsetParentGeometry.quat) else: msg = redmsg("Select exactly one plane to\ create a plane offset to it.") env.history.message(cmd + msg) return else: msg = redmsg("Select an existing plane first to\ create a plane offset to it.") env.history.message(cmd + msg) return self.glpane.gl_update()
def run_job(self): """ Slot method for the 'Save and Run' button """ self.accept() # Run GAMESS job. Return value r: # 0 = success # 1 = job cancelled # 2 = job failed. r = self.job.launch() if r == 1: # Job was cancelled env.history.message(redmsg("GAMESS job cancelled.")) return if r == 2: # Job failed. env.history.message( redmsg( "GAMESS job failed. Maybe you didn't set the right Gamess executable file. Make sure you can run the same job manually." )) return # Job success. fn = self.gamessJig.outputfile # Print energy or move atoms if self.pset.ui.runtyp == 0: #Energy self.gamessJig.print_energy() else: # Optimize try: r = self.gamessJig.move_optimized_atoms() # r = insertgms(self.gamessJig.assy, fn) except: print_compact_traceback( "GamessProp.run_job(): error reading GAMESS OUT file [%s]: " % fn) env.history.message( redmsg("Internal error while inserting GAMESS geometry: " + fn)) else: if r: env.history.message(redmsg("Atoms not adjusted.")) else: self.gamessJig.assy.changed( ) # The file and the part are not the same. self.gamessJig.print_energy( ) # Print the final energy from the optimize OUT file, too. env.history.message("Atoms adjusted.")
def do_main_menu_op(self, optype): """ @note: optype should be Undo or Redo """ op_was_available = not not self._current_main_menu_ops.get(optype) global _disable_UndoRedo if _disable_UndoRedo: #060414 env.history.message(redmsg("%s is not permitted now (and this action was only offered due to a bug)" % optype)) return global _AutoCheckpointing_enabled disabled = not _AutoCheckpointing_enabled #060312 if disabled: _AutoCheckpointing_enabled = True # temporarily enable it, just during the Undo or Redo command self.checkpoint( cptype = "preUndo" ) # do a checkpoint with it enabled, so Undo or Redo can work normally. # Note: in theory this might change what commands are offered and maybe even cause the error message below to come out # (so we might want to revise it when disabled is true ##e), but I think that can only happen if there's a change_counter # bug, since the only way the enabled cp will see changes not seen by disabled one is if archive.update_before_checkpoint() # is first to set the change_counters (probably a bug); if this happens it might make Redo suddenly unavailable. ####e if optype is Redo, we could pass an option to above checkpoint to not destroy redo stack or make it inaccessible! # (such an option is nim) try: op = self._current_main_menu_ops.get(optype) if op: undo_xxx = op.menu_desc() # note: menu_desc includes history sernos env.history.message(u"%s" % undo_xxx) #e say Undoing rather than Undo in case more msgs?? ######@@@@@@ TEST u"%s" self.archive.do_op(op) self.assy.w.update_select_mode() #bruce 060227 try to fix bug 1576 self.assy.w.win_update() #bruce 060227 not positive this isn't called elsewhere, or how we got away without it if not else: if not disabled: print "no op to %r; not sure how this slot was called, since it should have been disabled" % optype env.history.message(redmsg("Nothing to %s (and it's a bug that its menu item or tool button was enabled)" % optype)) else: print "no op to %r; autocp disabled (so ops to offer were recomputed just now; before that, op_was_available = %r); "\ "see code comments for more info" % ( optype, op_was_available) if op_was_available: env.history.message(redmsg("Nothing to %s (possibly due to a bug)" % optype)) else: env.history.message(redmsg("Nothing to %s (and this action was only offered due to a bug)" % optype)) pass except: print_compact_traceback() env.history.message(redmsg("Bug in %s; see traceback in console" % optype)) if disabled: # better get the end-cp done now (since we might be relying on it for some reason -- I'm not sure) self.checkpoint( cptype = "postUndo" ) _AutoCheckpointing_enabled = False # re-disable return
def optimize_geometry(self): """ Optimize geometry """ cmd = greenmsg("Optimize Geometry: ") errmsgs = ["GAMESS job aborted.", "Error: GAMESS job failed."] pset = self.pset runtyp = pset.ui.runtyp # Save runtyp (Calculate) setting to restore it later. pset.ui.runtyp = 1 # Optimize origCalType = self.gmsjob.Calculation self.gmsjob.Calculation = 'Optimize' self.update_gamess_parms() # Run GAMESS job. Return value r: # 0 = success # 1 = job aborted. # 2 = job failed. r = self.gmsjob.launch() pset.ui.runtyp = runtyp # Restore to original value self.gmsjob.Calculation = origCalType if r: # Job was aborted or an error occurred. msg = redmsg(errmsgs[r - 1]) env.history.message(cmd + msg) return try: r2 = self.move_optimized_atoms() except: print_compact_traceback( "GamessProp.run_job(): error reading GAMESS OUT file [%s]: " % \ self.outputfile ) env.history.message( redmsg(cmd + "Internal error while inserting GAMESS geometry: " + self.outputfile)) else: if r2: env.history.message(cmd + redmsg("Atoms not adjusted.")) else: self.assy.changed() # The file and the part are not the same. self.print_energy( ) # Print the final energy from the optimize OUT file, too. env.history.message(cmd + "Atoms adjusted.")
def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return number_of_segments, isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: if not number_of_segments == 0: #disable all widgets self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s"%(why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segments" self.updateMessage(msg) self.updateListWidgets()
def open_wiki_help_URL(url, whosdoingthis="Wiki help"): # bruce 051229 split this out of open_wiki_help_dialog """ Try to open the given url in the user's browser (unless they've set preferences to prevent this (NIM)), first emitting a history message containing the url (which is described as coming from whosdoingthis, which should be a capitalized string). Return True if there's no evidence of an error; print error message to history and return False if it definitely failed. """ url = str(url) # precaution in case of QString ###e should check prefs to see if we should really open browser; if not, print different hist message env.history.message("%s: opening " % whosdoingthis + url) # see module docstring re "wiki help" vs. "web help" # print this in case user wants to open it manually or debug the url prefix preference try: webbrowser_open(url) worked = True except: # bruce 051201 catch exception to mitigate bug 1167 # (e.g. when Linux user doesn't have BROWSER env var set). # Probably need to make this more intelligent, perhaps by # catching the specific exception in the bug report, knowing # the OS, passing options to webbrowser.open, etc. print_compact_traceback("webbrowser exception: ") env.history.message( redmsg("Problem opening web browser.") + "Suggest opening above URL by hand. " "On some platforms, setting BROWSER environment variable might help." ) worked = False return worked
def update_icon(self, print_missing_file=False, found=None): """ Update our icon according to whether our file exists or not (or use the boolean passed as found, if one is passed). (Exception: icon looks normal if filename is not set yet. Otherwise it looks normal if file is there, not normal if file is missing.) If print_missing_file is true, print an error message if the filename is non-null but the file doesn't exist. Return "not found" in case callers want to print their own error messages (for example, if they use a different filename). """ #bruce 060620 split this out of readmmp_info_povrayscene_setitem for later use in copy_fixup_at_end (not yet done ###@@@). # But its dual function is a mess (some callers use their own filename) so it needs more cleanup. #e filename = self.povrayscene_file if found is None: found = not filename or os.path.exists(filename) # otherwise found should have been passed as True or False if found: self.const_pixmap = imagename_to_pixmap( "modeltree/povrayscene.png") else: self.const_pixmap = imagename_to_pixmap( "modeltree/povrayscene-notfound.png") if print_missing_file: msg = redmsg( "POV-Ray Scene file [" + filename + "] does not exist." ) #e some callers would prefer orangemsg, cmd, etc. env.history.message(msg) return not found
def makeAnchor(self): """ Anchors the selected atoms so that they will not move during a minimization or simulation run. """ cmd = greenmsg("Anchor: ") atoms = self.assy.selatoms_list() if not atoms: msg = "You must select at least one atom to create an Anchor." env.history.message(cmd + redmsg(msg)) return # Print warning if over 200 atoms are selected. if atom_limit_exceeded_and_confirmed(self.assy.w, len(atoms), limit=200): return m = Anchor(self.assy, atoms) self.unpickall_in_GLPane() self.place_new_jig(m) env.history.message(cmd + "Anchor created") self.assy.w.win_update()
def selectDoubly(self): """ Select any atom that can be reached from any currently selected atom through two or more non-overlapping sequences of bonds. Also select atoms that are connected to this group by one bond and have no other bonds. """ ###@@@ same comment about interspace bonds as in selectConnected cmd = greenmsg("Select Doubly: ") if not self.selatoms: msg = redmsg("No atoms selected") env.history.message(cmd + msg) return alreadySelected = len(self.selatoms.values()) from operations.op_select_doubly import select_doubly # new code, bruce 050520 #e could also reload it now to speed devel! select_doubly(self.selatoms.values()) #e optim totalSelected = len(self.selatoms.values()) from platform_dependent.PlatformDependent import fix_plurals info = fix_plurals("%d new atom(s) selected (besides the %d initially selected)." % \ (totalSelected - alreadySelected, alreadySelected) ) env.history.message( cmd + info) if totalSelected > alreadySelected: ## otherwise, means nothing new selected. Am I right? ---Huaicai, not analyze the markdouble() algorithm yet #self.w.win_update() self.o.gl_update() return
def _makeDuplexChunk(self, dnaGroup): """ Returns a single DNA chunk given a dnaGroup containing multiple strand chunks. @param dnaGroup: The group object containing the DNA strand chunks. @type dnaGroup: L{Group} @return: The DNA chunk. @rtype: L{Chunk} """ if not isinstance(dnaGroup.members[0], Chunk): env.history.message(redmsg( "Internal error in creating a single chunk DNA")) return for m in dnaGroup.members[1:]: if isinstance(m, Chunk): dnaGroup.members[0].merge(m) # Rename the merged chunk dnaGroup.members[0].name = dnaGroup.name dnaChunk = dnaGroup.members[0] dnaChunk.setcolor(None) dnaGroup.ungroup() return dnaChunk
def __init__(self, mapping, chunk): # immediately memoize some settings which need to be constant # during use, as a bug precaution. Also do whatever precomputes # are convenient. writemmp_mapping_memo.__init__(self, mapping) self.chunk = chunk self.ladder = chunk.ladder if not dna_updater_is_enabled(): msg = "Warning: can't convert PAM model when dna updater is disabled; affects [N] chunk(s)" env.history.deferred_summary_message(orangemsg(msg)) elif not self.ladder: # (might happen if dna updater is turned off at runtime -- not sure; # note, doing that might have worse effects, like self.ladder existing # but being out of date, causing traceback errors. #### FIX those sometime (elsewhere).) print "error: ladder not set during writemmp, can't convert pam model, in %r" % chunk msg = "Error: [N] chunk(s) don't have ladders set" env.history.deferred_summary_message(redmsg(msg)) else: self.convert_pam_enabled = True if self.convert_pam_enabled: # Note: this only means conversion is possible -- we don't yet know # if it's requested by options on this mapping and chunk. # The ladder memo will decide that. self._ladder_memo = mapping.get_memo_for(self.ladder) self._save_as_pam = self._ladder_memo._f_save_as_what_PAM_model() return
def merge(self): """ Merges selected atoms into a single chunk, or merges the selected chunks into a single chunk. @note: If the selected atoms belong to the same chunk, nothing happens. """ #mark 050411 changed name from weld to merge (Bug 515) #bruce 050131 comment: might now be safe for clipboard items # since all selection is now forced to be in the same one; # this is mostly academic since there's no pleasing way to use it on them, # though it's theoretically possible (since Groups can be cut and maybe copied). cmd = greenmsg("Combine Chunks: ") if self.selatoms: self.makeChunkFromSelectedAtoms() return if len(self.selmols) < 2: msg = redmsg("Need two or more selected chunks to merge") env.history.message(cmd + msg) return self.changed() #bruce 050131 bugfix or precaution mol = self.selmols[0] for m in self.selmols[1:]: mol.merge(m)
def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return number_of_segments, isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: if not number_of_segments == 0: #disable all widgets self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s" % (why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segments" self.updateMessage(msg) self.updateListWidgets()
def conformationComboBoxChanged( self, inIndex ): """ Slot for the Conformation combobox. It is called whenever the Conformation choice is changed. @param inIndex: The new index. @type inIndex: int """ self.basesPerTurnComboBox.clear() conformation = self.conformationComboBox.currentText() if conformation == "B-DNA": self.basesPerTurnComboBox.insertItem(0, "10.0") self.basesPerTurnComboBox.insertItem(1, "10.5") self.basesPerTurnComboBox.insertItem(2, "10.67") #10.5 is the default value for Bases per turn. #So set the current index to 1 self.basesPerTurnComboBox.setCurrentIndex(1) elif conformation == "Z-DNA": self.basesPerTurnComboBox.insertItem(0, "12.0") elif inIndex == -1: # Caused by clear(). This is tolerable for now. Mark 2007-05-24. conformation = "B-DNA" # Workaround for "Restore Defaults". pass else: msg = redmsg("conformationComboBoxChanged(): \ Error - unknown DNA conformation. Index = "+ inIndex) env.history.message(msg) self.duplexLengthSpinBox.setSingleStep( self.getDuplexRise(conformation) )
def moveAbsolute(self): """ Move selected chunk(s), jig(s) to absolute X, Y, and Z by computing the bbox center of everything as if they were one big chunk, then move everything as a unit. """ movables = self.graphicsMode.getMovablesForLeftDragging() if not movables: env.history.message(redmsg("No chunks or movable jigs selected.")) return ## Compute bbox for selected chunk(s). bbox = BBox() for m in movables: if hasattr(m, "bbox"): # Fixes bug 1990. Mark 060702. bbox.merge(m.bbox) pt1 = bbox.center() # pt1 = center point for bbox of selected chunk(s). pt2 = self.propMgr.get_move_xyz() # pt2 = X, Y, Z values from PM offset = pt2 - pt1 # Compute offset for translating the selection self.assy.translateSpecifiedMovables(offset, movables = movables) # Print history message about what happened. if len(movables) == 1: msg = "[%s] moved to [X: %.2f] [Y: %.2f] [Z: %.2f]" % (movables[0].name, pt2[0], pt2[1], pt2[2]) else: msg = "Selected chunks/jigs moved by offset [X: %.2f] [Y: %.2f] [Z: %.2f]" % (offset[0], offset[1], offset[2]) env.history.message(msg) self.o.gl_update() return
def loadImage(self, file_name): """ Loads an image to be displayed on the plane as a texture. Displays a warning message if the image format is not supported or the file cannot be open. This method should be extened to support basic image operations (resizing, flipping, cropping). @param file_name: The name of the image file. """ # piotr 080528 self.deleteImage() try: mipmaps, image = load_image_into_new_texture_name(file_name) self.imagePath = file_name # piotr 080624 self.tex_image = image # this gl_update may not be enough to show the image immediately self.glpane.gl_update() except: msg = redmsg("Cannot load plane image " + file_name) env.history.message(msg) self.tex_image = None
def viewParallelTo(self): """ Set view parallel to the vector defined by 2 selected atoms. """ cmd = greenmsg("Set View Parallel To: ") atoms = self.assy.selatoms_list() if len(atoms) != 2: msg = redmsg("You must select 2 atoms.") env.history.message(cmd + msg) return v = norm(atoms[0].posn()-atoms[1].posn()) if vlen(v) < 0.0001: # Atoms are on top of each other. info = 'The selected atoms are on top of each other. No change in view.' env.history.message(cmd + info) return # If vec is pointing into the screen, negate (reverse) vec. if dot(v, self.glpane.lineOfSight) > 0: v = -v # Compute the destination quat (q2). q2 = Q(V(0,0,1), v) q2 = q2.conj() self.glpane.rotateView(q2) info = 'View set parallel to the vector defined by the 2 selected atoms.' env.history.message(cmd + info)
def __init__(self, mapping, chunk): # immediately memoize some settings which need to be constant # during use, as a bug precaution. Also do whatever precomputes # are convenient. writemmp_mapping_memo.__init__(self, mapping) self.chunk = chunk self.ladder = chunk.ladder if not dna_updater_is_enabled(): msg = "Warning: can't convert PAM model when dna updater is disabled; affects [N] chunk(s)" env.history.deferred_summary_message( orangemsg( msg)) elif not self.ladder: # (might happen if dna updater is turned off at runtime -- not sure; # note, doing that might have worse effects, like self.ladder existing # but being out of date, causing traceback errors. #### FIX those sometime (elsewhere).) print "error: ladder not set during writemmp, can't convert pam model, in %r" % chunk msg = "Error: [N] chunk(s) don't have ladders set" env.history.deferred_summary_message( redmsg( msg)) else: self.convert_pam_enabled = True if self.convert_pam_enabled: # Note: this only means conversion is possible -- we don't yet know # if it's requested by options on this mapping and chunk. # The ladder memo will decide that. self._ladder_memo = mapping.get_memo_for(self.ladder) self._save_as_pam = self._ladder_memo._f_save_as_what_PAM_model() return
def calculate_energy(self): """ Calculate energy. """ cmd = greenmsg("Calculate Energy: ") errmsgs = ["GAMESS job aborted.", "Error: GAMESS job failed."] pset = self.pset runtyp = pset.ui.runtyp # Save runtyp (Calculate) setting to restore it later. pset.ui.runtyp = 0 # Energy calculation origCalType = self.gmsjob.Calculation self.gmsjob.Calculation = 'Energy' self.update_gamess_parms() # Run GAMESS job. Return value r: # 0 = success # 1 = job aborted # 2 = job failed. r = self.gmsjob.launch() pset.ui.runtyp = runtyp # Restore to original value self.gmsjob.Calculation = origCalType if r: # Job was aborted or an error occurred. msg = redmsg(errmsgs[r-1]) env.history.message( cmd + msg ) return self.print_energy()
def conformationComboBoxChanged(self, inIndex): """ Slot for the Conformation combobox. It is called whenever the Conformation choice is changed. @param inIndex: The new index. @type inIndex: int """ self.basesPerTurnComboBox.clear() conformation = self.conformationComboBox.currentText() if conformation == "B-DNA": self.basesPerTurnComboBox.insertItem(0, "10.0") self.basesPerTurnComboBox.insertItem(1, "10.5") self.basesPerTurnComboBox.insertItem(2, "10.67") #10.5 is the default value for Bases per turn. #So set the current index to 1 self.basesPerTurnComboBox.setCurrentIndex(1) elif conformation == "Z-DNA": self.basesPerTurnComboBox.insertItem(0, "12.0") elif inIndex == -1: # Caused by clear(). This is tolerable for now. Mark 2007-05-24. conformation = "B-DNA" # Workaround for "Restore Defaults". pass else: msg = redmsg("conformationComboBoxChanged(): \ Error - unknown DNA conformation. Index = " + inIndex) env.history.message(msg) self.duplexLengthSpinBox.setSingleStep( self.getDuplexRise(conformation))
def calculate_energy(self): """ Calculate energy. """ cmd = greenmsg("Calculate Energy: ") errmsgs = ["GAMESS job aborted.", "Error: GAMESS job failed."] pset = self.pset runtyp = pset.ui.runtyp # Save runtyp (Calculate) setting to restore it later. pset.ui.runtyp = 0 # Energy calculation origCalType = self.gmsjob.Calculation self.gmsjob.Calculation = 'Energy' self.update_gamess_parms() # Run GAMESS job. Return value r: # 0 = success # 1 = job aborted # 2 = job failed. r = self.gmsjob.launch() pset.ui.runtyp = runtyp # Restore to original value self.gmsjob.Calculation = origCalType if r: # Job was aborted or an error occurred. msg = redmsg(errmsgs[r - 1]) env.history.message(cmd + msg) return self.print_energy()
def makeESPImage(self): cmd = greenmsg("ESP Image: ") atoms = self.assy.selatoms_list() if len(atoms) < 3: msg = "You must select at least 3 atoms to create an ESP Image." env.history.message(cmd + redmsg(msg)) return from analysis.ESP.ESPImage import ESPImage m = ESPImage(self.assy, atoms) m.edit() if m.cancelled: # User hit 'Cancel' button in the jig dialog. env.history.message(cmd + "Cancelled") return self.unpickall_in_GLPane() self.place_new_jig(m) # After placing the jig, remove the atom list from the jig. m.atoms = [] env.history.message(cmd + "ESP Image created.") self.assy.w.win_update() return
def update_node(self, ok_pressed=False): 'Update the POV-Ray Scene node.' self.set_params( self.node, self.gather_parameters()) ini, pov, out = self.node.get_povfile_trio() # If the node was renamed, rename the POV-Ray Scene file name, too. # Don't do this if the "Preview" button was pressed since the user could later # hit "Cancel". In that case we'd loose the original .pov file, which would not be good. # Mark 060702. if ok_pressed and self.originalName != self.node.name: if os.path.isfile(self.originalPov): if os.path.isfile(pov): # Normally, I'd never allow the user to delete an existing POV-Ray Scene file without asking. # For A8 I'll allow it since I've run out of time. # This will be fixed when Bruce implements the new File class in A9 (or later). Mark 060702. os.remove(pov) os.rename(self.originalPov, pov) # Write the POV-Ray Scene (.pov) file if this is a new node or if the node's ".pov" file doesn't exist. # Possible ways the ".pov" file could be missing from an existing node: # 1. the user renamed the node in the Model Tree, or # 2. the POV-Ray Scene node was deleted, which deletes the file in self.kill(), and then Undo was pressed, or # 3. the ".pov" file was deleted by the user another way (via OS). # In the future, the POV-Ray Scene should save the view quat in the MMP (info) record. Then it # would always be possible to regenerate the POV-Ray Scene file from the MMP record, even if # the node's .pov file didn't exist on disk anymore. Mark 060701. if self.node_is_new or not os.path.exists(pov): errorcode, filename_or_errortext = self.node.write_povrayscene_file() if errorcode: # The Pov-Ray Scene file could not be written, so remove the node. self.remove_node() env.history.message( self.cmdname + redmsg(filename_or_errortext) ) return
def unselectConnected(self, atomlist=None): """ Unselect any atom that can be reached from any currently selected atom through a sequence of bonds. If <atomlist> is supplied, use it instead of the currently selected atoms. """ cmd = greenmsg("Unselect Connected: ") if atomlist is None and not self.selatoms: msg = redmsg("No atoms selected") env.history.message(cmd + msg) return if atomlist is None: # test for None since atomlist can be an empty list. atomlist = self.selatoms.values() catoms = self.getConnectedAtoms(atomlist) if not len(catoms): return natoms = 0 for atom in catoms[:]: if atom.picked: atom.unpick() if not atom.picked: # Just in case a selection filter was applied to this atom. natoms += 1 from platform_dependent.PlatformDependent import fix_plurals info = fix_plurals( "%d atom(s) unselected." % natoms) env.history.message( cmd + info) self.o.gl_update()
def model_changed(self): """ @see: DnaSegment_EditCommand.model_changed() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s"%(why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg)
def setup(self, pov=None): """ Show the Properties Manager dialog. If <pov> is supplied, get the parameters from it and load the dialog widgets. """ if not self.win.assy.filename: env.history.message(self.cmdname + redmsg( "Can't insert POV-Ray Scene until the current part has been saved." )) return if not pov: self.node_is_new = True from model.PovrayScene import PovrayScene self.node = PovrayScene(self.win.assy, None) else: self.node_is_new = False self.node = pov self.name = self.originalName = self.node.name ini, self.originalPov, out = self.node.get_povfile_trio() self.width, self.height, self.output_type = self.node.get_parameters() self.update_widgets() self.previousParams = params = self.gather_parameters() self.show()
def command_for_insert_menu(self): """ Run an Insert Whatever menu command to let the user generate things using this plugin. """ if self.errorcode: env.history.message(redmsg("Plugin %r is permanently disabled due to this error, reported previously: %s" % \ (self.plugin_name, self.errortext))) return self.create_working_directory_if_needed() assert not self.errorcode if debug_run(): print 'ought to insert a', self.what_we_generate self.make_dialog_if_needed() dialog = self.dialog ###e Not yet properly handled: retaining default values from last time it was used. (Should pass dict of them to the maker.) dialog.set_defaults({}) ### IMPLEM controller = GeneratorController(self.win, dialog, self) # Note: this needs both self and the dialog, to be inited. # So it takes care of telling the dialog to control it (and not some prior controller). dialog.show() # now it's able to take commands and run its callbacks; that does not happen inside this method, though, does it? # hmm, good question... if it's modal, this makes things easier (re preview and bug protection)... # and it means the undo wrapping was ok... but what do we do here to make it modal? # 1. find out by test if other generators are modal. # 2. find out from code, how. pass###e
def moveAbsolute(self): """ Move selected chunk(s), jig(s) to absolute X, Y, and Z by computing the bbox center of everything as if they were one big chunk, then move everything as a unit. """ movables = self.graphicsMode.getMovablesForLeftDragging() if not movables: env.history.message(redmsg("No chunks or movable jigs selected.")) return ## Compute bbox for selected chunk(s). bbox = BBox() for m in movables: if hasattr(m, "bbox"): # Fixes bug 1990. Mark 060702. bbox.merge(m.bbox) pt1 = bbox.center( ) # pt1 = center point for bbox of selected chunk(s). pt2 = self.propMgr.get_move_xyz() # pt2 = X, Y, Z values from PM offset = pt2 - pt1 # Compute offset for translating the selection self.assy.translateSpecifiedMovables(offset, movables=movables) # Print history message about what happened. if len(movables) == 1: msg = "[%s] moved to [X: %.2f] [Y: %.2f] [Z: %.2f]" % ( movables[0].name, pt2[0], pt2[1], pt2[2]) else: msg = "Selected chunks/jigs moved by offset [X: %.2f] [Y: %.2f] [Z: %.2f]" % ( offset[0], offset[1], offset[2]) env.history.message(msg) self.o.gl_update() return
def debug_make_BorrowerChunk_raw(do_addmol=True): win = env.mainwindow() atomset = win.assy.selatoms if not atomset: env.history.message( redmsg( "Need selected atoms to make a BorrowerChunk (for debugging only)" )) else: atomset = dict( atomset ) # copy it, since we shouldn't really add singlets to assy.selatoms... for atom in atomset.values( ): # not itervalues, we're changing it in the loop! # BTW Python is nicer about this than I expected: # exceptions.RuntimeError: dictionary changed size during iteration for bp in atom.singNeighbors( ): # likely bugs if these are not added into the set! atomset[bp.key] = bp assy = atom.molecule.assy # these are all the same, and we do this at least once chunk = BorrowerChunk(assy, atomset) if do_addmol: win.assy.addmol(chunk) import __main__ __main__._bc = chunk env.history.message( orangemsg("__main__._bc = %s (for debugging only)" % quote_html(safe_repr(chunk)))) win.win_update() #k is this done by caller? return
def makeSimMovie(self): ####@@@@ some of this should be a Movie method since it uses attrs of Movie... #bruce 050324 made this from the Part method makeSimMovie. # It's called only from self.run() above; not clear it should be a separate method, # or if it is, that it's split from the caller at the right boundary. suffix = self.part.movie_suffix() if suffix is None: #bruce 050316 temporary kluge msg = redmsg( "Simulator is not yet implemented for clipboard items.") env.history.message(self.cmdname + ": " + msg) return -1 ###@@@ else use suffix below! self.simcntl = SimSetup(self.win, self.part, suffix = suffix) # this now has its own sticky params, doesn't need previous_movie [bruce 060601, fixing bug 1840] # Open SimSetup dialog [and run it until user dismisses it] movie = self.simcntl.movie # always a Movie object, even if user cancelled the dialog if movie.cancelled: # user hit Cancel button in SimSetup Dialog. No history msg went out; caller will do that. movie.destroy() return -1 r = writemovie(self.part, movie, print_sim_warnings = True, cmdname = self.cmdname) # not passing mtype means "run dynamic sim (not minimize), make movie" ###@@@ bruce 050324 comment: maybe should do following in that function too if not r: # Movie file created. Initialize. ###@@@ bruce 050325 comment: following mods private attrs, needs cleanup. movie.IsValid = True # Movie is valid.###@@@ bruce 050325 Q: what exactly does this (or should this) mean? ###@@@ bruce 050404: need to make sure this is a new obj-- if not always and this is not init False, will cause bugs self.movie = movie # bruce 050324 added this # it's up to caller to store self.movie in self.assy.current_movie if it wants to. return r
def _update_UI_do_updates(self): """ @see: Command_PropertyManager._update_UI_do_updates() @see: DnaSegment_EditCommand.command_update_UI() @see: DnaSegment_EditCommand.hasResizableStructure() @see: self._current_model_changed_params() """ currentParams = self._current_model_changed_params() #Optimization. Return from the model_changed method if the #params are the same. if same_vals(currentParams, self._previous_model_changed_params): return isStructResizable, why_not = currentParams #update the self._previous_model_changed_params with this new param set. self._previous_model_changed_params = currentParams if not isStructResizable: #disable all widgets if self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(False) msg = redmsg("DnaSegment is not resizable. Reason: %s" % (why_not)) self.updateMessage(msg) else: if not self._pmGroupBox1.isEnabled(): self._pmGroupBox1.setEnabled(True) msg = "Use resize handles to resize the segment. Drag any axis or sugar"\ " atom for translation or rotation about axis respectively. Dragging"\ " any bond will freely move the whole segment." self.updateMessage(msg)