diff options
author | Bruce Smith <bruce@nanorex.com> | 2008-09-30 03:53:53 +0000 |
---|---|---|
committer | Bruce Smith <bruce@nanorex.com> | 2008-09-30 03:53:53 +0000 |
commit | a7dfe5dca32a52b8528f974f66802b88c240b3b4 (patch) | |
tree | b9ec290390164cce8c64275a6a5a42ddab8bb7e4 /cad/src/command_support | |
parent | 647e6261b84cac77d68407778b9721acdde9c868 (diff) | |
download | nanoengineer-theirix-a7dfe5dca32a52b8528f974f66802b88c240b3b4.tar.gz nanoengineer-theirix-a7dfe5dca32a52b8528f974f66802b88c240b3b4.zip |
misc cleanup now that USE_COMMAND_STACK is always true
Diffstat (limited to 'cad/src/command_support')
-rwxr-xr-x | cad/src/command_support/Command.py | 288 | ||||
-rw-r--r-- | cad/src/command_support/baseCommand.py | 157 |
2 files changed, 157 insertions, 288 deletions
diff --git a/cad/src/command_support/Command.py b/cad/src/command_support/Command.py index 1cf9c2447..69c5fa8c0 100755 --- a/cad/src/command_support/Command.py +++ b/cad/src/command_support/Command.py @@ -12,6 +12,8 @@ bruce 071009 split modes.py into Command.py and GraphicsMode.py, leaving only temporary compatibility mixins in modes.py. For prior history see modes.py docstring before the split. +Bruce & Ninad did a big command sequencer refactoring, circa 080812 + TODO: A lot of methods in class Command are private helper methods, @@ -20,20 +22,13 @@ but are not yet named as private or otherwise distinguished from API methods. We should turn anyCommand into Command_API, add all the API methods to it, and rename the other methods in class Command to look private. - -Methods such as basicCommand.Done, basicCommand._enterMode, -basicCommand._exitMode and CommandSequencer.start_using_mode need cleanup -(needs to be done together). - -This is happening as part of a big command sequencer refactoring -by Bruce & Ninad, circa 080812 (ongoing). """ from PyQt4.Qt import QToolButton from utilities.debug import print_compact_traceback, print_compact_stack -from utilities.debug_prefs import debug_pref, Choice_boolean_False ##, Choice_boolean_True +from utilities.debug_prefs import debug_pref, Choice_boolean_False from utilities import debug_flags from platform_dependent.PlatformDependent import shift_name @@ -58,13 +53,15 @@ from command_support.baseCommand import baseCommand import foundation.changes as changes -DEBUG_TO_HELP_STRIP_OUT_OLD_COMMAND_API_METHODS = False # Temporary debug flag, can be removed when safe -- Ninad 2008-09-26 - # == class anyCommand(baseCommand, StateMixin): """ - abstract superclass for all Command objects, including nullCommand + abstract superclass for all Command objects, including nullCommand. + + @note: command base class methods are divided somewhat arbitrarily between + baseCommand, anyCommand, and basicCommand. In some cases, methods + defined in baseCommand are overridden in anyCommand or basicCommand. """ #bruce 071008 added object superclass; 071009 split anyMode -> anyCommand @@ -75,37 +72,13 @@ class anyCommand(baseCommand, StateMixin): # note: soon, command_level and command_parent, and some other of the # following default values, will be inherited from a new superclass baseCommand. - - from utilities.constants import CL_ABSTRACT - command_level = CL_ABSTRACT - # command_level is not yet documented, part of command stack refactoring __abstract_command_class = True - - command_parent = None - # Subclasses should set this to the commandName of the parent command - # they require, if any (and if that is not the default command). - # (Whether they require a parent command at all is determined by - # their command_level attribute.) - # - # For example, BreakStrands_Command requires parent command "Build Dna", - # so it sets this to 'BUILD_DNA' == BuildDna_EditCommand.commandName. - # This attr is used in a revised command stack scheme as of 2008-07-28 - # (still being developed). - - is_null = False # overridden only in nullCommand - - # internal name of command, e.g. 'DEPOSIT', - # only seen by users in "debug" error messages; - # might be used to create some prefs_keys and/or in some prefs values - # [but I don't know if any such uses remain -- bruce 080727 comment] - commandName = "(bug: missing commandName 1)" featurename = "" # Command's property manager. Subclasses should initialize the propMgr object # if they need one. [in command_enter_PM (after refactoring) or __init__] propMgr = None - # note: the following 2 command_ attributes may be ignored or revised # after the current command stack refactoring is complete [070830]: @@ -165,7 +138,6 @@ class anyCommand(baseCommand, StateMixin): # 'exit_using_done_cancel' in basicCommand.Done used (= False) for a # typical exit of a temporary mode . See that method for detailed # comment. -- Ninad 2007-11-09 - def __repr__(self): #bruce 080829, modified from Utility.py version """ @@ -177,7 +149,6 @@ class anyCommand(baseCommand, StateMixin): # (default methods that should be noops in both nullCommand and Command # can be put here instead if desired; for docstrings, see basicCommand) - def isCurrentCommand(self): #bruce 071008 # WARNING: this value of False means the nullCommand should never itself # run code which assumes that this returns true when self is current. @@ -185,9 +156,6 @@ class anyCommand(baseCommand, StateMixin): # at an early stage of startup, before the usual method would work. return False - def get_featurename(self): - return "null command" # should never be seen [revised, bruce 080727] - def keep_empty_group(self, group): #bruce 080305 """ When self is the current command, and an empty group with @@ -271,13 +239,13 @@ class anyCommand(baseCommand, StateMixin): pass # end of class anyCommand +# == class nullCommand(anyCommand): """ do-nothing command (for internal use only) to avoid crashes in case of certain bugs during transition between commands """ - # needs no __init__ method; constructor takes no arguments # WARNING: the next two methods are similar in all "null objects", of which @@ -302,8 +270,6 @@ class nullCommand(anyCommand): # Command-specific attribute null values - # TODO: revise the 'mode' term in the following attribute names - # (the nullCommand instance is not put into the command sequencer's _commandTable) is_null = True @@ -315,10 +281,6 @@ class nullCommand(anyCommand): # Command-specific null methods - def Done(self, *args, **kws): - #bruce 060316 added this to remove frequent harmless debug print - pass - def autodelete_empty_groups(self, topnode): return @@ -332,11 +294,14 @@ class basicCommand(anyCommand): and old-code-compatibility class basicMode. Will be merged with class Command (keeping that one's name) when basicMode is no longer needed. + + @note: command base class methods are divided somewhat arbitrarily between + baseCommand, anyCommand, and basicCommand. In some cases, methods + defined in baseCommand are overridden in anyCommand or basicCommand. """ # TODO: split into minimalCommand, which does as little as possible # which meets the Command API and permits switching between commands - # in conjunction with the Command Sequencer (e.g. it implements - # Done, _f_userEnterCommand, init_gui, etc etc); and basicCommand, which + # in conjunction with the Command Sequencer; and basicCommand, which # has all the rest (the basic functionality of an NE1 command). # (This is not urgent, since all commands should have that basic # functionality. It might make things clearer or ease refactoring @@ -351,13 +316,11 @@ class basicCommand(anyCommand): # and pass the CommandSequencer in which this command can run. commandName = "(bug: missing commandName)" featurename = "Undocumented Command" - from utilities.constants import CL_ABSTRACT - command_level = CL_ABSTRACT + __abstract_command_class = True command_can_be_suspended = True # good default value for most commands [bruce 071011] - PM_class = None #Command subclasses can override this class constant with the appropriate #Property Manager class, if they have their own Property Manager object. @@ -371,15 +334,7 @@ class basicCommand(anyCommand): # Note: for the new command API as of 2008-09-26, this is always used, # since base class command_enter_PM calls _createPropMgrObject. - # [bruce 080909] - - - FlyoutToolbar_class = None - #Command subclasses can override this class constant with the appropriate - #Flyout Toolbar class. - - flyoutToolbar = None #bruce 080924, redundant with baseCommand when we use that - + # [bruce 080909] def __init__(self, commandSequencer): """ @@ -416,10 +371,7 @@ class basicCommand(anyCommand): # check whether subclasses override methods we don't want them to # (after this works I might remove it, we'll see) - ### bruce 050130 removing 'Done' temporarily; see PanMode.Done for why. - # later note: as of 070521, we always get warned "subclass movieMode - # overrides basicMode._exitMode". I am not sure whether this override is - # legitimate, so I'm not removing the warning for now. [bruce 070521] + # [most methods have been removed after the command api was revised -- bruce 080929] weird_to_override = [ 'StartOver' #bruce 080806 ] @@ -431,25 +383,6 @@ class basicCommand(anyCommand): weird_to_override += [ 'command_Done', 'command_Cancel', #bruce 080827 ] - if DEBUG_TO_HELP_STRIP_OUT_OLD_COMMAND_API_METHODS: ### TODO: enable this once we'll never go back, to help strip out obsolete code - # also complain about commands not fully ported to the new API - # (i.e. in which obsolete methods are still defined) - for methodname, howtofix in ( - ('Enter', ""), - ('init_gui', ""), - ('resume_gui', ""), - ('Done', ""), - ('StateDone', ""), - ('StateCancel', ""), - ('restore_gui', ""), - ('restore_patches_by_Command', ""), - ('clear_command_state', ""), - ('haveNontrivialState', ""), - ): - weird_to_override += [methodname] - # todo: print howtofix when needed - continue - pass for attr in weird_to_override: def same_method(m1, m2): # m1/m2.im_class will differ (it's the class of the query, @@ -459,7 +392,7 @@ class basicCommand(anyCommand): getattr(basicCommand, attr) ): print "fyi (for developers): subclass %s overrides basicCommand.%s; " \ "this is deprecated after mode changes of 040924." % \ - (self.__class__.__name__, attr) # todo: print howtofix as well + (self.__class__.__name__, attr) # other inits self.glpane = glpane # REVIEW: needed? @@ -491,7 +424,6 @@ class basicCommand(anyCommand): return # from basicCommand.__init__ # == - def command_enter_PM(self): """ @@ -519,7 +451,6 @@ class basicCommand(anyCommand): propMgr = self.PM_class(self) return propMgr - def get_featurename(clas): #bruce 071227, revised into classmethod 080722 """ @@ -528,6 +459,8 @@ class basicCommand(anyCommand): concrete subclass. Usually, this is one or a few space-separated capitalized words. + + [overrides baseCommand method] """ # (someday: add debug command to list all known featurenames, # by object type -- optionally as wiki help links, for testing; @@ -743,57 +676,6 @@ class basicCommand(anyCommand): # confirmation corner methods [bruce 070405-070409, 070627] - # Note [obs?]: if we extend the conf. corner to "generators" in the short term, - # before the "command sequencer" is implemented, some of the following methods - # may be revised to delegate to the "current generator" or its PM. - # If so, when doing this, note that many modes currently act as their own PM widget. - - def _KLUGE_current_PM(self, get_old_PM = False): #bruce 070627; new option 080819 - """ - private method, and a kluge; - see KLUGE_current_PropertyManager docstring for more info - """ - if not get_old_PM: - return self.propMgr - - pw = self.w.activePartWindow() - if not pw: - # I don't know if pw can be None - print "fyi: _KLUGE_current_PM sees pw of None" ### - return None - try: - res = pw.KLUGE_current_PropertyManager() - if res is not self.propMgr and not get_old_PM: - # I think this should now be rare, now that Ninad removed - # all official "guest PM" commands; let's find out... - # unfortunately it's common, apparently due to a logic bug - # in terms of when we access this vs. when various things are - # updated, since the PMs don't match the command objects in the - # debug prints (see below, when entering or exiting Break Strands) -- - # or maybe it's a side effect of an exception in entering it, in - # current code? Try again when that bug is fixed... #### trying this now, 080812 - # - ## debug note: _KLUGE_current_PM returns - ## <dna.commands.BreakStrands.BreakStrands_PropertyManager.BreakStrands_PropertyManager - ## object at 0xb333858>, but <commands.SelectChunks.SelectChunks_Command.SelectChunks_Command - ## object at 0x9f66870>.propMgr is None - # - # [bruce 080806] - ## pass - print "debug note: _KLUGE_current_PM returns %r, but %r.propMgr is %r" % \ - (res, self, self.propMgr) ### if happens, fix; if not, clean up all calls -## assert 0, "failure in _KLUGE_current_PM, see console prints" -## #bruce 080812 (temporary) -- make this un-missable by -## # developers, for next few days -- also added 'raise' below - return res - except: -## raise #bruce 080812 (temporary) -- goes with above assert 0 - # I don't know if this can happen - msg = "ignoring exception in %r.KLUGE_current_PropertyManager()" % (pw,) - print_compact_traceback(msg + ": ") - return None - pass - def _KLUGE_visible_PM_buttons(self): #bruce 070627 """ private method (but ok for use by self._ccinstance), and a kluge: @@ -803,7 +685,12 @@ class basicCommand(anyCommand): Used both for deciding what CC buttons to show, and for acting on the buttons (assuming they are QToolButtons). """ - pm = self._KLUGE_current_PM() + # note: this is now much less of a kluge, but still somewhat klugy + # (since it makes one UI element depend on another one), + # so I'm not renaming it. [bruce 080929 comment] + + pm = self.propMgr #bruce 080929 revision, used to call _KLUGE_current_PM + # (but recently, it passed an option that made it equivalent) if not pm: return None, None # no CC if no PM is visible def examine(buttonname): @@ -874,7 +761,6 @@ class basicCommand(anyCommand): else: res = '+'.join(res) return res - def should_exit_when_ESC_key_pressed(self): # not overridden, as of 080815 """ @@ -892,86 +778,15 @@ class basicCommand(anyCommand): @see: ESC_to_exit_GraphicsMode_preMixin.keyPress() """ return (self.command_should_resume_prevMode and not self.is_default_command()) - - - def _init_gui_flyout_action( self, action_attr, parentCommandName = None ): - """ - [helper method for command entry] - - If our direct parent command has the expected commandName, - copy self.flyoutToolbar from it and call setChecked on the specified - action in it (if it has that action) (setting self.flyoutToolbar = None - if any of this fails by raising AttributeError, with no error message) - and return the parent command. Otherwise return None. - - @param action_attr: attribute name of this command's action in - this or parent command's flyout toolbar. - Example: 'breakStrandAction' - @type: string - - @param parentCommandName: commandName of expected parent command; - if not provided or None, we use - self.command_parent for this. - Example: 'BUILD_DNA' - @type: string - - @return: parent command, if it has expected commandName, otherwise None. - @rtype: Command or None - - [helper method for use in init_gui implementations; - might need refactoring] - """ - - if not action_attr: - return - - #bruce 080726 split this out of init_gui methods (by Ninad) - # of several Commands. - if parentCommandName is None: - parentCommandName = self.command_parent - assert self.command_parent, \ - "_init_gui_flyout_action in %r requires " \ - "self.command_parent assignment" % self - # note: it's ok that we don't interpret command_parent = None - # as the default commandName here, since the default command has no - # flyout toolbar. This only works by accident; it might be more - # principled to check self.is_fixed_parent_command() instead, once - # that's always defined, and if it's true, interpret - # command_parent = None as being the name of the default command. - # [bruce 080814 comment] - - #bruce 080804 - parentCommand = self.parentCommand - assert parentCommand # should be already set by now (during command_entered) - if parentCommand.commandName == parentCommandName: - try: - self.flyoutToolbar = parentCommand.flyoutToolbar - #Need a better way to deal with changing state of the - #corresponding action in the flyout toolbar. To be revised - #during command toolbar cleanup - action = getattr(self.flyoutToolbar, action_attr) - action.setChecked(True) - except AttributeError: - # REVIEW: this could have several causes; would any of them - # be bugs and deserve an error message? [bruce 080726 questions] - self.flyoutToolbar = None - return parentCommand - else: - print "fyi: _init_gui_flyout_action in %r found wrong kind " \ - "of parent command" % self # not sure if this ever happens; might be a bug if so - return None - pass - def is_default_command(self): #bruce 080709 refactoring - return self.commandName == self.commandSequencer.default_commandName() - - # methods for leaving this command (from a dashboard tool or an # internal request). # Notes on state-accumulating modes, e.g. Build Crystal, Extrude, # and [we hoped at the time] Build Atoms [bruce 040923]: - # [mostly obsolete after USE_COMMAND_STACK (new command API , which + # + # [WARNING: these comments are MOSTLY OBSOLETE now that + # USE_COMMAND_STACK is true (new command API, which # is the default API as of 2008-09-26) ] # # Each command which accumulates state, meant to be put into its @@ -1038,7 +853,7 @@ class basicCommand(anyCommand): print_compact_stack( "fyi: deprecated method basicCommand.warning(*%r, **%r) was called: " % (args, kws)) self._warning_for_abandon(*args, **kws) - def _warning_for_abandon(self, str, bother_user_with_dialog = 0, ensure_visible = 1): + def _warning_for_abandon(self, str1, bother_user_with_dialog = 0, ensure_visible = 1): """ Show a warning to the user, without interrupting them (i.e. not in a dialog) unless bother_user_with_dialog is @@ -1073,8 +888,7 @@ class basicCommand(anyCommand): # and renamed it, and added a deprecated compatibility # call from the old method name (warning). - # TODO: cleanup; rename str to not mask python builtin; - # merge with other 'def warning' methods and with + # TODO: cleanup; merge with other 'def warning' methods and with # env.history / statusbar methods. # Or, perhaps just inline it into its sole real caller. @@ -1090,8 +904,8 @@ class basicCommand(anyCommand): ### guarantee it lasts else: prefix = "warning" - str = str[0].upper() + str[1:] # capitalize the sentence - msg = "%s: %s" % (prefix, str,) + str1 = str1[0].upper() + str1[1:] # capitalize the sentence + msg = "%s: %s" % (prefix, str1,) ###e add a timestamp prefix, at least for the printed one # always print it so there's a semi-permanent record they can refer to @@ -1107,14 +921,13 @@ class basicCommand(anyCommand): ##e also linebreak it if it's very long? i might hope that some # arg to the messagebox could do this... QMessageBox.warning(self.o, prefix, msg) # args are widget, title, content - return + return - - # [bruce comment 040923; trimmed, 080806] # # The preceding and following methods, StartOver Cancel # Done, handle the common tools on the dashboards. + # [note: as of before 080929, only StartOver still exists.] # # Each dashboard uses instances of the same tools, for a uniform # look and action; the tool itself does not know which command it @@ -1152,16 +965,14 @@ class basicCommand(anyCommand): which has the given commandName, or None if none does (often an error, but no error message is printed). """ - # note: this implem ought to work both before and after the - # command stack refactoring related to USE_COMMAND_STACK; - # after it, it could be rewritten to not use self.commandSequencer + # note: this could be rewritten to not use self.commandSequencer # at all (a nice cleanup, but not urgent or required). cseq = self.commandSequencer res = cseq.find_innermost_command_named( commandName, starting_from = self ) return res - def find_parent_command_named(self, commandName): #bruce 080801; maybe untested + def find_parent_command_named(self, commandName): #bruce 080801 """ Return the first of self's parentCommands (if any) which has the given commandName, or None if none does @@ -1171,9 +982,8 @@ class basicCommand(anyCommand): commandName (at a given time), but this may not be checked or enforced. """ - # note: this implem ought to work both before and after the - # command stack refactoring related to USE_COMMAND_STACK; - # after it, it should be reviewed for possible simplification. + # review: can this be simplified, now that new command api is always used? + # e.g. it could probably work without referencing self.commandSequencer. cseq = self.commandSequencer commands = cseq.all_active_commands( starting_from = self ) for command in commands[1:]: # only look at our parent commands @@ -1181,25 +991,6 @@ class basicCommand(anyCommand): return command return None - def find_parentCommand(self): #bruce 080813; won't be needed once .parentCommand always works - cseq = self.commandSequencer - commands = cseq.all_active_commands( starting_from = self ) - commands = commands[1:] # only look at our parent commands - if not commands: - res = None - else: - res = commands[0] - if self.command_parent: - assert res is self.find_parent_command_named( self.command_parent) # not sure this is always required... - # note: this doesn't run when self.is_fixed_parent_command() and - # self.command_parent is None, meaning the default command! - # ok for now, since it's only an assert. - - assert res is self.parentCommand - # maybe: if not, add a property to make this always true... then use it - # to replace all calls of _reuse_attr_of_parentCommand with direct assignments. - return res - # == def _args_and_callback_for_request_command(self): #bruce 080801, might be revised/renamed @@ -1259,7 +1050,6 @@ class Command(basicCommand): # dependent then on the API of those GraphicsMode methods, # and not on their implem until it had to be instantiated. # Eventually, to librarify this code, we'll need to solve that problem. - def __init__(self, commandSequencer): basicCommand.__init__(self, commandSequencer) diff --git a/cad/src/command_support/baseCommand.py b/cad/src/command_support/baseCommand.py index b77366cba..1741fd5f7 100644 --- a/cad/src/command_support/baseCommand.py +++ b/cad/src/command_support/baseCommand.py @@ -29,6 +29,13 @@ DEBUG_USE_COMMAND_STACK = False #turn off the debug prints by default class baseCommand(object): """ Abstract base class for command objects compatible with Command Sequencer. + + @note: all actual command objects are instances of subclasses of our + subclass anyCommand. + + @note: command base class methods are divided somewhat arbitrarily between + baseCommand, anyCommand, and basicCommand. In some cases, methods + defined in baseCommand are overridden in anyCommand or basicCommand. """ __abstract_command_class = True @@ -56,29 +63,20 @@ class baseCommand(object): # For example, BreakStrands_Command requires parent command "Build Dna", # so it sets this to 'BUILD_DNA' == BuildDna_EditCommand.commandName. + # internal name of command, e.g. 'DEPOSIT', + # only seen by users in "debug" error messages; + # might be used to create some prefs_keys and/or in some prefs values + # [but I don't know if any such uses remain -- bruce 080727 comment] + commandName = "(bug: missing commandName 1)" + # default values of instance variables; properties; access methods # - related to parentCommand + + is_null = False # overridden only in nullCommand _parentCommand = None # parent command object, when self is on command stack - - FlyoutToolbar_class = None #Ninad 2008-09-12 - #Command subclasses can override this class attr with the appropriate - #Flyout Toolbar class. This is used to create a FlyoutToolbar object - #for the commands. this attr is also used to do flyout toolbar updates. - #Example: if the value of this attr is None then it either implies the - #command should use the flyout toolbar of the parent command and do - #some more UI changes to it (example check an action) OR the command - #shouldn't do anything with the flyout at all (this is decided using the - #'command_level) - #@see: self.command_update_flyout() - #@see: self._command_entered_prepare_flyout() - #@see: self._createFlyouttoolbarObject() - - flyoutToolbar = None - - def _get_parentCommand( self): return self._parentCommand @@ -95,6 +93,23 @@ class baseCommand(object): # might catch more bugs. return self.parentCommand is not None + # - related to flyout toolbar + + FlyoutToolbar_class = None #Ninad 2008-09-12 + #Command subclasses can override this class attr with the appropriate + #Flyout Toolbar class. This is used to create a FlyoutToolbar object + #for the commands. this attr is also used to do flyout toolbar updates. + #Example: if the value of this attr is None then it either implies the + #command should use the flyout toolbar of the parent command and do + #some more UI changes to it (example check an action) OR the command + #shouldn't do anything with the flyout at all (this is decided using the + #'command_level) + #@see: self.command_update_flyout() + #@see: self._command_entered_prepare_flyout() + #@see: self._createFlyouttoolbarObject() + + flyoutToolbar = None + # - related to a command's property manager (PM) command_has_its_own_PM = True @@ -103,6 +118,16 @@ class baseCommand(object): # == access methods + def is_default_command(self): #bruce 080709 refactoring; moved to this file 080929 + return self.commandName == self.commandSequencer.default_commandName() + + def get_featurename(self): + """ + [overridden in basicCommand, see there for doc] + """ + # revised, bruce 080727; moved to this class, bruce 080929 + return "null command" # should never be seen + def is_fixed_parent_command(cls): """ Is this command instance or class a "fixed-parent command", @@ -287,8 +312,8 @@ class baseCommand(object): is about to be exited for any reason. If the side effects need to depend on the manner of exit - (e.g. Done vs Cancel vs Abandon/exit_all_commands), or on - the command being exited from or intended to be entered, + (e.g. command_Done vs command_Cancel vs exit_all_commands), + or on the command being exited from or intended to be entered, this should be determined by testing an appropriate attribute of self.commandSequencer, e.g. exit_is_cancel, exit_is_forced, exit_is_implicit, exit_target, enter_target. For their meanings, @@ -300,7 +325,7 @@ class baseCommand(object): exited during the same user event). @note: base class implementation calls self methods - command_exit_misc_actions and command_exit_flyout. + command_exit_misc_actions and command_exit_PM. [subclasses should extend this as needed, typically calling superclass implementation at the end] @@ -321,7 +346,6 @@ class baseCommand(object): """ return - def command_exit_misc_actions(self): """ Undo whatever was done @@ -447,7 +471,7 @@ class baseCommand(object): "suspended upon entry" by a subcommand being pushed on top of it. @note: base class implementation calls other methods of self, - and command_enter_misc_actions. + including command_enter_misc_actions. @note: similar to old methods Enter and parts of init_gui. @@ -457,9 +481,7 @@ class baseCommand(object): @see: self._command_entered_prepare_flyout() @see: self.command_update_flyout() """ - - self.graphicsMode.Enter_GraphicsMode() ### REVIEW: refactor into a subclass which defines this attr? - # note: existing implems do some state-resetting (good) + self.graphicsMode.Enter_GraphicsMode() if not self.command_has_its_own_PM: # note: that flag must be True (so this doesn't run) in the default @@ -476,7 +498,6 @@ class baseCommand(object): def _command_entered_prepare_flyout(self): #Ninad 2008-09-12 """ - Create flyout toolbar object for the command if needed. Whether to create it is decided using the class attr self.FlyoutToolbar_class. @@ -485,7 +506,7 @@ class baseCommand(object): if one exists. When FlyoutToolbar_class is defined by the command, it uses that to create one for the command. - This method is called in self.command_entered(). Subclasses shoule + This method is called in self.command_entered(). Subclasses should NEVER override this method. @see: self.command_update_flyout() which actually does the updates to @@ -524,8 +545,7 @@ class baseCommand(object): return None flyout = self.FlyoutToolbar_class(self) - return flyout - + return flyout def command_enter_PM(self): """ @@ -569,7 +589,6 @@ class baseCommand(object): [subclasses should override as needed] """ return - def command_enter_misc_actions(self): """ @@ -599,12 +618,7 @@ class baseCommand(object): self.commandSequencer._f_update_current_command() return - def command_update_state(self): ### tentative; details under discussion - # note: likely implem of call to this: a new cseq method is called by - # existing method command_post_event_ui_updater, which loops over the methods - # described in the docstring - # note: code now in model_changed and other update methods - # is divided up into the new update methods listed here. + def command_update_state(self): """ At the end of any user event that may have changed system state which may need to cause changes to the command stack or to any @@ -729,7 +743,6 @@ class baseCommand(object): @see: AbstractFlyout.activateFlyoutToolbar() @see: CommandToolbar.resetToDefaultState() """ - if self.flyoutToolbar: #activate the flyout toolbar. self.flyoutToolbar.activateFlyoutToolbar() @@ -741,8 +754,7 @@ class baseCommand(object): #The following method needs to handle the empty action #string (flyoutActionToCheck) self._init_gui_flyout_action(flyoutActionToCheck, - parentCommandName = parentCommandString) - + parentCommandName = parentCommandString) else: #Its not a subcommand that is using the flyout toolbar. So #make sure that no action is checked when this flyout is shown @@ -790,6 +802,73 @@ class baseCommand(object): flyoutActionToCheck = '' parentCommandName = None return flyoutActionToCheck, parentCommandName + + def _init_gui_flyout_action( self, action_attr, parentCommandName = None ): + """ + [helper method for command entry] + + If our direct parent command has the expected commandName, + copy self.flyoutToolbar from it and call setChecked on the specified + action in it (if it has that action) (setting self.flyoutToolbar = None + if any of this fails by raising AttributeError, with no error message) + and return the parent command. Otherwise return None. + + @param action_attr: attribute name of this command's action in + this or parent command's flyout toolbar. + Example: 'breakStrandAction' + @type: string + + @param parentCommandName: commandName of expected parent command; + if not provided or None, we use + self.command_parent for this. + Example: 'BUILD_DNA' + @type: string + + @return: parent command, if it has expected commandName, otherwise None. + @rtype: Command or None + + [helper method for use in init_gui implementations; + might need refactoring] + """ + if not action_attr: + return + + #bruce 080726 split this out of init_gui methods (by Ninad) + # of several Commands; 080929 moved it into baseCommmand + if parentCommandName is None: + parentCommandName = self.command_parent + assert self.command_parent, \ + "_init_gui_flyout_action in %r requires " \ + "self.command_parent assignment" % self + # note: it's ok that we don't interpret command_parent = None + # as the default commandName here, since the default command has no + # flyout toolbar. This only works by accident; it might be more + # principled to check self.is_fixed_parent_command() instead, once + # that's always defined, and if it's true, interpret + # command_parent = None as being the name of the default command. + # [bruce 080814 comment] + + #bruce 080804 + parentCommand = self.parentCommand + assert parentCommand # should be already set by now (during command_entered) + if parentCommand.commandName == parentCommandName: + try: + self.flyoutToolbar = parentCommand.flyoutToolbar + #Need a better way to deal with changing state of the + #corresponding action in the flyout toolbar. To be revised + #during command toolbar cleanup + action = getattr(self.flyoutToolbar, action_attr) + action.setChecked(True) + except AttributeError: + # REVIEW: this could have several causes; would any of them + # be bugs and deserve an error message? [bruce 080726 questions] + self.flyoutToolbar = None + return parentCommand + else: + print "fyi: _init_gui_flyout_action in %r found wrong kind " \ + "of parent command" % self # not sure if this ever happens; might be a bug if so + return None + pass # == other methods |