Skip to main content

Painter set refactoring

38 replies [Last post]
Anonymous

I've just committed the latest (and hopefully final) refactoring of
the Painter API to CVS. Here's the basic idea:

JXComponent, an interface that JXPanel, JXLabel, etc will implement.
This is the signature:

public static final Integer BACKGROUND_LAYER = new Integer(-100);
public static final Integer COMPONENT_LAYER = new Integer(0);
public static final Integer FOREGROUND_LAYER = new Integer(100);
public static final Integer VALIDATION_LAYER = new Integer(200);
public static final Integer OVERLAY_LAYER = new Integer(300);

public Map> getPainters();
public void setPainters(Map> painters);

public void setPainter(Integer layer, Painter painter);
public Painter getPainter(Integer layer);
public void setBackgroundPainter(Painter painter);
public void setForegroundPainter(Painter painter);
public Painter getBackgroundPainter();
public Painter getForegroundPainter();

Most instances of JXComponent will simply delegate to
PainterSupportImpl which will do the real storage and work. The
various get/setPainter/Background/Foreground methods all eventually
modify something in the map that comes from getPainters(). This map
is live, meaning you can get it and change the contents, and the
changes will be reflected on the next paint cycle. This means it's
not threadsafe, but neither is setBackgroundColor or any other
property on a component and should always be manipulated from the EDT
anyway.

This new scheme lets us treat the set of painters as a property,
meaning 'comp.setPainters(comp.getPainters())' will do what you
expect. It also means you can grab the entire set of painters and
wrap them in a compound painter if you want. This lets you do things
like rotating the entire stack, *including the component's
paintBackground() method*!

So does this do everything we want? It seems to make life simpler and
cleaner for all of us.

- Josh

- Blasting forth in three part harmony!

[att1.html]

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mikaelgrev
Offline
Joined: 2006-09-27

> There will indeed be such a property editor. In fact, I can guarantee that NetBeans will have excellent support for Painters.

Josh, it would be tremendously valuable if you coordinated with primarily Tor Norbye using Richard as reference when you created that property editor.

We in the JSR-273 expert panel are trying to make Collection and Map property types a standard in the JavaBean spec and as I see it the "coordinating dialog" in that PainterPropertyEditor will be something like a pretty general CollectionPropertyEditor/MapPropertyEditor.

If you could code that part to be quite general and not include much "painter" specific code, if any at all, it would help us/all. If so, that implementation could be used directly or with small modifications as a general PE that can handle any class types as the element type for the Collection/Map.

What do you think? Are you that integrated within Sun so you can pull this one off?

Cheers,
Mikael

Joshua Marinacci

I'll certainly look into this. I'm not familiar with the 273 JSR. Is
Tor running it?

- J

On Dec 1, 2006, at 12:32 PM, jdnc-interest@javadesktop.org wrote:

>> There will indeed be such a property editor. In fact, I can
>> guarantee that NetBeans will have excellent support for Painters.
>
> Josh, it would be tremendously valuable if you coordinated with
> primarily Tor Norbye using Richard as reference when you created
> that property editor.
>
> We in the JSR-273 expert panel are trying to make Collection and
> Map property types a standard in the JavaBean spec and as I see it
> the "coordinating dialog" in that PainterPropertyEditor will be
> something like a pretty general CollectionPropertyEditor/
> MapPropertyEditor.
>
> If you could code that part to be quite general and not include
> much "painter" specific code, if any at all, it would help us/all.
> If so, that implementation could be used directly or with small
> modifications as a general PE that can handle any class types as
> the element type for the Collection/Map.
>
> What do you think? Are you that integrated within Sun so you can
> pull this one off?
>
> Cheers,
> Mikael
> [Message sent by forum member 'mikaelgrev' (mikaelgrev)]
>
> http://forums.java.net/jive/thread.jspa?messageID=181471
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

- Blasting forth in three part harmony!

[att1.html]

mikaelgrev
Offline
Joined: 2006-09-27

Yes he is. It's about a subject that you ought to be very interested in. Richard is on the mail list and maybe you should as well?

Cheers,
Mikael

mikaelgrev
Offline
Joined: 2006-09-27

1) You should read the spec. This is actually handled. Nothing is replaced and this was one of the major design goals of this approach. :)

2) History has proven otherwise. IDEs support JavaBeans at a terrible lowest denominator today. It is a royal mess to write advanced JavaBeans that works in all IDEs. Trust me and my now gray hair. ;)

Cheers,
Mikael

Noel Grandin

Hi Mikael

(1) It's not about getting it in exactly the right place. It's about
accidentally __overwriting__ something that is already there.

(2) We should not let the current limitations of IDE's constrain us.
IDE's will adapt to whatever we create.
I note that there is already an RFE for enums and Javabeans:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6219769

Regards,
Noel

