class MinimizeEnergyProp(QDialog, Ui_MinimizeEnergyPropDialog): cmdname = greenmsg("Minimize Energy: ") # WARNING: self.cmdname might be used by one of the superclasses plain_cmdname = "Minimize Energy" #@sponsor_keyword = None def __init__(self, win): QDialog.__init__(self, win) # win is parent. self.setupUi(self) self.watch_motion_buttongroup = QButtonGroup() self.watch_motion_buttongroup.setExclusive(True) for obj in self.watch_motion_groupbox.children(): if isinstance(obj, QAbstractButton): self.watch_motion_buttongroup.addButton(obj) #fix some icon problems self.setWindowIcon( geticon('ui/border/MinimizeEnergy.png')) self.connect(self.cancel_btn, SIGNAL("clicked()"), self.cancel_btn_clicked) self.connect(self.ok_btn, SIGNAL("clicked()"), self.ok_btn_clicked) self.connect(self.restore_btn, SIGNAL("clicked()"), self.restore_defaults_btn_clicked) self.whatsthis_btn.setIcon( geticon('ui/actions/Properties Manager/WhatsThis.png')) self.whatsthis_btn.setIconSize(QSize(22, 22)) self.whatsthis_btn.setToolTip('Enter "What\'s This?" help mode') self.connect(self.whatsthis_btn, SIGNAL("clicked()"), QWhatsThis.enterWhatsThisMode) connect_checkbox_with_boolean_pref( self.electrostaticsForDnaDuringMinimize_checkBox, electrostaticsForDnaDuringMinimize_prefs_key) connect_checkbox_with_boolean_pref( self.enableNeighborSearching_check_box, neighborSearchingInGromacs_prefs_key) self.connect(self.minimize_engine_combobox, SIGNAL("activated(int)"), self.update_minimize_engine) self.minimize_engine_combobox.setCurrentIndex( env.prefs[Minimize_minimizationEngine_prefs_key]) self.connect(self.endRmsDoubleSpinBox, SIGNAL("valueChanged(double)"), self.changeEndRms) self.connect(self.endMaxDoubleSpinBox, SIGNAL("valueChanged(double)"), self.changeEndMax) self.connect(self.cutoverRmsDoubleSpinBox, SIGNAL("valueChanged(double)"), self.changeCutoverRms) self.connect(self.cutoverMaxDoubleSpinBox, SIGNAL("valueChanged(double)"), self.changeCutoverMax) self.endRmsDoubleSpinBox.setSpecialValueText("Automatic") self.endMaxDoubleSpinBox.setSpecialValueText("Automatic") self.cutoverRmsDoubleSpinBox.setSpecialValueText("Automatic") self.cutoverMaxDoubleSpinBox.setSpecialValueText("Automatic") self.win = win self.previousParams = None self.setup_ruc() self.seltype = 'All' self.minimize_selection_enabled = True #bruce 080513 # Assign "What's This" text for all widgets. from commands.MinimizeEnergy.WhatsThisText_for_MinimizeEnergyDialog import whatsThis_MinimizeEnergyDialog whatsThis_MinimizeEnergyDialog(self) self.update_widgets() # to make sure self attrs are set return def setup_ruc(self): """ #doc """ #bruce 060705 use new common code, if it works from widgets.widget_controllers import realtime_update_controller self.ruc = realtime_update_controller( #( self.update_btngrp, self.update_number_spinbox, self.update_units_combobox ), ( self.watch_motion_buttongroup, self.update_number_spinbox, self.update_units_combobox ), self.watch_motion_groupbox, Minimize_watchRealtimeMinimization_prefs_key ) ## can't do this yet: self.ruc.set_widgets_from_update_data( self.previous_movie._update_data ) # includes checkbox # for A8, only the checkbox will be persistent; the others will be sticky only because the dialog is not remade at runtime return def setup(self): """ Setup and show the Minimize Energy dialog. """ # Get widget parameters, update widgets, save previous parameters (for Restore Defaults) and show dialog. # set up default & enabled choices for Minimize Selection vs. Min All # (details revised to fix nfr bug 2848, item 1, bruce 080513; # prior code used selection nonempty to determine default seltype) selection = self.win.assy.selection_from_glpane() # a compact rep of the currently selected subset of the Part's stuff if selection.nonempty(): ## self.seltype = 'Sel' self.seltype = 'All' self.minimize_selection_enabled = True else: self.seltype = 'All' self.minimize_selection_enabled = False self.update_widgets() # only the convergence criteria, for A8, plus All/Sel command from self.seltype self.previousParams = self.gather_parameters() # only used in case Cancel wants to restore them; only conv crit for A8 self.exec_() # Show dialog as a modal dialog. return def gather_parameters(self): ###e should perhaps include update_data from ruc (not sure it's good) -- but no time for A8 """ Returns a tuple with the current parameter values from the widgets. Also sets those in env.prefs. Doesn't do anything about self.seltype, since that is a choice of command, not a parameter for a command. """ return tuple([env.prefs[key] for key in (endRMS_prefs_key, endMax_prefs_key, cutoverRMS_prefs_key, cutoverMax_prefs_key)]) def update_widgets(self, update_seltype = True): """ Update the widgets using the current env.prefs values and self attrs. """ if update_seltype: if self.seltype == 'All': self.minimize_all_rbtn.setChecked(1) else: # note: this case might no longer ever happen after today's # change, but I'm not sure. Doesn't matter. [bruce 080513] self.minimize_sel_rbtn.setChecked(1) self.minimize_sel_rbtn.setEnabled( self.minimize_selection_enabled) pass # Convergence Criteria groupbox # WARNING: some of the following code is mostly duplicated by Preferences code self.endrms = get_pref_or_optval(endRMS_prefs_key, -1.0, 0.0) self.endRmsDoubleSpinBox.setValue(self.endrms) self.endmax = get_pref_or_optval(endMax_prefs_key, -1.0, 0.0) self.endMaxDoubleSpinBox.setValue(self.endmax) self.cutoverrms = get_pref_or_optval(cutoverRMS_prefs_key, -1.0, 0.0) self.cutoverRmsDoubleSpinBox.setValue(self.cutoverrms) self.cutovermax = get_pref_or_optval(cutoverMax_prefs_key, -1.0, 0.0) self.cutoverMaxDoubleSpinBox.setValue(self.cutovermax) self.update_minimize_engine() ###e also watch in realtime prefs for this -- no, thats in another method for now return def ok_btn_clicked(self): """ Slot for OK button """ QDialog.accept(self) if env.debug(): print "ok" self.gather_parameters() ### kluge: has side effect on env.prefs # (should we pass these as arg to Minimize_CommandRun rather than thru env.prefs??) if debug_flags.atom_debug: print "debug: reloading runSim & sim_commandruns on each use, for development" import simulation.runSim as runSim reload_once_per_event(runSim) # bug: only works some of the times runSim.py is modified, # don't know why; might be that sim_commandruns.py # also needs to be modified, but touching them both # doesn't seem to work consistently either. # [bruce 080520] import simulation.sim_commandruns as sim_commandruns reload_once_per_event(sim_commandruns) from simulation.sim_commandruns import Minimize_CommandRun # do this in gather? if self.minimize_all_rbtn.isChecked(): self.seltype = 'All' seltype_name = "All" else: self.seltype = 'Sel' seltype_name = "Selection" self.win.assy.current_command_info(cmdname = self.plain_cmdname + " (%s)" % seltype_name) # cmdname for Undo update_cond = self.ruc.get_update_cond_from_widgets() engine = self.minimize_engine_combobox.currentIndex() env.prefs[Minimize_minimizationEngine_prefs_key] = engine cmdrun = Minimize_CommandRun( self.win, self.seltype, type = 'Minimize', update_cond = update_cond, engine = engine) cmdrun.run() return def cancel_btn_clicked(self): """ Slot for Cancel button """ if env.debug(): print "cancel" # restore values we grabbed on entry. for key,val in zip((endRMS_prefs_key, endMax_prefs_key, cutoverRMS_prefs_key, cutoverMax_prefs_key), self.previousParams): env.prefs[key] = val self.update_widgets(update_seltype = False) #k might not matter since we're about to hide it, but can't hurt QDialog.reject(self) return def restore_defaults_btn_clicked(self): """ Slot for Restore Defaults button """ # restore factory defaults # for A8, only for conv crit, not for watch motion settings self.minimize_engine_combobox.setCurrentIndex(0) # ND1 env.prefs.restore_defaults([endRMS_prefs_key, endMax_prefs_key, cutoverRMS_prefs_key, cutoverMax_prefs_key]) self.update_widgets(update_seltype = False) return # Dialog slots def update_minimize_engine(self, ignoredIndex = 0): """ Slot for the Minimize Engine comobox. """ engineIndex = self.minimize_engine_combobox.currentIndex() if engineIndex == 0: # NanoDynamics-1 # Minimize options widgets. self.electrostaticsForDnaDuringMinimize_checkBox.setEnabled(False) self.enableNeighborSearching_check_box.setEnabled(False) # Watch minimize in real time widgets. self.watch_motion_groupbox.setEnabled(True) # Converence criteria widgets self.endMaxDoubleSpinBox.setEnabled(True) self.cutoverRmsDoubleSpinBox.setEnabled(True) self.cutoverMaxDoubleSpinBox.setEnabled(True) else: # GROMACS # Minimize options widgets. self.electrostaticsForDnaDuringMinimize_checkBox.setEnabled(True) self.enableNeighborSearching_check_box.setEnabled(True) # Watch minimize in real time widgets. self.watch_motion_groupbox.setEnabled(False) # Converence criteria widgets self.endMaxDoubleSpinBox.setEnabled(False) self.cutoverRmsDoubleSpinBox.setEnabled(False) self.cutoverMaxDoubleSpinBox.setEnabled(False) return def changeEndRms(self, endRms): """ Slot for EndRMS. """ if endRms: env.prefs[endRMS_prefs_key] = endRms else: env.prefs[endRMS_prefs_key] = -1.0 return def changeEndMax(self, endMax): """ Slot for EndMax. """ if endMax: env.prefs[endMax_prefs_key] = endMax else: env.prefs[endMax_prefs_key] = -1.0 return def changeCutoverRms(self, cutoverRms): """ Slot for CutoverRMS. """ if cutoverRms: env.prefs[cutoverRMS_prefs_key] = cutoverRms else: env.prefs[cutoverRMS_prefs_key] = -1.0 return def changeCutoverMax(self, cutoverMax): """ Slot for CutoverMax. """ if cutoverMax: env.prefs[cutoverMax_prefs_key] = cutoverMax else: env.prefs[cutoverMax_prefs_key] = -1.0 return pass # end of class MinimizeEnergyProp
class SimSetup(QDialog, Ui_SimSetupDialog): # before 050325 this class was called runSim """ The "Run Dynamics" dialog class for setting up and launching a simulator run. """ def __init__(self, win, part, previous_movie = None, suffix = ""): """ use previous_movie (if passed) for default values, otherwise use the same ones last ok'd by user (whether or not that sim got aborted), or default values if that never happened in this session; on success or failure, make a new Movie and store it as self.movie """ QDialog.__init__(self, win) # win is parent. self.setupUi(self) self.setWindowIcon(geticon('ui/border/RunDynamics.png')) self.whatsthis_btn.setIcon( geticon('ui/actions/Properties Manager/WhatsThis.png')) self.whatsthis_btn.setIconSize(QSize(22, 22)) self.whatsthis_btn.setToolTip('Enter "What\'s This?" help mode') self.connect(self.whatsthis_btn, SIGNAL("clicked()"), QWhatsThis.enterWhatsThisMode) self.watch_motion_buttongroup = QButtonGroup() self.watch_motion_buttongroup.setExclusive(True) for obj in self.watch_motion_groupbox.children(): if isinstance(obj, QAbstractButton): self.watch_motion_buttongroup.addButton(obj) self.connect(self.run_sim_btn,SIGNAL("clicked()"),self.createMoviePressed) self.connect(self.cancel_btn,SIGNAL("clicked()"),self.close) qt4todo('self.connect(self.watch_motion_groupbox,SIGNAL("toggled(bool)"),self.setEnabled) ???') self.watch_motion_groupbox.setEnabled(True) ## self.part = part # not yet needed, though in future we might display info # about this Part in the dialog, to avoid confusion # if it's not the main Part. connect_checkbox_with_boolean_pref(self.potential_energy_checkbox, Potential_energy_tracefile_prefs_key) connect_checkbox_with_boolean_pref( self.electrostaticsForDnaDuringDynamics_checkBox, electrostaticsForDnaDuringDynamics_prefs_key) self.assy = part.assy # used only for assy.filename self.suffix = suffix self.previous_movie = previous_movie or _stickyParams or Movie(self.assy) # used only for its parameter settings # note: as of bruce 060601 fixing bug 1840, previous_movie is no longer ever passed by caller. self.movie = Movie(self.assy) # public attr used by client code after we return; always a Movie even on failure. # (we need it here since no extra method runs on failure, tho that could probably be fixed) # bruce 050325 changes: # We make a new Movie here (but only when we return with success). # But we use default param settings from prior movie. # Caller should pass info about default filename (including uniqueness # when on selection or in clipboard item) -- i.e. the suffix. # We should set the params and filename using a Movie method, or warn it we did so, # or do them in its init... not yet cleaned up. ###@@@ # self.movie is now a public attribute. #bruce 050329 comment: couldn't we set .movie to None, until we learn we succeeded? ###e ###@@@ self.setup() self.watch_motion_groupbox.setWhatsThis( """<b>Watch motion in real time</b> <p> Enables real time graphical updates during simulation runs. """) self.update_number_spinbox.setWhatsThis( """<b>Update every <i>n units.</u></b> <p> Specify how often to update the model during the simulation. This allows the user to monitor simulation results while the simulation is running. </p>""") self.update_units_combobox.setWhatsThis( """<b>Update every <i>n units.</u></b> <p> Specify how often to update the model during the simulation. This allows the user to monitor simulation results while the simulation is running. </p>""") self.update_every_rbtn.setWhatsThis( """<b>Update every <i>n units.</u></b> <p> Specify how often to update the model during the simulation. This allows the user to monitor simulation results while the simulation is running.</p>""") self.update_asap_rbtn.setWhatsThis( """<b>Update as fast as possible</b> <p> Update every 2 seconds, or faster (up to 20x/sec) if it doesn't slow down the simulation by more than 20%. </p>""") self.temperatureSpinBox.setWhatsThis( """<b>Temperature</b> <p> The temperature of the simulation in Kelvin (300 K = room temperature)</p>""") self.totalFramesSpinBox.setWhatsThis( """<b>Total frames</b> <p> The total number of (movie) frames to create for the simulation run. </p>""") self.stepsPerFrameDoubleSpinBox.setWhatsThis( """<b>Steps per frame</b> <p> The time duration between frames in femtoseconds. </p>""") self.setWhatsThis( """<b>Run Dynamics</b> <p> The is the main dialog for configuring and launching a Molecular Dynamics simulation run. Specify the simulation parameters and click <b>Run Simulation</b> to launch.</p> <p> <img source=\"ui/actions/Simulation/PlayMovie.png\"><br> The <b>Play Movie</b> command can be used to play back the simulation. </p>""") if not debug_pref("GROMACS: Enable for Run Dynamics", Choice_boolean_False, prefs_key=True): # Hide the Simulation engine groupbox altogether. self.md_engine_groupbox.setHidden(True) self.exec_() def setup(self): self.movie.cancelled = True # We will assume the user will cancel #bruce 050324: fixed KnownBug item 27 by making these call setValue, not assign to it: # If the sim parameters change, they need to be updated in all places marked "SIMPARAMS" # Movie.__init__ (movie.py), toward the end # SimSetup.setup (SimSetup.py) # FakeMovie.__init (runSim.py) self.totalFramesSpinBox.setValue( self.previous_movie.totalFramesRequested ) self.temperatureSpinBox.setValue( self.previous_movie.temp ) self.stepsPerFrameDoubleSpinBox.setValue( self.previous_movie.stepsper / 10.0 ) # self.timestepSB.setValue( self.previous_movie.timestep ) # Not supported in Alpha # new checkboxes for Alpha7, circa 060108 #self.create_movie_file_checkbox.setChecked( self.previous_movie.create_movie_file ) # whether to store movie file (see NFR/bug 1286). [bruce & mark 060108] # create_movie_file_checkbox removed for A7 (bug 1729). mark 060321 ##e the following really belongs in the realtime_update_controller, # and the update_cond is not the best thing to set this from; # but we can leave it here, then let the realtime_update_controller override it if it knows how. [now it does] self.watch_motion_groupbox.setChecked( self.previous_movie.watch_motion ) # whether to move atoms in realtime try: #bruce 060705 use new common code, if it works from widgets.widget_controllers import realtime_update_controller self.ruc = realtime_update_controller( ( self.watch_motion_buttongroup, self.update_number_spinbox, self.update_units_combobox ), self.watch_motion_groupbox # no prefs key for checkbox ) self.ruc.set_widgets_from_update_data( self.previous_movie._update_data ) # includes checkbox except: print_compact_traceback( "bug; reverting to older code in simsetep setup: ") if self.previous_movie._update_data: update_number, update_units, update_as_fast_as_possible_data, watchjunk = self.previous_movie._update_data self.watch_motion_groupbox.setChecked(watchjunk) ###060705 self.watch_motion_groupbox.setButton( update_as_fast_as_possible_data) self.update_number_spinbox.setValue( update_number) self.update_units_combobox.setCurrentText( update_units) #k let's hope this changes the current choice, not the popup menu item text for the current choice! return def createMoviePressed(self): """ Creates a DPB (movie) file of the current part. [Actually only saves the params and filename which should be used by the client code (in writemovie?) to create that file.] The part does not have to be saved as an MMP file first, as it used to. """ ###@@@ bruce 050324 comment: Not sure if/when user can rename the file. QDialog.accept(self) if self.simulation_engine_combobox.currentIndex() == 1: # GROMACS was selected as the simulation engine. # # NOTE: This code is just for demo and prototyping purposes - the # real approach will be architected and utilize plugins. # # Brian Helfrich 2007-04-06 # from simulation.GROMACS.GROMACS import GROMACS gmx = GROMACS(self.assy.part) gmx.run("md") else: # NanoDynamics-1 was selected as the simulation engine # errorcode, partdir = self.assy.find_or_make_part_files_directory() self.movie.cancelled = False # This is the only way caller can tell we succeeded. self.movie.totalFramesRequested = self.totalFramesSpinBox.value() self.movie.temp = self.temperatureSpinBox.value() self.movie.stepsper = self.stepsPerFrameDoubleSpinBox.value() * 10.0 self.movie.print_energy = self.potential_energy_checkbox.isChecked() # self.movie.timestep = self.timestepSB.value() # Not supported in Alpha #self.movie.create_movie_file = self.create_movie_file_checkbox.isChecked() # removed for A7 (bug 1729). mark 060321 self.movie.create_movie_file = True # compute update_data and update_cond, using new or old code try: # try new common code for this, bruce 060705 ruc = self.ruc update_cond = ruc.get_update_cond_from_widgets() assert update_cond or (update_cond is False) ###@@@ remove when works, and all the others like this # note, if those widgets are connected to env.prefs, that's not handled here or in ruc; # I'm not sure if they are. Ideally we'd tell ruc the prefs_keys and have it handle that too, # perhaps making it a long-lived object (though that might not be necessary). update_data = ruc.get_update_data_from_widgets() # redundant, but we can remove it when ruc handles prefs except: print_compact_traceback("bug using realtime_update_controller in SimSetup, will use older code instead: ") # this older code can be removed after A8 if we don't see that message #bruce 060530 use new watch_motion rate parameters self.movie.watch_motion = self.watch_motion_groupbox.isChecked() # [deprecated for setattr as of 060705] if env.debug(): print "debug fyi: sim setup watch_motion = %r" % (self.movie.watch_motion,) # This code works, but I'll try to replace it with calls to common code (above). [bruce 060705] # first grab them from the UI update_as_fast_as_possible_data = self.watch_motion_groupbox.selectedId() # 0 means yes, 1 means no (for now) # ( or -1 means neither, but that's prevented by how the button group is set up, at least when it's enabled) update_as_fast_as_possible = (update_as_fast_as_possible_data != 1) update_number = self.update_number_spinbox.value() # 1, 2, etc (or perhaps 0??) update_units = str(self.update_units_combobox.currentText()) # 'frames', 'seconds', 'minutes', 'hours' # for sake of propogating them to the next sim run: update_data = update_number, update_units, update_as_fast_as_possible_data, self.movie.watch_motion ## if env.debug(): ## print "stored _update_data %r into movie %r" % (self.movie._update_data, self.movie) ## print "debug: self.watch_motion_groupbox.selectedId() = %r" % (update_as_fast_as_possible_data,) ## print "debug: self.update_number_spinbox.value() is %r" % self.update_number_spinbox.value() # e.g. 1 ## print "debug: combox text is %r" % str(self.update_units_combobox.currentText()) # e.g. 'frames' # Now figure out what these user settings mean our realtime updating algorithm should be, # as a function to be used for deciding whether to update the 3D view when each new frame is received, # which takes as arguments the time since the last update finished (simtime), the time that update took (pytime), # and the number of frames since then (nframes, 1 or more), and returns a boolean for whether to draw this new frame. # Notes: # - The Qt progress update will be done independently of this, at most once per second (in runSim.py). # - The last frame we expect to receive will always be drawn. (This func may be called anyway in case it wants # to do something else with the info like store it somewhere, or it may not (check runSim.py for details #k), # but its return value will be ignored if it's called for the last frame.) # The details of these functions (and the UI feeding them) might be revised. # This code for setting update_cond is duplicated (inexactly) in Minimize_CommandRun.doMinimize() if update_as_fast_as_possible: # This radiobutton might be misnamed; it really means "use the old code, # i.e. not worse than 20% slowdown, with threshholds". # It's also ambiguous -- does "fast" mean "fast progress" # or "often" (which are opposites)? It sort of means "often". update_cond = ( lambda simtime, pytime, nframes: simtime >= max(0.05, min(pytime * 4, 2.0)) ) elif update_units == 'frames': update_cond = ( lambda simtime, pytime, nframes, _nframes = update_number: nframes >= _nframes ) elif update_units == 'seconds': update_cond = ( lambda simtime, pytime, nframes, _timelimit = update_number: simtime + pytime >= _timelimit ) elif update_units == 'minutes': update_cond = ( lambda simtime, pytime, nframes, _timelimit = update_number * 60: simtime + pytime >= _timelimit ) elif update_units == 'hours': update_cond = ( lambda simtime, pytime, nframes, _timelimit = update_number * 3600: simtime + pytime >= _timelimit ) else: print "don't know how to set update_cond from (%r, %r)" % (update_number, update_units) update_cond = None # revision in this old code, 060705: if not self.movie.watch_motion: update_cond = False del self.movie.watch_motion # let getattr do it # now do this, however we got update_data and update_cond: self.movie._update_data = update_data # for propogating them to the next sim run self.movie.update_cond = update_cond # used this time # end of 060705 changes suffix = self.suffix tStamp = timeStamp() if self.assy.filename and not errorcode: # filename could be an MMP or PDB file. import shutil dir, fil = os.path.split(self.assy.filename) fil, ext = os.path.splitext(fil) self.movie.filename = os.path.join(partdir, fil + '.' + tStamp + suffix + '.dpb') self.movie.origfile = os.path.join(partdir, fil + '.' + tStamp + '.orig' + ext) shutil.copy(self.assy.filename, self.movie.origfile) else: self.movie.filename = os.path.join(self.assy.w.tmpFilePath, "Untitled.%s%s.dpb" % (tStamp, suffix)) # Untitled parts usually do not have a filename #bruce 060601 fix bug 1840, also make params sticky across opening of new files global _stickyParams _stickyParams = FakeMovie(self.movie) # these will be used as default params next time, whether or not this gets aborted return pass # end of class SimSetup
class PM_ToolButtonGrid(PM_WidgetGrid): """ The PM_ToolButtonGrid widget provides a grid of tool buttons that function as an I{exclusive button group}. @see: B{PM_ElementChooser} for an example of how this is used. @todo: Fix button size issue (e.g. all buttons are sized 32 x 32). """ buttonList = [] defaultCheckedId = -1 # -1 means no checked Id setAsDefault = True def __init__(self, parentWidget, title='', buttonList=[], alignment=None, label='', labelColumn=0, spanWidth=True, checkedId=-1, setAsDefault=False, isAutoRaise=False, isCheckable=True): """ Appends a PM_ToolButtonGrid widget to the bottom of I{parentWidget}, the Property Manager Group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox @param title: The group box title. @type title: str @param buttonList: A list of I{button info lists}. There is one button info list for each button in the grid. The button info list contains the following items: 1. Button Type - in this case its 'ToolButton'(str), 2. Button Id (int), 3. Button text (str), 4. Button icon path (str), 5. Button tool tip (str), 6. Column (int), 7. Row (int). @type buttonList: list @param alignment: The alignment of the toolbutton row in the parent groupbox. Based on its value,spacer items is added to the grid layout of the parent groupbox. @type alignment: str @param label: The label for the toolbutton row. If present, it is added to the same grid layout as the rest of the toolbuttons, in column number E{0}. @type label: str @param labelColumn: The column in the parentWidget's grid layout to which this widget's label will be added. The labelColum can only be E{0} or E{1} @type labelColumn: int @param spanWidth: If True, the widget and its label will span the width of the group box. Its label will appear directly above the widget (unless the label is empty) and is left justified. @type spanWidth: bool (default False) @param checkedId: Checked button id in the button group. Default value is -1 that implies no button is checked. @type checkedId: int @param setAsDefault: If True, sets the I{checkedId} specified by the user as the default checked @type setAsDefault: boolean """ self.buttonGroup = QButtonGroup() self.buttonGroup.setExclusive(True) self.isAutoRaise = isAutoRaise self.isCheckable = isCheckable self.buttonsById = {} self.buttonsByText = {} if setAsDefault: self.setDefaultCheckedId(checkedId) PM_WidgetGrid.__init__(self, parentWidget, title, buttonList, alignment, label, labelColumn, spanWidth) def _createWidgetUsingParameters(self, widgetParams): """ Returns a tool button created using the parameters specified by the user @param widgetParams: A list of label parameters. This is a modified using the original list returned by L{self.getWidgetInfoList}. The modified list doesn't contain the row and column information. @type widgetParams: list @see: L{PM_WidgetGrid._createWidgetUsingParameters} (overrided in this method) @see: L{PM_WidgetGrid.loadWidgets} which calls this method. """ buttonFont = self.getButtonFont() buttonParams = list(widgetParams) button = self._createToolButton(buttonParams) buttonId = buttonParams[1] if self.defaultCheckedId == buttonId: button.setChecked(True) button.setFont(buttonFont) button.setAutoRaise(self.isAutoRaise) button.setCheckable(self.isCheckable) self.buttonGroup.addButton(button, buttonId) self.buttonsById[buttonId] = button self.buttonsByText[str(button.text())] = button return button def getButtonFont(self): """ Returns the font for the tool buttons in the grid. @return: Button font. @rtype: U{B{QFont}<http://doc.trolltech.com/4/qfont.html>} """ # Font for tool buttons. buttonFont = QFont(self.font()) buttonFont.setFamily(BUTTON_FONT) buttonFont.setPointSize(BUTTON_FONT_POINT_SIZE) buttonFont.setBold(BUTTON_FONT_BOLD) return buttonFont def restoreDefault(self): """ Restores the default checkedId. """ if self.setAsDefault: for buttonInfo in self.buttonList: buttonId = buttonInfo[0] if buttonId == self.defaultCheckedId: button = self.getButtonById(buttonId) button.setChecked(True) return def setDefaultCheckedId(self, checkedId): """ Sets the default checked id (button) to I{checkedId}. The current checked button is unchanged. @param checkedId: The new default id for the tool button group. @type checkedId: int """ self.setAsDefault = True self.defaultCheckedId = checkedId def checkedButton(self): """ Returns the tool button group's checked button, or E{0} if no button is checked. @return: Checked tool button or E{0} @rtype: instance of QToolButton or int """ return self.buttonGroup.checkedButton() def checkedId(self): """ Returns the id of the checkedButton(), or -1 if no button is checked. @return: The checked button Id @rtype: int """ return self.buttonGroup.checkedId() def getButtonByText(self, text): """ Returns the button with its current text set to I{text}. @return: The button, or B{None} if no button was found. @rtype: U{B{QToolButton}<http://doc.trolltech.com/4/qtoolbutton.html>} @note: If multiple buttons have the same text, only the last one is returned. """ if self.buttonsByText.has_key(text): return self.buttonsByText[text] else: return None def getButtonById(self, buttonId): """ Returns the button with the button id of I{buttonId}. return: The button, or B{None} if no button was found. rtype: U{B{QToolButton}<http://doc.trolltech.com/4/qtoolbutton.html>} """ if self.buttonsById.has_key(buttonId): return self.buttonsById[buttonId] else: return None def setButtonSize(self, width=32, height=32): """ """ for btn in self.buttonGroup.buttons(): btn.setFixedSize(QSize(width, height))
class Ui_CommandToolbar( QWidget ): """ This provides most of the User Interface for the command toolbar called in CommandToolbar class. """ def __init__(self, win): """ Constructor for class Ui_CommandToolbar. @param win: Mainwindow object @type win: L{MWsemantics} """ QWidget.__init__(self) self.win = win def setupUi(self): """ Setup the UI for the command toolbar. """ #ninad 070123 : It's important to set the Vertical size policy of the # cmd toolbar widget. otherwise the flyout QToolbar messes up the #layout (makes the command toolbar twice as big) #I have set the vertical policy as fixed. Works fine. There are some # MainWindow resizing problems for but those are not due to this #size policy AFAIK self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed) layout_cmdtoolbar = QHBoxLayout(self) layout_cmdtoolbar.setMargin(2) layout_cmdtoolbar.setSpacing(2) #See comment at the top for details about this flag if DEFINE_CONTROL_AREA_AS_A_QWIDGET: self.cmdToolbarControlArea = QWidget(self) else: self.cmdToolbarControlArea = QToolBar_WikiHelp(self) self.cmdToolbarControlArea.setAutoFillBackground(True) self.ctrlAreaPalette = self.getCmdMgrCtrlAreaPalette() self.cmdToolbarControlArea.setPalette(self.ctrlAreaPalette) self.cmdToolbarControlArea.setMinimumHeight(62) self.cmdToolbarControlArea.setMinimumWidth(380) self.cmdToolbarControlArea.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) #See comment at the top for details about this flag if DEFINE_CONTROL_AREA_AS_A_QWIDGET: layout_controlArea = QHBoxLayout(self.cmdToolbarControlArea) layout_controlArea.setMargin(0) layout_controlArea.setSpacing(0) self.cmdButtonGroup = QButtonGroup() btn_index = 0 for name in ('Build', 'Insert', 'Tools', 'Move', 'Simulation'): btn = QToolButton(self.cmdToolbarControlArea) btn.setObjectName(name) btn.setMinimumWidth(75) btn.setMaximumWidth(75) btn.setMinimumHeight(62) btn.setAutoRaise(True) btn.setCheckable(True) btn.setAutoExclusive(True) iconpath = "ui/actions/Command Toolbar/ControlArea/" + name + ".png" btn.setIcon(geticon(iconpath)) btn.setIconSize(QSize(22, 22)) btn.setText(name) btn.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) btn.setPalette(self.ctrlAreaPalette) self.cmdButtonGroup.addButton(btn, btn_index) btn_index += 1 #See comment at the top for details about this flag if DEFINE_CONTROL_AREA_AS_A_QWIDGET: layout_controlArea.addWidget(btn) else: self.cmdToolbarControlArea.layout().addWidget(btn) #following has issues. so not adding widget directly to the #toolbar. (instead adding it in its layout)-- ninad 070124 ##self.cmdToolbarControlArea.addWidget(btn) layout_cmdtoolbar.addWidget(self.cmdToolbarControlArea) #Flyout Toolbar in the command toolbar self.flyoutToolBar = FlyoutToolBar(self) layout_cmdtoolbar.addWidget(self.flyoutToolBar) #ninad 070116: Define a spacer item. It will have the exact geometry # as that of the flyout toolbar. it is added to the command toolbar # layout only when the Flyout Toolbar is hidden. It is required # to keep the 'Control Area' widget fixed in its place (otherwise, #after hiding the flyout toolbar, the layout adjusts the position of #remaining widget items) self.spacerItem = QSpacerItem(0, 0, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.spacerItem.setGeometry = self.flyoutToolBar.geometry() for btn in self.cmdButtonGroup.buttons(): if str(btn.objectName()) == 'Build': btn.setMenu(self.win.buildStructuresMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Build Commands") whatsThisTextForCommandToolbarBuildButton(btn) if str(btn.objectName()) == 'Insert': btn.setMenu(self.win.insertMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Insert Commands") whatsThisTextForCommandToolbarInsertButton(btn) if str(btn.objectName()) == 'Tools': #fyi: cmd stands for 'command toolbar' - ninad070406 self.win.cmdToolsMenu = QtGui.QMenu(self.win) self.win.cmdToolsMenu.addAction(self.win.toolsExtrudeAction) self.win.cmdToolsMenu.addAction(self.win.toolsFuseChunksAction) self.win.cmdToolsMenu.addSeparator() self.win.cmdToolsMenu.addAction(self.win.modifyMergeAction) self.win.cmdToolsMenu.addAction(self.win.modifyMirrorAction) self.win.cmdToolsMenu.addAction(self.win.modifyInvertAction) self.win.cmdToolsMenu.addAction(self.win.modifyStretchAction) btn.setMenu(self.win.cmdToolsMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Tools") whatsThisTextForCommandToolbarToolsButton(btn) if str(btn.objectName()) == 'Move': self.win.moveMenu = QtGui.QMenu(self.win) self.win.moveMenu.addAction(self.win.toolsMoveMoleculeAction) self.win.moveMenu.addAction(self.win.rotateComponentsAction) self.win.moveMenu.addSeparator() self.win.moveMenu.addAction( self.win.modifyAlignCommonAxisAction) ##self.win.moveMenu.addAction(\ ## self.win.modifyCenterCommonAxisAction) btn.setMenu(self.win.moveMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Move Commands") whatsThisTextForCommandToolbarMoveButton(btn) if str(btn.objectName()) == 'Dimension': btn.setMenu(self.win.dimensionsMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Dimensioning Commands") if str(btn.objectName()) == 'Simulation': btn.setMenu(self.win.simulationMenu) btn.setPopupMode(QToolButton.MenuButtonPopup) btn.setToolTip("Simulation Commands") whatsThisTextForCommandToolbarSimulationButton(btn) # Convert all "img" tags in the button's "What's This" text # into abs paths (from their original rel paths). # Partially fixes bug 2943. --mark 2008-12-07 # [bruce 081209 revised this -- removed mac = False] fix_QAction_whatsthis(btn) return def truncateText(self, text, length = 12, truncateSymbol = '...'): """ Truncates the tooltip text with the given truncation symbol (three dots) in the case """ #ninad 070201 This is a temporary fix. Ideally it should show the whole #text in the toolbutton. But there are some layout / size policy #problems because of which the toolbar height increases after you print #tooltip text on two or more lines. (undesirable effect) if not text: print "no text to truncate. Returning" return truncatedLength = length - len(truncateSymbol) if len(text) > length: return text[:truncatedLength] + truncateSymbol else: return text def wrapToolButtonText(self, text): """ Add a newline character at the end of each word in the toolbutton text """ #ninad 070126 QToolButton lacks this method. This is not really a #'word wrap' but OK for now. #@@@ ninad 070126. Not calling this method as it is creating an annoying #resizing problem in the Command toolbar layout. Possible solution is #to add a spacer item in a vbox layout to the command toolbar layout stringlist = text.split(" ", QString.SkipEmptyParts) text2 = QString() if len(stringlist) > 1: for l in stringlist: text2.append(l) text2.append("\n") return text2 return None ##==================================================================## #color palettes (UI stuff) for different command toolbar areas def getCmdMgrCtrlAreaPalette(self): """ Return a palette for Command Manager control area (Palette for Tool Buttons in command toolbar control area) """ #See comment at the top for details about this flag if DEFINE_CONTROL_AREA_AS_A_QWIDGET: return getPalette(None, QPalette.Window, cmdTbarCntrlAreaBtnColor ) else: return getPalette(None, QPalette.Button, cmdTbarCntrlAreaBtnColor ) def getCmdMgrSubCtrlAreaPalette(self): """ Return a palette for Command Manager sub control area (Palette for Tool Buttons in command toolbar sub control area) """ #Define the color role. Make sure to apply color to QPalette.Button #instead of QPalette.Window as it is a QToolBar. - ninad 20070619 return getPalette(None, QPalette.Button, cmdTbarSubCntrlAreaBtnColor ) def getCmdMgrCommandAreaPalette(self): """ Return a palette for Command Manager 'Commands area'(flyout toolbar) (Palette for Tool Buttons in command toolbar command area) """ return self.flyoutToolBar.getPalette()
class PM_ToolButtonGrid( PM_WidgetGrid ): """ The PM_ToolButtonGrid widget provides a grid of tool buttons that function as an I{exclusive button group}. @see: B{PM_ElementChooser} for an example of how this is used. @todo: Fix button size issue (e.g. all buttons are sized 32 x 32). """ buttonList = [] defaultCheckedId = -1 # -1 means no checked Id setAsDefault = True def __init__(self, parentWidget, title = '', buttonList = [], alignment = None, label = '', labelColumn = 0, spanWidth = True, checkedId = -1, setAsDefault = False, isAutoRaise = False, isCheckable = True ): """ Appends a PM_ToolButtonGrid widget to the bottom of I{parentWidget}, the Property Manager Group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox @param title: The group box title. @type title: str @param buttonList: A list of I{button info lists}. There is one button info list for each button in the grid. The button info list contains the following items: 1. Button Type - in this case its 'ToolButton'(str), 2. Button Id (int), 3. Button text (str), 4. Button icon path (str), 5. Button tool tip (str), 6. Column (int), 7. Row (int). @type buttonList: list @param alignment: The alignment of the toolbutton row in the parent groupbox. Based on its value,spacer items is added to the grid layout of the parent groupbox. @type alignment: str @param label: The label for the toolbutton row. If present, it is added to the same grid layout as the rest of the toolbuttons, in column number E{0}. @type label: str @param labelColumn: The column in the parentWidget's grid layout to which this widget's label will be added. The labelColum can only be E{0} or E{1} @type labelColumn: int @param spanWidth: If True, the widget and its label will span the width of the group box. Its label will appear directly above the widget (unless the label is empty) and is left justified. @type spanWidth: bool (default False) @param checkedId: Checked button id in the button group. Default value is -1 that implies no button is checked. @type checkedId: int @param setAsDefault: If True, sets the I{checkedId} specified by the user as the default checked @type setAsDefault: boolean """ self.buttonGroup = QButtonGroup() self.buttonGroup.setExclusive(True) self.isAutoRaise = isAutoRaise self.isCheckable = isCheckable self.buttonsById = {} self.buttonsByText = {} if setAsDefault: self.setDefaultCheckedId(checkedId) PM_WidgetGrid.__init__(self, parentWidget , title, buttonList, alignment, label, labelColumn, spanWidth ) def _createWidgetUsingParameters(self, widgetParams): """ Returns a tool button created using the parameters specified by the user @param widgetParams: A list of label parameters. This is a modified using the original list returned by L{self.getWidgetInfoList}. The modified list doesn't contain the row and column information. @type widgetParams: list @see: L{PM_WidgetGrid._createWidgetUsingParameters} (overrided in this method) @see: L{PM_WidgetGrid.loadWidgets} which calls this method. """ buttonFont = self.getButtonFont() buttonParams = list(widgetParams) button = self._createToolButton(buttonParams) buttonId = buttonParams[1] if self.defaultCheckedId == buttonId: button.setChecked(True) button.setFont(buttonFont) button.setAutoRaise(self.isAutoRaise) button.setCheckable(self.isCheckable) self.buttonGroup.addButton(button, buttonId) self.buttonsById[buttonId] = button self.buttonsByText[str(button.text())] = button return button def getButtonFont(self): """ Returns the font for the tool buttons in the grid. @return: Button font. @rtype: U{B{QFont}<http://doc.trolltech.com/4/qfont.html>} """ # Font for tool buttons. buttonFont = QFont(self.font()) buttonFont.setFamily(BUTTON_FONT) buttonFont.setPointSize(BUTTON_FONT_POINT_SIZE) buttonFont.setBold(BUTTON_FONT_BOLD) return buttonFont def restoreDefault(self): """ Restores the default checkedId. """ if self.setAsDefault: for buttonInfo in self.buttonList: buttonId = buttonInfo[0] if buttonId == self.defaultCheckedId: button = self.getButtonById(buttonId) button.setChecked(True) return def setDefaultCheckedId(self, checkedId): """ Sets the default checked id (button) to I{checkedId}. The current checked button is unchanged. @param checkedId: The new default id for the tool button group. @type checkedId: int """ self.setAsDefault = True self.defaultCheckedId = checkedId def checkedButton(self): """ Returns the tool button group's checked button, or E{0} if no button is checked. @return: Checked tool button or E{0} @rtype: instance of QToolButton or int """ return self.buttonGroup.checkedButton() def checkedId(self): """ Returns the id of the checkedButton(), or -1 if no button is checked. @return: The checked button Id @rtype: int """ return self.buttonGroup.checkedId() def getButtonByText(self, text): """ Returns the button with its current text set to I{text}. @return: The button, or B{None} if no button was found. @rtype: U{B{QToolButton}<http://doc.trolltech.com/4/qtoolbutton.html>} @note: If multiple buttons have the same text, only the last one is returned. """ if self.buttonsByText.has_key(text): return self.buttonsByText[text] else: return None def getButtonById(self, buttonId): """ Returns the button with the button id of I{buttonId}. return: The button, or B{None} if no button was found. rtype: U{B{QToolButton}<http://doc.trolltech.com/4/qtoolbutton.html>} """ if self.buttonsById.has_key(buttonId): return self.buttonsById[buttonId] else: return None def setButtonSize(self, width = 32, height = 32): """ """ for btn in self.buttonGroup.buttons(): btn.setFixedSize(QSize(width, height))
class PM_RadioButtonList(PM_GroupBox): """ The PM_RadioButtonList widget provides a list of radio buttons that function as an I{exclusive button group}. """ buttonList = [] defaultCheckedId = -1 # -1 means no checked Id setAsDefault = True labelWidget = None def __init__(self, parentWidget, title='', label='', labelColumn=0, buttonList=[], checkedId=-1, setAsDefault=False, spanWidth=True, borders=True): """ Appends a PM_RadioButtonList widget to the bottom of I{parentWidget}, the Property Manager dialog or group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox or PM_Dialog @param title: The group box title. @type title: str @param label: The label for the coordinate spinbox. @type label: str @param labelColumn: The column in the parentWidget's grid layout to which this widget's label will be added. The labelColum can only be E{0} or E{1} @type labelColumn: int @param buttonList: A list of I{button info lists}. There is one button info list for each radio button in the list. The button info list contains the following three items: 1). Button Id (int), 2). Button text (str), 3). Button tool tip (str). @type buttonList: list @param spanWidth: If True, the widget and its label will span the width of the group box. Its label will appear directly above the widget (unless the label is empty) and is left justified. @type spanWidth: bool (default False) @param borders: If true (default), this widget will have borders displayed. otherwise the won't be any outside borders around the set of radio buttons this class provides @type borders: boolean """ # Intializing label, labelColumn etc is needed before doing # PM_GroupBox.__init__. This is done so that # self.parentWidget.addPmWidget(self) done at the end of __init__ # works properly. # 'self.parentWidget.addPmWidget(self)' is done to avoid a bug where a # groupbox is always appended as the 'last widget' when its # parentWidget is also a groupbox. This is due to other PM widgets #(e.g. PM_PushButton)add themselves to their parent widget in their #__init__ using self.parentWidget.addPmWidget(self). So doing the #same thing here. More general fix is needed in PM_GroupBox code # --Ninad 2007-11-14 (comment copied from PM_coordinateSpinBoxes) self.label = label self.labelColumn = labelColumn self.spanWidth = spanWidth if label: # Create this widget's QLabel. self.labelWidget = QLabel() self.labelWidget.setText(label) PM_GroupBox.__init__(self, parentWidget, title) # These are needed to properly maintain the height of the grid if # all buttons in a row are hidden via hide(). self.vBoxLayout.setMargin(0) self.vBoxLayout.setSpacing(0) self.buttonGroup = QButtonGroup() self.buttonGroup.setExclusive(True) self.parentWidget = parentWidget self.buttonList = buttonList if setAsDefault: self.setDefaultCheckedId(checkedId) self.buttonsById = {} self.buttonsByText = {} # Create radio button list from button info. for buttonInfo in buttonList: buttonId = buttonInfo[0] buttonText = buttonInfo[1] buttonToolTip = buttonInfo[2] button = QRadioButton(self) button.setText(buttonText) button.setToolTip(buttonToolTip) # Not working. button.setCheckable(True) if checkedId == buttonId: button.setChecked(True) self.buttonGroup.addButton(button, buttonId) self.vBoxLayout.addWidget(button) self.buttonsById[buttonId] = button self.buttonsByText[buttonText] = button if isinstance(self.parentWidget, PM_GroupBox): self.parentWidget.addPmWidget(self) else: #@@ Should self be added to self.parentWidget's widgetList? #don't know. Retaining old code -- Ninad 2008-06-23 self._widgetList.append(self) self._rowCount += 1 if not borders: #reset the style sheet so that there are no borders around the #radio button set this class provides. self.setStyleSheet(self._getAlternateStyleSheet()) def restoreDefault(self): """ Restores the default checkedId. """ if self.setAsDefault: for buttonInfo in self.buttonList: buttonId = buttonInfo[0] if buttonId == self.defaultCheckedId: button = self.getButtonById(buttonId) button.setChecked(True) return def setDefaultCheckedId(self, checkedId): """ Sets the default checked id (button) to I{checkedId}. The current checked button is unchanged. @param checkedId: The new default id for the tool button group. @type checkedId: int """ self.setAsDefault = True self.defaultCheckedId = checkedId def checkedButton(self): """ Returns the tool button group's checked button, or 0 if no buttons are checked. """ return self.buttonGroup.checkedButton() def checkedId(self): """ Returns the id of the checkedButton(), or -1 if no button is checked. """ return self.buttonGroup.checkedId() def getButtonByText(self, text): """ Returns the button with its current text set to I{text}. """ if self.buttonsByText.has_key(text): return self.buttonsByText[text] else: return None def getButtonById(self, buttonId): """ Returns the button with the button id of I{buttonId}. """ if self.buttonsById.has_key(buttonId): return self.buttonsById[buttonId] else: return None def _getAlternateStyleSheet(self): """ Return the style sheet for the groupbox. This sets the following properties only: - border style - border width - border color - border radius (on corners) @see: L{PM_GroupBox._getStyleSheet} (overrided here) """ styleSheet = "QGroupBox {border-style:hidden;\ border-width: 0px;\ border-color: " ";\ border-radius: 0px;\ min-width: 10em; }" return styleSheet # End of PM_RadioButtonList ############################
class GamessProp(QDialog, Ui_GamessPropDialog): """ The Gamess Jig Properties dialog used for: - running a GAMESS energy calculation on a structure (group of atoms). - running a GAMESS optimization on a structure. - setting and saving the GAMESS parameters used for an energy calculation or optimization. """ def __init__(self): QDialog.__init__(self) self.setModal(True) self.setupUi(self) self.ecm_btngrp = QButtonGroup() self.ecm_btngrp.setExclusive(True) objId = 0 for obj in self.ecm_grpbox.children(): if isinstance(obj, QAbstractButton): self.ecm_btngrp.addButton(obj) self.ecm_btngrp.setId(obj, objId) objId +=1 self.scftyp_btngrp = QButtonGroup() self.scftyp_btngrp.setExclusive(True) objId = 0 for obj in self.scftyp_grpbox.children(): if isinstance(obj, QAbstractButton): self.scftyp_btngrp.addButton(obj) self.scftyp_btngrp.setId(obj, objId) objId +=1 self.connect(self.cancel_btn,SIGNAL("clicked()"),self.reject) self.connect(self.ecm_btngrp,SIGNAL("buttonPressed(int)"),self.set_ecmethod) self.connect(self.multi_combox,SIGNAL("activated(int)"),self.set_multiplicity) self.connect(self.run_job_btn,SIGNAL("clicked()"),self.run_job) self.connect(self.save_btn,SIGNAL("clicked()"),self.accept) self.connect(self.runtyp_combox,SIGNAL("activated(int)"),self.calculate_changed) self.connect(self.choose_color_btn,SIGNAL("clicked()"),self.change_jig_color) self.connect(self.whats_this_btn,SIGNAL("clicked()"),self.whats_this) ##self.connect(self.new_btn,SIGNAL("clicked()"),self.addServer) ##self.connect(self.exit_btn,SIGNAL("clicked()"),self.close) ##self.connect(self.server_listview,SIGNAL("currentChanged(QListViewItem*)"),self.changeServer) ##self.connect(self.engine_combox,SIGNAL("activated(const QString&)"),self.engineChanged) ##self.connect(self.del_btn,SIGNAL("clicked()"),self.deleteServer) self.sManager = ServerManager() self.servers = self.sManager.getServers() self.server = self.servers[0] self.name_linedit.setWhatsThis("""Name of the GAMESS jig.""") self.runtyp_combox.setWhatsThis("""Type of calculation, where "Energy" calculates the Energy Minima,and "Optimization" calculates the "Equilibrium Geometry".""") self.comment_linedit.setWhatsThis("""Description, also placed in the comment line of the $DATA section of the INP file.""") self.choose_color_btn.setWhatsThis("""Change the GAMESS jig color.""") self.rhf_radiobtn.setWhatsThis("""Restricted Hartree-Fock. All electrons are paired and each spatial orbital is doubly occupied. Cannot be used with multiplicities greater than 1.""") self.uhf_radiobtn.setWhatsThis("""Unrestricted Hartree-Fock. All electrons are unpaired and spatial (spin) orbitals are uniquely defined for each electron. More time consuming, but more accurate, than ROHF. """) self.rohf_radiobtn.setWhatsThis("""Restricted Open-shell Hartree-Fock. Spin-paired electrons are assigned to doubly-occupied spatial orbitals, while electrons with unpaired spins are provided unique spatial orbitals.""") self.icharg_spinbox.setWhatsThis("""The total charge of the structure to be treated quantum mechanically (ICHARG).""") self.multi_combox.setWhatsThis("""N + 1, where N is the number of unpaired electrons (MULT).""") self.memory_spinbox.setWhatsThis("""System memory reserved for calculation""") self.dirscf_checkbox.setWhatsThis("""Check this box to run the calculation in RAM and avoid hard disk usage for integral storage.""") self.gbasis_combox.setWhatsThis("""Select from among the standard Gaussian-type basis sets and semi-empirical parameters in GAMESS.""") self.checkBox10_3_2.setWhatsThis("""Reads the $HESS group from the output file of a previous GAMESS calculation. Only valid for identical molecules.""") self.checkBox10_2_2_2.setWhatsThis("""Reads the $VEC group from the output of a previous GAMESS calculation. Requires that both the molecule and basis set be identical. Useful for restarted calculations and starting orbitals for electron correlation methods.""") self.none_radiobtn.setWhatsThis("""Select this button to neglect electron correlation in the calculation.""") self.dft_radiobtn.setWhatsThis("""Select this button to perform a density functional theory calculation.""") self.mp2_radiobtn.setWhatsThis("""Select this button to perform a Second-Order Moeller Plesset calculation.""") self.dfttyp_combox.setWhatsThis("""Select an available density functional in GAMESS.""") self.gridsize_combox.setWhatsThis("""Select the grid spacing for the DFT calculation.""") self.core_electrons_checkbox.setWhatsThis("""Check this box to include both the valence and core electrons in the MP2 calculation.""") self.density_conv_combox.setWhatsThis("""Selects the accuracy of the electron density convergence for the calculation (CONV).""") self.rmsd_combox.setWhatsThis("""Gradient convergence tolerance (OPTTOL), in Hartree/Bohr. Convergence of a geometry search requires the largest component of the gradient to be less than this value, and the root mean square gradient less than 1/3 of OPTTOL. (default=0.0001)""") self.iterations_spinbox.setWhatsThis("""Maximum number of SCF iteration cycles (MAXIT).""") self.edit_input_file_cbox.setWhatsThis("""Opens the INP file generated by NanoEngineer-1 in a text editor.""") self.whats_this_btn.setWhatsThis("""What's This Help Utility""") self.run_job_btn.setWhatsThis("""Save GAMESS parameters, generates the INP file and launches the GAMESS job.""") self.save_btn.setWhatsThis("""Save GAMESS parameters and generates the INP file. It does not launch the GAMESS job.""") self.cancel_btn.setWhatsThis("""Cancels changes and closes dialog.""") def showDialog(self, job): """ Display the GAMESS Jig Properties dialog """ self.gamessJig = job.gamessJig self.job = job self.pset = self.gamessJig.pset self.win = self.gamessJig.assy.w self.glpane = self.gamessJig.assy.o if self._setup(): return self.exec_() ######Private or helper methods############################### def _setup(self): """ Setup widgets to initial (default or defined) values. Return True on error. """ #To fix bug 684 #if gamess.is_disabled(): # self.run_job_btn.setEnabled(False) #else: # self.run_job_btn.setEnabled(True) self.jig_attrs = self.gamessJig.copyable_attrs_dict() # Save the jig's attributes in case of Cancel. # Jig color self.original_normcolor = self.gamessJig.normcolor self.jig_QColor = RGBf_to_QColor(self.gamessJig.normcolor) # Used as default color by Color Chooser self.jig_color_pixmap = get_widget_with_color_palette( self.jig_color_pixmap, self.jig_QColor) # Init the top widgets (name, runtyp drop box, comment) self.name_linedit.setText(self.gamessJig.name) self.runtyp_combox.setCurrentIndex(self.pset.ui.runtyp) # RUNTYP self.calculate_changed(self.pset.ui.runtyp) self.comment_linedit.setText(self.pset.ui.comment) # Electronic Structure Properties section. btn = self.scftyp_btngrp.button(self.pset.ui.scftyp)# RHF, UHF, or ROHF btn.setChecked(True) self.icharg_spinbox.setValue(self.pset.ui.icharg) # Charge self.multi_combox.setCurrentIndex(self.pset.ui.mult) # Multiplicity # Disable RHF if multiplicity is not the first item. if self.pset.ui.mult == 0: self.rhf_radiobtn.setEnabled(1) # Enable RHF else: self.rhf_radiobtn.setEnabled(0) # Disable RHF # System Memory and Usage self.dirscf_checkbox.setChecked(self.pset.ui.dirscf) # DIRSCF self.memory_spinbox.setValue(self.pset.ui.memory) # Memory # Electron Correlation Method and Basis Set ecm = self.pset.ui.ecm btn = self.ecm_btngrp.button(self.pset.ui.ecm)# None, DFT or MP2 btn.setChecked(True) self.set_ecmethod(self.pset.ui.ecm) # None, DFT or MP2 self.gbasis_combox.setCurrentIndex(self.pset.ui.gbasis) # Basis set # Load the combo box with all the valid DFT functions. self._load_dfttyp_combox() self.dfttyp_combox.setCurrentIndex(self.pset.ui.dfttyp) # DFT Functional self.gridsize_combox.setCurrentIndex(self.pset.ui.gridsize) # Grid Size self.core_electrons_checkbox.setChecked(self.pset.ui.ncore) # Include core electrons # Convergence Criteria self.density_conv_combox.setCurrentIndex(self.pset.ui.conv) # Density Convergence self.rmsd_combox.setCurrentIndex(self.pset.ui.rmsdconv) # RMSD Convergence self.iterations_spinbox.setValue(self.pset.ui.iterations) # Iterations # These have been removed per discussions with Damian. # Mark 050628 # self.extrap_checkbox.setChecked(self.pset.ui.extrap) # EXTRAP # self.damp_checkbox.setChecked(self.pset.ui.damp) # DAMP # self.diis_checkbox.setChecked(self.pset.ui.diis) # DIIS # self.shift_checkbox.setChecked(self.pset.ui.shift) # SHIFT # self.soscf_checkbox.setChecked(self.pset.ui.soscf) # SOSCF # self.rstrct_checkbox.setChecked(self.pset.ui.rstrct) # RSTRCT # Load the server combo box #self._reloadServerList() # Not used in A6. Mark. # If there is an error, return 1. NIY. return 0 def _reloadServerList(self): """ Load the server combo box """ self.server_combox.clear() for s in self.servers: self.server_combox.insertItem(100, s.hostname + "-" + s.engine) # 100 makes sure item is appended to list. [mark 2007-05-04] if self.server not in self.servers: self.server = self.servers[0] indx = self.servers.index(self.server) self.server_combox.setCurrentIndex(indx) def _load_dfttyp_combox(self): """ Load list of DFT function in a combobox widget """ self.dfttyp_combox.clear() # Clear all combo box items if self.server.engine == 'GAMESS': for f in gms_dfttyp_items: self.dfttyp_combox.insertItem(100, f) # 100 makes sure item is appended to list. [mark 2007-05-04] elif self.server.engine == 'PC GAMESS': for f in pcgms_dfttyp_items: self.dfttyp_combox.insertItem(100, f) # 100 makes sure item is appended to list. [mark 2007-05-04] else: print "load_dfttyp_combox: Unknown GAMESS Version. Loading GAMES DFT functionals." for f in gms_dfttyp_items: self.dfttyp_combox.insertItem(100, f) # 100 makes sure item is appended to list. [mark 2007-05-04] def _update_gbasis_list(self, val): """ Add/remove AM1 and PM3 to/from the gbasis list. """ citem = self.gbasis_combox.currentIndex() if val == DFT or val == MP2: if self.gbasis_combox.count() == 18: self.gbasis_combox.removeItem(0) self.gbasis_combox.removeItem(0) self.gbasis_combox.setCurrentIndex(max(0, citem-2)) else: if self.gbasis_combox.count() != 18: self.gbasis_combox.insertItem(0,"PM3") # 0 prepends item to list. self.gbasis_combox.insertItem(0,"AM1") self.gbasis_combox.setCurrentIndex(citem+2) def _save_ui_settings(self): """ Save the UI settings in the Gamess jig pset. There is one setting for each pset. """ self.pset.ui.comment = str(self.comment_linedit.text()) # Description self.pset.ui.runtyp = self.runtyp_combox.currentIndex() # RUNTYP = Energy or Optimize # Electronic Structure Props and Basis Set section. self.pset.ui.scftyp = self.scftyp_btngrp.checkedId() # SCFTYP = RHF, UHF, or ROHF self.pset.ui.icharg = self.icharg_spinbox.value() # Charge self.pset.ui.mult = self.multi_combox.currentIndex() # Multiplicity # System Memory and Usage self.pset.ui.memory = self.memory_spinbox.value() # Memory self.pset.ui.dirscf = self.dirscf_checkbox.isChecked() # DIRSCF # Electron Correlation Method self.pset.ui.ecm = self.ecm_btngrp.checkedId() # None, DFT or MP2 #self.pset.ui.inttyp = self.ecm_btngrp.selectedId() # INTTYP self.pset.ui.gbasis = self.gbasis_combox.currentIndex() # Basis Set self.pset.ui.gbasisname = str(self.gbasis_combox.currentText()) self.pset.ui.dfttyp = self.dfttyp_combox.currentIndex() # DFT Functional Type self.pset.ui.gridsize = self.gridsize_combox.currentIndex() # Grid Size self.pset.ui.ncore = self.core_electrons_checkbox.isChecked() # Include core electrons # Convergence Criteria self.pset.ui.conv = self.density_conv_combox.currentIndex() # Density Convergence self.pset.ui.rmsdconv = self.rmsd_combox.currentIndex() # RMSD Convergence self.pset.ui.iterations = self.iterations_spinbox.value() # Iterations # self.pset.ui.extrap = self.extrap_checkbox.isChecked() # EXTRAP # self.pset.ui.damp = self.damp_checkbox.isChecked() # DAMP # self.pset.ui.diis = self.diis_checkbox.isChecked() # DIIS # self.pset.ui.shift = self.shift_checkbox.isChecked() # SHIFT # self.pset.ui.soscf = self.soscf_checkbox.isChecked() # SOSCF # self.pset.ui.rstrct = self.rstrct_checkbox.isChecked() # RSTRCT def _save_job_parms(self): calculate = ['Energy', 'Optimization'] self.job.Calculation = calculate[self.pset.ui.runtyp] self.job.Description = self.pset.ui.comment self.job.server = self.server ##Copy some attributes from the server object to job description self.job.Server_id = self.server.server_id self.job.Engine = self.server.engine ######End of private or helper methods.######################## ###### Unused methods ############### def openServerManager(self): """ Pop up ServerManagerDialog to edit the properties of the servers. """ self.sManager.showDialog(self.server) self.servers = self.sManager.getServers() self._reloadServerList() def serverChanged(self, si): """ User has changed server, so update the DFT comboBox. Currently not used. """ self.server = self.servers[si] self._load_dfttyp_combox() ###### End of unused methods ############### ##########Slot methods for some GUI controls################ def calculate_changed(self, val): """ """ if val == 0: # Energy self.rmsd_lbl.setEnabled(0) self.rmsd_combox.setEnabled(0) self.iterations_lbl.setEnabled(0) self.iterations_spinbox.setEnabled(0) # self.extrap_checkbox.setEnabled(0) # self.rstrct_checkbox.setEnabled(0) # self.damp_checkbox.setEnabled(0) # self.diis_checkbox.setEnabled(0) # self.shift_checkbox.setEnabled(0) # self.soscf_checkbox.setEnabled(0) else: # Optimization self.rmsd_lbl.setEnabled(1) self.rmsd_combox.setEnabled(1) self.iterations_lbl.setEnabled(1) self.iterations_spinbox.setEnabled(1) # self.extrap_checkbox.setEnabled(1) # self.rstrct_checkbox.setEnabled(1) # self.damp_checkbox.setEnabled(1) # self.diis_checkbox.setEnabled(1) # self.shift_checkbox.setEnabled(1) # self.soscf_checkbox.setEnabled(1) def set_multiplicity(self, val): """ Enable/disable widgets when user changes Multiplicity. """ if val != 0: qt4todo("if scftyp[self.scftyp_btngrp.selectedId()] != 'RHF':") #if scftyp[self.scftyp_btngrp.selectedId()] != 'RHF': # self.rhf_radiobtn.setEnabled(0) # return ret = QMessageBox.warning( self, "Multiplicity Conflict", "If Multiplicity is greater than 1, then <b>UHF</b> or <b>ROHF</b> must be selected.\n" "Select Cancel to keep <b>RHF</b>.", "&UHF", "&ROHF", "Cancel", 0, 2 ) if ret == 0: # UHF self.uhf_radiobtn.toggle() self.rhf_radiobtn.setEnabled(0) elif ret == 1: # ROHF self.rohf_radiobtn.toggle() self.rhf_radiobtn.setEnabled(0) elif ret == 2: # Cancel self.multi_combox.setCurrentIndex(0) elif val == 0: self.rhf_radiobtn.setEnabled(1) def set_ecmethod(self, val): """ Enable/disable widgets when user changes Electron Correlation Method. """ #print "set_ecmethod = ", val if val == DFT: self.dfttyp_label.setEnabled(1) self.dfttyp_combox.setEnabled(1) self.gridsize_label.setEnabled(1) self.gridsize_combox.setEnabled(1) self.core_electrons_checkbox.setChecked(0) self.core_electrons_checkbox.setEnabled(0) elif val == MP2: self.core_electrons_checkbox.setEnabled(1) self.dfttyp_label.setEnabled(0) self.dfttyp_combox.setEnabled(0) self.gridsize_label.setEnabled(0) self.gridsize_combox.setEnabled(0) else: # None = Hartree-Fock self.dfttyp_label.setEnabled(0) self.dfttyp_combox.setEnabled(0) self.gridsize_label.setEnabled(0) self.gridsize_combox.setEnabled(0) self.core_electrons_checkbox.setChecked(0) self.core_electrons_checkbox.setEnabled(0) # AM1 and PM3 are not options for DFT or MP2. # We have to remove or add them from the combo box. self._update_gbasis_list(val) def open_tmp_inputfile(self): """ Writes a temporary GAMESS inputfile of the current Gamess jig and opens the file in an editor. """ # Make tmp_inputfile filename (i.e. ~/Nanorex/temp/jigname_parms_info.inp) from platform_dependent.PlatformDependent import find_or_make_Nanorex_subdir tmpdir = find_or_make_Nanorex_subdir('temp') basename = self.gamessJig.name + "-" + self.gamessJig.gms_parms_info('_') tmp_inputfile = os.path.join(tmpdir, "%s.inp" % basename) # Write INP file (in ~/Nanorex/temp subdirectory) from analysis.GAMESS.files_gms import writegms_inpfile writegms_inpfile(tmp_inputfile, self.gamessJig) from platform_dependent.PlatformDependent import open_file_in_editor open_file_in_editor(tmp_inputfile) 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 change_jig_color(self): """ Slot method to change the jig's color. """ color = QColorDialog.getColor(self.jig_QColor, self) if color.isValid(): self.jig_QColor = color self.jig_color_pixmap = get_widget_with_color_palette( self.jig_color_pixmap, self.jig_QColor) self.gamessJig.color = self.gamessJig.normcolor = QColor_to_RGBf(color) self.glpane.gl_update() def accept(self): """ The slot method for the 'Save' button. """ QDialog.accept(self) self.gamessJig.try_rename(self.name_linedit.text()) self._save_ui_settings() self.gamessJig.update_gamess_parms() # Update all the GAMESS parameters. self._save_job_parms() if self.edit_input_file_cbox.isChecked(): self.open_tmp_inputfile() def reject(self): """ The slot method for the 'Cancel' button. """ QDialog.reject(self) self.gamessJig.attr_update(self.jig_attrs) # Restore attributes of the jig. # self.gamessJig.color = self.gamessJig.normcolor = self.original_normcolor self.gamessJig.cancelled = True self.glpane.gl_update() def whats_this(self): from PyQt4.Qt import QWhatsThis, QDialog QWhatsThis.enterWhatsThisMode()
class GamessProp(QDialog, Ui_GamessPropDialog): """ The Gamess Jig Properties dialog used for: - running a GAMESS energy calculation on a structure (group of atoms). - running a GAMESS optimization on a structure. - setting and saving the GAMESS parameters used for an energy calculation or optimization. """ def __init__(self): QDialog.__init__(self) self.setModal(True) self.setupUi(self) self.ecm_btngrp = QButtonGroup() self.ecm_btngrp.setExclusive(True) objId = 0 for obj in self.ecm_grpbox.children(): if isinstance(obj, QAbstractButton): self.ecm_btngrp.addButton(obj) self.ecm_btngrp.setId(obj, objId) objId += 1 self.scftyp_btngrp = QButtonGroup() self.scftyp_btngrp.setExclusive(True) objId = 0 for obj in self.scftyp_grpbox.children(): if isinstance(obj, QAbstractButton): self.scftyp_btngrp.addButton(obj) self.scftyp_btngrp.setId(obj, objId) objId += 1 self.connect(self.cancel_btn, SIGNAL("clicked()"), self.reject) self.connect(self.ecm_btngrp, SIGNAL("buttonPressed(int)"), self.set_ecmethod) self.connect(self.multi_combox, SIGNAL("activated(int)"), self.set_multiplicity) self.connect(self.run_job_btn, SIGNAL("clicked()"), self.run_job) self.connect(self.save_btn, SIGNAL("clicked()"), self.accept) self.connect(self.runtyp_combox, SIGNAL("activated(int)"), self.calculate_changed) self.connect(self.choose_color_btn, SIGNAL("clicked()"), self.change_jig_color) self.connect(self.whats_this_btn, SIGNAL("clicked()"), self.whats_this) ##self.connect(self.new_btn,SIGNAL("clicked()"),self.addServer) ##self.connect(self.exit_btn,SIGNAL("clicked()"),self.close) ##self.connect(self.server_listview,SIGNAL("currentChanged(QListViewItem*)"),self.changeServer) ##self.connect(self.engine_combox,SIGNAL("activated(const QString&)"),self.engineChanged) ##self.connect(self.del_btn,SIGNAL("clicked()"),self.deleteServer) self.sManager = ServerManager() self.servers = self.sManager.getServers() self.server = self.servers[0] self.name_linedit.setWhatsThis("""Name of the GAMESS jig.""") self.runtyp_combox.setWhatsThis( """Type of calculation, where "Energy" calculates the Energy Minima,and "Optimization" calculates the "Equilibrium Geometry".""" ) self.comment_linedit.setWhatsThis( """Description, also placed in the comment line of the $DATA section of the INP file.""" ) self.choose_color_btn.setWhatsThis("""Change the GAMESS jig color.""") self.rhf_radiobtn.setWhatsThis( """Restricted Hartree-Fock. All electrons are paired and each spatial orbital is doubly occupied. Cannot be used with multiplicities greater than 1.""" ) self.uhf_radiobtn.setWhatsThis( """Unrestricted Hartree-Fock. All electrons are unpaired and spatial (spin) orbitals are uniquely defined for each electron. More time consuming, but more accurate, than ROHF. """ ) self.rohf_radiobtn.setWhatsThis( """Restricted Open-shell Hartree-Fock. Spin-paired electrons are assigned to doubly-occupied spatial orbitals, while electrons with unpaired spins are provided unique spatial orbitals.""" ) self.icharg_spinbox.setWhatsThis( """The total charge of the structure to be treated quantum mechanically (ICHARG).""" ) self.multi_combox.setWhatsThis( """N + 1, where N is the number of unpaired electrons (MULT).""") self.memory_spinbox.setWhatsThis( """System memory reserved for calculation""") self.dirscf_checkbox.setWhatsThis( """Check this box to run the calculation in RAM and avoid hard disk usage for integral storage.""" ) self.gbasis_combox.setWhatsThis( """Select from among the standard Gaussian-type basis sets and semi-empirical parameters in GAMESS.""" ) self.checkBox10_3_2.setWhatsThis( """Reads the $HESS group from the output file of a previous GAMESS calculation. Only valid for identical molecules.""" ) self.checkBox10_2_2_2.setWhatsThis( """Reads the $VEC group from the output of a previous GAMESS calculation. Requires that both the molecule and basis set be identical. Useful for restarted calculations and starting orbitals for electron correlation methods.""" ) self.none_radiobtn.setWhatsThis( """Select this button to neglect electron correlation in the calculation.""" ) self.dft_radiobtn.setWhatsThis( """Select this button to perform a density functional theory calculation.""" ) self.mp2_radiobtn.setWhatsThis( """Select this button to perform a Second-Order Moeller Plesset calculation.""" ) self.dfttyp_combox.setWhatsThis( """Select an available density functional in GAMESS.""") self.gridsize_combox.setWhatsThis( """Select the grid spacing for the DFT calculation.""") self.core_electrons_checkbox.setWhatsThis( """Check this box to include both the valence and core electrons in the MP2 calculation.""" ) self.density_conv_combox.setWhatsThis( """Selects the accuracy of the electron density convergence for the calculation (CONV).""" ) self.rmsd_combox.setWhatsThis( """Gradient convergence tolerance (OPTTOL), in Hartree/Bohr. Convergence of a geometry search requires the largest component of the gradient to be less than this value, and the root mean square gradient less than 1/3 of OPTTOL. (default=0.0001)""" ) self.iterations_spinbox.setWhatsThis( """Maximum number of SCF iteration cycles (MAXIT).""") self.edit_input_file_cbox.setWhatsThis( """Opens the INP file generated by NanoEngineer-1 in a text editor.""" ) self.whats_this_btn.setWhatsThis("""What's This Help Utility""") self.run_job_btn.setWhatsThis( """Save GAMESS parameters, generates the INP file and launches the GAMESS job.""" ) self.save_btn.setWhatsThis( """Save GAMESS parameters and generates the INP file. It does not launch the GAMESS job.""" ) self.cancel_btn.setWhatsThis("""Cancels changes and closes dialog.""") def showDialog(self, job): """ Display the GAMESS Jig Properties dialog """ self.gamessJig = job.gamessJig self.job = job self.pset = self.gamessJig.pset self.win = self.gamessJig.assy.w self.glpane = self.gamessJig.assy.o if self._setup(): return self.exec_() ######Private or helper methods############################### def _setup(self): """ Setup widgets to initial (default or defined) values. Return True on error. """ #To fix bug 684 #if gamess.is_disabled(): # self.run_job_btn.setEnabled(False) #else: # self.run_job_btn.setEnabled(True) self.jig_attrs = self.gamessJig.copyable_attrs_dict( ) # Save the jig's attributes in case of Cancel. # Jig color self.original_normcolor = self.gamessJig.normcolor self.jig_QColor = RGBf_to_QColor( self.gamessJig.normcolor) # Used as default color by Color Chooser self.jig_color_pixmap = get_widget_with_color_palette( self.jig_color_pixmap, self.jig_QColor) # Init the top widgets (name, runtyp drop box, comment) self.name_linedit.setText(self.gamessJig.name) self.runtyp_combox.setCurrentIndex(self.pset.ui.runtyp) # RUNTYP self.calculate_changed(self.pset.ui.runtyp) self.comment_linedit.setText(self.pset.ui.comment) # Electronic Structure Properties section. btn = self.scftyp_btngrp.button( self.pset.ui.scftyp) # RHF, UHF, or ROHF btn.setChecked(True) self.icharg_spinbox.setValue(self.pset.ui.icharg) # Charge self.multi_combox.setCurrentIndex(self.pset.ui.mult) # Multiplicity # Disable RHF if multiplicity is not the first item. if self.pset.ui.mult == 0: self.rhf_radiobtn.setEnabled(1) # Enable RHF else: self.rhf_radiobtn.setEnabled(0) # Disable RHF # System Memory and Usage self.dirscf_checkbox.setChecked(self.pset.ui.dirscf) # DIRSCF self.memory_spinbox.setValue(self.pset.ui.memory) # Memory # Electron Correlation Method and Basis Set ecm = self.pset.ui.ecm btn = self.ecm_btngrp.button(self.pset.ui.ecm) # None, DFT or MP2 btn.setChecked(True) self.set_ecmethod(self.pset.ui.ecm) # None, DFT or MP2 self.gbasis_combox.setCurrentIndex(self.pset.ui.gbasis) # Basis set # Load the combo box with all the valid DFT functions. self._load_dfttyp_combox() self.dfttyp_combox.setCurrentIndex( self.pset.ui.dfttyp) # DFT Functional self.gridsize_combox.setCurrentIndex( self.pset.ui.gridsize) # Grid Size self.core_electrons_checkbox.setChecked( self.pset.ui.ncore) # Include core electrons # Convergence Criteria self.density_conv_combox.setCurrentIndex( self.pset.ui.conv) # Density Convergence self.rmsd_combox.setCurrentIndex( self.pset.ui.rmsdconv) # RMSD Convergence self.iterations_spinbox.setValue(self.pset.ui.iterations) # Iterations # These have been removed per discussions with Damian. # Mark 050628 # self.extrap_checkbox.setChecked(self.pset.ui.extrap) # EXTRAP # self.damp_checkbox.setChecked(self.pset.ui.damp) # DAMP # self.diis_checkbox.setChecked(self.pset.ui.diis) # DIIS # self.shift_checkbox.setChecked(self.pset.ui.shift) # SHIFT # self.soscf_checkbox.setChecked(self.pset.ui.soscf) # SOSCF # self.rstrct_checkbox.setChecked(self.pset.ui.rstrct) # RSTRCT # Load the server combo box #self._reloadServerList() # Not used in A6. Mark. # If there is an error, return 1. NIY. return 0 def _reloadServerList(self): """ Load the server combo box """ self.server_combox.clear() for s in self.servers: self.server_combox.insertItem(100, s.hostname + "-" + s.engine) # 100 makes sure item is appended to list. [mark 2007-05-04] if self.server not in self.servers: self.server = self.servers[0] indx = self.servers.index(self.server) self.server_combox.setCurrentIndex(indx) def _load_dfttyp_combox(self): """ Load list of DFT function in a combobox widget """ self.dfttyp_combox.clear() # Clear all combo box items if self.server.engine == 'GAMESS': for f in gms_dfttyp_items: self.dfttyp_combox.insertItem(100, f) # 100 makes sure item is appended to list. [mark 2007-05-04] elif self.server.engine == 'PC GAMESS': for f in pcgms_dfttyp_items: self.dfttyp_combox.insertItem(100, f) # 100 makes sure item is appended to list. [mark 2007-05-04] else: print "load_dfttyp_combox: Unknown GAMESS Version. Loading GAMES DFT functionals." for f in gms_dfttyp_items: self.dfttyp_combox.insertItem(100, f) # 100 makes sure item is appended to list. [mark 2007-05-04] def _update_gbasis_list(self, val): """ Add/remove AM1 and PM3 to/from the gbasis list. """ citem = self.gbasis_combox.currentIndex() if val == DFT or val == MP2: if self.gbasis_combox.count() == 18: self.gbasis_combox.removeItem(0) self.gbasis_combox.removeItem(0) self.gbasis_combox.setCurrentIndex(max(0, citem - 2)) else: if self.gbasis_combox.count() != 18: self.gbasis_combox.insertItem( 0, "PM3") # 0 prepends item to list. self.gbasis_combox.insertItem(0, "AM1") self.gbasis_combox.setCurrentIndex(citem + 2) def _save_ui_settings(self): """ Save the UI settings in the Gamess jig pset. There is one setting for each pset. """ self.pset.ui.comment = str(self.comment_linedit.text()) # Description self.pset.ui.runtyp = self.runtyp_combox.currentIndex( ) # RUNTYP = Energy or Optimize # Electronic Structure Props and Basis Set section. self.pset.ui.scftyp = self.scftyp_btngrp.checkedId( ) # SCFTYP = RHF, UHF, or ROHF self.pset.ui.icharg = self.icharg_spinbox.value() # Charge self.pset.ui.mult = self.multi_combox.currentIndex() # Multiplicity # System Memory and Usage self.pset.ui.memory = self.memory_spinbox.value() # Memory self.pset.ui.dirscf = self.dirscf_checkbox.isChecked() # DIRSCF # Electron Correlation Method self.pset.ui.ecm = self.ecm_btngrp.checkedId() # None, DFT or MP2 #self.pset.ui.inttyp = self.ecm_btngrp.selectedId() # INTTYP self.pset.ui.gbasis = self.gbasis_combox.currentIndex() # Basis Set self.pset.ui.gbasisname = str(self.gbasis_combox.currentText()) self.pset.ui.dfttyp = self.dfttyp_combox.currentIndex( ) # DFT Functional Type self.pset.ui.gridsize = self.gridsize_combox.currentIndex( ) # Grid Size self.pset.ui.ncore = self.core_electrons_checkbox.isChecked( ) # Include core electrons # Convergence Criteria self.pset.ui.conv = self.density_conv_combox.currentIndex( ) # Density Convergence self.pset.ui.rmsdconv = self.rmsd_combox.currentIndex( ) # RMSD Convergence self.pset.ui.iterations = self.iterations_spinbox.value() # Iterations # self.pset.ui.extrap = self.extrap_checkbox.isChecked() # EXTRAP # self.pset.ui.damp = self.damp_checkbox.isChecked() # DAMP # self.pset.ui.diis = self.diis_checkbox.isChecked() # DIIS # self.pset.ui.shift = self.shift_checkbox.isChecked() # SHIFT # self.pset.ui.soscf = self.soscf_checkbox.isChecked() # SOSCF # self.pset.ui.rstrct = self.rstrct_checkbox.isChecked() # RSTRCT def _save_job_parms(self): calculate = ['Energy', 'Optimization'] self.job.Calculation = calculate[self.pset.ui.runtyp] self.job.Description = self.pset.ui.comment self.job.server = self.server ##Copy some attributes from the server object to job description self.job.Server_id = self.server.server_id self.job.Engine = self.server.engine ######End of private or helper methods.######################## ###### Unused methods ############### def openServerManager(self): """ Pop up ServerManagerDialog to edit the properties of the servers. """ self.sManager.showDialog(self.server) self.servers = self.sManager.getServers() self._reloadServerList() def serverChanged(self, si): """ User has changed server, so update the DFT comboBox. Currently not used. """ self.server = self.servers[si] self._load_dfttyp_combox() ###### End of unused methods ############### ##########Slot methods for some GUI controls################ def calculate_changed(self, val): """ """ if val == 0: # Energy self.rmsd_lbl.setEnabled(0) self.rmsd_combox.setEnabled(0) self.iterations_lbl.setEnabled(0) self.iterations_spinbox.setEnabled(0) # self.extrap_checkbox.setEnabled(0) # self.rstrct_checkbox.setEnabled(0) # self.damp_checkbox.setEnabled(0) # self.diis_checkbox.setEnabled(0) # self.shift_checkbox.setEnabled(0) # self.soscf_checkbox.setEnabled(0) else: # Optimization self.rmsd_lbl.setEnabled(1) self.rmsd_combox.setEnabled(1) self.iterations_lbl.setEnabled(1) self.iterations_spinbox.setEnabled(1) # self.extrap_checkbox.setEnabled(1) # self.rstrct_checkbox.setEnabled(1) # self.damp_checkbox.setEnabled(1) # self.diis_checkbox.setEnabled(1) # self.shift_checkbox.setEnabled(1) # self.soscf_checkbox.setEnabled(1) def set_multiplicity(self, val): """ Enable/disable widgets when user changes Multiplicity. """ if val != 0: qt4todo("if scftyp[self.scftyp_btngrp.selectedId()] != 'RHF':") #if scftyp[self.scftyp_btngrp.selectedId()] != 'RHF': # self.rhf_radiobtn.setEnabled(0) # return ret = QMessageBox.warning( self, "Multiplicity Conflict", "If Multiplicity is greater than 1, then <b>UHF</b> or <b>ROHF</b> must be selected.\n" "Select Cancel to keep <b>RHF</b>.", "&UHF", "&ROHF", "Cancel", 0, 2) if ret == 0: # UHF self.uhf_radiobtn.toggle() self.rhf_radiobtn.setEnabled(0) elif ret == 1: # ROHF self.rohf_radiobtn.toggle() self.rhf_radiobtn.setEnabled(0) elif ret == 2: # Cancel self.multi_combox.setCurrentIndex(0) elif val == 0: self.rhf_radiobtn.setEnabled(1) def set_ecmethod(self, val): """ Enable/disable widgets when user changes Electron Correlation Method. """ #print "set_ecmethod = ", val if val == DFT: self.dfttyp_label.setEnabled(1) self.dfttyp_combox.setEnabled(1) self.gridsize_label.setEnabled(1) self.gridsize_combox.setEnabled(1) self.core_electrons_checkbox.setChecked(0) self.core_electrons_checkbox.setEnabled(0) elif val == MP2: self.core_electrons_checkbox.setEnabled(1) self.dfttyp_label.setEnabled(0) self.dfttyp_combox.setEnabled(0) self.gridsize_label.setEnabled(0) self.gridsize_combox.setEnabled(0) else: # None = Hartree-Fock self.dfttyp_label.setEnabled(0) self.dfttyp_combox.setEnabled(0) self.gridsize_label.setEnabled(0) self.gridsize_combox.setEnabled(0) self.core_electrons_checkbox.setChecked(0) self.core_electrons_checkbox.setEnabled(0) # AM1 and PM3 are not options for DFT or MP2. # We have to remove or add them from the combo box. self._update_gbasis_list(val) def open_tmp_inputfile(self): """ Writes a temporary GAMESS inputfile of the current Gamess jig and opens the file in an editor. """ # Make tmp_inputfile filename (i.e. ~/Nanorex/temp/jigname_parms_info.inp) from platform_dependent.PlatformDependent import find_or_make_Nanorex_subdir tmpdir = find_or_make_Nanorex_subdir('temp') basename = self.gamessJig.name + "-" + self.gamessJig.gms_parms_info( '_') tmp_inputfile = os.path.join(tmpdir, "%s.inp" % basename) # Write INP file (in ~/Nanorex/temp subdirectory) from analysis.GAMESS.files_gms import writegms_inpfile writegms_inpfile(tmp_inputfile, self.gamessJig) from platform_dependent.PlatformDependent import open_file_in_editor open_file_in_editor(tmp_inputfile) 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 change_jig_color(self): """ Slot method to change the jig's color. """ color = QColorDialog.getColor(self.jig_QColor, self) if color.isValid(): self.jig_QColor = color self.jig_color_pixmap = get_widget_with_color_palette( self.jig_color_pixmap, self.jig_QColor) self.gamessJig.color = self.gamessJig.normcolor = QColor_to_RGBf( color) self.glpane.gl_update() def accept(self): """ The slot method for the 'Save' button. """ QDialog.accept(self) self.gamessJig.try_rename(self.name_linedit.text()) self._save_ui_settings() self.gamessJig.update_gamess_parms( ) # Update all the GAMESS parameters. self._save_job_parms() if self.edit_input_file_cbox.isChecked(): self.open_tmp_inputfile() def reject(self): """ The slot method for the 'Cancel' button. """ QDialog.reject(self) self.gamessJig.attr_update( self.jig_attrs) # Restore attributes of the jig. # self.gamessJig.color = self.gamessJig.normcolor = self.original_normcolor self.gamessJig.cancelled = True self.glpane.gl_update() def whats_this(self): from PyQt4.Qt import QWhatsThis, QDialog QWhatsThis.enterWhatsThisMode()
class PM_RadioButtonList( PM_GroupBox ): """ The PM_RadioButtonList widget provides a list of radio buttons that function as an I{exclusive button group}. """ buttonList = [] defaultCheckedId = -1 # -1 means no checked Id setAsDefault = True labelWidget = None def __init__(self, parentWidget, title = '', label = '', labelColumn = 0, buttonList = [], checkedId = -1, setAsDefault = False, spanWidth = True, borders = True ): """ Appends a PM_RadioButtonList widget to the bottom of I{parentWidget}, the Property Manager dialog or group box. @param parentWidget: The parent group box containing this widget. @type parentWidget: PM_GroupBox or PM_Dialog @param title: The group box title. @type title: str @param label: The label for the coordinate spinbox. @type label: str @param labelColumn: The column in the parentWidget's grid layout to which this widget's label will be added. The labelColum can only be E{0} or E{1} @type labelColumn: int @param buttonList: A list of I{button info lists}. There is one button info list for each radio button in the list. The button info list contains the following three items: 1). Button Id (int), 2). Button text (str), 3). Button tool tip (str). @type buttonList: list @param spanWidth: If True, the widget and its label will span the width of the group box. Its label will appear directly above the widget (unless the label is empty) and is left justified. @type spanWidth: bool (default False) @param borders: If true (default), this widget will have borders displayed. otherwise the won't be any outside borders around the set of radio buttons this class provides @type borders: boolean """ # Intializing label, labelColumn etc is needed before doing # PM_GroupBox.__init__. This is done so that # self.parentWidget.addPmWidget(self) done at the end of __init__ # works properly. # 'self.parentWidget.addPmWidget(self)' is done to avoid a bug where a # groupbox is always appended as the 'last widget' when its # parentWidget is also a groupbox. This is due to other PM widgets #(e.g. PM_PushButton)add themselves to their parent widget in their #__init__ using self.parentWidget.addPmWidget(self). So doing the #same thing here. More general fix is needed in PM_GroupBox code # --Ninad 2007-11-14 (comment copied from PM_coordinateSpinBoxes) self.label = label self.labelColumn = labelColumn self.spanWidth = spanWidth if label: # Create this widget's QLabel. self.labelWidget = QLabel() self.labelWidget.setText(label) PM_GroupBox.__init__(self, parentWidget, title) # These are needed to properly maintain the height of the grid if # all buttons in a row are hidden via hide(). self.vBoxLayout.setMargin(0) self.vBoxLayout.setSpacing(0) self.buttonGroup = QButtonGroup() self.buttonGroup.setExclusive(True) self.parentWidget = parentWidget self.buttonList = buttonList if setAsDefault: self.setDefaultCheckedId(checkedId) self.buttonsById = {} self.buttonsByText = {} # Create radio button list from button info. for buttonInfo in buttonList: buttonId = buttonInfo[0] buttonText = buttonInfo[1] buttonToolTip = buttonInfo[2] button = QRadioButton(self) button.setText(buttonText) button.setToolTip(buttonToolTip) # Not working. button.setCheckable(True) if checkedId == buttonId: button.setChecked(True) self.buttonGroup.addButton(button, buttonId) self.vBoxLayout.addWidget(button) self.buttonsById[buttonId] = button self.buttonsByText[buttonText] = button if isinstance(self.parentWidget, PM_GroupBox): self.parentWidget.addPmWidget(self) else: #@@ Should self be added to self.parentWidget's widgetList? #don't know. Retaining old code -- Ninad 2008-06-23 self._widgetList.append(self) self._rowCount += 1 if not borders: #reset the style sheet so that there are no borders around the #radio button set this class provides. self.setStyleSheet(self._getAlternateStyleSheet()) def restoreDefault(self): """ Restores the default checkedId. """ if self.setAsDefault: for buttonInfo in self.buttonList: buttonId = buttonInfo[0] if buttonId == self.defaultCheckedId: button = self.getButtonById(buttonId) button.setChecked(True) return def setDefaultCheckedId(self, checkedId): """ Sets the default checked id (button) to I{checkedId}. The current checked button is unchanged. @param checkedId: The new default id for the tool button group. @type checkedId: int """ self.setAsDefault = True self.defaultCheckedId = checkedId def checkedButton(self): """ Returns the tool button group's checked button, or 0 if no buttons are checked. """ return self.buttonGroup.checkedButton() def checkedId(self): """ Returns the id of the checkedButton(), or -1 if no button is checked. """ return self.buttonGroup.checkedId() def getButtonByText(self, text): """ Returns the button with its current text set to I{text}. """ if self.buttonsByText.has_key(text): return self.buttonsByText[text] else: return None def getButtonById(self, buttonId): """ Returns the button with the button id of I{buttonId}. """ if self.buttonsById.has_key(buttonId): return self.buttonsById[buttonId] else: return None def _getAlternateStyleSheet(self): """ Return the style sheet for the groupbox. This sets the following properties only: - border style - border width - border color - border radius (on corners) @see: L{PM_GroupBox._getStyleSheet} (overrided here) """ styleSheet = "QGroupBox {border-style:hidden;\ border-width: 0px;\ border-color: "";\ border-radius: 0px;\ min-width: 10em; }" return styleSheet # End of PM_RadioButtonList ############################
def __init__(self, dirname, purrlogs, parent=None, create=None, message=None): QWizardPage.__init__(self, parent) self.dirname = dirname self.purrlogs = purrlogs or [] bg = QButtonGroup(self) lo = QVBoxLayout() self.setLayout(lo) # set page titles self.setTitle("Starting PURR") message and self.setSubTitle(message) if not purrlogs: self.rbs_log = [] else: # add options for existing purrlogs self.rbs_log = [QRadioButton("Load %s" % Kittens.utils.collapseuser(log)) for log in purrlogs] for rb in self.rbs_log: lo.addWidget(rb) bg.addButton(rb) QObject.connect(rb, SIGNAL("toggled(bool)"), self.checkCompleteness) self.rbs_log[0].setChecked(True) # add option to load another purrlog lo1 = QHBoxLayout() self.rb_other = QRadioButton("Load purrlog from:") lo1.addWidget(self.rb_other) bg.addButton(self.rb_other) self.wother = QLineEdit() self.wother.setReadOnly(True) lo1.addWidget(self.wother, 1) pb = QPushButton(pixmaps.folder_open.icon(), "") QObject.connect(pb, SIGNAL("clicked()"), self._select_other_dialog) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), pb.setEnabled) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), self.wother.setEnabled) QObject.connect(self.rb_other, SIGNAL("toggled(bool)"), self.checkCompleteness) pb.setEnabled(False) self.wother.setEnabled(False) lo1.addWidget(pb) lo.addLayout(lo1) self.load_path = None # add option to create new purrlog lo1 = QHBoxLayout() self.rb_create = QRadioButton("Create new purrlog:") lo1.addWidget(self.rb_create) bg.addButton(self.rb_create) self.wcreate = QLineEdit() lo1.addWidget(self.wcreate, 1) pb = QPushButton(pixmaps.folder_open.icon(), "") QObject.connect(pb, SIGNAL("clicked()"), self._select_create_dialog) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), pb.setEnabled) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), self.wcreate.setEnabled) QObject.connect(self.rb_create, SIGNAL("toggled(bool)"), self.checkCompleteness) QObject.connect(self.wcreate, SIGNAL("editingFinished()"), self._validate_create_filename) pb.setEnabled(False) self.wcreate.setEnabled(False) # this holds the last validated name self._validated_create_path = None self._validated_result = False # generate default name for a new purrlog self.create_path = os.path.join(dirname, "purrlog") num = 0 while os.path.exists(self.create_path): self.create_path = os.path.join(dirname, "purrlog.%d" % num) num += 1 # This will be not None as long as a valid name is entered self.create_path = Kittens.utils.collapseuser(os.path.normpath(self.create_path)) if create: self.wcreate.setText(create or Kittens.utils.collapseuser(create)) # this will emit checkCompleteness(), causing a _validate_create_filename() call, causing the content of the wcreate widget # to be validated and copied to create_path if valid, or reset from create_path if invalid self.rb_create.setChecked(True) else: self.wcreate.setText(self.create_path) lo1.addWidget(pb) lo.addLayout(lo1) # make create option default, if no purrlogs if not purrlogs: self.rb_create.setChecked(True)