Re: CSS metadata boilerplate

2014-01-09 Thread John Hendrikx

Noticed a slight bug in the code.

The line:

  cssMetaDataByName.put(cssName, cssMetaData);

...needs to be added in the if block where the CssMetaData is created.

--John


Re: CSS metadata boilerplate

2014-01-09 Thread David Grieve
Thanks, John. It would be helpful if you could create an issue in jira to track 
this. 

On Jan 8, 2014, at 4:18 PM, John Hendrikx hj...@xs4all.nl wrote:

 On 8/01/2014 14:28, David Grieve wrote:
 The reason things are as they are is because most properties in the core 
 classes are lazily created and I didn't want cause the property to be 
 created just to see if it was bound. But that is a particular concern for 
 the core classes and not so much for controls.
 I see, this mechanism certainly doesn't try to do that.  It only works when 
 the properties are created in advance.
 I'm not sure if you are aware of the javafx.css.SimpleStyleableXXXProperty 
 classes. I'd be interested to see how your custom classes dovetail into 
 these as I'd be more than willing to consider taking  your additions and 
 calling them my own… uh, um, I mean, rolling them into the source code.
 I wasn't aware of those, but I just took a look at them.  They do make the 
 process a little bit easier, although still require creating a CssMetaData 
 object yourself.  If you want to use the code or just the idea, please feel 
 free -- it would be very nice for creating custom controls if it was part of 
 JavaFX.
 Have you looked at the initialization-on-demand holder pattern for creating 
 the List?
 That's the Super-lazy instantiation pattern from Bill Pugh ?  I've seen it 
 several times in the JavaFX sources, and I think it is a neat way to avoid 
 certain statics from being created immediately after the class loads.
 
 However, I'm not sure if it applies here, the first getCssMetaData call 
 basically is the trigger that causes all CssMetaData objects and the List to 
 get created...  I'm not sure how I could make it any more lazy than that.  
 The Map I use in the properties themselves is static, so shouldn't cause too 
 much footprint.
 
 The code I use for the one of the SimpleStyleableXXXProperty is below.  It 
 relies on a Map that will cache CssMetaData objects (for different instances 
 of the same property in a Control) and are only created when they're needed.  
 CssMetaData objects only get created one time on access, after that further 
 calls just do a quick map lookup.
 
 It makes assumptions about the kind of converter needed, which could be 
 parameterized further with another constructor option.
 
 public class SimpleStyleableDoubleProperty extends StyleableDoubleProperty {
  private static final MapClass?, MapString, CssMetaData? extends 
 Styleable, Number CSS_META_DATA_BY_NAME_BY_CLASS = new HashMap();
 
  private final Object bean;
  private final String name;
  private final String cssName;
  private final double initialValue;
 
  public SimpleStyleableDoubleProperty(Object bean, String name, String 
 cssName, double initialValue) {
super(initialValue);
 
this.bean = bean;
this.name = name;
this.cssName = cssName;
this.initialValue = initialValue;
  }
 
  @Override
  public CssMetaData? extends Styleable, Number getCssMetaData() {
// TODO consider synchronizing CSS_META_DATA_BY_NAME_BY_CLASS -- depends 
 on whether or not this ever gets called by more than one thread.
MapString, CssMetaData?, Number cssMetaDataByName = 
 CSS_META_DATA_BY_NAME_BY_CLASS.get(bean.getClass());
 
if(cssMetaDataByName == null) {
  cssMetaDataByName = new HashMap();
  CSS_META_DATA_BY_NAME_BY_CLASS.put(bean.getClass(), cssMetaDataByName);
}
 
CssMetaData? extends Styleable, Number cssMetaData = 
 cssMetaDataByName.get(cssName);
 
if(cssMetaData == null) {
  cssMetaData = new CssMetaDataStyleable, Number(cssName, 
 StyleConverter.getSizeConverter(), initialValue) {
@Override
public boolean isSettable(Styleable styleable) {
  return !SimpleStyleableDoubleProperty.this.isBound();
}
 
@Override
public StyleableDoubleProperty getStyleableProperty(Styleable 
 styleable) {
  return SimpleStyleableDoubleProperty.this;
}
  };
}
 
return cssMetaData;
  }
 
  @Override
  public Object getBean() {
return bean;
  }
 
  @Override
  public String getName() {
return name;
  }
 }
 
 --John
 
 
 
 On Jan 7, 2014, at 9:34 PM, John Hendrikxhj...@xs4all.nl  wrote:
 
 Hi List,
 
 I'm in the process of adding CSS metadata to a new control, and I noticed 
 there is a lot of boilerplate.
 
 In order to reduce this, I've created some custom classes StyleableProperty 
 classes (SimpleStyleableXXXProperty), which reduces the boilerplate 
 significantly without sacrificing much (if any) performance.  The only 
 thing that I cannot easily provide in this fashion is the static 
 getClassCssMetaData method.  From the documentation I understand it is 
 there just for convience for subclass creators and is not used by the CSS 
 engine at all -- atleast, everything seems to work.
 
 The shortened version for CSS aware properties basically looks like:
 
  private final SimpleStyleableDoubleProperty cellAlignment = new 
 

