Comments with >>>

-----Original Message-----
From: Greg Brown [mailto:gkbr...@mac.com] 
Sent: Sunday, June 13, 2010 7:41 PM
To: dev@pivot.apache.org
Subject: Re: [jira] Updated: (PIVOT-514)

I'm afraid I don't understand what you mean by "services" or "inject
enclosing component in me".

I suspect that you have a valid use case that you would like to address, and
I'd really like to understand what it is. I think it would really help if
you would do the following:

- Explain exactly what it is you are trying to do in as few sentences as
possible.

>>> Create reusable behaviors with minimalistic API and usage requirements.
Example: adding a single line in my WTKX using wtkx:define with a class
called EventBusSelectionPublisher. For that component, I get all selection
events published out on the event bus (if you like EventBus :-)). No
Component subclassing, no scripting, no AOP, no interceptors, no
springframework, no further configuration. Usable on all selection producing
objects (or whatever behavior you are programming). I am putting a
cross-cutting concern into the Component's scope and allowing it to
initialize itself on the component. I'm pushing code up into the class
inheritance tree but not using a dynamic language to do it.

- Describe how you have tried to apply existing Pivot constructs to solve
the problem, including source code as needed.

>>>By scripting and subclassing the serializer.

- Describe specifically what you think is lacking that is preventing you
from applying your solution. Include proposed API additions or changes as
appropriate.

>>>Issues #2 is completely addressed through serializer subclassing (thanks)
and a little internal tweak in the serializer in the other JIRA. It works
really well.

Issue #1, defaulting across the tree, is a bit more challenging and I would
not claim I'm an expert on it. I just want to some styles at the top level
and have them propagate. If necessary, I will set styles and repeat these
things in WTKX but I was hoping a few small changes would not break API and
allow an approach to be created but not enforced or promoted by the pivot
project. 

I think this is actually possible actually because the underlying pivot code
has some solid design behind it. I don't want to create a pivot style
inheritance mechanism because you need to figure it out and it'll be better
than what I can dream up.  But I can put something simple in and have it be
good enough until its in pivot. I spend most of time on domain model issues
but occasionally come across things that are harder to get right and look
for a way to make it repeatedly easier because its hard to remember all the
things you have to do otherwise. I can't remember code I wrote an hour ago.

To get #1 in a completely no-idea-what-I-am-doing approach and to keep it
easy like pivot's style syntax:

a) Added a find method to UserDataDictionary:

        /**
         * Find a resource across the component tree. If the tree
         * is not fully loaded yet, you may get back null results
         * when you think you should get back non-null results.
         */
        public Object find(String key) {
                if(userData.containsKey(key))
                        return userData.get(key);
                if(getParent() != null)
                        return getParent().getUserData().find(key);
                return null;
        }

b) Intercepted the paint(Graphics2D) method. Don't know if that's the right
place. But it was the only place I could find to apply the styles
consistently and the tree was fully built:

        /**
     * True if onReadyToPaint method has already been called.
     * This is equivalent to only setting the properties once.
     * Its better to call the onReadyToPaint method somewhere
     * else but GregB probably needs to provide insight here.
     * 
     * <p>NOTE: This is fairly poor engineering. We really
     * need to set up a "pool" of user data references
     * that handles either dynamic or static (once only)
     * lookup and let that "reference" update itself
     * in some way...then it automatically...something like this.
     * Saves oodles of tree-walking. Not sure what this 
     * would like but it looks like the smarter way to do this.
     */
    private boolean hasFiredOnReadyToPaint = false;
    
    /**
     * Call this after any change that makes the user data
     * lookup change its parent lookup path.
     */
    protected void resetFiredOnReadyToPaint() {
        hasFiredOnReadyToRender = false;
    }
    
    /**
     * Paints the component. Delegates to the skin.
     */
    @Override
    public void paint(Graphics2D graphics) {
        if(!hasFiredOnReadyToPaint) {
                onReadyToPaint();
                hasFiredOnReadyToPaint = true;
        }
        skin.paint(graphics);
    }

c) Caught the reparenting method which changes the user data lookup in find:

protected void setParent(..) {

   ...
   resetFiredOnReadyToPaint();
}