jdnc-interest@javadesktop.org wrote:
> Noel, there IS no way to add a layer at a later time and be 100% sure it gets to below/above some layer that you don't know about if the first place. It is mathematically impossible. Using Enums or Layer objects will not solve it.
>
> You can add layers to the same layer index using the ints.
>
> The only "bug" there could be is that something is painted in the wrong order. If you have a very strict set of rules for layering you can just create your own CompoundPainter and implement any layering algorithm you want.
>
> And as I said in an earier post we are using Painters and integer layer indexes in the same context as this will be used and it is woring great. The API is even public so you can check it and check our forums to see if people have had any problems with them.
>
> Even if Enums/Layer objects would actually be better they don't work in a JavaBean RAD IDE which means they are impossible to use anyway.
>
> Cheers,
> Mikael
> [Message sent by forum member 'mikaelgrev' (mikaelgrev)]
>
> http://forums.java.net/jive/thread.jspa?messageID=180772
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
>
>
>

Disclaimer: http://www.peralex.com/disclaimer.html

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Kleopatra

Noel Grandin wrote:
>
> (2) We should not let the current limitations of IDE's constrain us.
> IDE's will adapt to whatever we create.

+100!

Jeanette

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mikaelgrev
Offline
Joined: 2006-09-27

-101! ;)

See answer below.

Cheers,
Mikael

mikaelgrev
Offline
Joined: 2006-09-27

Yes, but this isn't the general use-case in think. You can however create your own CompoundPainter with these turbo-layers and implement all that. No problem.

Cheers,
Mikael

rbair
Offline
Joined: 2003-07-08

> The whole idea of layers really adds some complexity
> to the Painter idea. I
> guess it just depends on how much layers
> functionality is really needed vs
> how flexible the 'Layers api' should be for the
> future.

I agree there are some red flags. In the end, typical developers will be doing this:

[code]
Painter p = new MattePainter(...);
component.setBackgroundPainter(p);
[/code]

And that will be good enough. Really, layers is about letting frameworks add/remove painters from the component automatically. If we accept that as a use-case we want to support, then I think this API is close to what we want.

Richard

Joshua Marinacci

Looks like I picked the wrong day to stay off of email. :) The thread
has 27 messages now!

The integer constants are not being used as a poor mans enums. They
really do need to be numbers. You can define your own layers. Some
are worried that we would run out of layers and you might overwrite a
painter by setting your own at the same layer. This isn't a flaw.
This is the purpose of layers. I can overwrite what's there by
setting a new one. The constants are simply useful conventions. If
you want to have more than one painter at a given level then use the
List of painters. That's what I made it a Map of Lists of Painters
instead of a Map of Painters.

I am approaching this API design from two sides. One is the very
simple case of setting a fore or background painter. The other is the
complicated case of working with the entire set of painters and doing
tricky manipulation. I think what we have satisfies both needs. I
agree it would be nice to have an intermediate API that is less
complicated that working with the full structure, but everything I
have come up with compromises the full API.

I really do think that this API is a balance between the two needs.
If you want something more complicated that get/set fore/background
painter then work with the Map. Anything we do to hide the Map just
forces us to reimplement a Map-like interface; badly.

One change I might consider is changing the constants from Integers
to Floats. Then you wouldn't have to worry about not being able to
stuff a painter between two others. This is rather academic, I think,
since I can't imagine any components having more than a few painters,
but it might happen.

- Josh

On Nov 29, 2006, at 10:20 AM, jdnc-interest@javadesktop.org wrote:

>> The whole idea of layers really adds some complexity
>> to the Painter idea. I
>> guess it just depends on how much layers
>> functionality is really needed vs
>> how flexible the 'Layers api' should be for the
>> future.
>
> I agree there are some red flags. In the end, typical developers
> will be doing this:
>
> [code]
> Painter p = new MattePainter(...);
> component.setBackgroundPainter(p);
> [/code]
>
> And that will be good enough. Really, layers is about letting
> frameworks add/remove painters from the component automatically. If
> we accept that as a use-case we want to support, then I think this
> API is close to what we want.
>
> Richard
> [Message sent by forum member 'rbair' (rbair)]
>
> http://forums.java.net/jive/thread.jspa?messageID=180424
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

- Blasting forth in three part harmony!

[att1.html]

Noel Grandin

Hi Josh

Sorry to harp on this, but integers really do bite you in the long run
when used in layers.

I know this from painful experience because we use integers to describe
the layers in an internal graphing toolkit we built.

Every now and then two pieces of code will accidentally stick something
at the same integer constant in the map, and we get unpredictable bugs
depending on which layer managed to configure itself first.

And for something that might make it into core swing, and be widely
deployed and widely used, you really want to maximise the ability of
different pieces of code to mess with the painting layers without
stomping on each others toes.

Imagine the following situation
I build a wide variety of custom painters for my application.
Then, late in the day (perhaps after I have left)
someone discovers a real cool library
that works by adding additional layers
to ALL components in the system.
Except that we can't use it because every now and then it accidentally
conflicts with the custom layer code I built.

