Provided by: python-apptools-doc_4.5.0-1.1_all bug

NAME

       apptools - apptools 4.5.0

APPLICATION SCRIPTING FRAMEWORK

       The  Application  Scripting  Framework  is  a  component  of the Enthought Tool Suite that
       provides developers with an API that allows traits based objects to  be  made  scriptable.
       Operations on a scriptable object can be recorded in a script and subsequently replayed.

       The  framework  is  completely  configurable.   Alternate  implementations  of  all  major
       components can be provided if necessary.

   Framework Concepts
       The following are the concepts supported by the framework.

       · Scriptable Type

         A scriptable type is a sub-type of HasTraits that has scriptable methods and  scriptable
         traits.   If  a  scriptable  method  is  called, or a scriptable trait is set, then that
         action can be recorded in a script and subsequently replayed.

         If the __init__() method is scriptable then the creation of an object from the type  can
         be recorded.

         Scriptable  types  can be explicitly defined or created dynamically from any sub-type of
         HasTraits.

       · Scriptable API

         The set of a scriptable type's scriptable methods  and  traits  constitutes  the  type's
         scriptable API.

         The  API  can  be defined explicitly using the scriptable decorator (for methods) or the
         Scriptable wrapper (for traits).

         For scriptable types that are created dynamically then the API can be defined  in  terms
         of  one  or  more types or interfaces or an explicit list of method and trait names.  By
         default, all public methods and traits (ie.  those whose name does  not  begin  with  an
         underscore)  are part of the API.  It is also possible to then explicitly exclude a list
         of method and trait names.

       · Scriptable Object

         A scriptable object is an instance of a scriptable type.

         Scriptable  objects  can  be  explicitly  created  by  calling  the   scriptable   type.
         Alternatively a non-scriptable object can be made scriptable dynamically.

       · Script

         A script is a Python script and may be a recording or written from scratch.

         If  the  creation  of  scriptable objects can be recorded, then it may be possible for a
         recording to be run  directly  by  the  Python  interpreter  and  independently  of  the
         application  that made the recording.  Otherwise the application must run the script and
         first create any scriptable objects referred to in the script.

       · Binding

         A script runs in a namespace which is, by default, empty.   If  the  scriptable  objects
         referred  to  in a script are not created by the script (because their type's __init__()
         method isn't scriptable) then they must be created by the application and added  to  the
         namespace.  Adding an object to the namespace is called binding.

         Scriptable  objects  whose  creation  can be recorded will automatically bind themselves
         when they are created.

         It also possible to bind an object factory rather than the object itself.   The  factory
         will  be called, and the object created, only if the object is needed by the script when
         it is run.  This is typically used by plugins.

         The name that an object is bound to need bear no relation to the  object's  name  within
         the  application.   Names  may be dotted names (eg. aaa.bbb.ccc) and appropriate objects
         representing the intermediate parts of such a name will be created automatically.

         An event is fired whenever an object is bound (or when  a  bound  factory  is  invoked).
         This allows other objects (eg. an embedded Python shell) to expose scriptable objects in
         other ways.

       · Script Manager

         A script manager is responsible for the recording and subsequent  playback  of  scripts.
         An  application  has  a  single  script  manager instance which can be explicitly set or
         created automatically.

   Limitations
       In the current implementation scriptable Trait container types (eg. List, Dict)  may  only
       contain objects corresponding to fundamental Python types (eg.  int, bool, str).

   API Overview
       This  section gives an overview of the API implemented by the framework.  The complete API
       documentation is available as endo generated HTML.

       The example application demonstrates some the features of the framework.

   Module Level Objects
       get_script_manager()
              The application's script manager is returned.  One will be created automatically if
              needed.

       set_script_manager(script_manager)
              The  application's  script  manager  will  be  set  to script_manager replacing any
              existing script manager.

       scriptable
              This is a decorator used to explicitly mark methods as being scriptable.  Any  call
              to  a  scriptable  method  is recorded.  If a type's __init__() method is decorated
              then the creation of the object will be recorded.

       Scriptable
              This is a wrapper for a trait to explicitly  mark  it  as  being  scriptable.   Any
              change  to the value of the trait will be recorded.  Simple reads of the trait will
              not be recorded unless unless the value read is bound to another  scriptable  trait
              or  passed  as  an  argument to a scriptable method.  Passing has_side_effects=True
              when wrapping the trait will ensure that a read will always be recorded.

       create_scriptable_type(script_type,     name=None,      bind_policy='auto',      api=None,
       includes=None, excludes=None, script_init=True)
              This  creates  a  new  type  based on an existing type but with certain methods and
              traits marked as being scriptable.  Scriptable  objects  can  then  be  created  by
              calling the type.

              script_type is the existing, non-scriptable, type.  The new type will be a sub-type
              of it.  The api, includes and excludes arguments determine which methods and traits
              are  made  scriptable.   By default, all public methods and traits (ie. those whose
              name does not begin with an underscore) are made scriptable.

              The name and bind_policy arguments determine how scriptable objects are bound  when
              they  are  created.  name is the name that an object will be bound to.  It defaults
              to the name of script_type with the first character forced to lower case.  name may
              be a dotted name, eg. aaa.bb.c.

              bind_policy  determines what happens if an object is already bound to the name.  If
              it is auto then a numerical suffix will be added to the name of the new object.  If
              it  is  unique  then  an exception will be raised.  If it is rebind then the object
              currently bound to the name will be unbound.

              api is a class or interface (or a list of classes or interfaces) that  is  used  to
              provide  the  names  of the methods and traits to be made scriptable.  The class or
              interface effectively defines the scripting API.

              If api is not specified then includes is a list of method and trait names that  are
              made scriptable.

              If  api  and includes are not specified then excludes is a list of method and trait
              names that are not made scriptable.

              If script_init is set then the __init__() method is made scriptable irrespective of
              the api, includes and excludes arguments.

              If  script_init  is  not  set  then  objects  must be explicitly bound and name and
              bind_policy are ignored.

       make_object_scriptable(obj, api=None, includes=None, excludes=None)
              This takes an existing unscriptable object and makes it scriptable.   It  works  by
              calling  create_scriptable_type()  on  the  the objects existing type and replacing
              that existing type with the new scriptable type.

              See the description of create_scriptable_type() for  an  explanation  of  the  api,
              includes and excludes arguments.

   ScriptManager
       The ScriptManager class is the default implementation of the IScriptManager interface.

       bind_event
              This  event  is fired whenever an object is bound or unbound.  The event's argument
              implements the IBindEvent interface.

       recording
              This trait is set  if  a  script  is  currently  being  recorded.   It  is  updated
              automatically by the script manager.

       script This  trait  contains  the text of the script currently being recorded (or the last
              recorded  script  if  one  is  not  being  currently  recorded).   It  is   updated
              automatically by the script manager.

       script_updated
              This  event is fired whenever the script trait is updated.  The event's argument is
              the script manager.

       bind(self, obj, name=None, bind_policy='unique', api=None, includes=None, excludes=None)
              This method makes an object scriptable and binds it to a name.  See the description
              of create_scriptable_type() for an explanation of the api, includes, excludes, name
              and bind_policy arguments.

       bind_factory(self,   factory,   name,   bind_policy='unique',   api=None,   includes=None,
       excludes=None)
              This method binds an object factory to a name.  The factory is called to create the
              object (and make it scriptable) only when the object is needed by a running script.
              See  the description of create_scriptable_type() for an explanation of the name and
              bind_policy arguments.

       run(self, script)
              This method runs a script in a namespace containing all  currently  bound  objects.
              script is any object that can be used by Python's exec statement including a string
              or a file-like object.

       run_file(self, file_name)
              This method runs a script in a namespace containing all  currently  bound  objects.
              file_name is the name of a file containing the script.

       start_recording(self)
              This method starts the recording of a script.

       stop_recording(self)
              This method stops the recording of the current script.

   IBindEvent
       The  IBindEvent  interface  defines the interface that is implemented by the object passed
       when the script manager's bind_event is fired.

       name   This trait is the name being bound or unbound.

       obj    This trait is the obj being bound to name or None if name is being unbound.

   StartRecordingAction
       The StartRecordingAction class is a canned PyFace action  that  starts  the  recording  of
       changes to scriptable objects to a script.

   StopRecordingAction
       The StopRecordingAction class is a canned PyFace action that ends the recording of changes
       to scriptable objects to a script.

   Implementing Application Scripting
       The key part of supporting application scripting is to design an appropriate scripting API
       and  to ensure than the application itself uses the API so that changes to the data can be
       recorded.  The framework provides many ways to specify the scripting API.  Which  approach
       is  appropriate  in  a  particular  case  will  depend on when it is a new application, or
       whether scripting is  being  added  to  an  existing  application,  and  how  complex  the
       application's data model is.

   Static Specification
       A  scripting  API  is specified statically by the explicit use of the scriptable decorator
       and the Scriptable trait wrapper.  For example:

          from apptools.appscripting.api import scriptable, Scriptable
          from traits.api import HasTraits, Int, Str

          class DataModel(HasTraits):

              foo = Scriptable(Str)

              bar = Scriptable(Int, has_side_effects=True)

              @scriptable
              def baz(self):
                  pass

              def weeble(self)
                  pass

          # Create the scriptable object.  It's creation won't be recorded because
          # __init__() isn't decorated.
          obj = DataModel()

          # These will be recorded.
          obj.foo = ''
          obj.bar = 10
          obj.baz()

          # This will not be recorded.
          obj.weeble()

          # This won't be recorded unless 'f' is passed to something that is
          # recorded.
          f = obj.foo

          # This will be recorded because we set 'has_side_effects'.
          b = obj.bar

   Dynamic Specification
       A scripting API can also be specified  dynamically.   The  following  example  produces  a
       scriptable  object  with  the  same  scriptable  API  as  above  (with  the exception that
       has_side_effects cannot be specified dynamically):

          from apptools.appscripting.api import create_scriptable_type
          from traits.api import HasTraits, Int, Str

          class DataModel(HasTraits):

              foo = Str

              bar = Int

              def baz(self):
                  pass

              def weeble(self)
                  pass

          # Create a scriptable type based on the above.
          ScriptableDataModel = create_scriptable_type(DataModel, excludes=['weeble'])

          # Now create scriptable objects from the scriptable type.  Note that each
          # object has the same type.
          obj1 = ScriptableDataModel()
          obj2 = ScriptableDataModel()

       Instead we could bypass the type and make the objects themselves scriptable as follows:

          from apptools.appscripting.api import make_object_scriptable
          from traits.api import HasTraits, Int, Str

          class DataModel(HasTraits):

              foo = Str

              bar = Int

              def baz(self):
                  pass

              def weeble(self)
                  pass

          # Create unscriptable objects.
          obj1 = DataModel()
          obj2 = DataModel()

          # Now make the objects scriptable.  Note that each object has a different
          # type, each a sub-type of 'DataModel'.
          make_object_scriptable(obj1, excludes=['weeble'])
          make_object_scriptable(obj2, excludes=['weeble'])

       With a more sophisticated design we may  choose  to  specify  the  scriptable  API  as  an
       interface as follows:

          from apptools.appscripting.api import make_object_scriptable
          from traits.api import HasTraits, Int, Interface, Str

          class DataModel(HasTraits):

              foo = Str

              bar = Int

              def baz(self):
                  pass

              def weeble(self)
                  pass

          class IScriptableDataModel(Interface):

              foo = Str

              bar = Int

              def baz(self):
                  pass

          # Create an unscriptable object.
          obj = DataModel()

          # Now make the object scriptable.
          make_object_scriptable(obj, api=IScriptableDataModel)

   Scripting __init__()
       Making  a  type's  __init__()  method has advantages and disadvantages.  It means that the
       creation of scriptable objects will be recorded in a  script  (along  with  the  necessary
       import  statements).   This  means  that  the  script  can  be  run  independently of your
       application by the standard Python interpreter.

       The disadvantage is that, if you have a complex data model, with  many  interdependencies,
       then  defining  a  complete  and  consistent  scripting  API  that  allows a script to run
       independently may prove difficult.  In such cases it is better  to  have  the  application
       create and bind the scriptable objects itself.

PERMISSIONS FRAMEWORK - INTRODUCTION

       The  Permissions  Framework  is  a  component  of  the  Enthought Tool Suite that provides
       developers with the facility to limit access to parts of an application unless the user is
       appropriately  authorised.   In other words it enables and disables different parts of the
       GUI according to the identity of the user.

       The framework includes an API to allow it to be integrated with an organisation's existing
       security infrastructure, for example to look users up in a corporate LDAP directory.

       The  framework  is  completely  configurable.   Alternate  implementations  of  all  major
       components can be provided if necessary.  The default  implementations  provide  a  simple
       local filesystem user database and allows roles to be defined and assigned to users.

       The  framework  does  not  provide  any facility for protecting access to data.  It is not
       possible to implement such protection in Python and using the file security provided by  a
       typical operating system.

   Framework Concepts
       The following are the concepts supported by the framework.

       · Permission

         A permission is the basic tool that a developer uses to specify that access to a part of
         the application should be restricted.  If the  current  user  has  the  permission  then
         access  is  granted.   A  permission may be attached to a PyFace action, to an item of a
         TraitsUI view, or to a GUI toolkit specific widget.  When the user is denied access, the
         corresponding GUI control is disabled or completely hidden.

       · User

         Each  application has a current user who is either authorised or unauthorised.  In order
         to become authorised a user must identify themselves and authenticate that identity.

         An arbitrary piece of data (called a blob) can be associated  with  an  authorised  user
         which  (with  user  manager  support)  can  be stored securely.  This might be used, for
         example, to store sensitive user preferences, or to implement a roaming profile.

       · User Manager

         The user manager is responsible for authorising the current user and, therefore, defines
         how  that is done.  It also provides information about the user population to the policy
         manager.  It may also, optionally, provide the ability to  manage  the  user  population
         (eg. add or delete users).  The user manager must either maintain a persistent record of
         the user population, or interface with an external user database or directory service.

         The default user manager uses password based authorisation.

         The user manager persists its data  in  a  user  database.   The  default  user  manager
         provides  an API so that different implementations of the user database can be used (for
         example to store the data in an RDBMS,  or  to  integrate  with  an  existing  directory
         service).  A default user database is provided that pickles the data in a local file.

       · Policy Manager

         The policy manager is responsible for assigning permissions to users and for determining
         the permissions assigned to the current user.  To do this it must maintain a  persistent
         record of those assignments.

         The  default policy manager supplied with the framework uses roles to make it easier for
         an administrator to manage the relationships between permissions and users.  A  role  is
         defined as a named set of permissions, and a user may have one or more roles assigned to
         them.

         The policy manager persists its data in a policy database.  The default  policy  manager
         provides  an  API  so  that different implementations of the policy database can be used
         (for example to store the data in an RDBMS).  A default policy database is provided that
         pickles the data in a local file.

       · Permissions Manager

         The permissions manager is a singleton object used to get and set the current policy and
         user managers.

   Framework APIs
       The APIs provided by the permissions framework can be split into the following groups.

       · Application API

         This part of the API is used by application developers.

       · Policy Manager API

         This is the interface that an alternative policy manager must implement.   The  need  to
         implement  an  alternative  is  expected  to  be  very rare and so the API isn't covered
         further.  See the definition of the IPolicyManager interface for the details.

       · Default Policy Manager Data API

         This part of the API is used by developers to store the policy's persistent  data  in  a
         more  secure  location  (eg.  on  a  remote  server)  than  that provided by the default
         implementation.

       · User Manager API

         This is the interface that an alternative user manager  must  implement.   The  need  to
         implement  an  alternative  is  expected  to  be  very rare and so the API isn't covered
         further.  See the definition of the IUserManager interface for the details.

       · Default User Manager Data API

         This part of the API is used by developers to store the user database in a  more  secure
         location (eg. on a remote server) than that provided by the default implementation.

       The complete API documentation is available as endo generated HTML.

   What Do I Need to Reimplement?
       The  architecture of the permissions framework comprises several layers, each of which can
       reimplemented to meet  the  requirements  of  a  particular  environment.   Hopefully  the
       following  questions  and answers will clarify what needs to be reimplemented depending on
       your environment.

       Q: Do you want to use roles to group permissions and assign them to users?

       A: If yes then use the supplied PolicyManager, otherwise provide your own
              IPolicyManager implementation.

       Q: Do you want users to be authenticated using a password?

       A: If yes then use the supplied UserManager, otherwise provide your own
              IUserManager implementation.

       Q: Does the IUser interface allow you to store all the user specific
              information you need?

       A: If yes then use the supplied UserDatabase, otherwise provide your own
              IUserDatabase implementation.

       Q: Do you want to store your user accounts as pickled data in a local file?

       A: If yes then use the supplied default, otherwise provide UserDatabase with
              your own IUserStorage implementation.

       Q: Do you want to store your policy data (ie. roles and role assignments) as
              pickled data in a local file?

       A: If yes then use the supplied default, otherwise provide PolicyManager with
              your own IPolicyStorage implementation.

   Deploying Alternative Managers
       The permissions framework will first  try  to  import  the  different  managers  from  the
       apptools.permissions.external  namespace.   The  default  managers  are  only  used  if no
       alternative was found.  Therefore, alternative managers  should  be  deployed  as  an  egg
       containing that namespace.

       Specifically the framework looks for the following classes:
          PolicyManager from apptools.permissions.external.policy_manager

          PolicyStorage from apptools.permissions.external.policy_storage

          UserDatabase from apptools.permissions.external.user_database

          UserManager from apptools.permissions.external.user_manager

          UserStorage from apptools.permissions.external.user_storage

       The  example  server  is  such  a  package  that  provides  PolicyStorage  and UserStorage
       implementations that use an XML-RPC based server to provide remote (and consequently  more
       secure) policy and user databases.

   Using the Default Storage Implementations
       The default policy and user managers both (again by default) persist their data as pickles
       in local files called ets_perms_policydb and ets_perms_userdb  respectively.   By  default
       these   are   stored   in   the   application's  home  directory  (ie.  that  returned  by
       ETSConfig.application_home).

       Note that this directory is normally in the user's  own  directory  structure  whereas  it
       needs to be available to all users of the application.

       If the ETS_PERMS_DATA_DIR environment variable is set then its value is used instead.

       The directory must be writeable by all users of the application.

       It should be restated that the default implementations do not provide secure access to the
       permissions and user data.  They are useful in a cooperative environment  and  as  working
       examples.

