2
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
6
* The contents of this file are subject to the terms of either the GNU
7
* General Public License Version 2 only ("GPL") or the Common
8
* Development and Distribution License("CDDL") (collectively, the
9
* "License"). You may not use this file except in compliance with the
10
* License. You can obtain a copy of the License at
11
* http://www.netbeans.org/cddl-gplv2.html
12
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
* specific language governing permissions and limitations under the
14
* License. When distributing the software, include this License Header
15
* Notice in each file and include the License file at
16
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17
* particular file as subject to the "Classpath" exception as provided
18
* by Sun in the GPL Version 2 section of the License file that
19
* accompanied this code. If applicable, add the following below the
20
* License Header, with the fields enclosed by brackets [] replaced by
21
* your own identifying information:
22
* "Portions Copyrighted [year] [name of copyright owner]"
26
* The Original Software is NetBeans. The Initial Developer of the Original
27
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
* Microsystems, Inc. All Rights Reserved.
30
* If you wish your version of this file to be governed by only the CDDL
31
* or only the GPL Version 2, indicate your decision by adding
32
* "[Contributor] elects to include this software in this distribution
33
* under the [CDDL or GPL Version 2] license." If you do not indicate a
34
* single choice of license, a recipient has the option to distribute
35
* your version of this file under either the CDDL, the GPL Version 2 or
36
* to extend the choice of license to its licensees as provided above.
37
* However, if you add GPL Version 2 code and therefore, elected the GPL
38
* Version 2 license, then the option applies only if the new code is
39
* made subject to such option by the copyright holder.
42
package org.netbeans.modules.form;
44
import com.sun.source.tree.*;
45
import com.sun.source.util.TreePath;
46
import com.sun.source.util.Trees;
47
import java.lang.ref.*;
48
import java.lang.reflect.*;
51
import java.io.IOException;
52
import java.util.logging.Level;
53
import java.util.logging.Logger;
54
import javax.lang.model.element.Element;
55
import javax.lang.model.element.ElementKind;
56
import javax.lang.model.element.TypeElement;
57
import javax.lang.model.element.TypeParameterElement;
58
import javax.lang.model.type.TypeKind;
59
import javax.swing.JList;
60
import javax.swing.JTable;
61
import javax.swing.JComboBox;
62
import javax.swing.JSlider;
63
import javax.swing.JSpinner;
64
import javax.swing.text.JTextComponent;
65
import org.jdesktop.beansbinding.*;
66
import org.jdesktop.beansbinding.ext.BeanAdapterFactory;
67
import org.jdesktop.swingbinding.*;
68
import org.netbeans.api.java.classpath.ClassPath;
69
import org.netbeans.api.java.source.CancellableTask;
70
import org.netbeans.api.java.source.CompilationController;
71
import org.netbeans.api.java.source.JavaSource;
72
import org.netbeans.modules.form.FormUtils.TypeHelper;
73
import org.netbeans.modules.form.project.ClassPathUtils;
74
import org.openide.filesystems.FileObject;
75
import org.openide.nodes.Node;
78
* Design support for beans binding.
80
* @author Jan Stola, Tomas Pavek
82
public class BindingDesignSupport {
84
private FormModel formModel;
86
/** Realizations of bindings among replicated components. */
87
private Map<MetaBinding, List<Binding>> bindingsMap = new HashMap<MetaBinding, List<Binding>>();
88
/** Realizations of bindings among metacomponents. */
89
private Map<MetaBinding, Binding> modelBindings = new HashMap<MetaBinding, Binding>();
90
/** Binding to BindingGroup mapping. */
91
private Map<Binding, BindingGroup> bindingToGroup = new HashMap<Binding, BindingGroup>();
92
/** Binding group for reference instances in metacomponents. */
93
private BindingGroup bindingGroup;
96
* Create binding design support for the given form model.
98
* @param model form model to create the binding support for.
100
public BindingDesignSupport(FormModel model) {
103
bindingGroup = new BindingGroup();
106
formModel.addFormModelListener(new ModelListener());
110
* Changes the binding between two components (affects only replicated components).
112
* @param oldBinding the old definition of the binding.
113
* @param newBinding the new definition of the binding.
115
private void changeBinding(MetaBinding oldBinding, MetaBinding newBinding) {
116
if (oldBinding != null) {
117
removeBindings(oldBinding);
119
// non-model bindings are added from VisualReplicator
123
* Changes the binding between two components (affects only reference instances in the model).
125
* @param oldBinding the old definition of the binding.
126
* @param newBinding the new definition of the binding.
128
public void changeBindingInModel(MetaBinding oldBinding, MetaBinding newBinding) {
129
if (oldBinding != null) {
130
removeBindingInModel(oldBinding);
132
if (newBinding != null) {
133
addBindingInModel(newBinding);
138
* Turns given string (usually dot-separated path) into EL expression
139
* by adding <code>${</code> and <code>}</code> braces.
141
* @param path string to transform into EL expression.
142
* @return EL expression corresponding to the given path.
144
public static String elWrap(String path) {
145
return (path == null) ? null : "${" + path + "}"; // NOI18N
149
* Determines whether the given string is simple EL expression.
151
* @param expression string to check.
152
* @return <code>true</code> if the given string starts with
153
* <code>${</code> and ends with <code>}</code>, returns <code>false</code>
156
public static boolean isSimpleExpression(String expression) {
157
return (expression.startsWith("${") && expression.endsWith("}")); // NOI18N
161
* Removes <code>${</code> and <code>}</code> braces from a simple
162
* EL expression. Non-simple expressions are left untouched.
164
* @param expression expression to unwrap.
165
* @return unwrapped expression or the given string
166
* (if it is not a simple EL expression).
168
public static String unwrapSimpleExpression(String expression) {
169
if (isSimpleExpression(expression)) {
170
expression = expression.substring(2, expression.length()-1);
175
private static boolean hasRelativeType(Class clazz, String property) {
176
return ("elements".equals(property) // NOI18N
177
// selectedElement(_...), selectedElements(_...)
178
|| property.startsWith("selectedElement")) // NOI18N
179
&& (javax.swing.JTable.class.isAssignableFrom(clazz)
180
|| javax.swing.JList.class.isAssignableFrom(clazz)
181
|| javax.swing.JComboBox.class.isAssignableFrom(clazz));
184
// Used to determine binding properties only
185
List<BindingDescriptor>[] getBindingDescriptors(RADComponent component) {
186
BeanDescriptor beanDescriptor = component.getBeanInfo().getBeanDescriptor();
187
List<BindingDescriptor>[] descs = getBindingDescriptors(null, beanDescriptor);
188
Class<?> beanClass = component.getBeanClass();
189
if (JTextComponent.class.isAssignableFrom(beanClass)) {
190
// get rid of text_... descriptors
191
descs[0] = filterDescriptors(descs[0], "text_"); // NOI18N
192
} else if (JTable.class.isAssignableFrom(beanClass)
193
|| JList.class.isAssignableFrom(beanClass)
194
|| JComboBox.class.isAssignableFrom(beanClass)) {
195
// get rid of selectedElement(s)_... descriptors
196
descs[0] = filterDescriptors(descs[0], "selectedElement_"); // NOI18N
197
descs[0] = filterDescriptors(descs[0], "selectedElements_"); // NOI18N
198
// add elements descriptor
199
BindingDescriptor desc = new BindingDescriptor("elements", List.class); // NOI18N
200
descs[0].add(0, desc);
201
} else if (JSlider.class.isAssignableFrom(beanClass)) {
202
// get rid of value_... descriptor
203
descs[0] = filterDescriptors(descs[0], "value_"); // NOI18N
208
List<BindingDescriptor> filterDescriptors(List<BindingDescriptor> descs, String forbiddenPrefix) {
209
List<BindingDescriptor> filtered = new LinkedList<BindingDescriptor>();
210
for (BindingDescriptor bd : descs) {
211
if (!bd.getPath().startsWith(forbiddenPrefix)) { // NOI18N
218
private List<PropertyDescriptor> getSpecialBindingDescriptors(Class clazz) {
219
List<PropertyDescriptor> descs = BeanAdapterFactory.getAdapterPropertyDescriptors(clazz);
221
if (JComboBox.class.isAssignableFrom(clazz)) {
222
PropertyDescriptor desc = new PropertyDescriptor("selectedItem", JComboBox.class); // NOI18N
224
} else if (JSpinner.class.isAssignableFrom(clazz)) {
225
PropertyDescriptor desc = new PropertyDescriptor("value", JSpinner.class); // NOI18N
228
} catch (Exception ex) {
229
Logger.getLogger(getClass().getName()).log(Level.INFO, ex.getMessage(), ex);
234
private List<BindingDescriptor>[] getBindingDescriptors(TypeHelper type, BeanDescriptor beanDescriptor) {
235
Class<?> beanClass = beanDescriptor.getBeanClass();
236
List<BindingDescriptor> bindingList = new LinkedList<BindingDescriptor>();
237
List<BindingDescriptor> prefList = new LinkedList<BindingDescriptor>();
238
List<BindingDescriptor> observableList = new LinkedList<BindingDescriptor>();
239
List<BindingDescriptor> nonObservableList = new LinkedList<BindingDescriptor>();
240
List<BindingDescriptor> list;
241
Object[] propsCats = FormUtils.getPropertiesCategoryClsf(beanClass, beanDescriptor);
242
PropertyDescriptor[] pds;
244
pds = FormUtils.getBeanInfo(beanClass).getPropertyDescriptors();
245
} catch (Exception ex) {
246
Logger.getLogger(getClass().getName()).log(Level.INFO, ex.getMessage(), ex);
247
pds = new PropertyDescriptor[0];
249
List<PropertyDescriptor> specialPds = getSpecialBindingDescriptors(beanClass);
250
Map<String,PropertyDescriptor> pathToDesc = new HashMap<String,PropertyDescriptor>();
251
for (PropertyDescriptor pd : pds) {
252
pathToDesc.put(pd.getName(), pd);
254
for (PropertyDescriptor pd : specialPds) {
255
if (pathToDesc.get(pd.getName()) != null) {
256
pathToDesc.remove(pd.getName());
259
List<PropertyDescriptor> allPds = new LinkedList<PropertyDescriptor>(specialPds);
260
allPds.addAll(pathToDesc.values());
262
for (PropertyDescriptor pd : allPds) {
263
if (count++<specialPds.size()) {
266
Object propCat = FormUtils.getPropertyCategory(pd, propsCats);
267
if (propCat == FormUtils.PROP_HIDDEN) {
268
// hidden property => hide also the binding property
272
// observable property
273
if (propCat == FormUtils.PROP_PREFERRED) {
276
list = observableList;
279
// non-observable property
280
list = nonObservableList;
285
Method method = pd.getReadMethod();
286
if ((method != null) && ("getClass".equals(method.getName()))) continue; // NOI18N
287
Type retType = (method == null) ? pd.getPropertyType() : method.getGenericReturnType();
288
if (retType == null) continue;
289
BindingDescriptor bd;
291
bd = new BindingDescriptor(pd.getName(), retType);
293
TypeHelper t = new TypeHelper(retType, type.getActualTypeArgs()).normalize();
294
bd = new BindingDescriptor(pd.getName(), t);
296
bd.setDisplayName(pd.getDisplayName());
297
bd.setShortDescription(pd.getShortDescription());
299
if (hasRelativeType(beanClass, bd.getPath())) {
300
bd.markTypeAsRelative();
306
if (bindingList.isEmpty()) {
307
bindingList = prefList;
309
observableList.addAll(prefList);
311
Comparator<BindingDescriptor> bdComparator = new Comparator<BindingDescriptor>() {
312
public int compare(BindingDescriptor o1, BindingDescriptor o2) {
313
String path1 = o1.getPath();
314
String path2 = o2.getPath();
315
return path1.compareToIgnoreCase(path2);
318
Collections.sort(bindingList, bdComparator);
319
Collections.sort(observableList, bdComparator);
320
Collections.sort(nonObservableList, bdComparator);
322
return new List[] {bindingList, observableList, nonObservableList};
325
public List<BindingDescriptor> getAllBindingDescriptors(TypeHelper type) {
326
List<BindingDescriptor>[] descs = getBindingDescriptors(type);
327
List<BindingDescriptor> list = new LinkedList<BindingDescriptor>();
328
for (int i=0; i<descs.length; i++ ){
329
list.addAll(descs[i]);
335
* Returns possible bindings for the given type.
337
* @param type type whose possible bindings should be returned.
338
* @return list of <code>BindingDescriptor</code>s describing possible bindings.
340
@SuppressWarnings("unchecked") // generic array creation NOI18N
341
public List<BindingDescriptor>[] getBindingDescriptors(TypeHelper type) {
342
List<BindingDescriptor> typesFromSource = Collections.emptyList();
343
Class binarySuperClass = null;
344
if (type.getType() == null) {
345
FileObject fileInProject = FormEditor.getFormDataObject(formModel).getPrimaryFile();
346
ClassPath cp = ClassPath.getClassPath(fileInProject, ClassPath.SOURCE);
347
final List<BindingDescriptor> types = new LinkedList<BindingDescriptor>();
348
final String[] superClass = new String[1];
349
superClass[0] = type.getName();
351
String typeName = superClass[0];
352
final String resourceName = typeName.replace('.', '/') + ".java"; // NOI18N
353
int lastDot = typeName.lastIndexOf('.');
354
lastDot = (lastDot == -1) ? 0 : lastDot;
355
final String simpleTypeName = typeName.substring(lastDot+1);
356
FileObject fob = cp.findResource(resourceName);
359
binarySuperClass = ClassPathUtils.loadClass(typeName, fileInProject);
360
} catch (ClassNotFoundException cnfex) {}
363
JavaSource source = JavaSource.forFileObject(fob);
365
source.runUserActionTask(new CancellableTask<CompilationController>() {
366
public void run(CompilationController cc) throws Exception {
367
cc.toPhase(JavaSource.Phase.RESOLVED);
368
CompilationUnitTree cu = cc.getCompilationUnit();
369
ClassTree clazz = null;
370
for (Tree typeDecl : cu.getTypeDecls()) {
371
if (Tree.Kind.CLASS == typeDecl.getKind()) {
372
ClassTree candidate = (ClassTree)typeDecl;
373
if (candidate.getSimpleName().toString().equals(simpleTypeName)) {
379
if (clazz == null) { // issue 118690
381
Logger.getLogger(getClass().getName()).log(Level.INFO, "ClassTree not found in " + resourceName); // NOI18N
382
superClass[0] = Object.class.getName();
385
for (Tree clMember : clazz.getMembers()) {
386
if (clMember.getKind() == Tree.Kind.METHOD) {
387
MethodTree method = (MethodTree)clMember;
388
if (method.getParameters().size() != 0) continue;
389
Set<javax.lang.model.element.Modifier> modifiers = method.getModifiers().getFlags();
390
if (modifiers.contains(javax.lang.model.element.Modifier.STATIC)
391
|| !modifiers.contains(javax.lang.model.element.Modifier.PUBLIC)) {
394
String methodName = method.getName().toString();
395
Tree returnType = method.getReturnType();
398
if (methodName.startsWith("get")) { // NOI18N
399
propName = methodName.substring(3);
400
} else if (methodName.startsWith("is")) { // NOI18N
401
if ((returnType.getKind() == Tree.Kind.PRIMITIVE_TYPE)
402
&& (((PrimitiveTypeTree)returnType).getPrimitiveTypeKind() == TypeKind.BOOLEAN)) {
403
propName = methodName.substring(2);
410
if (propName.length() == 0) continue;
411
if ((propName.length() == 1) || (Character.isLowerCase(propName.charAt(1)))) {
412
propName = Character.toLowerCase(propName.charAt(0)) + propName.substring(1);
416
if (returnType.getKind() == Tree.Kind.PRIMITIVE_TYPE) {
417
PrimitiveTypeTree ptree = (PrimitiveTypeTree)returnType;
418
if (ptree.getPrimitiveTypeKind() == TypeKind.VOID) {
419
continue; // void return type
421
type = new TypeHelper(ptree.toString());
423
type = treeToType(cc, returnType, formModel);
425
types.add(0, new BindingDescriptor(propName, type));
428
Tree superTree = clazz.getExtendsClause();
429
TypeHelper type = treeToType(cc, superTree, formModel);
430
String typeName = type.getName();
431
superClass[0] = (typeName == null) ? FormUtils.typeToClass(type).getName() : typeName;
434
public void cancel() {
438
} catch (IOException ioex) {
439
Logger.getLogger(getClass().getName()).log(Level.INFO, ioex.getMessage(), ioex);
441
} while (!Object.class.equals(superClass[0]));
442
typesFromSource = types;
444
List<BindingDescriptor>[] list = new List[] {Collections.emptyList(), typesFromSource, Collections.emptyList()};
445
Class clazz = (type.getType() == null) ? binarySuperClass : FormUtils.typeToClass(type);
446
if ((clazz != null) && !clazz.getName().startsWith("java.lang.") // NOI18N
447
&& !Collection.class.isAssignableFrom(clazz)
448
&& !clazz.isArray()) {
450
BeanInfo beanInfo = FormUtils.getBeanInfo(clazz);
451
List<BindingDescriptor>[] typesFromBinary = getBindingDescriptors(type, beanInfo.getBeanDescriptor());
452
Map<String,BindingDescriptor>[] maps = new Map[3];
453
for (int i=0; i<3; i++) {
454
maps[i] = listToMap(typesFromBinary[i]);
456
for (BindingDescriptor descriptor : typesFromSource) {
457
String path = descriptor.getPath();
459
for (i=0; i<3; i++) {
460
if (maps[i].containsKey(path)) break;
463
i = 1; // put into observablle properties by default
465
maps[i].put(path, descriptor);
467
for (int i=0; i<3; i++) {
468
list[i] = new LinkedList<BindingDescriptor>(maps[i].values());
470
} catch (Exception ex) {
471
Logger.getLogger(getClass().getName()).log(Level.INFO, ex.getMessage(), ex);
477
private static TypeHelper treeToType(CompilationController cc, Tree tree, FormModel model) {
478
String typeName = Object.class.getName();
479
Map<String,TypeHelper> map = null;
481
CompilationUnitTree cu = cc.getCompilationUnit();
482
Trees trees = cc.getTrees();
483
if (tree.getKind() == Tree.Kind.EXTENDS_WILDCARD) {
484
tree = ((WildcardTree)tree).getBound();
486
TreePath path = trees.getPath(cu, tree);
487
Element el = trees.getElement(path);
488
if ((el != null) && ((el.getKind() == ElementKind.CLASS) || (el.getKind() == ElementKind.INTERFACE))) {
489
TypeElement tel = (TypeElement) el;
490
typeName = tel.getQualifiedName().toString();
491
if (tree.getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
492
List<? extends Tree> params = ((ParameterizedTypeTree)tree).getTypeArguments();
493
List<? extends TypeParameterElement> elems = tel.getTypeParameters();
494
map = new HashMap<String,TypeHelper>();
495
for (int i=0; i<params.size() && i<elems.size(); i++) {
496
Tree param = params.get(0);
497
TypeHelper paramType = treeToType(cc, param, model);
498
TypeParameterElement elem = elems.get(0);
499
map.put(elem.toString(), paramType);
504
TypeHelper type = new TypeHelper(typeName, map);
505
if (typeName.indexOf('.') != -1) {
507
Class clazz = FormUtils.loadClass(typeName, model);
508
type = new TypeHelper(clazz, map);
509
} catch (ClassNotFoundException cnfex) {
510
// not compiled - use just the name
516
private static Map<String,BindingDescriptor> listToMap(List<BindingDescriptor> list) {
517
Map<String,BindingDescriptor> map = new TreeMap<String,BindingDescriptor>();
518
for (BindingDescriptor descriptor : list) {
519
String path = descriptor.getPath();
520
map.put(path, descriptor);
526
* Determines type of RAD component.
528
* @param comp RAD component whose type should be returned.
529
* @return <code>TypeHelper</code> that corresponds to the type of the given component.
531
static TypeHelper determineType(RADComponent comp) {
533
if (comp.getFormModel().getTopRADComponent() == comp) {
534
FileObject fob = FormEditor.getFormDataObject(comp.getFormModel()).getPrimaryFile();
535
ClassPath cp = ClassPath.getClassPath(fob, ClassPath.SOURCE);
536
String className = cp.getResourceName(fob, '.', false);
537
type = new TypeHelper(className);
540
Map<String,TypeHelper> newMap = null;
541
Class clazz = comp.getBeanClass();
543
if (clazz.getTypeParameters().length == 1) {
545
TypeHelper elemType = determineTypeParameter(comp);
546
if (elemType != null) {
547
newMap = new HashMap<String,TypeHelper>();
548
newMap.put(clazz.getTypeParameters()[0].getName(), elemType);
550
} catch (Exception ex) {
551
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, ex.getMessage(), ex);
554
type = new TypeHelper(t, newMap);
559
static TypeHelper determineTypeParameter(final RADComponent comp) {
560
FileObject fob = FormEditor.getFormDataObject(comp.getFormModel()).getPrimaryFile();
561
JavaSource source = JavaSource.forFileObject(fob);
562
final String varName = comp.getName();
563
final TypeHelper[] result = new TypeHelper[1];
565
source.runUserActionTask(new CancellableTask<CompilationController>() {
566
public void run(CompilationController cc) throws Exception {
567
cc.toPhase(JavaSource.Phase.RESOLVED);
568
CompilationUnitTree cu = cc.getCompilationUnit();
569
ClassTree clazz = null;
570
for (Tree typeDecl : cu.getTypeDecls()) {
571
if (Tree.Kind.CLASS == typeDecl.getKind()) {
572
clazz = (ClassTree) typeDecl;
576
Node.Property prop = comp.getSyntheticProperty("useLocalVariable"); // NOI18N
577
Object value = prop.getValue();
578
VariableTree variable = null;
579
if (Boolean.TRUE.equals(value)) {
580
// local variable in initComponents()
581
for (Tree clMember : clazz.getMembers()) {
582
if (clMember.getKind() == Tree.Kind.METHOD) {
583
MethodTree method = (MethodTree)clMember;
584
String methodName = method.getName().toString();
585
if ("initComponents".equals(methodName)) { // NOI18N
586
for (StatementTree statement : method.getBody().getStatements()) {
587
if (statement.getKind() == Tree.Kind.VARIABLE) {
588
VariableTree var = (VariableTree)statement;
589
if (varName.equals(var.getName().toString())) {
599
for (Tree clMember : clazz.getMembers()) {
600
if (clMember.getKind() == Tree.Kind.VARIABLE) {
601
VariableTree var = (VariableTree)clMember;
602
if (varName.equals(var.getName().toString())) {
608
if (variable != null) {
609
Tree type = variable.getType();
610
if (type.getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
611
ParameterizedTypeTree params = (ParameterizedTypeTree)type;
612
List<? extends Tree> args = params.getTypeArguments();
613
if (args.size() == 1) {
614
Tree tree = args.get(0);
615
result[0] = treeToType(cc, tree, comp.getFormModel());
621
public void cancel() {
624
} catch (IOException ioex) {
625
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, ioex.getMessage(), ioex);
627
if (result[0] == null) {
628
// fallback - covers the situation where the component
629
// has been added but the code hasn't been generated yet
630
Class clazz = comp.getBeanClass();
631
if (clazz.getTypeParameters().length == 1) {
633
Object value = comp.getSyntheticProperty("typeParameters").getValue(); // NOI18N
634
if (value instanceof String) {
635
String type = (String)value;
636
if (type.startsWith("<")) { // NOI18N
637
type = type.substring(1, type.length()-1);
638
Map<String,TypeHelper> newMap = new HashMap<String,TypeHelper>();
640
Class elemType = ClassPathUtils.loadClass(type, FormEditor.getFormDataObject(comp.getFormModel()).getFormFile());
641
newMap.put(clazz.getTypeParameters()[0].getName(), new TypeHelper(elemType));
642
} catch (ClassNotFoundException cnfex) {
643
newMap.put(clazz.getTypeParameters()[0].getName(), new TypeHelper(type));
645
result[0] = new TypeHelper(type, newMap);
648
} catch (Exception ex) {
649
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, ex.getMessage(), ex);
657
* Determines type of the binding described by the given component and source path.
659
* @param comp source of the binding.
660
* @param sourcePath binding path from the source.
661
* @return type of the binding.
663
public TypeHelper determineType(RADComponent comp, String sourcePath) {
664
String[] path = parsePath(sourcePath);
665
TypeHelper type = determineType(comp);
666
for (int i=0; i<path.length; i++) {
667
String pathItem = path[i];
668
List<BindingDescriptor> descriptors = getAllBindingDescriptors(type);
669
BindingDescriptor descriptor = findDescriptor(descriptors, pathItem);
670
if (descriptor == null) return new TypeHelper();
671
type = descriptor.getGenericValueType();
673
if (javax.swing.JTable.class.isAssignableFrom(comp.getBeanClass())
674
|| javax.swing.JList.class.isAssignableFrom(comp.getBeanClass())
675
|| javax.swing.JComboBox.class.isAssignableFrom(comp.getBeanClass())) {
676
MetaBinding binding = comp.getBindingProperty("elements").getValue(); // NOI18N
677
if (binding != null) {
678
RADComponent subComp = binding.getSource();
679
String subSourcePath = binding.getSourcePath();
680
// PENDING beware of stack overflow
681
TypeHelper t = determineType(subComp, subSourcePath);
682
if ("selectedElement".equals(pathItem) || pathItem.startsWith("selectedElement_")) { // NOI18N
683
type = typeOfElement(t);
684
} else if (pathItem.startsWith("selectedElements") || "elements".equals(pathItem)) { // NOI18N
688
type = new TypeHelper();
697
* Finds descriptor that corresponds to the given binding path.
699
* @param descriptors list of descriptors that should be searched.
700
* @param path binding path to find descriptor for.
701
* @return descriptor that corresponds to the given binding path.
703
private static BindingDescriptor findDescriptor(List<BindingDescriptor> descriptors, String path) {
704
for (BindingDescriptor descriptor : descriptors) {
705
if (descriptor.getPath().equals(path)) return descriptor;
711
* Parses binding path into segments.
713
* @param path path to parse.
714
* @return segments of the binding path. The returned value cannot be <code>null</code>.
716
private static String[] parsePath(String path) {
717
if (path == null) return new String[0];
718
List<String> pathItems = new LinkedList<String>();
720
while ((index = path.indexOf('.')) != -1) {
721
pathItems.add(path.substring(0,index));
722
path = path.substring(index+1);
725
return pathItems.toArray(new String[pathItems.size()]);
729
* Returns type of element of the given type - expects type that implements
730
* <code>Collection</code> interface.
732
* @param type type that implements <code>Collection</code> interface.
733
* @return type of element of the given type.
735
static TypeHelper typeOfElement(TypeHelper type) {
736
Type t = type.getType();
737
TypeHelper elemType = new TypeHelper();
738
if (t instanceof ParameterizedType) {
739
ParameterizedType pt = (ParameterizedType)t;
740
Type[] args = pt.getActualTypeArguments();
741
// PENDING generalize and improve - track the type variables to the nearest
742
// known collection superclass or check parameter type of add(E o) method
743
if (args.length == 1) { // The only argument should be type of the collection element
745
elemType = new TypeHelper(tt, type.getActualTypeArgs());
747
} else if (t instanceof Class) {
748
Class classa = (Class)t;
749
TypeVariable[] tvar = classa.getTypeParameters();
751
Map<String,TypeHelper> actualTypeArgs = type.getActualTypeArgs();
752
if ((actualTypeArgs != null) && (tvar.length == 1)) {
753
TypeHelper tt = actualTypeArgs.get(tvar[0].getName());
755
if (tt.getType() == null) {
758
Type typ = FormUtils.typeToClass(tt);
759
elemType = new TypeHelper(typ, actualTypeArgs);
767
public void establishUpdatedBindings(RADComponent metacomp,
770
BindingGroup group, boolean inModel)
772
for (MetaBinding bindingDef : collectBindingDefs(metacomp, recursive)) {
773
RADComponent sourceComp = bindingDef.getSource();
774
RADComponent targetComp = bindingDef.getTarget();
775
if (sourceComp.isInModel() && targetComp.isInModel()) {
777
addBindingInModel(bindingDef);
779
Object source = null;
781
source = map.get(sourceComp.getId());
783
source = sourceComp.getBeanInstance(); // also used if clone not available
784
Object target = map != null ?
785
map.get(targetComp.getId()) : targetComp.getBeanInstance();
786
if (source != null && target != null)
787
addBinding(bindingDef, source, target, group, false);
793
public static void establishOneOffBindings(RADComponent metacomp,
798
for (MetaBinding bindingDef : collectBindingDefs(metacomp, recursive)) {
799
RADComponent sourceComp = bindingDef.getSource();
800
RADComponent targetComp = bindingDef.getTarget();
801
Object source = null;
803
source = map.get(sourceComp.getId());
805
source = sourceComp.getBeanInstance(); // also used if clone not available
806
Object target = map != null ?
807
map.get(targetComp.getId()) : targetComp.getBeanInstance();
808
if (source != null && target != null)
809
createBinding(bindingDef, source, target, group, null);
813
private void releaseBindings(RADComponent metacomp, boolean recursive) {
814
for (MetaBinding bindingDef : collectBindingDefs(metacomp, recursive)) {
815
removeBindings(bindingDef); // unbinds and removes all bindings
816
// created according to this definition
820
private static Collection<MetaBinding> collectBindingDefs(RADComponent metacomp, boolean recursive) {
821
Collection<MetaBinding> col = collectBindingDefs(metacomp, recursive, null);
823
col = Collections.emptyList();
827
private static Collection<MetaBinding> collectBindingDefs(
828
RADComponent metacomp, boolean recursive, Collection<MetaBinding> col)
830
for (BindingProperty bProp : metacomp.getKnownBindingProperties()) {
831
MetaBinding bindingDef = bProp.getValue();
832
if (bindingDef != null) {
834
col = new LinkedList<MetaBinding>();
839
if (recursive && metacomp instanceof ComponentContainer) {
840
for (RADComponent subcomp : ((ComponentContainer)metacomp).getSubBeans()) {
841
col = collectBindingDefs(subcomp, recursive, col);
848
private void addBindingInModel(MetaBinding bindingDef) {
849
addBinding(bindingDef,
850
bindingDef.getSource().getBeanInstance(),
851
bindingDef.getTarget().getBeanInstance(),
856
* Creates binding according to given MetaBinding between given source and
857
* target objects. The binding is registered, so it is automatically unbound
858
* and removed when the MetaBinding is removed (or the source/target component).
860
* @param bindingDef description of the binding
861
* @param source binding source
862
* @param target binding target
863
* @param group binding group where the binding should be added
864
* @param inModel determines whether we are creating binding in the model
866
public void addBinding(MetaBinding bindingDef,
867
Object source, Object target,
868
BindingGroup group, boolean inModel)
871
if (modelBindings.get(bindingDef) == null) {
872
modelBindings.put(bindingDef, createBinding(bindingDef, source, target, group, bindingToGroup));
875
List<Binding> establishedBindings = bindingsMap.get(bindingDef);
876
if (establishedBindings != null) {
877
for (Binding binding : establishedBindings) {
878
if (binding.getSourceObject() == source
879
&& binding.getTargetObject() == target)
880
return; // this binding already exists
884
establishedBindings = new LinkedList<Binding>();
885
bindingsMap.put(bindingDef, establishedBindings);
887
establishedBindings.add(createBinding(bindingDef, source, target, group, bindingToGroup));
891
private static String actualTargetPath(MetaBinding bindingDef) {
892
String targetPath = bindingDef.getTargetPath();
893
if ("text".equals(targetPath)) { // NOI18N
894
Class<?> targetClass = bindingDef.getTarget().getBeanClass();
895
if (JTextComponent.class.isAssignableFrom(targetClass)) {
896
String strategy = bindingDef.getParameter(MetaBinding.TEXT_CHANGE_STRATEGY);
897
if (MetaBinding.TEXT_CHANGE_ON_ACTION_OR_FOCUS_LOST.equals(strategy)) {
898
targetPath += "_ON_ACTION_OR_FOCUS_LOST"; // NOI18N
899
} else if (MetaBinding.TEXT_CHANGE_ON_FOCUS_LOST.equals(strategy)) {
900
targetPath += "_ON_FOCUS_LOST"; // NOI18N
903
} else if ("selectedElement".equals(targetPath) || "selectedElements".equals(targetPath)) { // NOI18N
904
Class<?> targetClass = bindingDef.getTarget().getBeanClass();
905
if (JList.class.isAssignableFrom(targetClass)
906
|| JTable.class.isAssignableFrom(targetClass)
907
|| JComboBox.class.isAssignableFrom(targetClass)) {
908
String value = bindingDef.getParameter(MetaBinding.IGNORE_ADJUSTING_PARAMETER);
909
if ("Y".equals(value)) { // NOI18N
910
targetPath += "_IGNORE_ADJUSTING"; // NOI18N
913
} else if ("value".equals(targetPath)) { // NOI18N
914
Class<?> targetClass = bindingDef.getTarget().getBeanClass();
915
if (JSlider.class.isAssignableFrom(targetClass)) {
916
String value = bindingDef.getParameter(MetaBinding.IGNORE_ADJUSTING_PARAMETER);
917
if ("Y".equals(value)) { // NOI18N
918
targetPath += "_IGNORE_ADJUSTING"; // NOI18N
925
private static void generateTargetProperty(MetaBinding bindingDef, StringBuilder buf) {
926
String targetPath = actualTargetPath(bindingDef);
927
String property = BeanProperty.class.getName() + ".create(\"" + targetPath + "\")"; // NOI18N
928
buf.append(property);
931
private static Property createTargetProperty(MetaBinding bindingDef) {
932
String targetPath = actualTargetPath(bindingDef);
933
Property property = BeanProperty.create(targetPath);
937
public static String generateBinding(BindingProperty prop, StringBuilder buf) {
939
MetaBinding bindingDef = prop.getValue();
941
int updateStrategy = bindingDef.getUpdateStrategy();
942
String strategy = AutoBinding.class.getName() + ".UpdateStrategy."; // NOI18N
943
if (updateStrategy == MetaBinding.UPDATE_STRATEGY_READ) {
944
strategy += "READ"; // NOI18N
945
} else if (updateStrategy == MetaBinding.UPDATE_STRATEGY_READ_ONCE) {
946
strategy += "READ_ONCE"; // NOI18N
948
strategy += "READ_WRITE"; // NOI18N
950
strategy += ", "; // NOI18N
952
RADComponent target = bindingDef.getTarget();
953
FormModel formModel = target.getFormModel();
954
JavaCodeGenerator generator = (JavaCodeGenerator)FormEditor.getCodeGenerator(formModel);
955
Class targetClass = target.getBeanClass();
956
String targetPath = bindingDef.getTargetPath();
957
String sourcePath = bindingDef.getSourcePath();
958
Class<?> sourceClass = bindingDef.getSource().getBeanClass();
959
if ("elements".equals(targetPath) && JTable.class.isAssignableFrom(targetClass)
960
&& (List.class.isAssignableFrom(sourceClass) || (sourcePath != null))) { // NOI18N
961
String elVariable = elVariableHelper(sourcePath, buf, generator);
962
variable = generator.getBindingDescriptionVariable(JTableBinding.class, buf, false);
963
if (variable == null) {
964
variable = generator.getBindingDescriptionVariable(JTableBinding.class, buf, true);
967
buf.append(variable);
968
buf.append(" = "); // NOI18N
969
buf.append(SwingBindings.class.getName()).append(".createJTableBinding("); // NOI18N
970
buf.append(strategy);
971
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getSource().getCodeExpression(), "this")); // NOI18N
972
buf.append(", "); // NOI18N
973
if (sourcePath != null) {
974
buf.append(elVariable);
975
buf.append(", "); // NOI18N
977
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getTarget().getCodeExpression(), "this")); // NOI18N
978
buf.append(");\n"); // NOI18N
979
if (bindingDef.hasSubBindings()) {
980
for (MetaBinding sub : bindingDef.getSubBindings()) {
981
String columnVariable = generator.getBindingDescriptionVariable(JTableBinding.ColumnBinding.class, buf, false);
982
if (columnVariable == null) {
983
columnVariable = generator.getBindingDescriptionVariable(JTableBinding.ColumnBinding.class, buf, true);
986
buf.append(columnVariable);
987
buf.append(" = "); // NOI18N
988
buf.append(variable);
989
buf.append(".addColumnBinding("); // NOI18N
990
buf.append(ELProperty.class.getName());
991
buf.append(".create(\""); // NOI18N
992
buf.append(sub.getSourcePath());
993
buf.append("\"));\n"); // NOI18N
994
String title = sub.getParameter(MetaBinding.NAME_PARAMETER);
996
title = sub.getSourcePath();
997
if (isSimpleExpression(title)) {
998
title = unwrapSimpleExpression(title);
999
title = capitalize(title);
1002
buf.append(columnVariable);
1003
buf.append(".setColumnName(\""); // NOI18N
1005
buf.append("\");\n"); // NOI18N
1006
String columnClass = sub.getParameter(MetaBinding.TABLE_COLUMN_CLASS_PARAMETER);
1007
if (columnClass != null) {
1008
buf.append(columnVariable);
1009
buf.append(".setColumnClass("); // NOI18N
1010
buf.append(columnClass);
1011
buf.append(");\n"); // NOI18N
1013
String editable = sub.getParameter(MetaBinding.EDITABLE_PARAMETER);
1014
if (editable != null) {
1015
buf.append(columnVariable);
1016
buf.append(".setEditable("); // NOI18N
1017
buf.append(editable);
1018
buf.append(");\n"); // NOI18N
1022
} else if ("elements".equals(targetPath) && javax.swing.JList.class.isAssignableFrom(targetClass)
1023
&& (List.class.isAssignableFrom(sourceClass) || (sourcePath != null))) { // NOI18N
1024
String elVariable = elVariableHelper(sourcePath, buf, generator);
1025
variable = generator.getBindingDescriptionVariable(JListBinding.class, buf, false);
1026
if (variable == null) {
1027
variable = generator.getBindingDescriptionVariable(JListBinding.class, buf, true);
1030
buf.append(variable);
1031
buf.append(" = "); // NOI18N
1032
buf.append(SwingBindings.class.getName()).append(".createJListBinding("); // NOI18N
1033
buf.append(strategy);
1034
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getSource().getCodeExpression(), "this")); // NOI18N
1035
buf.append(", "); // NOI18N
1036
if (sourcePath != null) {
1037
buf.append(elVariable);
1038
buf.append(", "); // NOI18N
1040
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getTarget().getCodeExpression(), "this")); // NOI18N
1041
buf.append(");\n"); // NOI18N
1042
String detailPath = bindingDef.getParameter(MetaBinding.DISPLAY_PARAMETER);
1043
if (detailPath != null) {
1044
buf.append(variable);
1045
buf.append(".setDetailBinding("); // NOI18N
1046
buf.append(ELProperty.class.getName());
1047
buf.append(".create(\""); // NOI18N
1048
buf.append(detailPath);
1049
buf.append("\"));\n"); // NOI18N
1051
} else if ("elements".equals(targetPath) && javax.swing.JComboBox.class.isAssignableFrom(targetClass)
1052
&& (List.class.isAssignableFrom(sourceClass) || (sourcePath != null))) { // NOI18N
1053
String elVariable = elVariableHelper(sourcePath, buf, generator);
1054
variable = generator.getBindingDescriptionVariable(JComboBoxBinding.class, buf, false);
1055
if (variable == null) {
1056
variable = generator.getBindingDescriptionVariable(JComboBoxBinding.class, buf, true);
1059
buf.append(variable);
1060
buf.append(" = "); // NOI18N
1061
buf.append(SwingBindings.class.getName()).append(".createJComboBoxBinding("); // NOI18N
1062
buf.append(strategy);
1063
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getSource().getCodeExpression(), "this")); // NOI18N
1064
buf.append(", "); // NOI18N
1065
if (sourcePath != null) {
1066
buf.append(elVariable);
1067
buf.append(", "); // NOI18N
1069
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getTarget().getCodeExpression(), "this")); // NOI18N
1070
buf.append(");\n"); // NOI18N
1071
// String detailPath = bindingDef.getParameter(MetaBinding.DISPLAY_PARAMETER);
1072
// if (detailPath != null) {
1073
// buf.append(variable);
1074
// buf.append(".setDetailBinding("); // NOI18N
1075
// buf.append(ELProperty.class.getName());
1076
// buf.append(".create(\""); // NOI18N
1077
// buf.append(detailPath);
1078
// buf.append("\"));\n"); // NOI18N
1081
variable = generator.getBindingDescriptionVariable(Binding.class, buf, false);
1082
StringBuilder sb = new StringBuilder();
1083
if (variable == null) {
1084
variable = generator.getBindingDescriptionVariable(Binding.class, buf, true);
1088
buf.append(variable);
1089
buf.append(" = "); // NOI18N
1090
buf.append(Bindings.class.getName()).append(sb).append(".createAutoBinding("); // NOI18N
1091
buf.append(strategy);
1092
buildBindingParamsCode(prop, buf);
1097
private static ELProperty createELProperty(String path) {
1098
ELProperty property;
1100
property = ELProperty.create(path);
1101
} catch (Exception ex) {
1102
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, ex.getMessage(), ex);
1104
property = ELProperty.create("error"); // NOI18N
1109
private static String elVariableHelper(String sourcePath, StringBuilder buf, JavaCodeGenerator generator) {
1110
String elVariable = null;
1111
if (sourcePath != null) {
1112
elVariable = generator.getBindingDescriptionVariable(ELProperty.class, buf, false);
1113
if (elVariable == null) {
1114
elVariable = generator.getBindingDescriptionVariable(ELProperty.class, buf, true);
1117
buf.append(elVariable);
1118
buf.append(" = "); // NOI18N
1119
buf.append(ELProperty.class.getName());
1120
buf.append(".create(\""); // NOI18N
1121
buf.append(sourcePath);
1122
buf.append("\");\n"); // NOI18N
1127
private static void buildBindingParamsCode(BindingProperty prop, StringBuilder buf) {
1128
MetaBinding bindingDef = prop.getValue();
1129
String sourcePath = bindingDef.getSourcePath();
1130
String targetPath = bindingDef.getTargetPath();
1131
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getSource().getCodeExpression(), "this")); // NOI18N
1132
buf.append(", "); // NOI18N
1133
if (sourcePath != null) {
1134
buf.append(ELProperty.class.getName());
1135
buf.append(".create(\""); // NOI18N
1136
buf.append(sourcePath);
1137
buf.append("\")"); // NOI18N
1139
buf.append(ObjectProperty.class.getName());
1140
buf.append(".create()"); // NOI18N
1142
buf.append(", "); // NOI18N
1143
buf.append(JavaCodeGenerator.getExpressionJavaString(bindingDef.getTarget().getCodeExpression(), "this")); // NOI18N
1144
buf.append(", "); // NOI18N
1145
if (targetPath != null) {
1146
generateTargetProperty(bindingDef, buf);
1148
buf.append(ObjectProperty.class.getName());
1149
buf.append(".create()"); // NOI18N
1151
if (bindingDef.isNameSpecified()) {
1153
FormProperty property = prop.getNameProperty();
1154
Object value = property.getValue();
1155
if (value != null) {
1156
buf.append(", "); // NOI18N
1157
buf.append(property.getJavaInitializationString());
1159
} catch (IllegalAccessException iaex) {
1160
iaex.printStackTrace();
1161
} catch (InvocationTargetException itex) {
1162
itex.printStackTrace();
1165
buf.append(");\n"); // NOI18N
1168
private static Binding createBinding0(MetaBinding bindingDef, Object source, Object target, BindingGroup group) {
1170
if (bindingDef.isNameSpecified()) {
1171
BindingProperty prop = bindingDef.getTarget().getBindingProperty(bindingDef.getTargetPath());
1172
FormProperty nameProp = prop.getNameProperty();
1174
Object value = nameProp.getRealValue();
1175
if ((value != null) && (value instanceof String)) {
1176
name = (String)value;
1178
} catch (IllegalAccessException iaex) {
1179
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, iaex.getMessage(), iaex);
1180
} catch (InvocationTargetException itex) {
1181
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, itex.getMessage(), itex);
1183
if ((name != null) && group.getBinding(name) != null) {
1184
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, "More than one binding with name: " + name); // NOI18N
1185
name = null; // ignore name parameter
1188
AutoBinding.UpdateStrategy updateStrategy = AutoBinding.UpdateStrategy.READ_WRITE;
1189
switch (bindingDef.getUpdateStrategy()) {
1190
case MetaBinding.UPDATE_STRATEGY_READ_WRITE:
1191
updateStrategy = AutoBinding.UpdateStrategy.READ_WRITE;
1193
case MetaBinding.UPDATE_STRATEGY_READ:
1194
updateStrategy = AutoBinding.UpdateStrategy.READ;
1196
case MetaBinding.UPDATE_STRATEGY_READ_ONCE:
1197
updateStrategy = AutoBinding.UpdateStrategy.READ_ONCE;
1199
default: assert false;
1201
Binding<Object,?,Object,?> binding;
1202
Property targetProperty = createTargetProperty(bindingDef);
1203
Property sourceProperty = (bindingDef.getSourcePath() == null) ? ObjectProperty.create() : createELProperty(bindingDef.getSourcePath());
1204
RADComponent targetComp = bindingDef.getTarget();
1205
String targetPath = bindingDef.getTargetPath();
1206
String sourcePath = bindingDef.getSourcePath();
1207
if ("elements".equals(targetPath) && javax.swing.JTable.class.isAssignableFrom(targetComp.getBeanClass())
1208
&& ((source instanceof List) || (sourcePath != null))) { // NOI18N
1209
JTableBinding<Object,Object,Object> tableBinding;
1210
if (sourcePath == null) {
1211
tableBinding = SwingBindings.createJTableBinding(updateStrategy, (List)source, (JTable)target, name);
1213
tableBinding = SwingBindings.createJTableBinding(updateStrategy, source, sourceProperty, (JTable)target, name);
1215
if (bindingDef.hasSubBindings()) {
1216
Collection<MetaBinding> subBindings = bindingDef.getSubBindings();
1217
for (MetaBinding sub : subBindings) {
1218
JTableBinding.ColumnBinding columnBinding = tableBinding.addColumnBinding(createELProperty(sub.getSourcePath()));
1219
String title = sub.getParameter(MetaBinding.NAME_PARAMETER);
1220
if (title == null) {
1221
title = sub.getSourcePath();
1222
if (isSimpleExpression(title)) {
1223
title = unwrapSimpleExpression(title);
1224
title = capitalize(title);
1227
columnBinding.setColumnName(title);
1228
String columnClass = sub.getParameter(MetaBinding.TABLE_COLUMN_CLASS_PARAMETER);
1229
if (columnClass != null) {
1231
if ((columnClass != null) && columnClass.trim().endsWith(".class")) { // NOI18N
1232
columnClass = columnClass.trim();
1233
columnClass = columnClass.substring(0, columnClass.length()-6);
1235
if (columnClass.indexOf('.') == -1) {
1236
String prefix = ""; // NOI18N
1237
while (columnClass.endsWith("[]")) { // NOI18N
1238
columnClass = columnClass.substring(0, columnClass.length()-2);
1239
prefix += "["; // NOI18N
1241
if ("".equals(prefix)) { // NOI18N
1242
columnClass = "java.lang." + columnClass; // NOI18N
1244
String suffix = columnClass;
1245
if (columnClass.equals("boolean")) { // NOI18N
1246
suffix = "Z"; // NOI18N
1247
} else if (columnClass.equals("byte")) { // NOI18N
1248
suffix = "B"; // NOI18N
1249
} else if (columnClass.equals("char")) { // NOI18N
1250
suffix = "C"; // NOI18N
1251
} else if (columnClass.equals("char")) { // NOI18N
1252
suffix = "D"; // NOI18N
1253
} else if (columnClass.equals("float")) { // NOI18N
1254
suffix = "F"; // NOI18N
1255
} else if (columnClass.equals("int")) { // NOI18N
1256
suffix = "I"; // NOI18N
1257
} else if (columnClass.equals("long")) { // NOI18N
1258
suffix = "J"; // NOI18N
1259
} else if (columnClass.equals("short")) { // NOI18N
1260
suffix = "S"; // NOI18N
1262
prefix += "L"; // NOI18N
1263
if (suffix.indexOf('.') == -1) {
1264
suffix = "java.lang." + suffix; // NOI18N
1266
suffix += ";"; // NOI18N
1268
columnClass = prefix + suffix;
1271
Class<?> clazz = FormUtils.loadClass(columnClass, bindingDef.getSource().getFormModel());
1272
columnBinding.setColumnClass(clazz);
1273
} catch (ClassNotFoundException cnfex) {
1274
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, cnfex.getMessage(), cnfex);
1277
String editable = sub.getParameter(MetaBinding.EDITABLE_PARAMETER);
1278
if (editable != null) {
1279
Boolean value = "false".equals(editable) ? Boolean.FALSE : Boolean.TRUE; // NOI18N
1280
columnBinding.setEditable(value);
1284
binding = tableBinding;
1285
} else if ("elements".equals(targetPath) && javax.swing.JList.class.isAssignableFrom(targetComp.getBeanClass())
1286
&& ((source instanceof List) || (sourcePath != null))) { // NOI18N
1287
JListBinding listBinding;
1288
if (sourcePath == null) {
1289
listBinding = SwingBindings.createJListBinding(updateStrategy, (List)source, (JList)target, name);
1291
listBinding = SwingBindings.createJListBinding(updateStrategy, source, sourceProperty, (JList)target, name);
1293
String detailPath = bindingDef.getParameter(MetaBinding.DISPLAY_PARAMETER);
1294
if (detailPath != null) {
1295
listBinding.setDetailBinding(createELProperty(detailPath));
1297
binding = listBinding;
1298
} else if ("elements".equals(targetPath) && javax.swing.JComboBox.class.isAssignableFrom(targetComp.getBeanClass())
1299
&& ((source instanceof List) || (sourcePath != null))) { // NOI18N
1300
JComboBoxBinding comboBinding;
1301
if (sourcePath == null) {
1302
comboBinding = SwingBindings.createJComboBoxBinding(updateStrategy, (List)source, (JComboBox)target, name);
1304
comboBinding = SwingBindings.createJComboBoxBinding(updateStrategy, source, sourceProperty, (JComboBox)target, name);
1306
// String detailPath = bindingDef.getParameter(MetaBinding.DISPLAY_PARAMETER);
1307
// if (detailPath != null) {
1308
// comboBinding.setDetailBinding(createELProperty(detailPath));
1310
binding = comboBinding;
1312
binding = Bindings.createAutoBinding(updateStrategy, source, sourceProperty, target, targetProperty, name);
1317
private static Binding createBinding(MetaBinding bindingDef,
1318
Object source, Object target,
1320
Map<Binding,BindingGroup> bindingToGroup) {
1321
Binding<Object,Object,Object,Object> binding = (Binding<Object,Object,Object,Object>)createBinding0(bindingDef, source, target, group);
1322
if (bindingDef.isNullValueSpecified()) {
1323
BindingProperty prop = bindingDef.getTarget().getBindingProperty(bindingDef.getTargetPath());
1324
FormProperty nullProp = prop.getNullValueProperty();
1326
Object value = nullProp.getRealValue();
1327
if (value != null) {
1328
binding.setSourceNullValue(value);
1330
} catch (IllegalAccessException iaex) {
1331
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, iaex.getMessage(), iaex);
1332
} catch (InvocationTargetException itex) {
1333
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, itex.getMessage(), itex);
1336
if (bindingDef.isIncompletePathValueSpecified()) {
1337
BindingProperty prop = bindingDef.getTarget().getBindingProperty(bindingDef.getTargetPath());
1338
FormProperty incompleteProp = prop.getIncompleteValueProperty();
1340
Object value = incompleteProp.getRealValue();
1341
if (value != null) {
1342
binding.setSourceUnreadableValue(value);
1344
} catch (IllegalAccessException iaex) {
1345
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, iaex.getMessage(), iaex);
1346
} catch (InvocationTargetException itex) {
1347
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, itex.getMessage(), itex);
1350
if (bindingDef.isConverterSpecified()) {
1351
BindingProperty prop = bindingDef.getTarget().getBindingProperty(bindingDef.getTargetPath());
1352
FormProperty converterProp = prop.getConverterProperty();
1354
Object value = converterProp.getRealValue();
1355
if ((value != null) && (value instanceof Converter)) {
1356
binding.setConverter((Converter)value);
1358
} catch (IllegalAccessException iaex) {
1359
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, iaex.getMessage(), iaex);
1360
} catch (InvocationTargetException itex) {
1361
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, itex.getMessage(), itex);
1364
if (bindingDef.isValidatorSpecified()) {
1365
BindingProperty prop = bindingDef.getTarget().getBindingProperty(bindingDef.getTargetPath());
1366
FormProperty validatorProp = prop.getValidatorProperty();
1368
Object value = validatorProp.getRealValue();
1369
if ((value != null) && (value instanceof Validator)) {
1370
binding.setValidator((Validator)value);
1372
} catch (IllegalAccessException iaex) {
1373
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, iaex.getMessage(), iaex);
1374
} catch (InvocationTargetException itex) {
1375
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, itex.getMessage(), itex);
1378
group.addBinding(binding);
1379
if (bindingToGroup != null) {
1380
bindingToGroup.put(binding, group);
1385
} catch (Exception ex) {
1386
Logger.getLogger(BindingDesignSupport.class.getName()).log(Level.INFO, ex.getMessage(), ex);
1391
private void removeBindings(MetaBinding bindingDef) {
1392
removeBindingInModel(bindingDef);
1393
List<Binding> establishedBindings = bindingsMap.get(bindingDef);
1394
if (establishedBindings != null) {
1395
for (Binding binding : establishedBindings) {
1396
removeBinding(binding);
1398
bindingsMap.remove(bindingDef);
1402
private void removeBinding(Binding binding) {
1403
BindingGroup group = bindingToGroup.remove(binding);
1404
// It may happen that binding.bind() fails. Binding may
1405
// stay unbound in such situation and binding.unbind()
1406
// throws exception is this case
1407
if (binding.isBound()) {
1410
group.removeBinding(binding);
1413
private void removeBindingInModel(MetaBinding bindingDef) {
1414
Binding binding = modelBindings.remove(bindingDef);
1415
if (binding != null) {
1416
removeBinding(binding);
1420
private static String capitalize(String title) {
1421
StringBuilder builder = new StringBuilder(title);
1422
boolean lastWasUpper = false;
1423
for (int i = 0; i < builder.length(); i++) {
1424
char aChar = builder.charAt(i);
1426
builder.setCharAt(i, Character.toUpperCase(aChar));
1427
lastWasUpper = true;
1428
} else if (Character.isUpperCase(aChar)) {
1429
if (!lastWasUpper) {
1430
builder.insert(i, ' ');
1432
lastWasUpper = true;
1435
lastWasUpper = false;
1438
return builder.toString();
1442
* Form model listener that updates the bindings.
1444
private class ModelListener implements FormModelListener {
1445
public void formChanged(FormModelEvent[] events) {
1449
for (int i=0; i < events.length; i++) {
1450
FormModelEvent ev = events[i];
1451
switch (ev.getChangeType()) {
1452
case FormModelEvent.BINDING_PROPERTY_CHANGED:
1453
if (ev.getSubPropertyName() == null) {
1454
changeBinding(ev.getOldBinding(), ev.getNewBinding());
1457
case FormModelEvent.COMPONENT_REMOVED:
1458
releaseBindings(ev.getComponent(), true);
1460
case FormModelEvent.COMPONENT_ADDED:
1461
if (!ev.getCreatedDeleted()) {
1462
establishUpdatedBindings(ev.getComponent(), true, null, bindingGroup, true);
1470
static class ModifiableBoolean {