Regards,
Noel Grandin

Joshua Marinacci wrote:
> Looks like I picked the wrong day to stay off of email. :) The thread
> has 27 messages now!
>
> The integer constants are not being used as a poor mans enums. They
> really do need to be numbers. You can define your own layers. Some
> are worried that we would run out of layers and you might overwrite a
> painter by setting your own at the same layer. This isn't a flaw.
> This is the purpose of layers. I can overwrite what's there by setting
> a new one. The constants are simply useful conventions. If you want
> to have more than one painter at a given level then use the List of
> painters. That's what I made it a Map of Lists of Painters instead of
> a Map of Painters.
>
> I am approaching this API design from two sides. One is the very
> simple case of setting a fore or background painter. The other is the
> complicated case of working with the entire set of painters and doing
> tricky manipulation. I think what we have satisfies both needs. I
> agree it would be nice to have an intermediate API that is less
> complicated that working with the full structure, but everything I
> have come up with compromises the full API.
>
> I really do think that this API is a balance between the two needs. If
> you want something more complicated that get/set fore/background
> painter then work with the Map. Anything we do to hide the Map just
> forces us to reimplement a Map-like interface; badly.
>
> One change I might consider is changing the constants from Integers to
> Floats. Then you wouldn't have to worry about not being able to stuff
> a painter between two others. This is rather academic, I think, since
> I can't imagine any components having more than a few painters, but it
> might happen.
>
> - Josh
>
>
> On Nov 29, 2006, at 10:20 AM, jdnc-interest@javadesktop.org wrote:
>
>>> The whole idea of layers really adds some complexity
>>> to the Painter idea. I
>>> guess it just depends on how much layers
>>> functionality is really needed vs
>>> how flexible the 'Layers api' should be for the
>>> future.
>>
>> I agree there are some red flags. In the end, typical developers will
>> be doing this:
>>
>> [code]
>> Painter p = new MattePainter(...);
>> component.setBackgroundPainter(p);
>> [/code]
>>
>> And that will be good enough. Really, layers is about letting
>> frameworks add/remove painters from the component automatically. If
>> we accept that as a use-case we want to support, then I think this
>> API is close to what we want.
>>
>> Richard
>> [Message sent by forum member 'rbair' (rbair)]
>>
>> http://forums.java.net/jive/thread.jspa?messageID=180424
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
>> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
>
> - Blasting forth in three part harmony!
>
>
>

Disclaimer: http://www.peralex.com/disclaimer.html

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mikaelgrev
Offline
Joined: 2006-09-27

Noel, there IS no way to add a layer at a later time and be 100% sure it gets to below/above some layer that you don't know about if the first place. It is mathematically impossible. Using Enums or Layer objects will not solve it.

You can add layers to the same layer index using the ints.

The only "bug" there could be is that something is painted in the wrong order. If you have a very strict set of rules for layering you can just create your own CompoundPainter and implement any layering algorithm you want.

And as I said in an earier post we are using Painters and integer layer indexes in the same context as this will be used and it is woring great. The API is even public so you can check it and check our forums to see if people have had any problems with them. (www.migcalendar.com)

Even if Enums/Layer objects would actually be better they don't work in a JavaBean RAD IDE which means they are impossible to use anyway.

Cheers,
Mikael

Patrick Wright

> Even if Enums/Layer objects would actually be better they don't work in a JavaBean RAD IDE which means they are impossible to use anyway.

What is the technical limitation here, as regards IDEs?

Thanks
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mikaelgrev
Offline
Joined: 2006-09-27

If you don't follow the get/set paradigm you can't register custom PropertyEditors.

Hopefully there will be a PainterSetPropertyEditor developed that can be used in an IDE to select which Painter you want and configure them.

addXxx/removeXxx is something we are working in JSR-273 to add.

Cheers,
Mikael

Joshua Marinacci

There will indeed be such a property editor. In fact, I can guarantee
that NetBeans will have excellent support for Painters. :)

- Josh

On Nov 30, 2006, at 4:59 AM, jdnc-interest@javadesktop.org wrote:

> If you don't follow the get/set paradigm you can't register custom
> PropertyEditors.
>
> Hopefully there will be a PainterSetPropertyEditor developed that
> can be used in an IDE to select which Painter you want and
> configure them.
>
> addXxx/removeXxx is something we are working in JSR-273 to add.
>
> Cheers,
> Mikael
> [Message sent by forum member 'mikaelgrev' (mikaelgrev)]
>
> http://forums.java.net/jive/thread.jspa?messageID=180826
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

- Blasting forth in three part harmony!

[att1.html]

evickroy
Offline
Joined: 2004-07-23

> There will indeed be such a property editor. In fact,
> I can guarantee
> that NetBeans will have excellent support for
> Painters. :)
Good luck trying. I've heard rumors that those Netbeans GUI developers are really pig-headed and prefer toying around with cool graphics effects too much. lol ;)