d) Then wrote a onReadyToPaint() method that informs the tree that the
styles need to be reapplied:


        /**
     * Post-traversal order (bottoms) up call indicating that the component
was
     * loaded into the tree. <p>Hack'ish approach to having pivot tree
events.
     * This embeds the calling strategy directly into this method and it
should
     * be a parameterized routing strategy via an "event descriptor" and
     * pluggable router. It also references Container which is not needed if
we
     * had tree events or I stuck this in the Container class :-). 
     * 
     * <p>TODO: Add tree events. Remove hack. Even with events,
     * can keep the mechanism entirely internal for now until the mechanism
is
     * robust or something else easy is created.
     */
    protected void onReadyToPaint() {
        if (this instanceof Container) {
            for (Component c : ((Container) this)) {
                if (c != null)
                    c.doPrePaintProcessing();
            }
        }
        this.doPrePaintProcessing();
    }

e) Then in doPrePaintProcessing() call the applyStyles method:

    /**
     * Apply styles to a component based on styles defined in the user data
     * using the component class as a key. We really just need to make this
     * either a user specified key or the class as a key. That way you can
look
     * it up any way you want to without potential conflicts. Being lazy...
     * 
     * @param theComponent
     */
    protected void applyStyles(Component theComponent) {
        if (theComponent == null)
            return;
        final Collection<String> keys = generateKeyList(theComponent);
        key_list: for (final String key : keys) {
            final Object value = theComponent.getUserData().find(key);
            if (value != null) {
                if (value instanceof String) {
                    // This actually does not replace, it adds to the
styles.
                    theComponent.setStyles((String) value);
                    break key_list;
                }
            }
        }
    }

f) That's it. Inherited styles. Took about an hour initially. I've had to
write this type of code before in other frameworks. No extensive testing. If
there is no easy way to support this, then do not. My emails are too long as
it is AND there a lot of important things for you to focus on. I'm hoping
there are some easy answers to this that don't break API or commit you to a
path that is not the right one in the long run. That's why I look for some
internal API flexibility that allows me to do something but keep it useful
for others.

g) What's needed? Not 100% sure. Given the approach of issue #1 I think if
find() is added to UserDataDictionary and a way to intercept the paint()
method, #1's approach can be used to add style inheritance to any Component
in my application on a per component basis or all of them transparently when
using the serializer changes. It would be doable from a WTKX file with one
line of XML.  Or no lines because the serializer can add this behavior to
all components transparently.

h) I don't know if this is workable. I just tried it and it worked almost
the first time (very lucky). Was looking for help.
 
i) It did not make sense asking for inheritable properties in a JIRA.  Its
almost all in there already which amazes me because it was so easy to add
something quickly. To be honest, I have spent more time trying to get a
split pane (horizontal) to show another split pane (right side, but
vertical) than inherited styles.




That way, we can probably come to a workable solution.

Greg


On Jun 13, 2010, at 3:19 PM, aappddeevv wrote:

> Greg,
> 
> On the 2nd issue about services in the component, I tried using the script
> but failed after an hour. I could not get it to work and it was getting a
> bit hard to see how this would be easy for clients.
> 
> However, I found a better answer. Because of (PIVOT-513), the serializer
can
> use wtkx:define object's and insert the enclosing object into the newly
> created object (e.g. because it has the interface
> "InjectEnclosingComponentInMe" on it) all of which is non-pivot.
> 
> The services can be placed into the user data directly after this
processing
> so it won't get gc'd. Its coding once, but the capability can be bundled
> into a serializer class and re-used easily by clients. The only downside
is
> that a specific serializer has to be used but that's life under PIVOT-513.
> 
> So component level services can be added to a component through this
> mechanism, which works very nicely. It does require a protected method to
be
> created (to retrieve a serializer value) to get the enclosing object that
> contains the wtkx:define - 3 lines. Even though the approach for #2 was
> really small (about 5 lines to the Component class) this one is even
smaller
> and more general. There is a 3 line change in the serializer class but no
> existing APIs are changed.
> 
> I am still looking at #1 around defaulting across the tree.
> 
> 
> 
> -----Original Message-----
> From: aappddeevv [mailto:aappdde...@verizon.net] 
> Sent: Sunday, June 13, 2010 1:05 PM
> To: dev@pivot.apache.org
> Subject: RE: [jira] Updated: (PIVOT-514)
> 
> BTW, I am trying to get item 2 below moved completely into script as you
had
> suggested. Running into problems when I need to attach the same behavior
> object to 2-3 listeners to execute the needed behavior. I don't mind using
> script.
> 
> -----Original Message-----
> From: aappddeevv [mailto:aappdde...@verizon.net] 
> Sent: Sunday, June 13, 2010 10:02 AM
> To: dev@pivot.apache.org
> Subject: RE: [jira] Updated: (PIVOT-514)
> 
> Whew...emails like mine always come out when you are rushing to get on the
> plane...
> 
> Those are good thoughts on design intent.  Its really a question of where
> you force users to encounter this complexity. Where you force complexity
> /flexibility to be dealt with (the boundary line) is based on how you
think
> the market responds to these choices and where you wish to lay claim to
> differentiation.
> 
> I thought about my email after I sent it and wondered where the changes
> really needed to go.  I spent a few minutes making some changes to the
> Component class and was able to allow it to set style properties at any
> parent object and have it flow appropriately to every component of a
certain
> type below it in the tree automatically--no changes to the serializer.
It's
> not production quality and requires more thought, but its illustrative. I
> was of course fortunate that the pivot code base is good as it took longer
> to write the email than it did to change the code.
> 
> <Frame ...>
> <userData org.apache.pivot.wtk.TreeView="{showEmptyBranchControls: false}"
> org.apache.pivot.wtk.Border="{backgroundColor:null, padding:2}"/>
>       <content stuff here>
>               <MyTreeView ... /> <!-- Styles auto-applied here based on
> the class type, but any key could work. In this example, all TreeViews
will
> have the same style automatically -->
>       </content stuff here>
> </Frame>
> 
> Of course, there are different ways I could set styles including
> subclassing, setting the skin or repeating styling info. I have to
subclass
> for the data management part (no way around that a lot of times) but this
> was easy and consistent with pivot syntax and keeps it out of my value-add
> work around domain data.
> 
> I also tested the Initializer (which I called ComponentExtensionLifecycle
> after seeing another pivot class with a similar name) thing to the user
data
> and the proof point was that I was able to send EventBus messages from the
> component class for selection classes per bushe's blog I saw somewhere all
> as a service.  Since it's a component service...add it if you want,
> otherwise skip it by not adding it to your user data. I was able to extend
> behavior through composition and its highly reusable by others. For
managing
> the selection coming from anywhere in my application, this is a good
thing.
> I did not do the menu idea because I am still having trouble with the menu
> syntax. Without element-map, I had to add it in code but the idea is the
> same. It needs more thinking but showed potential for extension through
> composition and services. I was bit surprised it worked the first time but
> it needs some more proof points. I'll add the menu thing next to determine
> real reusability.
> 
> It was not a lot of change to demonstrate the use cases all without
script.
> Getting the hierarchical resources right may require more thought of
course
> so you never have to change the basics infrastructure again the future. I
> was wrong about the serializer needing changes except needing element-map
> support. But Component had some minor changes.
> 
> 
> -----Original Message-----
> From: Greg Brown [mailto:gkbr...@mac.com] 
> Sent: Friday, June 11, 2010 5:08 PM
> To: aappddeevv; dev@pivot.apache.org
> Subject: Re: [jira] Updated: (PIVOT-514)
> 
> This all sounds quite interesting, but may be a bit more than we want or
> need WTKXSerializer to do. Using the existing implementation you can
> delegate a lot of what you are proposing to Java or script. I'm extremely
> wary of making WTKXSerializer more complex than it needs to be, especially
> since we haven't run into a real use case for a lot of this stuff. It
makes
> it harder to maintain the code and harder for users to understand.
> 
> 
> ----- Reply message -----
> From: "aappddeevv" <aappdde...@verizon.net>
> Date: Fri, Jun 11, 2010 12:26 pm
> Subject: [jira] Updated: (PIVOT-514)
> To: <dev@pivot.apache.org>
> 
> Yes, this is very cool. My collection comment on this issue was purely
what
> interface is used to detect a call to add(). Declarative programming is an
> important option for pivot clients and more importantly, has great tooling
> potential.
> 
> Just thinking out loud...and typing fast...
> 
> Related to maps, probably one good user XML extension for the serializer
and
> that has a lot of uses cases is to specify a map as elements versus
> attributes.  Also, through more annotation magic, the default key
generator
> can be specified. Many lookups occur using a class (name) as a lookup key
or
> the key is easily statically specified by the object or its static nature.
> The "elements vs attributes" approach allows you to specify the object
> instance inline because specifying an object class to be instantianted in
an
> attribute value is ambiguous unless you add more DSL (e.g. instead of a $
> for a reference lookup, a % for an object creation).
> 
> This allows me to specify a bunch of objects without always having to use
> attributes. The object can be defined and instantiated inline for the map
> versus referenced elsewhere. There are 2-3 major use cases for this e.g.
> automated menu population/configuration. And by establishing a very small
> convention, allows a large number of declarative processing scenarios that
> create new class behaviors without subclassing/coding. This is the true
> power of the serializer/component as a container thinking and doesn't put
> too much burden on the serializer (i.e. avoiding full DI-container
semantics
> which is a lot of work to create and is not needed here).
> 
> However, this is not compelling enough yet to suggest unless other pivot
> elements (those 2-3 uses cases) are also enabled.
> 
> For example, as a small convention with support, if the serializer
> automatically scans the user data and finds an object with an
> interface/annotation called "Initializer", the interface is called. This
> initialize can in turn scan the user data for a menu specification and
> automatically add or substract a menu (also in the user data) from the
main
> menu when the component has focus (or whatever). By combining this with
> Component's "name", I can specify the attach point as a menu URL. This is
> Component-level services configured at the Component level and entirely
> optional all without subclassing in my application---I just write services
> that are reusable and use composition to create new behaviors. All of this
> has minimal API impact (almost none) but does need a small amount of
> pivot-library level support. Any Component can be a menu contributor.
> 
> If we add cross-tree hierarchical user data lookup (minimal API impact)
and
> object initialization lifecycle event signaling (some API impact), you
have
> ingredients to create significant defaulting and user data management
> behaviors. This would help with additional application-level, declarative
> thematic and stylizing defaulting. By using JSON for style specifications,
> which I think is clever, combined with a defaulting system that is
> cross-tree, you have a nice set of customization capabilities that reduces
> the experience level needed to create great looking applications, avoids
> coding (subclassing or using code to configure), enables easier tooling
and
> can employ declarative configuration for those that like it. Conceptually,
> this is at the heart of managing the boundary between coding and
> configuration in a *balanced* way.
> 
> So in this area (element map, small "initializer" interface, cross-tree
user
> data lookup, contract for object creation/initialization), plus a little
> convention enables a lot of flexibility and to Dirk's point, doesn't box
you
> in. This is an unique, targeted fusion of WPF and eclipse e4 thinking that
> could be possible in pivot. I don't know enough about Adobe and other
> frameworks to say how they handle complexity and flexibility.
> 
> 
> 
> -----Original Message-----
> From: Greg Brown [mailto:gkbr...@mac.com] 
> Sent: Friday, June 11, 2010 9:14 AM
> To: dev@pivot.apache.org
> Subject: Re: [jira] Updated: (PIVOT-514)
> 
> I should add that WTKXSerializer *does* actually know about maps (or, more
> specifically, dictionaries). If your class exposes a read-only dictionary
> property (e.g. Component#getUserData()), WTKXSerializer will properly
> populate the dictionary based on markup. For example:
> 
> <Window>
>  <userData foo="abc" bar="$def"/>
> </Window>
> 
> The serializer will effectively call getUserData().put("foo", "abc") and
> getUserData().put("bar", def), where def is the value of the page-scoped
> variable referred to by "def". This is what allows styles to be set using
an
> element vs. a JSON string, for example:
> 
> <Label>
>  <styles color="#ff0000"/>
> </Label>
> 
> vs.
> 
> <Label styles="{color:'#ff0000'}">
> 
> WTKXSerializer caters to sequences and dictionaries because those are the
> structures employed by XML. An XML element is effectively both a sequence
> (containing sub-elements and text nodes) and a dictionary (mapping string
> attribute names to attribute values). Since sets aren't really used by
XML,
> there's no need for WTKXSerializ
> 
> 

Reply via email to