APPLICATION API

       This section provides an overview of the part of the ETS Permissions Framework API used by
       application developers.  The Permissions Framework example demonstrates the  API  in  use.
       An application typically uses the API to do the following:

       · define permissions

       · apply permissions

       · user authentication

       · getting and setting user data

       · integrate management actions.

   Defining Permissions
       A  permission is the object that determines the user's access to a part of an application.
       While it is possible to apply the same permission to more than one part of an application,
       it  is  generally a bad idea to do so as it makes it difficult to separate them at a later
       date.

       A permission has an id and a human readable description.  Permission ids must  be  unique.
       By  convention  a dotted notation is used for ids to give them a structure.  Ids should at
       least be given an application or plugin specific prefix to ensure their uniqueness.

       Conventionally all an applications permissions are  defined  in  a  single  permissions.py
       module.  The following is an extract of the example's permissions.py module:

          from apptools.permissions.api import Permission

          # Add a new person.
          NewPersonPerm = Permission(id='ets.permissions.example.person.new',
                  description=u"Add a new person")

          # Update a person's age.
          UpdatePersonAgePerm = Permission(id='ets.permissions.example.person.age.update',
                  description=u"Update a person's age")

          # View or update a person's salary.
          PersonSalaryPerm = Permission(id='ets.permissions.example.person.salary',
                  description=u"View or update a person's salary")

   Applying Permissions
       Permissions are applied to different parts of an applications GUI.  When the user has been
       granted a permission then the corresponding part of the GUI is displayed  normally.   When
       the  user  is  denied  a  permission then the corresponding part of the GUI is disabled or
       completely hidden.

       Permissions can be applied to TraitsUI view items and to any object which can  be  wrapped
       in a SecureProxy.

   TraitsUI View Items
       Items  in  TraitsUI  views have enabled_when and visible_when traits that are evaluated to
       determine if the item should be enabled or visible respectively.  These are used to  apply
       permissions by storing the relevant permissions in the model so that they are available to
       the view.  The enabled_when and visible_when traits then simply reference the permission's
       granted trait.  The granted trait automatically reflects whether or not the user currently
       has the corresponding permission.

       In order for the view to be correctly updated when the user's permissions change (ie. when
       they become authenticated) the view must use the SecureHandler handler.  This handler is a
       simple sub-class of the standard Traits Handler class.

       The following extract from the example shows a default view  of  the  Person  object  that
       enables  the  age  item when the user has the UpdatePersonAgePerm permission and shows the
       salary item when the user has the PersonSalaryPerm permission:

          from apptools.permissions.api import SecureHandler
          from traits.api import HasTraits, Int, Unicode
          from traitsui.api import Item, View

          from permissions import UpdatePersonAgePerm, PersonSalaryPerm

          class Person(HasTraits):
              """A simple example of an object model"""

              # Name.
              name = Unicode

              # Age in years.
              age = Int

              # Salary.
              salary = Int

              # Define the default view with permissions attached.
              age_perm = UpdatePersonAgePerm
              salary_perm = PersonSalaryPerm

              traits_view = View(
                      Item(name='name'),
                      Item(name='age', enabled_when='object.age_perm.granted'),
                      Item(name='salary', visible_when='object.salary_perm.granted'),
                      handler=SecureHandler)

   Wrapping in a SecureProxy
       Any object can have permissions applied by  wrapping  it  in  a  SecureProxy  object.   An
       adapter  is  used  that  manages  the  enabled  and  visible  states of the proxied object
       according to the current user's permissions.  Otherwise the proxy behaves  just  like  the
       object being proxied.

       Adapters are included for the following types of object:

       · PyFace actions

       · PyFace widgets FIXME: TODO

       · Qt widgets

       · wx widgets

       See  Writing  SecureProxy  Adapters  for  a description of how to write adapters for other
       types of objects.

       The following extract from the example shows the wrapping of a standard PyFace action  and
       the application of the NewPersonPerm permission:

          from apptools.permissions.api import SecureProxy

          from permissions import NewPersonPerm

          ...

              def _new_person_action_default(self):
                  """Trait initializer."""

                  # Create the action and secure it with the appropriate permission.
                  act = Action(name='New Person', on_perform=self._new_person)
                  act = SecureProxy(act, permissions=[NewPersonPerm])

                  return act

       A  SecureProxy also accepts a show argument that, when set to False, hides the object when
       it becomes disabled.

   Authenticating the User
       The user manager supports  the  concept  of  the  current  user  and  is  responsible  for
       authenticating the user (and subsequently unauthorising the user if required).

       The code fragment to authenticate the current user is:

          from apptools.permissions.api import get_permissions_manager

          get_permissions_Manager().user_manager.authenticate_user()

       Unauthorising the current user is done using the unauthenticate_user() method.

       As  a  convenience  two  PyFace actions, called LoginAction and LogoutAction, are provided
       that wrap these two methods.

       As a further convenience a PyFace menu manager, called UserMenuManager, is  provided  that
       contains  all  the  user  and management actions (see below) in the permissions framework.
       This is used by the example.

       The    user    menu,    login    and    logout    actions    can    be    imported    from
       apptools.permissions.action.api.

   Getting and Setting User Data
       The  user  manager has a user trait that is an object that implements the IUser interface.
       It is only valid once the user has been authenticated.

       The IUser interface has a blob trait that holds any binary data (as a Python string).  The
       data will be read when the user is authenticated.  The data will be written whenever it is
       changed.

   Integrating Management Actions
       Both policy and  user  managers  can  provide  actions  that  provide  access  to  various
       management  functions.   Both  have  a  management_actions  trait that is a list of PyFace
       actions that invoke appropriate dialogs that allow the user to manage the policy  and  the
       user population appropriately.

       User  managers also have a user_actions trait that is a list of PyFace actions that invoke
       appropriate dialogs that allow the user to manage themselves.  For  example,  the  default
       user manager provides an action that allows a user to change their password.

       The  default  policy  manager provides actions that allows roles to be defined in terms of
       sets of permissions, and allows users to be assigned one or more roles.

       The default user manager provides actions that allows users  to  be  added,  modified  and
       deleted.  A user manager that integrates with an enterprise's secure directory service may
       not provide any management actions.

       All management actions have appropriate permissions attached to them.

   Writing SecureProxy Adapters
       SecureProxy will automatically handle most of the object types  you  will  want  to  apply
       permissions  to.  However it is possible to implement additional adapters to support other
       object types.  To do this you need to implement a sub-class of  AdapterBase  and  register
       it.

       Adapters  tend  to  be one of two styles according to how the object's enabled and visible
       states are changed.  If the states are changed  via  attributes  (typically  Traits  based
       objects)  then the adapter will cause a proxy to be created for the object.  If the states
       are changed via methods (typically toolkit widgets) then the adapter will probably  modify
       the  object  itself.   We will refer to these two styles as wrapping adapters and patching
       adapters respectively.

       The following gives a brief overview of the AdapterBase class:

       proxied
              This instance attribute is a reference to the original object.

       register_adapter(adapter, type, type, ...)
              This is a class method that is used to register your adapter and one or more object
              types that it handles.

       adapt()
              This  is  a method that should be reimplemented by patching adapters.  (The default
              implementation will cause a proxy to be created for wrapping  adapters.)   This  is
              where  any  patching of the proxied attribute is done.  The object returned will be
              returned by SecureProxy() and would normally be the patched object - but can be any
              object.

       setattr(name, value)
              This  method  should be reimplemented by wrapping adapters to intercept the setting
              of relevant attributes of the proxied object.  The default implementation should be
              used as the fallback for irrelevant attributes.

       get_enabled()
              This method must be reimplemented to return the current enabled state.

       set_enabled(value)
              This method must be reimplemented to set the enabled state to the given value.

       update_enabled(value)
              This  method  is  called  by  your  adapter to set the desired value of the enabled
              state.  The actual state set will depend on the current user's permissions.

       get_visible()
              This method must be reimplemented to return the current visible state.

       set_visible(value)
              This method must be reimplemented to set the visible state to the given value.

       update_visible(value)
              This method is called by your adapter to set  the  desired  value  of  the  visible
              state.  The actual state set will depend on the current user's permissions.

       The AdapterBase class is defined in adapter_base.py.

       The PyFace action adapter is an example of a wrapping adapter.

       The PyQt widget adapter is an example of a patching adapter.

