KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > form > I18nSupport


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.form;
21
22 import java.awt.Component JavaDoc;
23 import java.beans.*;
24 import java.io.IOException JavaDoc;
25 import java.util.*;
26
27 import org.openide.ErrorManager;
28 import org.openide.filesystems.FileObject;
29 import org.openide.loaders.DataObject;
30 import org.openide.nodes.Node;
31 import org.openide.nodes.PropertySupport;
32 import org.openide.util.Lookup;
33 import org.netbeans.api.java.classpath.ClassPath;
34
35 import org.netbeans.modules.form.editors2.BorderDesignSupport;
36
37 /**
38  * This class controls internationalization of a form.
39  *
40  * @author Tomas Pavek
41  */

42
43 class I18nSupport {
44
45     private FormModel formModel;
46
47     private String JavaDoc defaultBundle;
48     private String JavaDoc designLocale = ""; // locale suffix (including initial _)
49

50     private I18nService i18nService;
51
52     private Map<Object JavaDoc, I18nValue> droppedValues;
53
54     private static Map<DataObject, String JavaDoc> rememberedLocales = new WeakHashMap();
55
56     private static final String JavaDoc I18N_KEY_PREFIX = ""; // configurable? // NOI18N
57
private static final String JavaDoc EXCLUDE_I18N = "NOI18N"; // NOI18N
58
private static final String JavaDoc PE_PLAIN_SET = "Plain_StringPropertyEditor"; // NOI18N
59
private static final String JavaDoc DEFAULT_BUNDLE_NAME = "Bundle"; // NOI18N
60

61     static final String JavaDoc PROP_FORM_BUNDLE = "formBundle"; // NOI18N
62
private static final String JavaDoc PROP_DESIGN_LOCALE = "designLocale"; // NOI18N
63
// PROP_AUTO_I18N is defined in FormLoaderSettings
64

65     // auxiliary class used to associate path (where a property comes from)
66
// to the property
67
private static class I18nPropertyInfo {
68         private FormProperty property;
69         private String JavaDoc path; // path to the property within the form
70
// (excl. form name and the property name)
71
I18nPropertyInfo(FormProperty prop, String JavaDoc path) {
72             this.property = prop;
73             this.path = path;
74         }
75         boolean sameProperty(I18nPropertyInfo pInfo) {
76             return path.equals(pInfo.path) && property.getName().equals(property.getName());
77         }
78     }
79
80     // -----
81

82     I18nSupport(FormModel model) {
83         formModel = model;
84         formModel.addFormModelListener(new ModelListener());
85
86         String JavaDoc locale = rememberedLocales.get(getSrcDataObject());
87         if (locale != null) {
88             designLocale = locale;
89             if (!locale.equals("")) // NOI18N
90
updateDesignLocale();
91         }
92     }
93
94     private I18nService getI18nService() {
95         if (i18nService == null) {
96             i18nService = Lookup.getDefault().lookup(I18nService.class);
97         }
98         return i18nService;
99     }
100
101     private static I18nSupport getI18nSupport(FormProperty prop) {
102         return FormEditor.getI18nSupport(prop.getPropertyContext().getFormModel());
103     }
104
105     private static I18nSupport getI18nSupport(RADComponent metacomp) {
106         return FormEditor.getI18nSupport(metacomp.getFormModel());
107     }
108
109     // -----
110

111     /**
112      * Converts given value (String) to an internationalized value. Called when
113      * a component property is going to change.
114      * This method is not called during undo/redo.
115      * @param value new value being set to the property
116      * @param property the property to which the value is going to be set (still
117      * contains the previous value)
118      * @param metacomp the meta-component that owns the property (used to compute
119      * the path for the key)
120      */

121     public static Object JavaDoc internationalizeProperty(Object JavaDoc value, FormProperty property, RADComponent metacomp) {
122         if (Boolean.TRUE.equals(property.getValue(EXCLUDE_I18N))) { // excluded property
123
if (Boolean.TRUE.equals(property.getValue(PE_PLAIN_SET))) {
124                 // excluded only because switching to plain String editor
125
property.setValue(EXCLUDE_I18N, Boolean.FALSE);
126                 // (in case of nested value, collectNestedI18nProperties does the same)
127
}
128             return value;
129         }
130
131         String JavaDoc compPath = getComponentPath(metacomp);
132         I18nSupport support = getI18nSupport(property);
133
134         if (isI18nType(property.getValueType())) { // single value
135
return support.internationalizeProperty(value, property, compPath);
136         }
137         else { // check nested value (TitledBorder is the only meaningful example)
138
for (I18nPropertyInfo pInfo : getNestedI18nProperties(value, property, compPath, false)) {
139                 FormProperty prop = pInfo.property;
140                 try {
141                     Object JavaDoc val = prop.getValue();
142                     Object JavaDoc i18nValue = support.internationalizeProperty(val, prop, pInfo.path);
143                     if (i18nValue != val) {
144                         boolean fire = prop.isChangeFiring();
145                         prop.setChangeFiring(false);
146                         prop.setValue(i18nValue);
147                         prop.setChangeFiring(fire);
148                     }
149                 }
150                 catch (Exception JavaDoc ex) {
151                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
152                 }
153             }
154         }
155         return value; // returned value is set to the property which leads to
156
// call of updateStoredValue
157
}
158
159     /**
160      * Creates internationalized value from given value. Not set to the property,
161      * the property is used to obtain the current value.
162      */

163     private Object JavaDoc internationalizeProperty(Object JavaDoc value, FormProperty property, String JavaDoc path) {
164         if (getI18nService() == null)
165             return value;
166
167         I18nValue i18nValue;
168         if (value instanceof I18nValue) {
169             i18nValue = (I18nValue) value;
170             if (i18nValue.getKey() == I18nValue.COMPUTE_AUTO_KEY) {
171                 i18nValue = i18nService.changeKey(i18nValue, getAutoKey(path, property.getName()));
172             }
173             return i18nValue;
174         }
175
176         if (!(value instanceof String JavaDoc))
177             return value;
178
179         I18nValue prevI18nValue = getI18nValue(property);
180         if (prevI18nValue != null) { // update existing I18nValue
181
i18nValue = i18nService.changeValue(prevI18nValue, value.toString());
182         }
183         else if (!isAutoMode()) {
184             return value; // do not convert String to I18nValue
185
}
186         else {
187             i18nValue = searchDroppedValues(property, value.toString());
188             if (i18nValue == null) {
189                 String JavaDoc key = getAutoKey(path, property.getName());
190                 i18nValue = i18nService.create(key, value.toString(), getSrcDataObject());
191             }
192         }
193         return new FormProperty.ValueWithEditor(i18nValue,
194                 i18nService.getPropertyEditor(property.getValueType(), property.getCurrentEditor()));
195     }
196
197     private I18nValue searchDroppedValues(Object JavaDoc key, String JavaDoc value) {
198         if (droppedValues != null) {
199             I18nValue i18nValue = droppedValues.get(key);
200             if (i18nValue != null && i18nValue.getValue().equals(value))
201                 return i18nValue;
202         }
203         return null;
204     }
205
206     /**
207      * Changes all String properties to internationalized values.
208      * This method is not called during undo/redo.
209      */

210     public static void internationalizeComponent(RADComponent metacomp) {
211         I18nSupport support = getI18nSupport(metacomp);
212         if (support.isAutoMode())
213             support.internationalizeComponent(metacomp, false);
214     }
215
216     private void internationalizeComponent(RADComponent metacomp, boolean update) {
217         if (getI18nService() == null)
218             return;
219
220         for (I18nPropertyInfo pInfo : getComponentI18nProperties(metacomp, false, !update)) {
221             FormProperty prop = pInfo.property;
222             try {
223                 Object JavaDoc i18nValue = internationalizeProperty(prop.getValue(), prop, pInfo.path);
224                 // suppress firing - update is not done the usual way
225
boolean fire = prop.isChangeFiring();
226                 prop.setChangeFiring(false);
227                 prop.setValue(i18nValue);
228                 prop.setChangeFiring(fire);
229                 if (update) {
230                     i18nService.update(null, getI18nValue(prop),
231                                        getSrcDataObject(), getBundleName(), designLocale,
232                                        true);
233                 }
234                 // otherwise update will be triggered by component addition
235
// (called when copying a component)
236
}
237             catch (Exception JavaDoc ex) {
238                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
239             }
240         }
241     }
242
243     private void internationalizeForm() {
244         if (getI18nService() == null)
245             return;
246
247         for (RADComponent metacomp : formModel.getAllComponents()) {
248             internationalizeComponent(metacomp, true);
249         }
250
251         if (droppedValues != null)
252             droppedValues.clear();
253     }
254
255     private void deinternationalizeForm() {
256         if (getI18nService() == null)
257             return;
258
259         for (RADComponent metacomp : formModel.getAllComponents()) {
260             for (I18nPropertyInfo pInfo : getComponentI18nProperties(metacomp, true, false)) {
261                 if (isExclusiveValue(pInfo)) {
262                     FormProperty prop = pInfo.property;
263                     I18nValue i18nValue = getI18nValue(prop);
264                     try {
265                         boolean fire = prop.isChangeFiring();
266                         prop.setChangeFiring(false);
267                         prop.setValue(new FormProperty.ValueWithEditor(
268                                 i18nValue.getValue(), prop.findDefaultEditor()));
269                         prop.setChangeFiring(fire);
270                         i18nService.update(i18nValue, null, getSrcDataObject(), getBundleName(), null, true);
271                         addDroppedValue(prop, i18nValue); // it will keep data from all locales
272
// (there is no other way to remember this data for undo)
273
}
274                     catch (Exception JavaDoc ex) {
275                         ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
276                     }
277                 }
278             }
279         }
280     }
281
282     private void addDroppedValue(FormProperty property, I18nValue i18nValue) {
283         if (droppedValues == null)
284             droppedValues = new HashMap();
285
286         droppedValues.put(property, i18nValue);
287     }
288
289     /**
290      * Racts on component's variable renaming. All automatically created keys
291      * that use the name will be changed to the new name.
292      * (Note: This method must be called while the component still has the old
293      * name so the update method finds the current keys matching the component
294      * name and adjusts them to the new name.)
295      */

296     public static void componentRenamed(RADComponent metacomp, String JavaDoc newName) {
297         I18nSupport support = getI18nSupport(metacomp);
298         if (support.isAutoMode())
299             support.renameAutoKeys(metacomp, newName);
300     }
301
302     private void renameAutoKeys(RADComponent metacomp, String JavaDoc newName) {
303         if (getI18nService() == null)
304             return;
305
306         assert metacomp != metacomp.getFormModel().getTopRADComponent();
307
308         for (I18nPropertyInfo pInfo : getComponentI18nProperties(metacomp, true, false)) {
309             String JavaDoc oldAutoKey = getAutoKey(pInfo);
310             I18nValue oldI18nValue = getI18nValue(pInfo);
311             if (isExclusiveValue(oldI18nValue, oldAutoKey)) { // let's rename this key
312
String JavaDoc oldName = metacomp.getName();
313                 String JavaDoc oldPath = pInfo.path;
314                 int idx = oldPath.indexOf(oldName);
315                 String JavaDoc newPath = oldPath.substring(0, idx) + newName + oldPath.substring(idx+oldName.length());
316                 FormProperty prop = pInfo.property;
317                 String JavaDoc newKey = getAutoKey(newPath, prop.getName());
318                 String JavaDoc oldKey = oldI18nValue.getKey();
319                 if (oldKey.length() > oldAutoKey.length()) // key can be more than auto-key
320
newKey = newKey + oldKey.substring(oldAutoKey.length());
321                 I18nValue newI18nValue = i18nService.changeKey(oldI18nValue, newKey);
322                 try { // suppress firing - update is not done the usual way
323
// (would not work for nested properties) but directly here
324
boolean fire = prop.isChangeFiring();
325                     prop.setChangeFiring(false);
326                     prop.setValue(newI18nValue);
327                     prop.setChangeFiring(fire);
328                     i18nService.update(oldI18nValue, newI18nValue,
329                                        getSrcDataObject(), getBundleName(), designLocale,
330                                        true);
331                 }
332                 catch (Exception JavaDoc ex) {
333                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
334                 }
335             }
336         }
337     }
338
339     /**
340      * Called when the user changes the property editor explicitly. If changed
341      * to plain String editor then we suppress automatic i18n on this property.
342      */

343     public static void propertyEditorChanging(FormProperty prop, PropertyEditor newPE) {
344         I18nSupport support = getI18nSupport(prop);
345         if (support.getI18nService() != null) {
346             support.markI18nProperty(prop, newPE);
347         }
348     }
349
350     private void markI18nProperty(FormProperty prop, PropertyEditor newPE) {
351         PropertyEditor oldPE = prop.getCurrentEditor();
352         int changeType = i18nService.analyzePropertyEditorChange(oldPE, newPE);
353         if (changeType < 0
354             && !Boolean.TRUE.equals(prop.getValue(EXCLUDE_I18N)))
355         { // explicitly chnaged to plain String editor - do not internationalize
356
prop.setValue(EXCLUDE_I18N, Boolean.TRUE);
357             prop.setValue(PE_PLAIN_SET, Boolean.TRUE);
358         }
359         else if (changeType > 0
360                  && Boolean.TRUE.equals(prop.getValue(EXCLUDE_I18N))
361                  && Boolean.TRUE.equals(prop.getValue(PE_PLAIN_SET)))
362         { // explicitly changed to i18n editor - allow internationalization
363
prop.setValue(EXCLUDE_I18N, Boolean.FALSE);
364         }
365     }
366
367     /**
368      * Reacts on a change in an internationalized property value. Makes sure
369      * that added/changed/removed I18nValue is updated in the properties bundle
370      * file. (This method is called only for component properties, so it scans
371      * the value for nested internationalized properties.)
372      */

373     public static void updateStoredValue(Object JavaDoc oldValue, Object JavaDoc newValue,
374                                   FormProperty property, RADComponent metacomp)
375     {
376         I18nSupport support = getI18nSupport(metacomp);
377         if (support.getI18nService() == null)
378             return;
379
380         if (property.getValueType() == String JavaDoc.class) {
381             I18nValue oldVal = oldValue instanceof I18nValue ? (I18nValue) oldValue : null;
382             I18nValue newVal = newValue instanceof I18nValue ? (I18nValue) newValue : null;
383             if (oldVal != null || newVal != null)
384                 support.updateValue(oldVal, newVal, getComponentPath(metacomp), property.getName());
385         }
386         else {
387             String JavaDoc compPath = getComponentPath(metacomp);
388             Collection<I18nPropertyInfo> colOld = getNestedI18nProperties(oldValue, property, compPath, true);
389             Collection<I18nPropertyInfo> colNew = getNestedI18nProperties(newValue, property, compPath, true);
390
391             for (I18nPropertyInfo pInfoO : colOld) {
392                 boolean foundInNew = false;
393                 for (Iterator<I18nPropertyInfo> it=colNew.iterator(); it.hasNext(); ) {
394                     I18nPropertyInfo pInfoN = it.next();
395                     if (pInfoN.sameProperty(pInfoO)) { // changed i18n value
396
I18nValue oldVal = getI18nValue(pInfoO);
397                         I18nValue newVal = getI18nValue(pInfoN);
398                         support.updateValue(oldVal, newVal, pInfoN.path, pInfoN.property.getName());
399                         it.remove(); // remove so only newly added remain
400
foundInNew = true;
401                         break;
402                     }
403                 }
404                 if (!foundInNew) { // removed i18n value
405
I18nValue oldVal = getI18nValue(pInfoO);
406                     support.updateValue(oldVal, null, pInfoO.path, pInfoO.property.getName());
407                 }
408             }
409             // colNew now contains newly added i18n values
410
for (I18nPropertyInfo pInfoN : colNew) {
411                 I18nValue newVal = getI18nValue(pInfoN);
412                 support.updateValue(null, newVal, pInfoN.path, pInfoN.property.getName());
413             }
414         }
415     }
416
417     private void updateValue(I18nValue oldValue, I18nValue newValue,
418                              String JavaDoc path, String JavaDoc propertyName)
419     {
420         try {
421             i18nService.update(oldValue, newValue,
422                                getSrcDataObject(), getBundleName(), designLocale,
423                                isExclusiveValue(oldValue, getAutoKey(path, propertyName)));
424         }
425         catch (IOException JavaDoc ex) {
426             // [can't store to properties bundle - should do something?]
427
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
428         }
429     }
430
431     public boolean isDefaultInternationalizableProject() {
432         getI18nService();
433         return i18nService != null ?
434             i18nService.isDefaultInternationalizableProject(getSrcDataObject()) :
435             false;
436     }
437
438     private void changeBundle(String JavaDoc newBundle) {
439         deinternationalizeForm();
440         formModel.getSettings().setFormBundle(newBundle);
441         String JavaDoc oldLocale = designLocale;
442         setDesignLocale(""); // NOI18N
443
FormEditor.getFormEditor(formModel).getFormRootNode()
444                         .firePropertyChangeHelper(PROP_DESIGN_LOCALE, oldLocale, designLocale);
445         internationalizeForm();
446
447     }
448
449     private void changeDesignLocale(String JavaDoc designLocale) {
450         setDesignLocale(designLocale);
451         updateDesignLocale();
452         // hack to update designer...
453
formModel.fireEvents(null);
454     }
455
456     private void setDesignLocale(String JavaDoc locale) {
457         designLocale = locale;
458         rememberedLocales.put(getSrcDataObject(), locale); // keep to survive form reload
459
}
460
461     private void updateDesignLocale() {
462         if (getI18nService() == null)
463             return;
464
465         for (I18nPropertyInfo pInfo : getAllI18nProperties(true)) {
466             FormProperty prop = pInfo.property;
467             I18nValue i18nValue = getI18nValue(prop);
468             if (i18nValue != null) {
469                 try {
470                     boolean fire = prop.isChangeFiring();
471                     prop.setChangeFiring(false);
472                     prop.setValue(i18nService.switchLocale(i18nValue, designLocale));
473                     prop.setChangeFiring(fire);
474                 }
475                 catch (Exception JavaDoc ex) {
476                     ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
477                 }
478             }
479         }
480     }
481
482     // -----
483
// listener on FormModel - reacts on component additions/removals
484

485     private class ModelListener implements FormModelListener {
486         public void formChanged(FormModelEvent[] events) {
487             if (getI18nService() == null)
488                 return;
489             if (events == null)
490                 return;
491
492             for (int i=0; i < events.length; i++) {
493                 FormModelEvent ev = events[i];
494                 switch (ev.getChangeType()) {
495
496                 case FormModelEvent.COMPONENT_REMOVED:
497                     for (I18nPropertyInfo pInfo : getComponentI18nProperties(ev.getComponent(), true, true)) {
498                         if (isExclusiveValue(pInfo)) {
499                             // let's remove this key from properties file
500
try {
501                                 i18nService.update(getI18nValue(pInfo), null,
502                                                    getSrcDataObject(), getBundleName(), null,
503                                                    true);
504                             }
505                             catch (IOException JavaDoc ex) {
506                                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
507                             }
508                         }
509                     }
510                     break;
511
512                 case FormModelEvent.COMPONENT_ADDED:
513                     for (I18nPropertyInfo pInfo : getComponentI18nProperties(ev.getComponent(), true, true)) {
514                         I18nValue value = getI18nValue(pInfo);
515                         if (value != null) { // add this to properties file (restore)
516
try {
517                                 i18nService.update(null, value,
518                                                    getSrcDataObject(), getBundleName(), designLocale,
519                                                    false);
520                             }
521                             catch (IOException JavaDoc ex) {
522                                 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
523                             }
524                         }
525                     }
526                     break;
527
528                 case FormModelEvent.FORM_TO_BE_SAVED:
529                     if (i18nService != null)
530                         i18nService.autoSave(getSrcDataObject());
531                     break;
532
533                 case FormModelEvent.FORM_TO_BE_CLOSED:
534                     if (i18nService != null)
535                         i18nService.close(getSrcDataObject());
536                     break;
537                 }
538             }
539         }
540     }
541
542     // -----
543

544     private Collection<I18nPropertyInfo> getAllI18nProperties(boolean internationalized) {
545         Collection<RADComponent> components = formModel.getAllComponents();
546         List<I18nPropertyInfo> propList = new ArrayList<I18nPropertyInfo>(components.size());
547         for (RADComponent metacomp : components) {
548             collectI18nProperties(metacomp, internationalized, false, propList);
549         }
550         return propList;
551     }
552
553     private static Collection<I18nPropertyInfo> getComponentI18nProperties(RADComponent metacomp, boolean internationalized, boolean recursive) {
554         Collection<I18nPropertyInfo> col = collectI18nProperties(metacomp, internationalized, recursive, null);
555         if (col == null)
556             col = Collections.emptyList();
557         return col;
558     }
559
560     private static Collection<I18nPropertyInfo> getNestedI18nProperties(Object JavaDoc value, FormProperty prop, String JavaDoc path, boolean internationalized) {
561         Collection<I18nPropertyInfo> col = collectNestedI18nProperties(value, prop, path, internationalized, null);
562         if (col == null)
563             col = Collections.emptyList();
564         return col;
565     }
566
567     private static Collection<I18nPropertyInfo> collectI18nProperties(RADComponent metacomp, boolean internationalized, boolean recursive, Collection<I18nPropertyInfo> col) {
568         // check bean properties
569
for (FormProperty prop : metacomp.getKnownBeanProperties()) {
570             if (!Boolean.TRUE.equals(prop.getValue(EXCLUDE_I18N)) && prop.isChanged())
571                 col = collectNestedI18nProperties(prop, getComponentPath(metacomp), internationalized, col);
572         }
573
574         // check layout constraints (tab title, tab description)
575
if (metacomp instanceof RADVisualComponent) {
576             Node.Property[] constrProps = ((RADVisualComponent)metacomp).getConstraintsProperties();
577             if (constrProps != null) {
578                 for (Node.Property p : constrProps) {
579                     if (p instanceof FormProperty && !Boolean.TRUE.equals(p.getValue(EXCLUDE_I18N))) {
580                         FormProperty prop = (FormProperty) p;
581                         if (prop.isChanged())
582                             col = collectNestedI18nProperties(prop, getComponentPath(metacomp), internationalized, col);
583                     }
584                 }
585             }
586         }
587
588         // check subcomponents
589
if (recursive && metacomp instanceof ComponentContainer) {
590             for (RADComponent subcomp : ((ComponentContainer)metacomp).getSubBeans()) {
591                 col = collectI18nProperties(subcomp, internationalized, recursive, col);
592             }
593         }
594
595         return col;
596     }
597
598     private static Collection<I18nPropertyInfo> collectNestedI18nProperties(
599             Object JavaDoc value, FormProperty property, String JavaDoc path,
600             boolean internationalized,
601             Collection<I18nPropertyInfo> col)
602     {
603         Node.Property[] nestedProps = getNestedProperties(value);
604
605         if (nestedProps == null) {
606             if (isI18nType(property.getValueType()) && !internationalized == needsI18n(value)) {
607                 // already internationalized or yet to be internationalized
608
if (col == null) {
609                     col = new LinkedList<I18nPropertyInfo>();
610                 }
611                 col.add(new I18nPropertyInfo(property, path));
612             }
613             return col;
614         }
615
616         path = path != null ? (path + "." + property.getName()) : property.getName(); // NOI18N
617
for (Node.Property p : nestedProps) {
618             if (p instanceof FormProperty) {
619                 if (!Boolean.TRUE.equals(p.getValue(EXCLUDE_I18N))) {
620                     FormProperty prop = (FormProperty) p;
621                     if (prop.isChanged())
622                         col = collectNestedI18nProperties(prop, path, internationalized, col);
623                 }
624                 else if (Boolean.TRUE.equals(p.getValue(PE_PLAIN_SET))) {
625                     // excluded only because switching to plain String editor
626
p.setValue(EXCLUDE_I18N, Boolean.FALSE);
627                 }
628             }
629         }
630         return col;
631     }
632
633     private static boolean isI18nType(Class JavaDoc type) {
634         return type == String JavaDoc.class;
635     }
636
637     private static boolean needsI18n(Object JavaDoc value) {
638         if (value instanceof I18nValue) {
639             I18nValue i18nValue = (I18nValue) value;
640             return i18nValue.getKey() == I18nValue.COMPUTE_AUTO_KEY;
641         }
642         return value != null && isI18nType(value.getClass());
643     }
644
645     private static Collection<I18nPropertyInfo> collectNestedI18nProperties(
646             FormProperty property, String JavaDoc path, boolean internationalized,
647             Collection<I18nPropertyInfo> col)
648     {
649         Object JavaDoc value = null;
650         try {
651             return collectNestedI18nProperties(
652                     property.getValue(), property, path, internationalized, col);
653         }
654         catch (Exception JavaDoc ex) {
655             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
656         }
657         return col;
658     }
659
660     private static Node.Property[] getNestedProperties(Object JavaDoc value) {
661         if (value instanceof BorderDesignSupport) {
662             return ((BorderDesignSupport)value).getProperties();
663         }
664         // [An alternative would be to use BeanPropertyEditor, but calling
665
// getCurrentEditor() forces searching for the PropertyEditor.
666
// Maybe not a problem because "known" properties should have it
667
// already, or will have to find it sooner or later.]
668
return null;
669     }
670
671     private static I18nValue getI18nValue(I18nPropertyInfo pInfo) {
672         return getI18nValue(pInfo.property);
673     }
674
675     private static I18nValue getI18nValue(FormProperty prop) {
676         try {
677             Object JavaDoc value = prop.getValue();
678             if (value instanceof I18nValue) {
679                 I18nValue i18nValue = (I18nValue) value;
680                 if (i18nValue.getKey() != I18nValue.COMPUTE_AUTO_KEY
681                         && i18nValue.getKey() != I18nValue.NOI18N_KEY)
682                     return i18nValue;
683             }
684         }
685         catch (Exception JavaDoc ex) { // FormProperty.getValue should not fail
686
ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex);
687         }
688         return null;
689     }
690
691     private boolean isExclusiveValue(I18nPropertyInfo pInfo) {
692         I18nValue i18nValue = getI18nValue(pInfo);
693         return isExclusiveValue(i18nValue, getAutoKey(pInfo));
694     }
695
696     private static boolean isExclusiveValue(I18nValue value, String JavaDoc autoKey) {
697         if (value == null)
698             return false;
699
700         String JavaDoc key = value.getKey();
701         return key != null && key != I18nValue.NOI18N_KEY && key.startsWith(autoKey);
702     }
703
704     private String JavaDoc getAutoKey(I18nPropertyInfo pInfo) {
705         return getAutoKey(pInfo.path, pInfo.property.getName());
706     }
707
708     private String JavaDoc getAutoKey(String JavaDoc middlePart, String JavaDoc propertyName) {
709         StringBuilder JavaDoc str = new StringBuilder JavaDoc();
710         str.append(I18N_KEY_PREFIX);
711         str.append(formModel.getName());
712         if (middlePart != null) {
713             str.append("."); // NOI18N
714
str.append(middlePart);
715         }
716         str.append("."); // NOI18N
717
str.append(propertyName);
718         return str.toString();
719     }
720
721     private static String JavaDoc getComponentPath(RADComponent metacomp) {
722         return metacomp != metacomp.getFormModel().getTopRADComponent() ?
723                metacomp.getName() : null;
724     }
725
726     private String JavaDoc getBundleName() {
727         String JavaDoc bundleName = formModel.getSettings().getFormBundle();
728         if (bundleName == null) {
729             if (defaultBundle == null) {
730                 FileObject file = getSrcDataObject().getPrimaryFile();
731                 ClassPath cp = ClassPath.getClassPath(file, ClassPath.SOURCE);
732                 if (cp == null)
733                     return null;
734
735                 String JavaDoc resName = cp.getResourceName(file.getParent());
736                 defaultBundle = resName != null && resName.length() > 0 ?
737                         resName + "/" + DEFAULT_BUNDLE_NAME : DEFAULT_BUNDLE_NAME; // NOI18N
738
// [we could also search for another properties file in the package
739
// (what if there is properties file not for i18n?),
740
// or try to remember last specified properties file for another form in this package]
741
// formModel.getSettings().setFormBundle(bundleName);
742
}
743             bundleName = defaultBundle;
744         }
745         return bundleName;
746     }
747
748     DataObject getSrcDataObject() {
749         return FormEditor.getFormDataObject(formModel);
750     }
751
752     boolean isAutoMode() {
753         return formModel.getSettings().getI18nAutoMode();
754     }
755
756     String JavaDoc getDesignLocale() {
757         return designLocale;
758     }
759
760     // -----
761