jk

Erik

mikaelgrev
Offline
Joined: 2006-09-27

What can possibly be cooler than "cool graphics effects" and can you actually have too much of it ??!! ;)

Bill Snyder

Isn't the intent for using Enums here to make the Layer thing more verbose
and immutable? Once you start adding methods and such to the Layer classes,
it adds more complexity, I think.

But, maybe the Layer support should be expanded more. I just fired up Adobe
Illustrator - here are the basic options it provides for Layers:

- Name - Specifies the name of the item as it appears in the Layers
palette.
- Color (Layers only) - Specifies the layer's color setting. You can
either choose a color from the menu or double-click the color swatch to
select a color.
- Template (Layers only) - Makes the layer a template layer.
- Lock - Prevents changes to the item.
- Show - Displays all artwork contained in the layer on the artboard.
- Print (Layers only) Makes the artwork contained in the layer
printable.
- Preview (Layers only) - Displays the artwork contained in the layer
in color instead of as outlines.
- Dim Images - (Layers only) Reduces the intensity of linked images
and bitmap images contained in the layer to the specified percentage.

On 11/29/06, Bill Snyder wrote:
>
> The whole idea of layers really adds some complexity to the Painter idea.
> I guess it just depends on how much layers functionality is really needed vs
> how flexible the 'Layers api' should be for the future.
>
> On 11/29/06, Patrick Wright
wrote:
> >
> > What I like about Noel's approach, and the one Richard suggested
> > (enums) is that they both carry the sense that there are pre-defined
> > layers that are well-established and immutable. Integers don't give me
> > that same feeling.
> >
> > I'd think if we could do something like,
> > comp.setPainter(BACKGROUND_LAYER.before(),painter);
> >
> > then we could encapsulate the sense of what above/below while still
> > remaning type-safe in some sense.
> >
> > My sense is that if you go with integers you'll have a long line of
> > emails from here to eternity asking what this value "100" means, and
> > why my painter isn't showing up where I expect it to.
> >
> > Patrick
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> > For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
> >
> >
>
[att1.html]

Patrick Wright

> But, maybe the Layer support should be expanded more. I just fired up Adobe
> Illustrator - here are the basic options it provides for Layers:

Side note--given that Josh just posted a cool stacked image editor
tool on his blog, it would be a nice trick to pick a component at
runtime and see its layers split out

http://weblogs.java.net/blog/joshy/archive/2006/11/free_projects_p_1.html

TODO.

Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Bill Snyder

Right! Using that type of view in the Painter editor would be cool.

On 11/29/06, Patrick Wright
wrote:
>
> > But, maybe the Layer support should be expanded more. I just fired up
> Adobe
> > Illustrator - here are the basic options it provides for Layers:
>
> Side note--given that Josh just posted a cool stacked image editor
> tool on his blog, it would be a nice trick to pick a component at
> runtime and see its layers split out
>
> http://weblogs.java.net/blog/joshy/archive/2006/11/free_projects_p_1.html
>
>
> TODO.
>
> Patrick
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
>
>
[att1.html]

mikaelgrev
Offline
Joined: 2006-09-27

I admit that the enum or Layer object approach is nicer in an engineering sense. However the this that make it not fly is the tools support. "custom" code like that will never be tool friendly and hard to persist in a standard JavaBean way.

Also, there is nothing wrong with numbers. They shouldn't be used everywhere but with a little JavaDoc it is really easy to get that:

addPainter(BACKGROUND + 1, painter);

would be the same thing as

addPainter(BACKGROUND.before(), painter);

Actually we have been using integer layers for Painters in MiG Calendar for a long time and I've had no one asking how the layering works (that I can remember at least), and a lot of people have written their own Painters (except we call the Decorators). You can browse our forums to check the validity of this statement if you like. www.migcalendar.com.

Cheers,
Mikael

Patrick Wright

What I like about Noel's approach, and the one Richard suggested
(enums) is that they both carry the sense that there are pre-defined
layers that are well-established and immutable. Integers don't give me
that same feeling.

I'd think if we could do something like,
comp.setPainter(BACKGROUND_LAYER.before(),painter);

then we could encapsulate the sense of what above/below while still
remaning type-safe in some sense.

My sense is that if you go with integers you'll have a long line of
emails from here to eternity asking what this value "100" means, and
why my painter isn't showing up where I expect it to.

Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Bill Snyder

The whole idea of layers really adds some complexity to the Painter idea. I
guess it just depends on how much layers functionality is really needed vs
how flexible the 'Layers api' should be for the future.