DEFAULT POLICY MANAGER DATA API

       This section provides an overview of the part of the ETS Permissions Framework API used by
       developers who want to store a policy manager's persistent data in a more secure  location
       (eg. a remote server) than that provided by the default implementation.

       The  API  is  defined  by the default policy manager which uses roles to make it easier to
       assign permissions to users.  If this API isn't sufficiently flexible,  or  if  roles  are
       inappropriate, then an alternative policy manager should be implemented.

       The  API  is fully defined by the IPolicyStorage interface.  The default implementation of
       this interface stores the policy database as a pickle in a local file.

   Overview of IPolicyStorage
       The IPolicyStorage interface defines a number of methods that must be implemented to  read
       and write to the policy database.  The methods are designed to be implemented using simple
       SQL statements.

       In the event of an error a method must raise the PolicyStorageError exception.  The string
       representation of the exception is used as an error message that is displayed to the user.

DEFAULT USER MANAGER DATA API

       This section provides an overview of the part of the ETS Permissions Framework API used by
       developers who want to store a user database in a  more  secure  location  (eg.  a  remote
       server) than that provided by the default implementation.

       The  API  is  defined by the default user manager which uses password based authorisation.
       If this API isn't sufficiently flexible, or if another method  of  authorisation  is  used
       (biometrics for example) then an alternative user manager should be implemented.

       The API is fully defined by the IUserDatabase interface.  This allows user databases to be
       implemented that extend the IUser interface and store additional user  related  data.   If
       the  user  database  is  being  persisted in secure storage (eg. a remote RDBMS) then this
       could be used to store sensitive data (eg. passwords for external systems) that  shouldn't
       be stored as ordinary preferences.

       In most cases there will be no requirement to store additional user related data than that
       defined by IUser so the supplied UserDatabase implementation (which provides all  the  GUI
       code  required  to  implement  the IUserDatabase interface) can be used.  The UserDatabase
       implementation delegates the access to the user database to  an  object  implementing  the
       IUserStorage  interface.   The  default  implementation  of this interface stores the user
       database as a pickle in a local file.

   Overview of IUserStorage
       The IUserStorage interface defines a number of methods that must be  implemented  to  read
       and  write  to the user database.  The methods are designed to be implemented using simple
       SQL statements.

       In the event of an error a method must raise the UserStorageError exception.   The  string
       representation of the exception is used as an error message that is displayed to the user.

   Overview of IUserDatabase
       The  IUserDatabase  interface  defines a set of Bool traits, all beginning with can_, that
       describe the capabilities of a particular implementation.  For example,  the  can_add_user
       trait  is  set  by  an  implementation if it supports the ability to add a new user to the
       database.

       Each of these capability traits has a corresponding method which has the same name  except
       for  the can_ prefix.  The method only needs to be implemented if the corresponding traits
       is True.  The method, for example add_user() is called by the user  manager  to  implement
       the capability.

       The interface has two other methods.

       The  bootstrapping()  method is called by the user manager to determine if the database is
       bootstrapping.  Typically this is when the database is empty and no users  have  yet  been
       defined.  The permissions framework treats this situation as a special case and is able to
       relax the enforcement of permissions to  allow  users  and  permissions  to  be  initially
       defined.

       The  user_factory()  method is called by the user manager to create a new user object, ie.
       an object that implements the IUser interface.  This allows an  implementation  to  extend
       the IUser interface and store additional user related data in the object if the blob trait
       proves insufficient.