762     Node.Property[] createFormProperties() {
763         Node.Property autoModeProp = new PropertySupport.ReadWrite(
764             FormLoaderSettings.PROP_AUTO_I18N,
765             Boolean.TYPE,
766             FormUtils.getBundleString("PROP_AUTO_I18N"), // NOI18N
767
FormUtils.getBundleString("HINT_AUTO_I18N_LOCAL")) // NOI18N
768
{
769             public void setValue(Object JavaDoc value) {
770                 Boolean JavaDoc oldValue = isAutoMode() ? Boolean.TRUE : Boolean.FALSE;
771                 if (!oldValue.equals(value)) {
772                     boolean autoMode = ((Boolean JavaDoc)value).booleanValue();
773                     formModel.getSettings().setI18nAutoMode(autoMode);
774
775                     if (autoMode)
776                         internationalizeForm();
777                     else
778                         deinternationalizeForm();
779
780                     formModel.fireSyntheticPropertyChanged(
781                             null, FormLoaderSettings.PROP_AUTO_I18N, oldValue, value);
782                     FormEditor.getFormEditor(formModel).getFormRootNode()
783                         .firePropertyChangeHelper(FormLoaderSettings.PROP_AUTO_I18N,
784                                                   oldValue, value);
785                 }
786             }
787
788             public Object JavaDoc getValue() {
789                 return isAutoMode() ? Boolean.TRUE : Boolean.FALSE;
790             }
791         };
792
793         Node.Property formBundleProp = new PropertySupport.ReadWrite(
794             PROP_FORM_BUNDLE,
795             String JavaDoc.class,
796             FormUtils.getBundleString("PROP_FORM_BUNDLE"), // NOI18N
797
FormUtils.getBundleString("HINT_FORM_BUNDLE")) // NOI18N
798
{
799             public void setValue(Object JavaDoc value) {
800                 Object JavaDoc oldValue = getBundleName();
801                 if ((oldValue == null && value != null) || !oldValue.equals(value)) {
802                     String JavaDoc resourceName = (String JavaDoc) value;
803                     if (resourceName != null && resourceName.toLowerCase().endsWith(".properties")) { // NOI18N
804
resourceName = resourceName.substring(
805                                 0, resourceName.length()-".properties".length()); // NOI18N
806
}
807                     changeBundle(resourceName);
808                     formModel.fireSyntheticPropertyChanged(null, PROP_FORM_BUNDLE, oldValue, value);
809                     FormEditor.getFormEditor(formModel).getFormRootNode()
810                             .firePropertyChangeHelper(PROP_FORM_BUNDLE, oldValue, value);
811                 }
812             }
813             public Object JavaDoc getValue() {
814                 return getBundleName(); //formModel.getSettings().getFormBundle();
815
}
816
817             public PropertyEditor getPropertyEditor() {
818                 return new BundleFilePropertyEditor();
819             }
820         };
821
822         Node.Property localeProp = new PropertySupport.ReadWrite(
823             PROP_DESIGN_LOCALE,
824             String JavaDoc.class,
825             FormUtils.getBundleString("PROP_DESIGN_LOCALE"), // NOI18N
826
FormUtils.getBundleString("HINT_DESIGN_LOCALE")) // NOI18N
827
{
828             public void setValue(Object JavaDoc value) {
829                 // this property is not persistent (not stored in .form file)
830
String JavaDoc oldValue = designLocale;
831                 changeDesignLocale((String JavaDoc)value);
832                 formModel.fireSyntheticPropertyChanged(null, PROP_DESIGN_LOCALE, oldValue, value);
833                 FormEditor.getFormEditor(formModel).getFormRootNode()
834                         .firePropertyChangeHelper(PROP_DESIGN_LOCALE, oldValue, value);
835             }
836
837             public Object JavaDoc getValue() {
838                 return designLocale;
839             }
840
841             public PropertyEditor getPropertyEditor() {
842                 return new LocalePropertyEditor();
843             }
844         };
845
846         return new Node.Property[] { autoModeProp, formBundleProp, localeProp };
847     }
848
849     private class BundleFilePropertyEditor extends PropertyEditorSupport {
850         public boolean supportsCustomEditor() {
851             return getI18nService() != null;
852         }
853
854         public Component JavaDoc getCustomEditor() {
855             return getI18nService() != null ?
856                 i18nService.getBundleSelectionComponent(this, getSrcDataObject()) :
857                 null;
858         }
859     }
860
861     private class LocalePropertyEditor extends PropertyEditorSupport {
862         private String JavaDoc[][] tags;
863
864         public String JavaDoc[] getTags() {
865             if (getI18nService() == null)
866                 return null;
867             if (tags == null) {
868                 DataObject srcDO = getSrcDataObject();
869                 if (srcDO != null)
870                     tags = i18nService.getAvailableLocales(srcDO, getBundleName());
871             }
872             return tags != null ? tags[1] : null;
873         }
874
875         public void setAsText(String JavaDoc text) {
876             getTags();
877             if (tags != null) {
878                 for (int i=0,n=tags[0].length; i < n; i++) {
879                     if (tags[1][i].equals(text)) {
880                         setValue(tags[0][i]);
881                         return;
882                     }
883                 }
884             }
885             setValue(text);
886         }
887
888         public String JavaDoc getAsText() {
889             Object JavaDoc value = getValue();
890             getTags();
891             if (tags != null) {
892                 for (int i=0,n=tags[0].length; i < n; i++) {
893                     if (tags[0][i].equals(value))
894                         return tags[1][i];
895                 }
896             }
897             return value != null ? value.toString() : null;
898         }
899
900         public boolean supportsCustomEditor() {
901             return getI18nService() != null && getTags() != null;
902         }
903
904         public Component JavaDoc getCustomEditor() {
905             return getI18nService() != null && getTags() != null ?
906                 i18nService.getCreateLocaleComponent(this, getSrcDataObject(), getBundleName()) :
907                 null;
908         }
909     }
910 }
911
Popular Tags