Re: CSS metadata boilerplate

2014-01-08 Thread Tomas Mikula
+1. I ended up creating such property subclasses myself, too. And I don't
provide the static getClassCssMetaData() either.

Tomas


On Wed, Jan 8, 2014 at 7:05 AM, Tom Eugelink t...@tbee.org wrote:


 Yes, I had similar considerations. I was thinking about providing exactly
 such extended Property classes in JFXtras to remove as much of the
 boilerplate.

 Tom



 On 2014-1-8 3:34, John Hendrikx wrote:

 Hi List,

 I'm in the process of adding CSS metadata to a new control, and I noticed
 there is a lot of boilerplate.

 In order to reduce this, I've created some custom classes
 StyleableProperty classes (SimpleStyleableXXXProperty), which reduces the
 boilerplate significantly without sacrificing much (if any) performance.
  The only thing that I cannot easily provide in this fashion is the static
 getClassCssMetaData method.  From the documentation I understand it is
 there just for convience for subclass creators and is not used by the CSS
 engine at all -- atleast, everything seems to work.

 The shortened version for CSS aware properties basically looks like:

   private final SimpleStyleableDoubleProperty cellAlignment = new
 SimpleStyleableDoubleProperty(this, cellAlignment,
 -fx-cell-alignment, 0.8);
   private final SimpleStyleableDoubleProperty density= new
 SimpleStyleableDoubleProperty(this, density, -fx-density, 0.02);
   private final SimpleStyleableBooleanProperty reflectionEnabled= new
 SimpleStyleableBooleanProperty(this, reflectionEnabled,
 -fx-reflection-enabled, true);
   private final SimpleStyleableBooleanProperty clipReflections= new
 SimpleStyleableBooleanProperty(this, clipReflections,
 -fx-clip-reflections, true);

 With one small bit of supporting code in the relevant class (Skin or
 Control), which is basically a non-static implementation of the standard
 CSS List example code:

   private static ListCssMetaData? extends Styleable, ? cssMetaData;

   @Override
   public ListCssMetaData? extends Styleable, ? getCssMetaData() {  //
 Unsynchronized. WC: list gets initialized multiple times.
 if(cssMetaData == null) {
   ListCssMetaData? extends Styleable, ? metaData = new
 ArrayList(super.getCssMetaData());
   Collections.addAll(metaData,
   cellAlignment.getCssMetaData(),
   density.getCssMetaData(),
   reflectionEnabled.getCssMetaData(),
   clipReflections.getCssMetaData()
   );
   cssMetaData = Collections.unmodifiableList(metaData);
 }

 return cssMetaData;
   }

 Note that the List is static and lazy-final.  The same goes for the
 getCssMetaData method in the SimpleStyleableXXXProperty classes.  There is
 a slight performance decrease in those classes as getCssMetaData is looked
 up from a static Map (indexed by Class + css property name) and lazily
 created as needed -- a Map lookup however should be quite fast enough.

 I'm sure the design had good reason to do things as they are, and I'm
 wondering if reducing the boilerplate has left me missing something
 important.

 I welcome any insights!

 --John






Re: CSS metadata boilerplate

2014-01-08 Thread David Grieve
The reason things are as they are is because most properties in the core 
classes are lazily created and I didn't want cause the property to be created 
just to see if it was bound. But that is a particular concern for the core 
classes and not so much for controls. 

I'm not sure if you are aware of the javafx.css.SimpleStyleableXXXProperty 
classes. I'd be interested to see how your custom classes dovetail into these 
as I'd be more than willing to consider taking  your additions and calling them 
my own… uh, um, I mean, rolling them into the source code. 