On 11/29/06, Patrick Wright
wrote:
>
> What I like about Noel's approach, and the one Richard suggested
> (enums) is that they both carry the sense that there are pre-defined
> layers that are well-established and immutable. Integers don't give me
> that same feeling.
>
> I'd think if we could do something like,
> comp.setPainter(BACKGROUND_LAYER.before(),painter);
>
> then we could encapsulate the sense of what above/below while still
> remaning type-safe in some sense.
>
> My sense is that if you go with integers you'll have a long line of
> emails from here to eternity asking what this value "100" means, and
> why my painter isn't showing up where I expect it to.
>
> Patrick
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
>
>
[att1.html]

mikaelgrev
Offline
Joined: 2006-09-27

In any event there is always the possibility to create your own CompoundPainter-clone and implement whatever cool layering support you can dream up! :)

Cheers,
Mikael

smartini
Offline
Joined: 2005-09-01

Hi,
what do you think on multiplying the values * 10, having a 1000 value step on any layer, to have more flexibility (for very complex gui) ?

In the int/Integer range this could not be a problem ...

Bye,
sandro

mikaelgrev
Offline
Joined: 2006-09-27

Do you think you would ever get remotely close to having 100 painters on a single component between two layers?

Remember that you can use CompoundPainters as well "bunch up" a few painters into one.

Cheers,
Mikael Grev

Noel Grandin

The integer->Painter mapping reminds me of line numbers in the old days
of Basic.

Something like this might be cleaner:

// Note: we use a class instead of an enum so that API consumers can
create their own layers.
public class Layer {
public static final Layer BACKGROUND = new Layer(null);
public static final Layer COMPONENT = new Layer(BACKGROUND);
public static final Layer FOREGROUND = new Layer(COMPONENT)
public static final Layer VALIDATION = new Layer(FOREGROUND);
public static final Layer OVERLAY = new Layer(VALIDATION);

/** Used to impose ordering on Layers.
* "null" indicates that it is the first layer.
*/
private final Layer previousLayer;

public Layer(Layer previousLayer) { this.previousLayer = previousLayer; }

/** Given a set of layers, return an ordered list, using the
previousLayer field to order the list.
* Note that the relative ordering of Layer's which share the same
previousLayer is undefined.
*/
public static List orderLayers(Set layerSet) {}

}

interface ComponentPainter {

// remove all painters for the given layer
void remove(Layer l);
// remove a painter
void remove(Painter p);
// remove all painters
void removeAll();

void addBefore(Layer l, Painter p);
void addAfter(Layer l, Painter p);

// replace the painter at the given layer
void replace(Layer l, Painter p);

// return an iteration of the list of painters ordered by Layer
Iteration layerOrderedIterator();
}

Regards, Noel.

Joshua Marinacci wrote:
> I've just committed the latest (and hopefully final) refactoring of
> the Painter API to CVS. Here's the basic idea:
>
> JXComponent, an interface that JXPanel, JXLabel, etc will implement.
> This is the signature:
>
> public static final Integer BACKGROUND_LAYER = new Integer(-100);
> public static final Integer COMPONENT_LAYER = new Integer(0);
> public static final Integer FOREGROUND_LAYER = new Integer(100);
> public static final Integer VALIDATION_LAYER = new Integer(200);
> public static final Integer OVERLAY_LAYER = new Integer(300);
>
> public Map> getPainters();
> public void setPainters(Map> painters);
>
> public void setPainter(Integer layer, Painter painter);
> public Painter getPainter(Integer layer);
> public void setBackgroundPainter(Painter painter);
> public void setForegroundPainter(Painter painter);
> public Painter getBackgroundPainter();
> public Painter getForegroundPainter();
>
>
> Most instances of JXComponent will simply delegate to
> PainterSupportImpl which will do the real storage and work. The
> various get/setPainter/Background/Foreground methods all eventually
> modify something in the map that comes from getPainters(). This map
> is live, meaning you can get it and change the contents, and the
> changes will be reflected on the next paint cycle. This means it's not
> threadsafe, but neither is setBackgroundColor or any other property on
> a component and should always be manipulated from the EDT anyway.
>
> This new scheme lets us treat the set of painters as a property,
> meaning 'comp.setPainters(comp.getPainters())' will do what you
> expect. It also means you can grab the entire set of painters and
> wrap them in a compound painter if you want. This lets you do things
> like rotating the entire stack, *including the component's
> paintBackground() method*!
>
> So does this do everything we want? It seems to make life simpler and
> cleaner for all of us.
>
> - Josh
>
>
> - Blasting forth in three part harmony!
>
>
>

Disclaimer: http://www.peralex.com/disclaimer.html

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

Bill Snyder

I dont see anything wrong with keeping Layers as ints. It makes it simpler.