PREFERENCES

       The preferences package provides a simple API for managing  application  preferences.  The
       classes  in  the  package  are implemented using a layered approach where the lowest layer
       provides access to the raw preferences mechanism and each  layer  on  top  providing  more
       convenient ways to get and set preference values.

THE BASIC PREFERENCES MECHANISM

       Lets  start  by  taking  a  look  at  the  lowest layer which consists of the IPreferences
       interface and its default implementation in the Preferences class. This  layer  implements
       the  basic  preferences  system which is a hierarchical arrangement of preferences 'nodes'
       (where each node is simply an object that implements the IPreferences interface). Nodes in
       the hierarchy can contain preference settings and/or child nodes. This layer also provides
       a default way to read and write  preferences  from  the  filesystem  using  the  excellent
       ConfigObj package.

       This  all sounds a bit complicated but, believe me, it isn't! To prove it (hopefully) lets
       look at an example. Say I have the following preferences in a file 'example.ini':

          [acme.ui]
          bgcolor = blue
          width = 50
          ratio = 1.0
          visible = True

          [acme.ui.splash_screen]
          image = splash
          fgcolor = red

       I can create a preferences hierarchy from this file by:

          >>> from apptools.preferences.api import Preferences
          >>> preferences = Preferences(filename='example.ini')
          >>> preferences.dump()

           Node() {}
              Node(acme) {}
                Node(ui) {'bgcolor': 'blue', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                  Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}

       The 'dump' method  (useful  for  debugging  etc)  simply  'pretty  prints'  a  preferences
       hierarchy.  The  dictionary  next  to each node contains the node's actual preferences. In
       this case, the root node (the node with  no  name)  is  the  preferences  object  that  we
       created.  This  node  now  has  one  child node 'acme', which contains no preferences. The
       'acme' node has one child, 'ui', which contains some preferences (e.g. 'bgcolor') and also
       a child node 'splash_screen' which also contains preferences (e.g. 'image').

       To look up a preference we use:

          >>> preferences.get('acme.ui.bgcolor')
          'blue'

       If no such preferences exists then, by default, None is returned:

          >>> preferences.get('acme.ui.bogus') is None
          True

       You can also specify an explicit default value:

          >>> preferences.get('acme.ui.bogus', 'fred')
          'fred'

       To set a preference we use:

          >>> preferences.set('acme.ui.bgcolor', 'red')
          >>> preferences.get('acme.ui.bgcolor')
          'red'

       And to make sure the preferences are saved back to disk:

          >>> preferences.flush()

       To add a new preference value we simply set it:

          >>> preferences.set('acme.ui.fgcolor', 'black')
          >>> preferences.get('acme.ui.fgcolor')
          'black'

       Any missing nodes in a call to 'set' are created automatically, hence:

          >>> preferences.set('acme.ui.button.fgcolor', 'white')
          >>> preferences.get('acme.ui.button.fgcolor')
          'white'

       Preferences  can  also  be 'inherited'. e.g. Notice that the 'splash_screen' node does not
       contain a 'bgcolor' preference, and hence:

          >>> preferences.get('acme.ui.splash_screen.bgcolor') is None
          True

       But if we allow the 'inheritance' of preference values then:

          >>> preferences.get('acme.ui.splash_screen.bgcolor', inherit=True)
          'red'

       By using 'inheritance' here the preferences system will try the following preferences:

          'acme.ui.splash_screen.bgcolor'
          'acme.ui.bgcolor'
          'acme.bgcolor'
          'bgcolor'

   Strings, Glorious Strings
       At this point it is worth mentioning that preferences are always stored  and  returned  as
       strings.  This  is  because  of the limitations of the traditional '.ini' file format i.e.
       they don't contain any type information! Now before you start panicking, this doesn't mean
       that  all of your preferences have to be strings! Currently the preferences system allows,
       strings(!), booleans, ints, longs, floats and complex numbers. When you store a non-string
       value it gets converted to a string for you, but you always get a string back:

          >>> preferences.get('acme.ui.width')
          '50'
          >>> preferences.set('acme.ui.width', 100)
          >>> preferences.get('acme.ui.width')
          '100'

          >>> preferences.get('acme.ui.visible')
          'True'
          >>> preferences.set('acme.ui.visible', False)
          >>> preferences.get('acme.ui.visible')
          'False'

       This  is  obviously not terribly convenient, and so the following section discusses how we
       associate type information with our preferences to make  getting  and  setting  them  more
       natural.