Have you looked at the initialization-on-demand holder pattern for creating the 
List?
 
On Jan 7, 2014, at 9:34 PM, John Hendrikx hj...@xs4all.nl wrote:

 Hi List,
 
 I'm in the process of adding CSS metadata to a new control, and I noticed 
 there is a lot of boilerplate.
 
 In order to reduce this, I've created some custom classes StyleableProperty 
 classes (SimpleStyleableXXXProperty), which reduces the boilerplate 
 significantly without sacrificing much (if any) performance.  The only thing 
 that I cannot easily provide in this fashion is the static 
 getClassCssMetaData method.  From the documentation I understand it is there 
 just for convience for subclass creators and is not used by the CSS engine at 
 all -- atleast, everything seems to work.
 
 The shortened version for CSS aware properties basically looks like:
 
  private final SimpleStyleableDoubleProperty cellAlignment = new 
 SimpleStyleableDoubleProperty(this, cellAlignment, -fx-cell-alignment, 
 0.8);
  private final SimpleStyleableDoubleProperty density= new 
 SimpleStyleableDoubleProperty(this, density, -fx-density, 0.02);
  private final SimpleStyleableBooleanProperty reflectionEnabled= new 
 SimpleStyleableBooleanProperty(this, reflectionEnabled, 
 -fx-reflection-enabled, true);
  private final SimpleStyleableBooleanProperty clipReflections= new 
 SimpleStyleableBooleanProperty(this, clipReflections, 
 -fx-clip-reflections, true);
 
 With one small bit of supporting code in the relevant class (Skin or 
 Control), which is basically a non-static implementation of the standard CSS 
 List example code:
 
  private static ListCssMetaData? extends Styleable, ? cssMetaData;
 
  @Override
  public ListCssMetaData? extends Styleable, ? getCssMetaData() {  // 
 Unsynchronized. WC: list gets initialized multiple times.
if(cssMetaData == null) {
  ListCssMetaData? extends Styleable, ? metaData = new 
 ArrayList(super.getCssMetaData());
  Collections.addAll(metaData,
  cellAlignment.getCssMetaData(),
  density.getCssMetaData(),
  reflectionEnabled.getCssMetaData(),
  clipReflections.getCssMetaData()
  );
  cssMetaData = Collections.unmodifiableList(metaData);
}
 
return cssMetaData;
  }
 
 Note that the List is static and lazy-final.  The same goes for the 
 getCssMetaData method in the SimpleStyleableXXXProperty classes.  There is a 
 slight performance decrease in those classes as getCssMetaData is looked up 
 from a static Map (indexed by Class + css property name) and lazily created 
 as needed -- a Map lookup however should be quite fast enough.
 
 I'm sure the design had good reason to do things as they are, and I'm 
 wondering if reducing the boilerplate has left me missing something important.
 
 I welcome any insights!
 
 --John



Re: CSS metadata boilerplate

2014-01-08 Thread John Hendrikx

On 8/01/2014 14:28, David Grieve wrote:

The reason things are as they are is because most properties in the core 
classes are lazily created and I didn't want cause the property to be created 
just to see if it was bound. But that is a particular concern for the core 
classes and not so much for controls.
I see, this mechanism certainly doesn't try to do that.  It only works 
when the properties are created in advance.

I'm not sure if you are aware of the javafx.css.SimpleStyleableXXXProperty 
classes. I'd be interested to see how your custom classes dovetail into these 
as I'd be more than willing to consider taking  your additions and calling them 
my own… uh, um, I mean, rolling them into the source code.
I wasn't aware of those, but I just took a look at them.  They do make 
the process a little bit easier, although still require creating a 
CssMetaData object yourself.  If you want to use the code or just the 
idea, please feel free -- it would be very nice for creating custom 
controls if it was part of JavaFX.

Have you looked at the initialization-on-demand holder pattern for creating the 
List?
That's the Super-lazy instantiation pattern from Bill Pugh ?  I've 
seen it several times in the JavaFX sources, and I think it is a neat 
way to avoid certain statics from being created immediately after the 
class loads.


However, I'm not sure if it applies here, the first getCssMetaData call 
basically is the trigger that causes all CssMetaData objects and the 
List to get created...  I'm not sure how I could make it any more lazy 
than that.  The Map I use in the properties themselves is static, so 
shouldn't cause too much footprint.