On 11/29/06, Noel Grandin wrote:
>
>
> The integer->Painter mapping reminds me of line numbers in the old days
> of Basic.
>
>
> Something like this might be cleaner:
>
> // Note: we use a class instead of an enum so that API consumers can
> create their own layers.
> public class Layer {
> public static final Layer BACKGROUND = new Layer(null);
> public static final Layer COMPONENT = new Layer(BACKGROUND);
> public static final Layer FOREGROUND = new Layer(COMPONENT)
> public static final Layer VALIDATION = new Layer(FOREGROUND);
> public static final Layer OVERLAY = new Layer(VALIDATION);
>
> /** Used to impose ordering on Layers.
> * "null" indicates that it is the first layer.
> */
> private final Layer previousLayer;
>
> public Layer(Layer previousLayer) { this.previousLayer = previousLayer;
> }
>
> /** Given a set of layers, return an ordered list, using the
> previousLayer field to order the list.
> * Note that the relative ordering of Layer's which share the same
> previousLayer is undefined.
> */
> public static List orderLayers(Set layerSet) {}
>
> }
>
> interface ComponentPainter {
>
> // remove all painters for the given layer
> void remove(Layer l);
> // remove a painter
> void remove(Painter p);
> // remove all painters
> void removeAll();
>
> void addBefore(Layer l, Painter p);
> void addAfter(Layer l, Painter p);
>
> // replace the painter at the given layer
> void replace(Layer l, Painter p);
>
> // return an iteration of the list of painters ordered by Layer
> Iteration layerOrderedIterator();
> }
>
>
> Regards, Noel.
>
> Joshua Marinacci wrote:
> > I've just committed the latest (and hopefully final) refactoring of
> > the Painter API to CVS. Here's the basic idea:
> >
> > JXComponent, an interface that JXPanel, JXLabel, etc will implement.
> > This is the signature:
> >
> > public static final Integer BACKGROUND_LAYER = new Integer(-100);
> > public static final Integer COMPONENT_LAYER = new Integer(0);
> > public static final Integer FOREGROUND_LAYER = new Integer(100);
> > public static final Integer VALIDATION_LAYER = new Integer(200);
> > public static final Integer OVERLAY_LAYER = new Integer(300);
> >
> > public Map> getPainters();
> > public void setPainters(Map> painters);
> >
> > public void setPainter(Integer layer, Painter painter);
> > public Painter getPainter(Integer layer);
> > public void setBackgroundPainter(Painter painter);
> > public void setForegroundPainter(Painter painter);
> > public Painter getBackgroundPainter();
> > public Painter getForegroundPainter();
> >
> >
> > Most instances of JXComponent will simply delegate to
> > PainterSupportImpl which will do the real storage and work. The
> > various get/setPainter/Background/Foreground methods all eventually
> > modify something in the map that comes from getPainters(). This map
> > is live, meaning you can get it and change the contents, and the
> > changes will be reflected on the next paint cycle. This means it's not
> > threadsafe, but neither is setBackgroundColor or any other property on
> > a component and should always be manipulated from the EDT anyway.
> >
> > This new scheme lets us treat the set of painters as a property,
> > meaning 'comp.setPainters(comp.getPainters())' will do what you
> > expect. It also means you can grab the entire set of painters and
> > wrap them in a compound painter if you want. This lets you do things
> > like rotating the entire stack, *including the component's
> > paintBackground() method*!
> >
> > So does this do everything we want? It seems to make life simpler and
> > cleaner for all of us.
> >
> > - Josh
> >
> >
> > - Blasting forth in three part harmony!
> >
> >
> >
>
>
> Disclaimer: http://www.peralex.com/disclaimer.html
>
>
>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
>
>
[att1.html]

Noel Grandin

The basic problem with using integers is this:

Sooner or later 2 parts of someone's code are going to use the same
integer, register 2 different painters at the same integer location, and
unpredictable bugs will result, depending on who registers which painter
first.

Or

Someone will code a library which uses integers 3, 5 and 7.
Someone else will use that library and use integer 6, and all will be well.
Then a minor upgrade to the library will change it to use 6, and
suddenly the application using that library is broken.