PREFERENCES AND TYPES

       As mentioned previously, we would like to be able to get and set non-string preferences in
       a more convenient way. This is where the PreferencesHelper class comes in.

       Let's take another look at 'example.ini':

          [acme.ui]
          bgcolor = blue
          width = 50
          ratio = 1.0
          visible = True

          [acme.ui.splash_screen]
          image = splash
          fgcolor = red

       Say, I am interested in the preferences in the 'acme.ui' section. I can use a  preferences
       helper as follows:

          from apptools.preferences.api import PreferencesHelper

          class SplashScreenPreferences(PreferencesHelper):
              """ A preferences helper for the splash screen. """

              PREFERENCES_PATH = 'acme.ui'

              bgcolor = Str
              width   = Int
              ratio   = Float
              visible = Bool

          >>> preferences = Preferences(filename='example.ini')
          >>> helper = SplashScreenPreferences(preferences=preferences)
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

       And, obviously, I can set the value of the preferences via the helper too:

          >>> helper.ratio = 0.5

       And if you want to prove to yourself it really did set the preference:

          >>> preferences.get('acme.ui.ratio')
          '0.5'

       Using  a  preferences  helper you also get notified via the usual trait mechanism when the
       preferences are changed (either via the helper or via the preferences node directly:

          def listener(obj, trait_name, old, new):
              print trait_name, old, new

          >>> helper.on_trait_change(listener)
          >>> helper.ratio = 0.75
          ratio 0.5 0.75
          >>> preferences.set('acme.ui.ratio', 0.33)
          ratio 0.75 0.33

       If you always use the same preference node as the root of your preferences  you  can  also
       set  the  class attribute 'PreferencesHelper.preferences' to be that node and from then on
       in, you don't have to pass a preferences collection in each time you create a helper:

          >>> PreferencesHelper.preferences = Preferences(filename='example.ini')
          >>> helper = SplashScreenPreferences()
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

SCOPED PREFERENCES

       In many applications the idea of preferences scopes is useful.  In  a  scoped  system,  an
       actual  preference  value  can be stored in any scope and when a call is made to the 'get'
       method the scopes are searched in order of precedence.

       The default implementation  (in  the  ScopedPreferences  class)  provides  two  scopes  by
       default:

       1. The application scope

       This  scope  stores  itself  in  the 'ETSConfig.application_home' directory. This scope is
       generally used when setting any user preferences.

       2. The default scope

       This scope is transient (i.e. it does not store itself anywhere). This scope is  generally
       used to load any predefined default values into the preferences system.

       If  you  are happy with the default arrangement, then using the scoped preferences is just
       like using the plain old non-scoped version:

          >>> from apptools.preferences.api import ScopedPreferences
          >>> preferences = ScopedPreferences(filename='example.ini')
          >>> preferences.load('example.ini')
          >>> p.dump()

            Node() {}
              Node(application) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'blue', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                    Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}
              Node(default) {}

       Here you can see that the root node now has a child node representing each scope.

       When we are getting and setting preferences using scopes we generally want  the  following
       behaviour:

       a)  When we get a preference we want to look it up in each scope in order. The first scope
       that contains a value 'wins'.

       b) When we set a preference, we want to set it in the first scope. By default  this  means
       that  when  we  set  a preference it will be set in the application scope. This is exactly
       what we want as the application scope is the scope that is persistent.

       So usually, we just use the scoped preferences as before:

          >>> preferences.get('acme.ui.bgcolor')
          'blue'
          >>> preferences.set('acme.ui.bgcolor', 'red')
          >>> preferences.dump()

            Node() {}
              Node(application) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'red', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                    Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}
              Node(default) {}

       And, conveniently, preference helpers work just the same with scoped preferences too:

          >>> PreferencesHelper.preferences = ScopedPreferences(filename='example.ini')
          >>> helper = SplashScreenPreferences()
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

   Accessing a particular scope
       Should you care about getting or setting a preference in a particular scope then  you  use
       the following syntax:

          >>> preferences.set('default/acme.ui.bgcolor', 'red')
          >>> preferences.get('default/acme.ui.bgcolor')
          'red'
          >>> preferences.dump()

            Node() {}
              Node(application) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'red', 'ratio': '1.0', 'width': '50', 'visible': 'True'}
                    Node(splash_screen) {'image': 'splash', 'fgcolor': 'red'}
              Node(default) {}
                Node(acme) {}
                  Node(ui) {'bgcolor': 'red'}

       You can also get hold of a scope via:

          >>> default = preferences.get_scope('default')

       And then perform any of the usual operations on it.

FURTHER READING

       So  that's  a  quick  tour  around  the  basic  useage  of  the  preferences API. For more
       imformation about what is provided take a look at the API documentation.

       If you are using Envisage to build your applications then you might also be interested  in
       the Preferences in Envisage section.