The code I use for the one of the SimpleStyleableXXXProperty is below.  
It relies on a Map that will cache CssMetaData objects (for different 
instances of the same property in a Control) and are only created when 
they're needed.  CssMetaData objects only get created one time on 
access, after that further calls just do a quick map lookup.


It makes assumptions about the kind of converter needed, which could be 
parameterized further with another constructor option.


public class SimpleStyleableDoubleProperty extends StyleableDoubleProperty {
  private static final MapClass?, MapString, CssMetaData? extends 
Styleable, Number CSS_META_DATA_BY_NAME_BY_CLASS = new HashMap();


  private final Object bean;
  private final String name;
  private final String cssName;
  private final double initialValue;

  public SimpleStyleableDoubleProperty(Object bean, String name, String 
cssName, double initialValue) {

super(initialValue);

this.bean = bean;
this.name = name;
this.cssName = cssName;
this.initialValue = initialValue;
  }

  @Override
  public CssMetaData? extends Styleable, Number getCssMetaData() {
// TODO consider synchronizing CSS_META_DATA_BY_NAME_BY_CLASS -- 
depends on whether or not this ever gets called by more than one thread.
MapString, CssMetaData?, Number cssMetaDataByName = 
CSS_META_DATA_BY_NAME_BY_CLASS.get(bean.getClass());


if(cssMetaDataByName == null) {
  cssMetaDataByName = new HashMap();
  CSS_META_DATA_BY_NAME_BY_CLASS.put(bean.getClass(), 
cssMetaDataByName);

}

CssMetaData? extends Styleable, Number cssMetaData = 
cssMetaDataByName.get(cssName);


if(cssMetaData == null) {
  cssMetaData = new CssMetaDataStyleable, Number(cssName, 
StyleConverter.getSizeConverter(), initialValue) {

@Override
public boolean isSettable(Styleable styleable) {
  return !SimpleStyleableDoubleProperty.this.isBound();
}

@Override
public StyleableDoubleProperty getStyleableProperty(Styleable 
styleable) {

  return SimpleStyleableDoubleProperty.this;
}
  };
}

return cssMetaData;
  }

  @Override
  public Object getBean() {
return bean;
  }

  @Override
  public String getName() {
return name;
  }
}

--John




On Jan 7, 2014, at 9:34 PM, John Hendrikxhj...@xs4all.nl  wrote:


Hi List,

I'm in the process of adding CSS metadata to a new control, and I noticed there 
is a lot of boilerplate.

In order to reduce this, I've created some custom classes StyleableProperty 
classes (SimpleStyleableXXXProperty), which reduces the boilerplate 
significantly without sacrificing much (if any) performance.  The only thing 
that I cannot easily provide in this fashion is the static getClassCssMetaData 
method.  From the documentation I understand it is there just for convience for 
subclass creators and is not used by the CSS engine at all -- atleast, 
everything seems to work.

The shortened version for CSS aware properties basically looks like:

  private final SimpleStyleableDoubleProperty cellAlignment = new 
SimpleStyleableDoubleProperty(this, cellAlignment, -fx-cell-alignment, 0.8);
  private final SimpleStyleableDoubleProperty density= new SimpleStyleableDoubleProperty(this, 
density, -fx-density, 0.02);
  private final 

CSS metadata boilerplate

2014-01-07 Thread John Hendrikx

Hi List,

I'm in the process of adding CSS metadata to a new control, and I 
noticed there is a lot of boilerplate.


In order to reduce this, I've created some custom classes 
StyleableProperty classes (SimpleStyleableXXXProperty), which reduces 
the boilerplate significantly without sacrificing much (if any) 
performance.  The only thing that I cannot easily provide in this 
fashion is the static getClassCssMetaData method.  From the 
documentation I understand it is there just for convience for subclass 
creators and is not used by the CSS engine at all -- atleast, everything 
seems to work.


The shortened version for CSS aware properties basically looks like:

  private final SimpleStyleableDoubleProperty cellAlignment = new 
SimpleStyleableDoubleProperty(this, cellAlignment, 
-fx-cell-alignment, 0.8);
  private final SimpleStyleableDoubleProperty density= new 
SimpleStyleableDoubleProperty(this, density, -fx-density, 0.02);
  private final SimpleStyleableBooleanProperty reflectionEnabled= new 