Bill Snyder wrote:
> I dont see anything wrong with keeping Layers as ints. It makes it
> simpler.
>
> On 11/29/06, Noel Grandin wrote:
>>
>>
>> The integer->Painter mapping reminds me of line numbers in the old days
>> of Basic.
>>
>>
>> Something like this might be cleaner:
>>
>> // Note: we use a class instead of an enum so that API consumers can
>> create their own layers.
>> public class Layer {
>> public static final Layer BACKGROUND = new Layer(null);
>> public static final Layer COMPONENT = new Layer(BACKGROUND);
>> public static final Layer FOREGROUND = new Layer(COMPONENT)
>> public static final Layer VALIDATION = new Layer(FOREGROUND);
>> public static final Layer OVERLAY = new Layer(VALIDATION);
>>
>> /** Used to impose ordering on Layers.
>> * "null" indicates that it is the first layer.
>> */
>> private final Layer previousLayer;
>>
>> public Layer(Layer previousLayer) { this.previousLayer =
>> previousLayer;
>> }
>>
>> /** Given a set of layers, return an ordered list, using the
>> previousLayer field to order the list.
>> * Note that the relative ordering of Layer's which share the same
>> previousLayer is undefined.
>> */
>> public static List orderLayers(Set layerSet) {}
>>
>> }
>>
>> interface ComponentPainter {
>>
>> // remove all painters for the given layer
>> void remove(Layer l);
>> // remove a painter
>> void remove(Painter p);
>> // remove all painters
>> void removeAll();
>>
>> void addBefore(Layer l, Painter p);
>> void addAfter(Layer l, Painter p);
>>
>> // replace the painter at the given layer
>> void replace(Layer l, Painter p);
>>
>> // return an iteration of the list of painters ordered by Layer
>> Iteration layerOrderedIterator();
>> }
>>
>>
>> Regards, Noel.
>>
>> Joshua Marinacci wrote:
>> > I've just committed the latest (and hopefully final) refactoring of
>> > the Painter API to CVS. Here's the basic idea:
>> >
>> > JXComponent, an interface that JXPanel, JXLabel, etc will implement.
>> > This is the signature:
>> >
>> > public static final Integer BACKGROUND_LAYER = new Integer(-100);
>> > public static final Integer COMPONENT_LAYER = new Integer(0);
>> > public static final Integer FOREGROUND_LAYER = new Integer(100);
>> > public static final Integer VALIDATION_LAYER = new Integer(200);
>> > public static final Integer OVERLAY_LAYER = new Integer(300);
>> >
>> > public Map> getPainters();
>> > public void setPainters(Map> painters);
>> >
>> > public void setPainter(Integer layer, Painter painter);
>> > public Painter getPainter(Integer layer);
>> > public void setBackgroundPainter(Painter painter);
>> > public void setForegroundPainter(Painter painter);
>> > public Painter getBackgroundPainter();
>> > public Painter getForegroundPainter();
>> >
>> >
>> > Most instances of JXComponent will simply delegate to
>> > PainterSupportImpl which will do the real storage and work. The
>> > various get/setPainter/Background/Foreground methods all eventually
>> > modify something in the map that comes from getPainters(). This map
>> > is live, meaning you can get it and change the contents, and the
>> > changes will be reflected on the next paint cycle. This means it's not
>> > threadsafe, but neither is setBackgroundColor or any other property on
>> > a component and should always be manipulated from the EDT anyway.
>> >
>> > This new scheme lets us treat the set of painters as a property,
>> > meaning 'comp.setPainters(comp.getPainters())' will do what you
>> > expect. It also means you can grab the entire set of painters and
>> > wrap them in a compound painter if you want. This lets you do things
>> > like rotating the entire stack, *including the component's
>> > paintBackground() method*!
>> >
>> > So does this do everything we want? It seems to make life simpler and
>> > cleaner for all of us.
>> >
>> > - Josh
>> >
>> >
>> > - Blasting forth in three part harmony!
>> >
>> >
>> >
>>
>>
>> Disclaimer: http://www.peralex.com/disclaimer.html
>>
>>
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
>> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net
>>
>>
>

Disclaimer: http://www.peralex.com/disclaimer.html

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mikaelgrev
Offline
Joined: 2006-09-27

You are overreacting IMO. This integer thing is a good KISS approach. It's unlikely that there will be more layers than two custom plus the background/foreground ones. Therefore your approach just makes it harder to use for 100% of the cases and solves 0.001% of the use cases. IMHO.

Also, being absolutely sure where a layer ends up is not possible with any method unless you know what is there already. And that would take a fair amount of AI in the setXxx() code..

In the current implementation you can actually add several layers to the same layer index.

Cheers,
Mikael Grev

Patrick Wright

On 11/29/06, jdnc-interest@javadesktop.org
wrote:
> You are overreacting IMO. This integer thing is a good KISS approach. It's unlikely that there will be more layers than two custom plus the background/foreground ones. Therefore your approach just makes it harder to use for 100% of the cases and solves 0.001% of the use cases. IMHO.

a) how does it make it harder?

b) when did magic integer indexes hidden as constants ever help
anyone, or lead to better code?

c) swing needs less magic, not more

I tend to agree with Noel, I prefer the feeling of type safety on this
one. Some layers are reserved, others are open.
Patrick

---------------------------------------------------------------------
To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

mikaelgrev
Offline
Joined: 2006-09-27

> a) how does it make it harder?

1) His Layer approach isn't JavaBean spec friendly which would rule out RAD IDE support.
2) If you add two painters before BACKGROUND how would they be layered? Same problem as with ints.

> when did magic integer indexes hidden as constants
ever help anyone, or lead to better code?

When did KISS not apply? :)

> swing needs less magic, not more

Swing needs to be simpler to use with RAD IDEs.

If you are sorting something, an integer as the layer is a valid choice and has nothing to do with BASIC line numbers.

Cheers,

mikaelgrev
Offline
Joined: 2006-09-27

And remember, we are talking about a very small number of painters in the 99.5% case. Usually one or two.

