[kepler-dev] Kepler specific Director and ComponentEntity classes and _addIcon()

Christopher Brooks cxh at eecs.berkeley.edu
Tue Apr 18 19:12:16 PDT 2006


Edward writes:

> A simple workaround that would not require having the icon
> information in each model's moml file would be to create
> a moml class somewhere, and instantiate that in the library.

I'm not sure I understand what you mean here.
What would the MoML class look like?

> A better alternative would be to make the current icon
> mechanism smarter.  Currently, vergil looks for a particular
> file named FooIcon.xml in the same directory as actor and/or
> director, and if it finds it, uses that to define the icon.
> We could make where to look for this icon something controlled
> by the configuration. Then kepler could simply put its
> icon definitions, each of which instantiates a subclass
> of EditorIcon, in some other directory tree.  Your subclass
> of EditorIcon could look wherever you want for the icon
> definition, including in a centralized system.

Below is my random train (wreck) of thoughts.

It looks like this private method in MoMLParser is what looks
for the FooIcon.xml:

    /** Look for a MoML file associated with the specified class
     *  name, and if it exists, parse it in the context of the
     *  specified instance. The file name is constructed from
     *  the class name by replacing periods with file separators
     *  ("/") and appending "Icon.xml".  So, for example, for
     *  the class name "ptolemy.actor.lib.Ramp", if there is a
     *  file "ptolemy/actor/lib/RampIcon.xml" in the classpath
     *  then that file be read.
     *  @param className The class name.
     *  @param context The context into which to load the file.
     *  @return True if a file was found.
     *  @exception Exception If the file exists but cannot be read
     *   for some reason.
     */
    private boolean _loadIconForClass(String className, NamedObj context)
            throws Exception {
        String fileName = className.replace('.', '/') + "Icon.xml";
        return _loadFileInContext(fileName, context);
    }

For example, BooleanSwitchIcon.xml contains:
<property name="BooleanSwitchIcon" class="ptolemy.vergil.icon.EditorIcon">
    <property name="rectangle" class="ptolemy.vergil.kernel.attributes.RectangleAttribute">
...
So when we call _loadIconForClass(), we create an EditorIcon
named BooleanSwitchIcon. 

There are lots of places where we iterate over EditorIcon, but
it seems like we don't really need a Kepler specific EditorIcon
since
  ComponentEntityConfig.addSVGIconTo(context);
basically adds attributes to the NamedObj context (I think).
I suspect this might just work, though there is a custom
version of XMLIcon to deal with which could cause problems.

Unfortunately, MoMLParser does not know about the configuration, so we
would have to add something here to MoMLParser so that we can tell
MoMLParser to invoke our Kepler specific loader.  We could use my
Iconable interface which would have a method that loads the icon.  We
would then call MoMLParser.setIconable() which would refer to our
loader.

I'll see what I can do about this.

> This would deal with the legacy model problem and the problem
> of bloating the moml files.

Seems doable!

_Christopher

