KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > properties > BundleStructure


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-2007 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20
21 package org.netbeans.modules.properties;
22
23 import java.beans.PropertyChangeEvent JavaDoc;
24 import java.beans.PropertyChangeListener JavaDoc;
25 import java.util.List JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.Collections JavaDoc;
28 import java.util.Comparator JavaDoc;
29 import java.util.Iterator JavaDoc;
30 import java.util.Map JavaDoc;
31 import java.util.TreeMap JavaDoc;
32 import org.openide.loaders.MultiDataObject.Entry;
33 import org.openide.util.WeakListeners;
34
35
36 /**
37  * Structure of a bundle of <code>.properties</code> files.
38  * Provides structure of entries (one entry per one .properties file)
39  * for one <code>PropertiesDataObject</code>.
40  * <p>
41  * This structure provides support for sorting entries and fast mapping
42  * of integers to <code>entries</code>.
43  * <p>
44  * The sorting support in this class is a design flaw&nbsp;-
45  * consider it deprecated.
46  *
47  * @author Petr Jiricka
48  */

49 public class BundleStructure {
50     
51     /**
52      * <code>PropertiesDataObject</code> whose structure is described
53      * by this object
54      */

55     PropertiesDataObject obj;
56
57     /**
58      * file entries of the <code>PropertiesDataObject</code>.
59      * The first entry always represents the primary file.
60      * The other entries represent secondary files and are sorted
61      * by the corresponding files' names.
62      *
63      * @see #updateEntries
64      */

65     private PropertiesFileEntry[] entries;
66
67     /**
68      * sorted list of non-escaped keys from all entries
69      *
70      * @see #buildKeySet
71      */

72     private List JavaDoc<String JavaDoc> keyList;
73     
74     /**
75      * Compartor which sorts keylist.
76      * Default set is sort according keys in file order.
77      */

78     private KeyComparator comparator = new KeyComparator();
79
80     /**
81      * registry of <code>PropertyBundleListener</code>s and support
82      * for firing <code>PropertyBundleEvent</code>s.
83      * Methods for registering and notification of listeners delegate to it.
84      */

85     private PropertyBundleSupport propBundleSupport
86             = new PropertyBundleSupport(this);
87
88     /** listens to changes on the underlying <code>PropertyDataObject</code> */
89     private PropertyChangeListener JavaDoc propListener;
90     
91     /**
92      * Creates a new instance describing a given
93      * <code>PropertiesDataObject</code>.
94      *
95      * @param obj <code>PropertiesDataObject</code> to be desribed
96      * @param ch children container for the node
97      */

98     public BundleStructure(PropertiesDataObject obj) {
99         this.obj = obj;
100         updateEntries();
101
102         // Listen on the PropertiesDataObject.
103
propListener = new PropertyChangeListener JavaDoc() {
104             public void propertyChange(PropertyChangeEvent JavaDoc evt) {
105                 if (evt.getPropertyName().equals(
106                         PropertiesDataObject.PROP_FILES)) {
107                     updateEntries();
108                     propBundleSupport.fireBundleStructureChanged();
109                 }
110             }
111         };
112         obj.addPropertyChangeListener(
113                 WeakListeners.propertyChange(propListener, obj));
114     }
115
116     
117     /**
118      * Retrieves n-th entry from the list, indexed from <code>0</code>.
119      * The first entry is always the primary entry.
120      *
121      * @param index index of entry to be retrieved, starting at <code>0</code>
122      * @return entry at the specified index;
123      * or <code>null</code> if the index is out of bounds
124      */

125     public PropertiesFileEntry getNthEntry(int index) {
126         if (entries == null) {
127             notifyEntriesNotInitialized();
128         }
129         if (index >= 0 && index < entries.length) {
130             return entries[index];
131         } else {
132             return null;
133         }
134     }
135
136     /**
137      * Retrieves an index of a file entry representing the given file.
138      *
139      * @param fileName simple name (without path and extension) of the
140      * primary or secondary file
141      * @return index of the entry representing a file with the given filename;
142      * or <code>-1</code> if no such entry is found
143      * @exception java.lang.IllegalStateException
144      * if the list of entries has not been initialized yet
145      * @see #getEntryByFileName
146      */

147     public int getEntryIndexByFileName(String JavaDoc fileName) {
148         if (entries == null) {
149             notifyEntriesNotInitialized();
150         }
151         for (int i = 0; i < getEntryCount(); i++) {
152             if (entries[i].getFile().getName().equals(fileName)) {
153                 return i;
154             }
155         }
156         return -1;
157     }
158
159     /**
160      * Retrieves a file entry representing the given file
161      *
162      * @param fileName simple name (excl. path, incl. extension) of the
163      * primary or secondary file
164      * @return entry representing the given file;
165      * or <code>null</code> if not such entry is found
166      * @exception java.lang.IllegalStateException
167      * if the list of entries has not been initialized yet
168      * @see #getEntryIndexByFileName
169      */

170     public PropertiesFileEntry getEntryByFileName(String JavaDoc fileName) {
171         int index = getEntryIndexByFileName(fileName);
172         return ((index == -1) ? null : entries[index]);
173     }
174
175     /**
176      * Retrieves number of file entries.
177      *
178      * @return number of file entries
179      * @exception java.lang.IllegalStateException
180      * if the list of entries has not been initialized yet
181      */

182     public int getEntryCount() {
183         if (entries == null) {
184             notifyEntriesNotInitialized();
185         }
186         return entries.length;
187     }
188
189     // Sorted keys management ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
190

191     /**
192      * Retrieves all un-escaped keys in bundle.
193      *
194      * @return sorted array of non-escaped keys
195      * @exception java.lang.IllegalStateException
196      * if the list of keys has not been initialized yet
197      * @see #sort
198      */

199     public String JavaDoc[] getKeys() {
200         if (keyList == null) {
201             notifyKeyListNotInitialized();
202         }
203         return keyList.toArray(new String JavaDoc[0]);
204     }
205
206     /**
207      * Retrieves the n-th bundle key from the list, indexed from <code>0</code>.
208      *
209      * @param keyIndex index according to the current order of keys
210      * @return non-escaped key at the given position;
211      * or <code>null</code> if the given index is out of range
212      * @exception java.lang.IllegalStateException
213      * if the list of keys has not been initialized yet
214      */

215     public String JavaDoc keyAt(int keyIndex) {
216         if (keyList == null) {
217             notifyKeyListNotInitialized();
218         }
219         if (keyIndex < 0 || keyIndex >= keyList.size()) {
220             return null;
221         } else {
222             return keyList.get(keyIndex);
223         }
224     }
225
226     /**
227      * Returns the index of the given key within the sorted list of keys
228      *
229      * @param key non-escaped key
230      * @return position of the given key in the bundle;
231      * or <code>-1</code> if the key was not found
232      * @exception java.lang.IllegalStateException
233      * if the list of keys has not been initialized yet
234      */

235     public int getKeyIndexByName(String JavaDoc key) {
236         if (keyList == null) {
237             notifyKeyListNotInitialized();
238         }
239         return keyList.indexOf(key);
240     }
241
242     /**
243      * Finds a free key in the budnle. If the suggested key is not free,
244      * a number is appended to it.
245      */

246     public String JavaDoc findFreeKey(String JavaDoc keySpec) {
247         if (keyList == null) {
248             notifyKeyListNotInitialized();
249         }
250
251         int n = 1;
252         String JavaDoc key = keySpec;
253         while (keyList.contains(key)) {
254             key = keySpec + "_" + n++;
255         }
256         return key;
257     }
258
259     /**
260      * Retrieves keyIndex-th key in the entryIndex-th entry from the list,
261      * indexed from <code>0</code>.
262      *
263      * @return item for keyIndex-th key in the entryIndex-th entry;
264      * or <code>null</code> if the entry does not contain
265      * the key or entry doesn't exist
266      */

267     public Element.ItemElem getItem(int entryIndex, int keyIndex) {
268         String JavaDoc key = keyAt(keyIndex);
269         return getItem(entryIndex, key);
270     }
271
272     /**
273      * Returns a property item having a given key, from a given file entry.
274      *
275      * @param entryIndex index of the file entry to get the item from
276      * @param key key of the property to receive
277      * @return item from the given file entry, having the given key;
278      * or <code>null</code> if one of the following is true:
279      * <ul>
280      * <li>entry index is out of bounds</li>
281      * <li><code>null</code> was passed as a key</li>
282      * <li>the given key was not found in the given entry</li>
283      * <li>structure of the given file entry is not available
284      * because of an error while reading the entry
285      * or because parsing of the file entry was stopped
286      * for some reason</li>
287      * </ul>
288      * @see org.netbeans.modules.properties.Element.ItemElem
289      */

290     public Element.ItemElem getItem(int entryIndex, String JavaDoc key) {
291         if (key == null) {
292             return null;
293         }
294         PropertiesFileEntry pfe = getNthEntry(entryIndex);
295         if (pfe == null) {
296             return null;
297         }
298         PropertiesStructure ps = pfe.getHandler().getStructure();
299         if (ps != null) {
300             return ps.getItem(key);
301         } else {
302             return null;
303         }
304     }
305
306     /**
307      * Returns property item of given key from localization corresponding to
308      * given file name. If not found in given file directly then "parent" files
309      * are scanned - the same way as ResourceBundle would work when asked for
310      * locale specific key.
311      * @param localizationFile name of file entry without extension
312      * corresponding to the desired specific localization
313      */

314     public Element.ItemElem getItem(String JavaDoc localizationFile, String JavaDoc key) {
315         int score = 0; // number of same characters in the file name
316
Element.ItemElem item = null;
317         for (int i=0; i < getEntryCount(); i++) {
318             PropertiesFileEntry pfe = getNthEntry(i);
319             if (pfe != null) {
320                 String JavaDoc fName = pfe.getFile().getName();
321                 if (localizationFile.startsWith(fName)
322                     && (item == null || fName.length() > score))
323                 { // try to find the item in the entry with longest file name
324
// matching (most specific localization)
325
PropertiesStructure ps = pfe.getHandler().getStructure();
326                     if (ps != null) {
327                         Element.ItemElem it = ps.getItem(key);
328                         if (it != null) {
329                             item = it;
330                             score = fName.length();
331                         }
332                     }
333                 }
334             }
335         }
336         return item;
337     }
338
339     /**
340      * Gets all data for given key from all locales.
341      * @return String[] array of strings - repeating: locale, value, comments
342      */

343     public String JavaDoc[] getAllData(String JavaDoc key) {
344         List JavaDoc<String JavaDoc> list = null;
345         for (int i=0; i < getEntryCount(); i++) {
346             PropertiesFileEntry pfe = getNthEntry(i);
347             if (pfe != null) {
348                 PropertiesStructure ps = pfe.getHandler().getStructure();
349                 if (ps != null) {
350                     Element.ItemElem item = ps.getItem(key);
351                     if (item != null) {
352                         String JavaDoc locale = Util.getLocaleSuffix(pfe);
353                         if (list == null) {
354                             list = new ArrayList JavaDoc<String JavaDoc>();
355                         }
356                         list.add(locale);
357                         list.add(item.getValue());
358                         list.add(item.getComment());
359                     }
360                 }
361             }
362         }
363         return list != null ? list.toArray(new String JavaDoc[list.size()]) : null;
364     }
365
366     public void setAllData(String JavaDoc key, String JavaDoc[] data) {
367         // create missing file entries
368
boolean entryCreated = false;
369         for (int i=0; i < data.length; i+=3) {
370             String JavaDoc locale = data[i];
371             PropertiesFileEntry localeFile = null;
372             for (int j=0; j < getEntryCount(); j++) {
373                 PropertiesFileEntry pfe = getNthEntry(j);
374                 if (pfe != null && Util.getLocaleSuffix(pfe).equals(locale)) {
375                     localeFile = pfe;
376                     break;
377                 }
378             }
379             if (localeFile == null) {
380                 Util.createLocaleFile(obj, locale.substring(1), false);
381                 entryCreated = true;
382             }
383         }
384         if (entryCreated)
385             updateEntries();
386
387         // add all provided data
388
for (int i=0; i < data.length; i+=3) {
389             String JavaDoc locale = data[i];
390             for (int j=0; j < getEntryCount(); j++) {
391                 PropertiesFileEntry pfe = getNthEntry(j);
392                 if (pfe != null && Util.getLocaleSuffix(pfe).equals(locale)) {
393                     PropertiesStructure ps = pfe.getHandler().getStructure();
394                     if (ps != null) {
395                         Element.ItemElem item = ps.getItem(key);
396                         if (item != null) {
397                             item.setValue(data[i+1]);
398                             item.setComment(data[i+2]);
399                         }
400                         else {
401                             ps.addItem(key, data[i+1], data[i+2]);
402                         }
403                     }
404                     break;
405                 }
406             }
407         }
408
409         // remove superfluous data
410
if (getEntryCount() > data.length/3) {
411             for (int j=0; j < getEntryCount(); j++) {
412                 PropertiesFileEntry pfe = getNthEntry(j);
413                 PropertiesStructure ps = pfe.getHandler().getStructure();
414                 if (pfe == null || ps == null) continue;
415
416                 boolean found = false;
417                 for (int i=0; i < data.length; i+=3) {
418                     String JavaDoc locale = data[i];
419                     if (Util.getLocaleSuffix(pfe).equals(locale)) {
420                         found = true;
421                         break;
422                     }
423                 }
424                 if (!found) {
425                     ps.deleteItem(key);
426                 }
427             }
428         }
429     }
430
431     /**
432      * Returns count of all unique keys found in all file entries.
433      *
434      * @return size of a union of keys from all entries
435      * @exception java.lang.IllegalStateException
436      * if the list of keys has not been initialized yet
437      */

438     public int getKeyCount() {
439         if (keyList != null) {
440             return keyList.size();
441         } else {
442             notifyKeyListNotInitialized();
443             return 0; //will not happen
444
}
445     }
446
447     /**
448      * Adds to or changes an item in specified localization file and its parents.
449      */

450     public void addItem(String JavaDoc localizationFile,
451                         String JavaDoc key, String JavaDoc value, String JavaDoc comment,
452                         boolean changeIfExists)
453     {
454         PropertiesStructure[] ps = getRelatedStructures(localizationFile);
455         boolean changed = false;
456         for (int i=0; i < ps.length; i++) {
457             Element.ItemElem item = ps[i].getItem(key);
458             if (item != null) {
459                 if (changeIfExists && !changed) {
460                     item.setValue(value);
461                     item.setComment(comment);
462                     changed = true; // change only once - in the most specific set
463
}
464             }
465             else {
466                 ps[i].addItem(key, value, comment);
467                 changed = true; // change only once - in the most specific set
468
}
469         }
470     }
471
472     /**
473      * Deletes item with given key from all files of this bundle.
474      */

475     public void removeItem(String JavaDoc key) {
476         for (int i=0; i < getEntryCount(); i++) {
477             PropertiesFileEntry pfe = getNthEntry(i);
478             if (pfe != null) {
479                 PropertiesStructure ps = pfe.getHandler().getStructure();
480                 if (ps != null) {
481                     ps.deleteItem(key);
482                 }
483             }
484         }
485     }
486
487     /**
488      * Sorts the keylist according the values of entry which index is given
489      * to this method.
490      *
491      * @param index sorts accordinng nth-1 entry values, <code>0</code> means
492      * sort by keys, if less than <code>0</code> it re-compares
493      * keylist with the same un-changed comparator.
494      */

495     public void sort(int index) {
496         if (index >= 0) {
497             comparator.setIndex(index);
498         }
499         Collections.sort(keyList, comparator);
500         propBundleSupport.fireBundleDataChanged();
501     }
502
503     /**
504      * Gets index accoring which is bundle key list sorted.
505      *
506      * @return index, <code>0</code> means according keys,
507      * <code>-1</code> means sorting as in default
508      * properties file
509      */

510     public int getSortIndex() {
511         return comparator.getIndex();
512     }
513     
514     /**
515      * Gets current order of sort.
516      *
517      * @return true if ascending, alse descending order
518      * (until sort index is <code>-1</code>, then unsorted)
519      */

520     public boolean getSortOrder() {
521         return comparator.isAscending();
522     }
523
524     /**
525      * Builds (or rebuilds) a sorted list of entries of the underlying
526      * <code>PropertiesDataObject<code> and a sorted list of keys gathered
527      * from all the entries.
528      *
529      * @see #entries
530      * @see #keyList
531      */

532     private void updateEntries() {
533         Map JavaDoc<String JavaDoc,PropertiesFileEntry> tm = new TreeMap JavaDoc<String JavaDoc,PropertiesFileEntry>(
534                 PropertiesDataObject.getSecondaryFilesComparator());
535         for (Entry entry : obj.secondaryEntries()) {
536             tm.put(entry.getFile().getName(), (PropertiesFileEntry) entry);
537         }
538
539         synchronized (this) {
540             // Move the entries.
541
int entriesCount = tm.size();
542             entries = new PropertiesFileEntry[entriesCount + 1];
543             entries[0] = (PropertiesFileEntry) obj.getPrimaryEntry();
544             
545             int index = 0;
546             for (Map.Entry JavaDoc<String JavaDoc,PropertiesFileEntry> mapEntry : tm.entrySet()) {
547                 entries[++index] = mapEntry.getValue();
548             }
549         }
550         buildKeySet();
551     }
552
553     /**
554      * Constructs a sorted list of all keys gathered from all entries.
555      *
556      * @see #keyList
557      */

558     private synchronized void buildKeySet() {
559         List JavaDoc<String JavaDoc> keyList = new ArrayList JavaDoc<String JavaDoc>() {
560             public boolean equals(Object JavaDoc obj) {
561                 if (!(obj instanceof ArrayList JavaDoc)) {
562                     return false;
563                 }
564                 ArrayList JavaDoc list2 = (ArrayList JavaDoc) obj;
565                 
566                 if (this.size() != list2.size()) {
567                     return false;
568                 }
569                 for (int i = 0; i < this.size(); i++) {
570                     if (!this.contains(list2.get(i))
571                             || !list2.contains(this.get(i))) {
572                         return false;
573                     }
574                 }
575                 return true;
576             }
577         };
578
579         // for all entries add all keys
580
int entriesCount = getEntryCount();
581         for (int index = 0; index < entriesCount; index++) {
582             PropertiesFileEntry entry = getNthEntry(index);
583             PropertiesStructure ps = entry.getHandler().getStructure();
584             if (ps != null) {
585                 for (Iterator JavaDoc<Element.ItemElem> it = ps.allItems(); it.hasNext(); ) {
586                     Element.ItemElem item = it.next();
587                     if (item == null) {
588                         continue;
589                     }
590                     String JavaDoc key = item.getKey();
591                     if (key != null && !(keyList.contains(key))) {
592                         keyList.add(item.getKey());
593                     }
594                 }
595             }
596         }
597         
598         Collections.sort(keyList, comparator);
599         this.keyList = keyList;
600     }
601
602     /**
603      * Collects PropertyStructure objects that are related for given design time
604      * localization - i.e. the structure corresponding to the given file name
605      * plus all the "parents". Sorted from the most specific.
606      * @param localizationFile name of specific file entry (without extension)
607      */

608     private PropertiesStructure[] getRelatedStructures(String JavaDoc localizationFile) {
609         List JavaDoc<PropertiesFileEntry> list = null;
610         for (int i=0; i < getEntryCount(); i++) {
611             PropertiesFileEntry pfe = getNthEntry(i);
612             if (pfe != null) {
613                 if (localizationFile.startsWith(pfe.getFile().getName())
614                         && pfe.getHandler().getStructure() != null) {
615                     if (list == null) {
616                         list = new ArrayList JavaDoc<PropertiesFileEntry>(4);
617                     }
618                     list.add(pfe);
619                 }
620             }
621         }
622         if (list == null) {
623             return new PropertiesStructure[] {};
624         }
625         Collections.sort(list, new Comparator JavaDoc<PropertiesFileEntry>() {
626             public int compare(PropertiesFileEntry pfe1, PropertiesFileEntry pfe2) {
627                 return pfe2.getFile().getName().length() - pfe1.getFile().getName().length();
628             }
629         });
630
631         PropertiesStructure[] array = new PropertiesStructure[list.size()];
632         for (int i=0, n=list.size(); i < n; i++) {
633             array[i] = list.get(i).getHandler().getStructure();
634         }
635         return array;
636     }
637
638     boolean isReadOnly() {
639         boolean canWrite = false;
640         for (int i=0; i < getEntryCount(); i++) {
641             PropertiesFileEntry entry = getNthEntry(i);
642             canWrite |= entry.getFile().canWrite();
643         }
644         return !canWrite;
645     }
646
647     /**
648      * Registers a given listener so that it will receive notifications
649      * about changes in a property bundle.
650      * If the given listener is already registered, a duplicite registration
651      * will be performed, so that it will get notifications multiple times.
652      *
653      * @param l listener to be registered
654      * @see #removePropertyBundleListener
655      */

656     public void addPropertyBundleListener(PropertyBundleListener l) {
657         propBundleSupport.addPropertyBundleListener(l);
658     }
659
660     /**
661      * Unregisters a given listener so that it will no more receive
662      * notifications about changes in a property bundle.
663      * If the given listener has been registered multiple times,
664      * only one registration item will be removed.
665      *
666      * @param l the PropertyBundleListener
667      * @see #addPropertyBundleListener
668      */

669     public void removePropertyBundleListener(PropertyBundleListener l) {
670         propBundleSupport.removePropertyBundleListener(l);
671     }
672
673     /**
674      * Notifies registered listeners of a change of a single item
675      * in a single file entry.
676      *
677      * @param struct object describing the file entry
678      * @param item changed item (within the entry)
679      * @see #addPropertyBundleListener
680      */

681     void notifyItemChanged(PropertiesStructure struct, Element.ItemElem item) {
682         propBundleSupport.fireItemChanged(
683             struct.getParent().getEntry().getFile().getName(),
684             item.getKey()
685         );
686     }
687
688     /**
689      * Notifies registered listeners of a change in a single file entry.
690      * Depending whether a list of keys has changed, either an event
691      * for a single file is fired (if the list of keys has remained unchanged)
692      * or a notification of a complex change is fired.
693      *
694      * @param handler handler of an object keeping structure of the modified
695      * file (entry)
696      */

697     void notifyOneFileChanged(StructHandler handler) {
698         // PENDING - events should be finer
699
// find out whether global key table has changed and fire a change
700
// according to that
701
List JavaDoc oldKeyList = keyList;
702         
703         buildKeySet();
704         if (!keyList.equals(oldKeyList)) {
705             propBundleSupport.fireBundleDataChanged();
706         } else {
707             propBundleSupport.fireFileChanged(
708                     handler.getEntry().getFile().getName());
709         }
710     }
711
712     /**
713      * Notifies registered listeners of a change in a single file entry.
714      * The <code>Map</code> arguments are actually list of items,
715      * each <code>Map</code> entry is a pair &lt;item&nbsp;key, item&gt;.
716      *
717      * @param handler handler of an object keeping structure of the modified
718      * file (entry)
719      * @param itemsChanged list of modified items in the entry
720      * @param itemsAdded list of items added to the entry
721      * @param itemsDeleted list of items removed from the entry
722      */

723     void notifyOneFileChanged(StructHandler handler,
724                               Map JavaDoc<String JavaDoc,Element.ItemElem> itemsChanged,
725                               Map JavaDoc<String JavaDoc,Element.ItemElem> itemsAdded,
726                               Map JavaDoc<String JavaDoc,Element.ItemElem> itemsDeleted) {
727         // PENDING - events should be finer
728
// find out whether global key table has changed
729
// should use a faster algorithm of building the keyset
730
buildKeySet();
731         propBundleSupport.fireBundleDataChanged();
732     }
733
734     /**
735      * Throws a runtime exception with a message that the list of bundle keys
736      * has not been initialized yet.
737      *
738      * @exception java.lang.IllegalStateException thrown always
739      * @see #buildKeySet
740      */

741     private void notifyKeyListNotInitialized() {
742         throw new IllegalStateException JavaDoc(
743                 "Resource Bundles: KeyList not initialized"); //NOI18N
744
}
745     
746     /**
747      * Throws a runtime exception with a message that the entries
748      * have not been initialized yet.
749      *
750      * @exception java.lang.IllegalStateException thrown always
751      * @see #updateEntries
752      */

753     private void notifyEntriesNotInitialized() {
754         throw new IllegalStateException JavaDoc(
755                 "Resource Bundles: Entries not initialized"); //NOI18N
756
}
757     
758     /**
759      * Comparator which compares keys according which locale (column in table was selected).
760      */

761     private final class KeyComparator implements Comparator JavaDoc<String JavaDoc> {
762
763         /** Index of column to compare with. */
764         private int index;
765         
766         /** Flag if ascending order should be performed. */
767         private boolean ascending;
768
769         
770         /** Constructor. */
771         public KeyComparator() {
772             this.index = -1;
773             ascending = false;
774         }
775         
776         
777         /**
778          * Setter for <code>index</code> property.
779          * ascending -&gt; descending -&gt; primary file key order -&gt; ....
780          *
781          * @param index interval <code>0</code> .. entry count
782          */

783         public void setIndex(int index) {
784             if (index == -1) {
785                 throw new IllegalArgumentException JavaDoc();
786             }
787             // if same column toggle order
788
if (this.index == index) {
789                 if (ascending) {
790                     ascending = false;
791                 } else {
792                     // sort as in properties file
793
index = -1;
794                     ascending = true;
795                 }
796             } else {
797                 ascending = true;
798             }
799             this.index = index;
800         }
801
802         /**
803          * Getter for <code>index</code> property.
804          *
805          * @return <code>-1</code>..entry count, <code>-1</code> means unsorted
806          * */

807         public int getIndex() {
808             return index;
809         }
810         
811         /** Getter for <code>ascending</code> property. */
812         public boolean isAscending() {
813             return ascending;
814         }
815
816         /**
817          * It's strange as it access just being compared list
818          */

819         public int compare(String JavaDoc o1, String JavaDoc o2) {
820             String JavaDoc str1;
821             String JavaDoc str2;
822             
823             // sort as in default properties file
824
if (index < 0) {
825                 Element.ItemElem item1 = getItem(0, o1);
826                 Element.ItemElem item2 = getItem(0, o2);
827                 if (item1 != null && item2 != null) {
828                     int i1 = item1.getBounds().getBegin().getOffset();
829                     int i2 = item2.getBounds().getBegin().getOffset();
830                     return i1 - i2;
831                 } else if (item1 != null) {
832                     return -1;
833                 } else if (item2 != null) {
834                     return 1;
835                 } else {
836                     /*
837                      * None of the keys is in the default (primary) properties
838                      * file. Order the files by name.
839                      */

840                     str1 = o1;
841                     str2 = o2;
842                 }
843             }
844             // key column
845
if (index == 0) {
846                 str1 = o1;
847                 str2 = o2;
848             } else {
849                 Element.ItemElem item1 = getItem(index - 1, o1);
850                 Element.ItemElem item2 = getItem(index - 1, o2);
851                 if (item1 == null) {
852                     if (item2 == null) {
853                         return 0;
854                     } else {
855                         return ascending ? 1 : -1;
856                     }
857                 } else {
858                     if (item2 == null) {
859                         return ascending ? -1 : 1;
860                     }
861                 }
862                 str1 = item1.getValue();
863                 str2 = item2.getValue();
864             }
865
866             if (str1 == null) {
867                 if (str2 == null) {
868                     return 0;
869                 } else {
870                     return ascending ? 1 : -1;
871                 }
872             } else if (str2 == null) {
873                 return ascending ? -1 : 1;
874             }
875             int res = str1.compareToIgnoreCase(str2);
876
877             return ascending ? res : -res;
878         }
879         
880     } // End of inner class KeyComparator.
881

882 }
883
Popular Tags