Also you can check out this thread as it contains some background info:

http://forums.java.net/jive/thread.jspa?forumID=73&threadID=14296&messag...

Cheers,
Mikael

mnuttall
Offline
Joined: 2004-02-17

Excellent news. I am enjoying playing with painters. My stick figures have never looked so good. :)

rbair
Offline
Joined: 2003-07-08

Hey Josh,

I wish there were a way to do it with enums instead of ints, but since enums are implicitly final I don't see any way to go that route. Possibly the use of a typesafe enum class would work. Integers are always a bit dodgy.

get/setPainters: why the List of painters? I'd have expected Map. A List of painters is just a CompoundPainter, right?

One edge case: if I call setBackgroundPainter(), the call will fire a property change event (good thing). If I call setPainter(BACKGROUND_LAYER, painter) it won't necessarily do so. If I call getPainters() and manipulate the map directly, then no PropertyChangeEvent is likely to be fired.

I'd like to see a PropertyChangeEvent be fired in all those cases. A custom Map implementation would do it (the API can stay the same, but behind the scenes use a custom Map).

Joshua Marinacci

On Nov 28, 2006, at 12:05 PM, jdnc-interest@javadesktop.org wrote:

> Hey Josh,
>
> I wish there were a way to do it with enums instead of ints, but
> since enums are implicitly final I don't see any way to go that
> route. Possibly the use of a typesafe enum class would work.
> Integers are always a bit dodgy.
>

We could use enums instead, but the point of the layers is that you
can create your own. If I want to put something between the component
and background layers I could do
comp.setPainter(BACKGROUND_LAYER+1,painter);

> get/setPainters: why the List of painters? I'd have expected
> Map. A List of painters is just a
> CompoundPainter, right?

Because you can have more than one painter at a given level. If there
is already a background painter then when you add another one it will
take the place of the background painter, pushing it down so that
they are both there. The question is whether this is a good idea.
Should we only allow one painter at each level and if you want more
then manually use a compound painter. That might be simpler.

> One edge case: if I call setBackgroundPainter(), the call will fire
> a property change event (good thing). If I call setPainter
> (BACKGROUND_LAYER, painter) it won't necessarily do so. If I call
> getPainters() and manipulate the map directly, then no
> PropertyChangeEvent is likely to be fired.
>
> I'd like to see a PropertyChangeEvent be fired in all those cases.
> A custom Map implementation would do it (the API can stay the same,
> but behind the scenes use a custom Map).

We can use a custom map for this. That's really an implementation
detail, though. Or does the property change behavior need to be
specified in the JXComponent interface? Do we really want this,
though? It seems like mucking around with the map is an advanced
behavior which doesn't necessarily need property change events. What
would you use it for?

- Josh

> [Message sent by forum member 'rbair' (rbair)]
>
> http://forums.java.net/jive/thread.jspa?messageID=179982
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: jdnc-unsubscribe@jdnc.dev.java.net
> For additional commands, e-mail: jdnc-help@jdnc.dev.java.net

- Blasting forth in three part harmony!

[att1.html]

rbair
Offline
Joined: 2003-07-08

> Because you can have more than one painter at a given
> level. If there
> is already a background painter then when you add
> another one it will
> take the place of the background painter, pushing it
> down so that
> they are both there. The question is whether this is
> a good idea.
> Should we only allow one painter at each level and if
> you want more
> then manually use a compound painter. That might be
> simpler.

I would vote for having a single painter, and if you want more than one, use a CompoundPainter.

> We can use a custom map for this. That's really an
> implementation
> detail, though. Or does the property change behavior
> need to be
> specified in the JXComponent interface? Do we really
> want this,
> though? It seems like mucking around with the map is
> an advanced
> behavior which doesn't necessarily need property
> change events. What
> would you use it for?

No, it's really just an implementation detail. I think you want the property change event (even when manipulating via the map) because the "background"property IS changing when the map values change.

Richard

mikaelgrev
Offline
Joined: 2006-09-27

Hello Richard,

I just want to point you to this thread as it is discussing this in great detail.

http://forums.java.net/jive/thread.jspa?forumID=73&threadID=14296&messag...

> I would vote for having a single painter, and if you want more than one, use a CompoundPainter.

Basically the problem here that if you add a painter to a component that has a few already (target component is unknown as compile time) you can never safely find a layer that you are sure will not replace anything that is already there. You can not either "wrap" the existing one in a CompoundPainter since the owner of the other Painter can the for instance never remove its painter then.

This is why the "add" approach was used.

If you want Map then there are a few ugly ways to solve it:

getFreeLayerAbove(int layer) and getFreeLayerBelow(int layer)
or
int actualLayer = setPainter(myPainter, layer)

But they are a bit "hacky". Might be worth it though?

I don't think we should give up the option to add a Painter to a component in a totally neutral way that will never break the target component.

Cheers,