PREFERENCES IN ENVISAGE

       This  section  discusses  how  an  Envisage  application  uses  the preferences mechanism.
       Envisage tries not to dictate too much, and so this describes the default  behaviour,  but
       you are free to override it as desired.

       Envisage  uses  the  default  implementation  of the ScopedPreferences class which is made
       available via the application's 'preferences' trait:

          >>> application = Application(id='myapplication')
          >>> application.preferences.set('acme.ui.bgcolor', 'yellow')
          >>> application.preferences.get('acme.ui.bgcolor')
          'yellow'

       Hence, you use the Envisage preferences just like you would any other scoped preferences.

       It also registers itself as the default preferences node  used  by  the  PreferencesHelper
       class. Hence you don't need to provide a preferences node explicitly to your helper:

          >>> helper = SplashScreenPreferences()
          >>> helper.bgcolor
          'blue'
          >>> helper.width
          100
          >>> helper.ratio
          1.0
          >>> helper.visible
          True

       The  only  extra  thing  that  Envisage does for you is to provide an extension point that
       allows you to contribute any number of '.ini' files that are loaded into the default scope
       when the application is started.

       e.g. To contribute a preference file for my plugin I might use:

          class MyPlugin(Plugin):
              ...

              @contributes_to('envisage.preferences')
              def get_preferences(self, application):
                  return ['pkgfile://mypackage:preferences.ini']

AUTOMATIC SCRIPT RECORDING

       This  package  provides  a very handy and powerful Python script recording facility.  This
       can be used to:

          · record all actions performed on a traits based  UI  into  a  human  readable,  Python
            script that should be able to recreate your UI actions.

          · easily learn the scripting API of an application.

       This  package  is  not  just a toy framework and is powerful enough to provide full script
       recording to the Mayavi application.  Mayavi is a powerful 3D visualization tool  that  is
       part of ETS.

   The scripting API
       The  scripting API primarily allows you to record UI actions for objects that have Traits.
       Technically the framework listens to all trait changes so will work outside a UI.   We  do
       not   document   the   full   API   here,   the  best  place  to  look  for  that  is  the
       apptools.scripting.recorder module which is reasonably well documented.  We provide a high
       level overview of the library.

       The quickest way to get started is to look at a small example.

   A tour by example
       The  following  example  is  taken  from the test suite.  Consider a set of simple objects
       organized in a hierarchy:

          from traits.api import (HasTraits, Float, Instance,
                  Str, List, Bool, HasStrictTraits, Tuple, Range, TraitPrefixMap,
                  Trait)
          from apptools.scripting.api import (Recorder, recordable,
              set_recorder)

          class Property(HasStrictTraits):
              color = Tuple(Range(0.0, 1.0), Range(0.0, 1.0), Range(0.0, 1.0))
              opacity = Range(0.0, 1.0, 1.0)
              representation = Trait('surface',
                                     TraitPrefixMap({'surface':2,
                                                     'wireframe': 1,
                                                     'points': 0}))
          class Toy(HasTraits):
              color = Str
              type = Str
              # Note the use of the trait metadata to ignore this trait.
              ignore = Bool(False, record=False)

          class Child(HasTraits):
              name = Str('child')
              age = Float(10.0)
              # The recorder walks through sub-instances if they are marked
              # with record=True
              property = Instance(Property, (), record=True)
              toy = Instance(Toy, record=True)
              friends = List(Str)

              # The decorator records the method.
              @recordable
              def grow(self, x):
                  """Increase age by x years."""
                  self.age += x

          class Parent(HasTraits):
              children = List(Child, record=True)
              recorder = Instance(Recorder, record=False)

       Using these simple classes we first create a simple object hierarchy as follows:

          p = Parent()
          c = Child()
          t = Toy()
          c.toy = t
          p.children.append(c)

       Given this hierarchy, we'd like to be able to record a script.  To do this  we  setup  the
       recording infrastructure:

          from mayavi.core.recorder import Recorder, set_recorder
          # Create a recorder.
          r = Recorder()
          # Set the global recorder so the decorator works.
          set_recorder(r)
          r.register(p)
          r.recording = True

       The  key  method  here  is  the r.register(p) call above.  It looks at the traits of p and
       finds all traits and nested objects that specify a record=True  in  their  trait  metadata
       (all  methods  starting  and  ending  with  _  are  ignored).  All sub-objects are in turn
       registered with the recorder and so on.  Callbacks are  attached  to  traits  changes  and
       these  are  wired up to produce readable and executable code.  The set_recorder(r) call is
       also very important and sets the global recorder so the framework listens to any functions
       that are decorated with the recordable decorator.

       Now lets test this out like so:

          # The following will be recorded.
          c.name = 'Shiva'
          c.property.representation = 'w'
          c.property.opacity = 0.4
          c.grow(1)

       To see what's been recorded do this:

          print r.script

       This prints:

          child = parent.children[0]
          child.name = 'Shiva'
          child.property.representation = 'wireframe'
          child.property.opacity = 0.40000000000000002
          child.grow(1)

       The  recorder  internally  maintains  a  mapping between objects and unique names for each
       object.  It also stores the information about the location of a particular object  in  the
       object  hierarchy.   For  example,  the path to the Toy instance in the hierarchy above is
       parent.children[0].toy.  Since scripting with lists this way can be tedious, the  recorder
       first instantiates the child:

          child = parent.children[0]

       Subsequent  lines  use  the child attribute.  The recorder always tries to instantiate the
       object referred to using its path information in this manner.

       To record a function or method call one must simply decorate the function/method with  the
       recordable  decorator.  Nested recordable functions are not recorded and trait changes are
       also not recorded if done inside a recordable function.

       NOTE:

          1. It is very important  to  note  that  the  global  recorder  must  be  set  via  the
             set_recorder method.  The recordable decorator relies on this being set to work.

          2. The recordable decorator will work with plain Python classes and with functions too.

       To stop recording do this:

          r.unregister(p)
          r.recording = False

       The  r.unregister(p) reverses the r.register(p) call and unregisters all nested objects as
       well.

   Advanced use cases
       Here are a few advanced use cases.

          · The API also provides a RecorderWithUI class that provides a  simple  user  interface
            that prints the recorded script and allows the user to save the script.

          · Sometimes  it  is  not  enough  to just record trait changes, one may want to pass an
            arbitrary string or command when recording is occurring.  To allow for this,  if  one
            defines  a  recorder trait on the object, it is set to the current recorder.  One can
            then use this recorder to do whatever one wants.  This is very convenient.

          · To ignore specific traits one must specify either  a  record=False  metadata  to  the
            trait  definition  or  specify a list of strings to the register method in the ignore
            keyword argument.

          · If you want to use a specific name for an object on  the  script  you  can  pass  the
            script_id parameter to the register function.

       For  more details on the recorder itself we suggest reading the module source code.  It is
       fairly well documented and with the above background should be enough to get you going.

