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

Edward A. Lee eal at eecs.berkeley.edu
Tue Apr 18 21:32:49 PDT 2006


I haven't had a chance to think about this much, so this may not
make much sense, but how about if we define an interface:

     public interface IconLoader {
         public boolean loadIconForClass(String className, NamedObj context);
     }

then create a static field in MoMLParser:

     private static IconLoader _iconLoader;

and a method

     public static void setIconLoader(IconLoader loader) {
         _iconLoader = loader;
     }

and then modify the method in MoMLParser as follows:

     private boolean _loadIconForClass(String className, NamedObj context)
             throws Exception {
         if (_iconLoader != null) {
             return _iconLoader.loadIconForClass(className, context);
         } else {
             // Default behavior if no icon loader has been specified.
             String fileName = className.replace('.', '/') + "Icon.xml";
             return _loadFileInContext(fileName, context);
         }
     }

Then KeplerApplication just needs to specify an icon loader.

Edward


At 07:12 PM 4/18/2006, Christopher Brooks wrote:
>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

------------
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