SimpleStyleableBooleanProperty(this, reflectionEnabled, 
-fx-reflection-enabled, true);
  private final SimpleStyleableBooleanProperty clipReflections= new 
SimpleStyleableBooleanProperty(this, clipReflections, 
-fx-clip-reflections, true);


With one small bit of supporting code in the relevant class (Skin or 
Control), which is basically a non-static implementation of the standard 
CSS List example code:


  private static ListCssMetaData? extends Styleable, ? cssMetaData;

  @Override
  public ListCssMetaData? extends Styleable, ? getCssMetaData() {  
// Unsynchronized. WC: list gets initialized multiple times.

if(cssMetaData == null) {
  ListCssMetaData? extends Styleable, ? metaData = new 
ArrayList(super.getCssMetaData());

  Collections.addAll(metaData,
  cellAlignment.getCssMetaData(),
  density.getCssMetaData(),
  reflectionEnabled.getCssMetaData(),
  clipReflections.getCssMetaData()
  );
  cssMetaData = Collections.unmodifiableList(metaData);
}

return cssMetaData;
  }

Note that the List is static and lazy-final.  The same goes for the 
getCssMetaData method in the SimpleStyleableXXXProperty classes.  There 
is a slight performance decrease in those classes as getCssMetaData is 
looked up from a static Map (indexed by Class + css property name) and 
lazily created as needed -- a Map lookup however should be quite fast 
enough.


I'm sure the design had good reason to do things as they are, and I'm 
wondering if reducing the boilerplate has left me missing something 
important.


I welcome any insights!

--John


Re: CSS metadata boilerplate

2014-01-07 Thread Tom Eugelink


Yes, I had similar considerations. I was thinking about providing exactly such 
extended Property classes in JFXtras to remove as much of the boilerplate.

Tom


On 2014-1-8 3:34, John Hendrikx wrote:

Hi List,

I'm in the process of adding CSS metadata to a new control, and I noticed there 
is a lot of boilerplate.

In order to reduce this, I've created some custom classes StyleableProperty 
classes (SimpleStyleableXXXProperty), which reduces the boilerplate 
significantly without sacrificing much (if any) performance.  The only thing 
that I cannot easily provide in this fashion is the static getClassCssMetaData 
method.  From the documentation I understand it is there just for convience for 
subclass creators and is not used by the CSS engine at all -- atleast, 
everything seems to work.

The shortened version for CSS aware properties basically looks like:

  private final SimpleStyleableDoubleProperty cellAlignment = new 
SimpleStyleableDoubleProperty(this, cellAlignment, -fx-cell-alignment, 0.8);
  private final SimpleStyleableDoubleProperty density= new SimpleStyleableDoubleProperty(this, 
density, -fx-density, 0.02);
  private final SimpleStyleableBooleanProperty reflectionEnabled= new 
SimpleStyleableBooleanProperty(this, reflectionEnabled, 
-fx-reflection-enabled, true);
  private final SimpleStyleableBooleanProperty clipReflections= new 
SimpleStyleableBooleanProperty(this, clipReflections, -fx-clip-reflections, 
true);

With one small bit of supporting code in the relevant class (Skin or Control), 
which is basically a non-static implementation of the standard CSS List example 
code:

  private static ListCssMetaData? extends Styleable, ? cssMetaData;

  @Override
  public ListCssMetaData? extends Styleable, ? getCssMetaData() {  // 
Unsynchronized. WC: list gets initialized multiple times.
if(cssMetaData == null) {
  ListCssMetaData? extends Styleable, ? metaData = new 
ArrayList(super.getCssMetaData());
  Collections.addAll(metaData,
  cellAlignment.getCssMetaData(),
  density.getCssMetaData(),
  reflectionEnabled.getCssMetaData(),
  clipReflections.getCssMetaData()
  );
  cssMetaData = Collections.unmodifiableList(metaData);
}

return cssMetaData;
  }

Note that the List is static and lazy-final.  The same goes for the 
getCssMetaData method in the SimpleStyleableXXXProperty classes.  There is a 
slight performance decrease in those classes as getCssMetaData is looked up 
from a static Map (indexed by Class + css property name) and lazily created as 
needed -- a Map lookup however should be quite fast enough.

I'm sure the design had good reason to do things as they are, and I'm wondering 
if reducing the boilerplate has left me missing something important.

I welcome any insights!

--John