UNDO FRAMEWORK

       The Undo Framework is a component of the Enthought Tool  Suite  that  provides  developers
       with an API that implements the standard pattern for do/undo/redo commands.

       The  framework  is  completely  configurable.   Alternate  implementations  of  all  major
       components can be provided if necessary.

   Framework Concepts
       The following are the concepts supported by the framework.

       · Command

         A command is an application defined operation that can be done (i.e.  executed),  undone
         (i.e. reverted) and redone (i.e. repeated).

         A  command operates on some data and maintains sufficient state to allow it to revert or
         repeat a change to the data.

         Commands may be merged so that potentially long sequences of similar commands  (e.g.  to
         add a character to some text) can be collapsed into a single command (e.g. to add a word
         to some text).

       · Macro

         A macro is a sequence of commands that is treated as a single command when being  undone
         or redone.

       · Command Stack

         A  command  is  done by pushing it onto a command stack.  The last command can be undone
         and redone by calling appropriate command stack methods.  It is also  possible  to  move
         the  stack's  position  to any point and the command stack will ensure that commands are
         undone or redone as required.

         A command stack maintains a clean state which  is  updated  as  commands  are  done  and
         undone.   It  may  be explicitly set, for example when the data being manipulated by the
         commands is saved to disk.

         Canned PyFace actions are provided as wrappers around command stack methods to implement
         common menu items.

       · Undo Manager

         An  undo manager is responsible for one or more command stacks and maintains a reference
         to the currently active stack.  It provides  convenience  undo  and  redo  methods  that
         operate on the currently active stack.

         An  undo  manager  ensures  that  each  command execution is allocated a unique sequence
         number, irrespective of which command stack it is pushed to.  Using this it is  possible
         to synchronise multiple command stacks and restore them to a particular point in time.

         An  undo  manager  will  generate  an event whenever the clean state of the active stack
         changes.  This can be used to maintain some sort of GUI status  indicator  to  tell  the
         user that their data has been modified since it was last saved.

       Typically  an application will have one undo manager and one undo stack for each data type
       that can be edited.  However this is  not  a  requirement:  how  the  command  stack's  in
       particular  are  organised  and  linked (with the user manager's sequence number) can need
       careful thought so as not to confuse the user - particularly in a plugin based application
       that may have many editors.

       To support this typical usage the PyFace Workbench class has an undo_manager trait and the
       PyFace Editor class has a command_stack trait.  Both are lazy loaded so can be  completely
       ignored if they are not used.

   API Overview
       This  section  gives a brief overview of the various classes implemented in the framework.
       The complete API documentation is available as endo generated HTML.

       The example application demonstrates all the major features of the framework.

   UndoManager
       The UndoManager class is the default implementation of the IUndoManager interface.

       active_stack
              This trait is a reference to the currently active command stack and  may  be  None.
              Typically it is set when some sort of editor becomes active.

       active_stack_clean
              This  boolean trait reflects the clean state of the currently active command stack.
              It is intended to support a "document  modified"  indicator  in  the  GUI.   It  is
              maintained by the undo manager.

       stack_updated
              This  event  is fired when the index of a command stack is changed.  A reference to
              the stack is passed as an argument to the event and may not be the currently active
              stack.

       undo_name
              This Unicode trait is the name of the command that can be undone, and will be empty
              if there is no such command.  It is maintained by the undo manager.

       redo_name
              This Unicode trait is the name of the command that can be redone, and will be empty
              if there is no such command.  It is maintained by the undo manager.

       sequence_nr
              This  integer  trait is the sequence number of the next command to be executed.  It
              is incremented immediately before a command's do() method is called.  A  particular
              sequence  number  identifies  the  state  of all command stacks handled by the undo
              manager and allows those stacks to be set to the point they were at at a particular
              point  in  time.   In other words, the sequence number allows otherwise independent
              command stacks to be synchronised.

       undo() This method calls the undo() method of the  last  command  on  the  active  command
              stack.

       redo() This  method  calls  the  redo()  method  of  the last undone command on the active
              command stack.

   CommandStack
       The CommandStack class is the default implementation of the ICommandStack interface.

       clean  This boolean traits reflects the clean state  of  the  command  stack.   Its  value
              changes as commands are executed, undone and redone.  It may also be explicitly set
              to mark the current stack position as being clean (when data is saved to  disk  for
              example).

       undo_name
              This Unicode trait is the name of the command that can be undone, and will be empty
              if there is no such command.  It is maintained by the command stack.

       redo_name
              This Unicode trait is the name of the command that can be redone, and will be empty
              if there is no such command.  It is maintained by the command stack.

       undo_manager
              This trait is a reference to the undo manager that manages the command stack.

       push(command)
              This  method  executes  the  given  command  by calling its do() method.  Any value
              returned by do() is returned by push().  If the command couldn't be merged with the
              previous one then it is saved on the command stack.

       undo(sequence_nr=0)
              This  method  undoes  the  last  command.   If  a sequence number is given then all
              commands are undone up to an including the sequence number.

       redo(sequence_nr=0)
              This method redoes the last command and returns any result.  If a  sequence  number
              is  given  then  all commands are redone up to an including the sequence number and
              any result of the last of these is returned.

       clear()
              This method clears the command stack, without undoing or redoing any commands,  and
              leaves  the  stack  in a clean state.  It is typically used when all changes to the
              data have been abandoned.

       begin_macro(name)
              This method begins a macro by creating an empty command with the given  name.   The
              commands  passed  to  all subsequent calls to push() will be contained in the macro
              until the next call to end_macro().  Macros may be nested.  The  command  stack  is
              disabled  (ie. nothing can be undone or redone) while a macro is being created (ie.
              while there is an outstanding end_macro() call).

       end_macro()
              This method ends the current macro.

   ICommand
       The  ICommand  interface  defines  the  interface  that  must  be   implemented   by   any
       undoable/redoable command.

       data   This optional trait is a reference to the data object that the command operates on.
              It is not used by the framework itself.

       name   This Unicode trait is the name of the command as it will appear in any GUI  element
              (e.g.  in the text of an undo and redo menu entry).  It may include & to indicate a
              keyboard shortcut which will be automatically removed whenever it is inappropriate.

       __init__(*args)
              If the command takes arguments then the command must ensure that deep copies should
              be made if appropriate.

       do()   This  method  is called by a command stack to execute the command and to return any
              result.  The command must save any  state  necessary  for  the  undo()  and  redo()
              methods to work.  It is guaranteed that this will only ever be called once and that
              it will be called before any call to undo() or redo().

       undo() This method is called by a command stack to undo the command.

       redo() This method is called by a command stack to redo the  command  and  to  return  any
              result.

       merge(other)
              This  method is called by the command stack to try and merge the other command with
              this one.  True should be returned if the commands were merged.   If  the  commands
              are  merged  then other will not be placed on the command stack.  A subsequent undo
              or redo of this modified command must have the same  effect  as  the  two  original
              commands.

   AbstractCommand
       AbstractCommand  is  an  abstract  base  class that implements the ICommand interface.  It
       provides a default implementation of the merge() method.

   CommandAction
       The CommandAction class is a sub-class of the PyFace Action class that  is  used  to  wrap
       commands.

       command
              This  callable  trait  must  be  set  to  a factory that will return an object that
              implements ICommand.  It will be called when the action is invoked and  the  object
              created pushed onto the command stack.

       command_stack
              This  instance  trait must be set to the command stack that commands invoked by the
              action are pushed to.

       data   This optional trait is a reference to the data object that will be  passed  to  the
              command factory when it is called.

   UndoAction
       The  UndoAction class is a canned PyFace action that undoes the last command of the active
       command stack.

   RedoAction
       The RedoAction class is a canned PyFace action that redoes the last command undone of  the
       active command stack.

THE SELECTION SERVICE

       It  is  quite  common  in GUI applications to have a UI element displaying a collection of
       items that a user can select ("selection providers"), while other parts of the application
       must react to changes in the selection ("selection listeners").

       Ideally,  the  listeners  would  not  have  a direct dependency on the UI object.  This is
       especially important in extensible envisage applications, where a  plugin  might  need  to
       react to a selection change, but we do not want to expose the internal organization of the
       application to external developers.

       This package defines a selection service that manages the communication between  providers
       and listener.

   The SelectionService object
       The  SelectionService object is the central manager that handles the communication between
       selection providers and listener.

       Selection providers are components that wish to publish information  about  their  current
       selection for public consumption.  They register to a selection service instance when they
       first have a selection available (e.g., when the UI showing a list of selectable items  is
       initialized), and un-register as soon as the selection is not available anymore (e.g., the
       UI is destroyed when the windows is closed).

       Selection listeners can query the selection service to get the current selection published
       by a provider, using the provider unique ID.

       The  service  acts  as a broker between providers and listeners, making sure that they are
       notified when the selection event is fired.

   Selection providers
       Any object  can  become  a  selection  provider  by  implementing  the  ISelectionProvider
       interface, and registering to the selection service.

       Selection  providers  must  provide a unique ID provider_id, which is used by listeners to
       request its current selection.

       Whenever its selection changes, providers fire a selection event. The content of the event
       is an instance implementing ISelection that contains information about the selected items.
       For example, a ListSelection object contains a list of selected items, and their indices.

       Selection providers can also be queried directly about their current selection  using  the
       get_selection method, and can be requested to change their selection to a new one with the
       set_selection method.

   Registration
       Selection providers publish their selection by registering to the selection service  using
       the  add_selection_provider  method.  When the selection is no longer available, selection
       providers should un-register through remove_selection_provider.

       Typically, selection providers are UI objects showing  a  list  or  tree  of  items,  they
       register as soon as the UI component is initialized, and un-register when the UI component
       disappears (e.g., because their window has been closed).  In  more  complex  applications,
       the registration could be done by a controller object instead.

   Selection listeners
       Selection  listeners  request  information  regarding the current selection of a selection
       provider given their provider ID. The SelectionService supports two distinct use cases:

          1. Passively listening to selection changes: listener connect to  a  specific  provider
             and are notified when the provider's selection changes.

          2. Actively querying a provider for its current selection: the selection service can be
             used to query a provider using its unique ID.

   Passive listening
       Listeners  connect  to  the  selection   events   for   a   given   provider   using   the
       connect_selection_listener method. They need to provide the unique ID of the provider, and
       a function (or callable) that is called to send the event. This  callback  function  takes
       one argument, an implementation of the ISelection that represents the selection.

       It is possible for a listener to connect to a provider ID before it is registered. As soon
       as the provider is registered, the listener will receive  a  notification  containing  the
       provider's initial selection.

       To disconnect a listener use the methods disconnect_selection_listener.

   Active querying
       In  other  instances,  an element of the application only needs the current selection at a
       specific time. For example, a toolbar button could open dialog representing a user  action
       based on what is currently selected in the active editor.

       The  get_selection method calls the corresponding method on the provider with the given ID
       and returns an ISelection instance.

   Setting a selection
       Finally, it is possible to request a provider to set its  selection  to  a  given  set  of
       objects  with  set_selection.   The main use case for this method is multiple views of the
       same list of objects, which need to keep their selection synchronized.

       If  the  items  specified  in  the  arguments  are  not  available  in  the  provider,   a
       ProviderNotRegisteredError  is raised, unless the optional keyword argument ignore_missing
       is set to True.

   API Reference
   apptools.selection Package
       Users of the apptools.selection package can access the objects that are part of the public
       API through the convenience apptools.selection.api.

   selection_service Module
       class apptools.selection.selection_service.SelectionService
              Bases: traits.has_traits.HasTraits

              The selection service connects selection providers and listeners.

              The  selection  service  is  a  register of selection providers, i.e., objects that
              publish their current selection.

              Selections  can  be  requested  actively,  by  explicitly  requesting  the  current
              selection in a provider (get_selection(id)()), or passively by connecting selection
              listeners.

              add_selection_provider(provider)
                     Add a selection provider.

                     The provider is identified by its ID. If a provider with  the  same  ID  has
                     been already registered, an IDConflictError is raised.

                     Arguments:

                            provider -- ISelectionProvider
                                   The selection provider added to the internal registry.

              connect_selection_listener(provider_id, func)
                     Connect a listener to selection events from a specific provider.

                     The  signature  if the listener callback is func(i_selection).  The listener
                     is called:

                     1. When a provider with  the  given  ID  is  registered,  with  its  initial
                        selection as argument, or

                     2. whenever the provider fires a selection event.

                     It is perfectly valid to connect a listener before a provider with the given
                     ID is registered. The listener will remain connected even if the provider is
                     repeatedly connected and disconnected.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                            func -- callable(i_selection)
                                   A callable object that is notified when the selection changes.

              disconnect_selection_listener(provider_id, func)
                     Disconnect a listener from a specific provider.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                            func -- callable(provider_id, i_selection)
                                   A callable object that is notified when the selection changes.

              get_selection(provider_id)
                     Return the current selection of the provider with the given ID.

                     If    a    provider    with   that   ID   has   not   been   registered,   a
                     ProviderNotRegisteredError is raised.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                     Returns:

                            selection -- ISelection
                                   The current selection of the provider.

              has_selection_provider(provider_id)
                     Has a provider with the given ID been registered?

              remove_selection_provider(provider)
                     Remove a selection provider.

                     If the provider has not been  registered,  a  ProviderNotRegisteredError  is
                     raised.

                     Arguments:

                            provider -- ISelectionProvider
                                   The selection provider added to the internal registry.

              set_selection(provider_id, items, ignore_missing=False)
                     Set the current selection in a provider to the given items.

                     If   a   provider   with   the   given   ID   has  not  been  registered,  a
                     ProviderNotRegisteredError is raised.

                     If ignore_missing is True, items that are not  available  in  the  selection
                     provider are silently ignored. If it is False (default), a ValueError should
                     be raised.

                     Arguments:

                            provider_id -- str
                                   The selection provider ID.

                            items -- list
                                   List of items to be selected.

                            ignore_missing -- bool
                                   If False (default), the provider raises an exception if any of
                                   the   items   in  items  is  not  available  to  be  selected.
                                   Otherwise, missing elements are silently ignored, and the rest
                                   is selected.

   i_selection_provider Module
       class apptools.selection.i_selection_provider.ISelectionProvider(**kw)
              Bases: traits.has_traits.Interface

              Source of selections.

              get_selection()
                     Return the current selection.

                     Returns:

                            selection -- ISelection
                                   Object representing the current selection.

              provider_id = Str()
                     Unique ID identifying the provider.

              selection = Event
                     Event  triggered when the selection changes.  The content of the event is an
                     ISelection instance.

              set_selection(items, ignore_missing=False)
                     Set the current selection to the given items.

                     If ignore_missing is True, items that are not  available  in  the  selection
                     provider  are  silently  ignored.  If  it  is False (default), an ValueError
                     should be raised.

                     Arguments:

                            items -- list
                                   List of items to be selected.

                            ignore_missing -- bool
                                   If False (default), the provider raises an exception if any of
                                   the   items   in  items  is  not  available  to  be  selected.
                                   Otherwise, missing elements are silently ignored, and the rest
                                   is selected.

   is_selection Module
       class apptools.selection.i_selection.IListSelection(**kw)
              Bases: apptools.selection.i_selection.ISelection

              Selection for ordered sequences of items.

              indices = List
                     Indices of the selected objects in the selection provider.

              items = List
                     Selected objects.

       class apptools.selection.i_selection.ISelection(**kw)
              Bases: traits.has_traits.Interface

              Collection of selected items.

              is_empty()
                     Is the selection empty?

              provider_id = Str
                     ID of the selection provider that created this selection object.

   list_selection Module
       class apptools.selection.list_selection.ListSelection
              Bases: traits.has_traits.HasTraits

              Selection for ordered sequences of items.

              This is the default implementation of the IListSelection interface.

              classmethod from_available_items(provider_id, selected, all_items)
                     Create a list selection given a list of all available items.

                     Fills  in  the  required information (in particular, the indices) based on a
                     list of selected items and a list of all available items.

                     NOTE:

                        · The list of available items must not contain any duplicate items.

                        · It is expected that selected is populated by items in all_items.

              indices = List
                     Indices of the selected objects in the selection provider.

              is_empty()
                     Is the selection empty?

              items = List
                     Selected objects.

              provider_id = Str
                     ID of the selection provider that created this selection object.

   errors Module
       exception apptools.selection.errors.IDConflictError(provider_id)
              Bases: Exception

              Raised when a provider is added and its ID is already registered.

       exception apptools.selection.errors.ListenerNotConnectedError(provider_id, listener)
              Bases: Exception

              Raised when a listener that was never connected is disconnected.

       exception apptools.selection.errors.ProviderNotRegisteredError(provider_id)
              Bases: Exception

              Raised when a provider is requested by ID and not found.

       · search

AUTHOR

       Enthought

COPYRIGHT

       2008-2020, Enthought