> 
> Edward
> 
> At 09:47 AM 4/18/2006, Matthew Brooke wrote:
> 
> >Hi Christopher/Edward -
> >
> >A couple of thoughts and some additional info:
> >
> >
> >
> > > Also, this means that every Director and ComponentEntity would
> > > have to have a BatikEditorIcon attribute in the MoML file.
> >
> >We are specifically trying not to include icon descriptions or 
> >assignments in the MOML files (or in *Icon.xml files, or hard-coded 
> >in java), since it presents a maintenance problem for us (if/when 
> >icon assignments change, older models will still show the old 
> >assignments). This obviously becomes a larger and larger problem as 
> >models proliferate.
> >
> >We therefore have all our icon assignments in 2 text files - one has 
> >icons assigned by classname, and the other assigned by LSID. When 
> >Director or ComponentEntity make the call to:
> >
> >  ComponentEntityConfig.addSVGIconTo(this);
> >
> >the method does a lookup to try to match the specific subclass (ie 
> >the actor or director) by LSID, and then by classname. It then sets 
> >a ConfigurableAttribute (called "_svgIcon") on the actor/director, 
> >which is subsequently used by the Batik rendering system. (We don't 
> >change the existing "_iconDescription" attributes, so these are 
> >still present as a"fallback" in case anything goes wrong with the assignments.
>     )
> >
> >Having this centralized system is important to us, because it 
> >provides a level of decoupling between the models and their visual 
> >representations - we can make changes to icon assignments, and even 
> >completely change out *all* the icons at once if needed, and thus 
> >"re-skin" workflows entirely.
> >
> >
> > > 4) My previous idea, where we have some code that sets the Iconable
> > > class that gets called.  This results in one method being
> > > added to Directory and ComponentEntity.
> >
> >Cool idea, but we'd still need to introduce an "Iconable" interface 
> >into ptii (maybe I'm just missing the point ;-).  To be completely 
> >Kepler agnostic, we'd have to use your reflection solution, I think?
> >
> >
> >Just some extra stuff to add to the mix...
> >
> >m
> >
> >
> >
> >---------------------------------------------
> >Matthew Brooke, Ph.D.
> >Marine Sciences Research Building, Room #3407
> >University of California
> >Santa Barbara, CA  93106-6150
> >ph: (805) 893-7108   fx: 805-893-8062
> >brooke at nceas.ucsb.edu
> >---------------------------------------------
> >
> >
> >Christopher Brooks wrote:
> >>Interesting idea.  We could create a subclass of EditorIcon called
> >>BatikEditorIcon that would do this.
> >>However, how would we handle changing the icons of preexisting models?
> >>I suppose we could use the MoMLFilter.  This would slow down the Kepler
> >>a little, but would not be noticable.
> >>Also, this means that every Director and ComponentEntity would have to
> >>have a BatikEditorIcon attribute in the MoML file. This will increase
> >>model file size a certain amount, say 10%?
> >>Besides my proposal below, an alternative that is more in keeping with
> >>_iconDescription would be to either modify _iconDescription so it
> >>calls the addSVGIcon method or add a static text valued attribute that
> >>named the class that was to be called.  I think this would be
> >>definitely pollute Director and ComponentEntity with more UI code, but
> >>it would also be more lightweight (smaller MoML files).
> >>We really need to do something, having separate copies of these files
> >>is not maintainable.  I keep fixing problems in Ptolemy and then
> >>I or someone else has to update the copies in Kepler.
> >>To recap, I see several solutions
> >>1) Do nothing - we keep updating these files by hand
> >>This is not maintainable.
> >>2) Hack in Kepler specific code that calls ComponentEntityConfig
> >>I have this implemented in my tree, there is a static initializer
> >>that uses reflection to see if ComponentEntityConfig exists and if 
> >>it does then each _addIcon() method calls
> >>ComponentEntityConfig.addSVGIconTo(this);
> >>The problem here is that it is somewhat hardwired and ugly.
> >>3) My new idea, which would be to somehow modify _iconDescription so
> >>that we can invoke a method that creates the icon.  We could either
> >>have another attribute, say _iconFactory or we could add a field It
> >>would be nice to be able to change the icon once for all Directors and
> >>once for all ComponentEntities, so I'd like to create a static method
> >>that allows the user to override what text _addIcon attaches.  Perhaps
> >>we could attach the BatikEditorIcon here?  Or, _iconDescription could
> >>take a class name and method name to be invoked somehow.  This has the
> >>advantage of being done once each for Director and ComponentEntity.
> >>4) My previous idea, where we have some code that sets the Iconable
> >>class that gets called.  This results in one method being
> >>added to Directory and ComponentEntity.
> >>5) Your idea of using EditorIcon here.
> >>This would bulk up the Kepler models a little, say 10%?
> >>Also, current models would need a filter.
> >>I'm still feeling that I'd prefer to see #4, adding setIcon().
> >>What do you think?  I agree that #4 is not perfect but it seems like
> >>less work and not much uglification of the UI.  At least I'm staying
> >>out of NamedObj :-)
> >>My goal here is to help the Kepler folks with some UI problems.  In my
> >>mind, it should not be necessary to override Ptolemy classes, it 
> >>should be possible to extend classes or use attributes like
> >>EditorIcon.
> >>A good example of this is that for the DBConnectionToken class it was
> >>not necessary to override ptolemy.data.type.BaseType, instead I 
> >>used an inner class like what we do for
> >>ptolemy.actor.lib.security.KeyToken.
> >>If a Ptolemy class is being overridden with a copy of a class, it is
> >>either a bug in Ptolemy or a bug in Kepler and it should be fixed
> >>so as to avoid problems.
> >>_Christopher
> >>--------
> >>
> >>     There is no need to modify any Java class to change the icon...
> >>     Any attribute (including directors) that contains an instance of
> >>     EditorIcon or any subclass of EditorIcon will defer to that class
> >>     to render the icon.
> >>
> >>     So why can't the Kepler configuration just include such an
> >>     attribute in every director in the director library?
> >>
> >>     We have tried to keep the support in the kernel for visual rendering
> >>     to an absolute minimum... At most some text-valued attributes,
> >>     like _iconDescription. In retrospect, even this was probably a
> >>     mistake.  Icons should be controlled by attributes contained
> >>     by the object being represented by the icon.
> >>
> >>     Edward
> >>
> >>
> >>     At 09:21 PM 4/17/2006, Christopher Brooks wrote:
> >>     >Hi Edward,
> >>     >
> >>     >I'm looking at folding in the Kepler copies of Director
> >>     >and ComponentEntity.  The reason to fold these in is
> >>     >to avoid code duplication and reduce maintenance.
> >>     >
> >>     >Both of these classes have _addIcon methods like:
> >>     >
> >>     >     private void _addIcon() {
> >>     >
> >>     >       //simple Icon:
> >>     >       _attachText("_iconDescription", "<svg>\n"
> >>     >                   + "<rect x=\"-30\" y=\"-20\" width=\"60\" "
> >>     >                   + "height=\"40\" style=\"fill:white\"/>\n"
> >>     >                   + "<polygon points=\"-20,-10 20,0 -20,10\" "
> >>     >                   + "style=\"fill:blue\"/>\n" + "</svg>\n");
> >>     >
> >>     >       try {
> >>     >         ComponentEntityConfig.addSVGIconTo(this);
> >>     >       } catch (Exception ex) {
> >>     >         //ignore exceptions - they just mean that the
> >>     >         //default icon will be used, as defined above
> >>     >       }
> >>     >     }
> >>     >
> >>     >In this case,
> >>     >         ComponentEntityConfig.addSVGIconTo(this);
> >>     >is a Kepler static method that takes a NamedObj as an argument
> >>     >and adds an SVG icon.  So, we need some way for Kepler
> >>     >to override the icons without subclassing Director.  We
> >>     >can't subclass Director here because SDFDirector etc all
> >>     >extend Director and they would not extend our new class that
> >>     >had the custom Kepler icons.
> >>     >
> >>     >I could hack some Kepler specific hack that used reflection to look
> >>     >for a specific class that added the icon, but I think it would be
> >>     >better to add methods that named a class that on which we invoked a
> >>     >method that would add the Icon.
> >>     >
> >>     >Unfortunately, it looks like this would go in NamedObj and thus would
> >>     >be present for all NamedObjs.  I think it would be better for Director
> >>     >and ComponentEntity to have a setter that sets a class on which we can
> >>     >call an addIcon().  Yes, this is a little bit of code duplication, but
> >>     >it is not horrible.  Perhaps we could have Director and
> >>     >ComponentEntity implement a IconableFactory(?) interface that just has
> >>     >the setIconable method.
> >>     >
> >>     >
> >>     >Director and ComponentEntity would both get
> >>     >     setIconable(Iconable iconable) {
> >>     >         _iconable = iconable
> >>     >     }
> >>     >     private static Iconable _iconable;
> >>     >
> >>     >     private void _addIcon() {
> >>     >         _attachText("...");
> >>     >         if (_iconable != null) {
> >>     >             try {
> >>     >                 _iconable.addIcon(this)
> >>     >             } catch (Exception ex) {
> >>     >                 //ignore exceptions - they just mean that the
> >>     >                 //default icon will be used, as defined above
> >>     >             }
> >>     >     }
> >>     >
> >>     >ComponentEntityConfig would implement Iconable and have
> >>     >     public static addIcon(NamedObj) {
> >>     >         ....
> >>     >     }
> >>     >The KeplerInitiailizer would call setIconable() for
> >>     >Director and ComponentEntity and set it to ComponentEntityConfig.
> >>     >
> >>     >Whattya think?  Do you have any ideas?
> >>     >
> >>     >Director and ComponentEntity should not really have icon specific code
> >>     >in them, but they already have _attachText() calls.
> >>     >
> >>     >_Christopher
> >>
> >>     ------------
> >>     Edward A. Lee
> >>     Professor, Chair of the EE Division, Associate Chair of EECS
> >>     231 Cory Hall, UC Berkeley, Berkeley, CA 94720-1770
> >>     phone: 510-642-0253 or 510-642-0455, fax: 510-642-2845
> >>     eal at eecs.Berkeley.EDU, http://ptolemy.eecs.berkeley.edu/~eal
> >>--------
> >>_______________________________________________
> >>Kepler-dev mailing list
> >>Kepler-dev at ecoinformatics.org
> >>http://mercury.nceas.ucsb.edu/ecoinformatics/mailman/listinfo/kepler-dev
> >
> >------------
> >Edward A. Lee
> >Professor, Chair of the EE Division, Associate Chair of EECS
> >231 Cory Hall, UC Berkeley, Berkeley, CA 94720-1770
> >phone: 510-642-0253 or 510-642-0455, fax: 510-642-2845
> >eal at eecs.Berkeley.EDU, http://ptolemy.eecs.berkeley.edu/~eal


More information about the Kepler-dev mailing list