KickJava   Java API By Example, From Geeks To Geeks.

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


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
24 import java.io.Serializable JavaDoc;
25 import javax.swing.event.TableModelEvent JavaDoc;
26 import javax.swing.table.AbstractTableModel JavaDoc;
27 import javax.swing.table.TableColumn JavaDoc;
28 import javax.swing.JTable JavaDoc;
29
30 import org.openide.util.NbBundle;
31 import org.openide.util.WeakListeners;
32
33
34 /**
35  * Model for the properties edit table. First column represents keys containing all .properties
36  * files belonging to bundle represnted by this model. Each next columns represents values
37  * for on .properties file from that bundle.
38  *
39  * @author Petr Jiricka
40  * @see BundleEditPanel
41  * @see javax.swing.table.AbstractTableModel
42  */

43 public class PropertiesTableModel extends AbstractTableModel JavaDoc {
44
45     /** Generated serialized version UID. */
46     static final long serialVersionUID = -7882925922830244768L;
47
48     /** <code>PropertiesDataObject</code> this table presents. */
49     private BundleStructure structure;
50
51     /** Listens to changes on the bundle structure. */
52     private PropertyBundleListener bundleListener;
53     
54     /** Create a data node for a given data object.
55      * The provided children object will be used to hold all child nodes.
56      * @param structure model to work with
57      */

58     public PropertiesTableModel(BundleStructure structure) {
59         super();
60         this.structure = structure;
61
62         // listener for the BundleStructure
63
bundleListener = new TablePropertyBundleListener();
64         
65         structure.addPropertyBundleListener(
66             (PropertyBundleListener) WeakListeners.create(PropertyBundleListener.class, bundleListener, structure)
67         );
68         
69     }
70
71     /** Gets the class for a model. Overrides column class. */
72     public Class JavaDoc getColumnClass(int columnIndex) {
73         return StringPair.class;
74     }
75
76     /** Gets the number of rows in the model. Implements superclass abstract method. */
77     public int getRowCount() {
78         return structure.getKeyCount();
79     }
80
81     /** Gets the number of columns in the model. Implements superclass abstract method. */
82     public int getColumnCount() {
83         return structure.getEntryCount() + 1;
84     }
85
86     /** Gets the value for the given row and column. Implements superclass abstract method. */
87     public Object JavaDoc getValueAt(int row, int column) {
88         BundleStructure bs = structure;
89         
90         if(column == 0)
91             // Get StringPair for key.
92
return stringPairForKey(row);//bs.keyAt(row);
93
else {
94             // Get StringPair for value.
95
Element.ItemElem item;
96             try {
97                 item = bs.getItem(column - 1, bs.keyAt(row));
98             } catch (ArrayIndexOutOfBoundsException JavaDoc aie) {
99                 item = null;
100             }
101             return stringPairForValue(item);
102         }
103     }
104
105     /** Gets string pair for a key in an item (may be null). */
106     private StringPair stringPairForKey(int row) {
107         BundleStructure bs = structure;
108         Element.ItemElem item = bs.getItem(0, bs.keyAt(row));
109         StringPair sp;
110         if (item == null)
111             sp = new StringPair("", bs.keyAt(row), true); // NOI18N
112
else
113             sp = new StringPair(item.getComment(), bs.keyAt(row), true);
114         
115         if (structure.getEntryCount() > 1)
116             sp.setCommentEditable(false);
117         
118         return sp;
119     }
120
121     /** Gets string pair for a value in an item (may be null). */
122     private StringPair stringPairForValue(Element.ItemElem item) {
123         if (item == null)
124             // item doesnt't exist -> value is null
125
return new StringPair(null, null);
126         else
127             return new StringPair(item.getComment(), item.getValue());
128     }
129
130     /** Gets name for column. Overrides superclass method.
131      * @param column model index of column
132      * @return name for column */

133     public String JavaDoc getColumnName(int column) {
134         String JavaDoc leading;
135         
136         // Construct label.
137
if(column == structure.getSortIndex())
138             // Place for drawing ascending/descending mark in renderer.
139
leading = " "; // NOI18N
140
else
141             leading = " "; // NOI18N
142

143         if(column == 0)
144             return leading+NbBundle.getBundle(PropertiesTableModel.class).getString("LAB_KeyColumnLabel");
145         else {
146             if(structure.getEntryCount() == 1)
147                 return leading+NbBundle.getBundle(PropertiesTableModel.class).getString("LBL_ColumnValue");
148             else {
149                 PropertiesFileEntry entry = structure.getNthEntry(column - 1);
150                 return entry == null ? "" : leading+Util.getLocaleLabel(entry); // NOI18N
151
}
152         }
153     }
154
155     /** Sets the value at rowIndex and columnIndex. Overrides superclass method. */
156     public void setValueAt(Object JavaDoc aValue, int rowIndex, int columnIndex) {
157         // If values equals -> no change was made -> return immediatelly.
158
if (aValue.equals(getValueAt(rowIndex, columnIndex))) {
159             return;
160         }
161         
162         // PENDING - set comment for all files
163
// Is key.
164
if (columnIndex == 0) {
165             BundleStructure bs = structure;
166             String JavaDoc oldValue = (String JavaDoc)bs.keyAt(rowIndex);
167             if (oldValue == null) {
168                 return;
169             }
170             String JavaDoc newValue = ((StringPair)aValue).getValue();
171             if (newValue == null) { // Key can be an empty string
172
// Remove from all files.
173
return;
174             } else {
175                 // Set in all files
176
for (int i=0; i < structure.getEntryCount(); i++) {
177                     PropertiesFileEntry entry = structure.getNthEntry(i);
178                     if (entry != null) {
179                         PropertiesStructure ps = entry.getHandler().getStructure();
180                         if (ps != null) {
181                             // set the key
182
if (!oldValue.equals(newValue)) {
183                                 ps.renameItem(oldValue, newValue);
184                                 // this resorting is necessary only if this column index is same as
185
// column according the sort is performed, REFINE
186
structure.sort(-1);
187                             }
188                             // set the comment
189
if (i == 0) {
190                                 Element.ItemElem item = ps.getItem(newValue);
191                                 if (item != null && ((StringPair)aValue).isCommentEditable()) {
192                                     // only set if they differ
193
if (!item.getComment().equals(((StringPair)aValue).getComment()))
194                                         item.setComment(((StringPair)aValue).getComment());
195                                 }
196                             }
197                         }
198                     }
199                 }
200             }
201         } else {
202             // Property value.
203
PropertiesFileEntry entry = structure.getNthEntry(columnIndex - 1);
204             String JavaDoc key = structure.keyAt(rowIndex);
205             if (entry != null && key != null) {
206                 PropertiesStructure ps = entry.getHandler().getStructure();
207                 if (ps != null) {
208                     Element.ItemElem item = ps.getItem(key);
209                     if (item != null) {
210                         item.setValue(((StringPair)aValue).getValue());
211                         item.setComment(((StringPair)aValue).getComment());
212                         // this resorting is necessary only if this column index is same as
213
// column according the sort is performed, REFINE
214
structure.sort(-1);
215                     } else {
216                         if ((((StringPair)aValue).getValue().length() > 0) || (((StringPair)aValue).getComment().length() > 0)) {
217                             ps.addItem(key, ((StringPair)aValue).getValue(), ((StringPair)aValue).getComment());
218                             // this resorting is necessary only if this column index is same as
219
// column according the sort is performed, REFINE
220
structure.sort(-1);
221                         }
222                     }
223                 }
224             }
225         }
226     }
227
228     /** Overrides superclass method. Overrides superclass method.
229      * @return true for all cells */

230     public boolean isCellEditable(int rowIndex, int columnIndex) {
231         if (columnIndex == 0) {
232             return !structure.isReadOnly();
233         } else {
234             PropertiesFileEntry entry = structure.getNthEntry(columnIndex-1);
235             return entry.getFile().canWrite();
236         }
237     }
238
239     /** Fires a TableModelEvent - change of one column */
240     public void fireTableColumnChanged(int index) {
241         int columnModelIndex = index;
242         
243         // reset the header value as well
244
Object JavaDoc list[] = listenerList.getListenerList();
245         for (int i = 0; i < list.length; i++) {
246             if (list[i] instanceof JTable JavaDoc) {
247                 JTable JavaDoc jt = (JTable JavaDoc)list[i];
248                 try {
249                     TableColumn JavaDoc column = jt.getColumnModel().getColumn(index);
250                     columnModelIndex = column.getModelIndex();
251                     column.setHeaderValue(jt.getModel().getColumnName(columnModelIndex));
252                 } catch (ArrayIndexOutOfBoundsException JavaDoc abe) {
253                     // only catch exception
254
}
255                 jt.getTableHeader().repaint();
256             }
257         }
258         fireTableChanged(new TableModelEvent JavaDoc(this, 0, getRowCount() - 1, columnModelIndex));
259     }
260
261     /** Overrides superclass method. */
262     public String JavaDoc toString() {
263         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
264         result.append("------------------------------ TABLE MODEL DUMP -----------------------\n"); // NOI18N
265
for (int row = 0; row < getRowCount(); row ++) {
266             for (int column = 0; column < getColumnCount(); column ++) {
267                 StringPair sp = (StringPair)getValueAt(row, column);
268                 result.append("[" /*+ sp.getComment() + "," */+ sp.getValue() + "]"); // NOI18N
269
if (column == 0)
270                     result.append(" : "); // NOI18N
271
else
272                     if (column == getColumnCount() - 1)
273                         result.append("\n"); // NOI18N
274
else
275                         result.append(","); // NOI18N
276
}
277         }
278         result.append("---------------------------- END TABLE MODEL DUMP ---------------------\n"); // NOI18N
279
return result.toString();
280     }
281
282     /** Cancels editing in all listening JTables if appropriate. */
283     private void cancelEditingInTables(CancelSelector can) {
284         
285         Object JavaDoc list[] = listenerList.getListenerList();
286         for(int i = 0; i < list.length; i++) {
287             if(list[i] instanceof BundleEditPanel.BundleTable) {
288                 BundleEditPanel.BundleTable jt = (BundleEditPanel.BundleTable)list[i];
289                 if (can.doCancelEditing(jt.getEditingRow(), jt.getEditingColumn())) {
290                     jt.removeEditorSilent();
291                 }
292             }
293         }
294     }
295
296     /** Gets <code>CancelSelector</code> for this table. */
297     private CancelSelector getDefaultCancelSelector() {
298         return new CancelSelector() {
299                    /** Returns whether editing should be canceled for given row and column. */
300                    public boolean doCancelEditing(int row, int column) {
301                        return (row >= 0 && row < getRowCount() && column >= 0 && column < getColumnCount());
302                    }
303                };
304     }
305     
306
307     /** Interface which finds out whether editing should be canceled if given cell is edited. */
308     private static interface CancelSelector {
309         /** Returns whether editing should be canceled for given row and column. */
310         public boolean doCancelEditing(int row, int column);
311     } // End of interface CancelSelector.
312

313     
314     /** Inner class. Listener for changes on bundle structure. */
315     private class TablePropertyBundleListener implements PropertyBundleListener {
316         public void bundleChanged(final PropertyBundleEvent evt) {
317             // quick patch for bug #13026
318
// (ensure visual updates are performed in AWT thread)
319
if (java.awt.EventQueue.isDispatchThread()) {
320                 doBundleChanged(evt);
321             }
322             else {
323                 java.awt.EventQueue.invokeLater(new Runnable JavaDoc() {
324                     public void run() {
325                         doBundleChanged(evt);
326                     }
327                 });
328             }
329         }
330
331         private void doBundleChanged(PropertyBundleEvent evt) {
332             int changeType = evt.getChangeType();
333             
334             if(changeType == PropertyBundleEvent.CHANGE_STRUCT) {
335                 // Structure changed.
336

337                 // Note: Normal way would be use the next commented out rows, which should do in effect
338
// the same thing like reseting the model, but it doesn't, therefore we reset the model directly.
339

340                 //cancelEditingInTables(getDefaultCancelSelector());
341
//fireTableStructureChanged();
342

343                 Object JavaDoc[] list = PropertiesTableModel.super.listenerList.getListenerList();
344                 for(int i = 0; i < list.length; i++) {
345                     if(list[i] instanceof JTable JavaDoc) {
346                         //!!! strange comment this model should be only stateless proxy
347
// Its necessary to create new instance of model otherwise the 'old' model values would remain.
348
((JTable JavaDoc)list[i]).setModel(new PropertiesTableModel(PropertiesTableModel.this.structure));
349                     }
350                 }
351             } else if(changeType == PropertyBundleEvent.CHANGE_ALL) {
352                 // All items changed (keyset).
353
cancelEditingInTables(getDefaultCancelSelector());
354                 
355                 // reset all header values as well
356
Object JavaDoc[] list = PropertiesTableModel.super.listenerList.getListenerList();
357                 for (int i = 0; i < list.length; i++) {
358                     if (list[i] instanceof JTable JavaDoc) {
359                         JTable JavaDoc jt = (JTable JavaDoc)list[i];
360
361                         for (int j=0 ; j < jt.getColumnModel().getColumnCount(); j++) {
362                             TableColumn JavaDoc column = jt.getColumnModel().getColumn(j);
363                             column.setHeaderValue(jt.getModel().getColumnName(column.getModelIndex()));
364                         }
365                     }
366                 }
367                 
368                 fireTableDataChanged();
369             } else if(changeType == PropertyBundleEvent.CHANGE_FILE) {
370                 // File changed.
371
final int index = structure.getEntryIndexByFileName(evt.getEntryName());
372                 if (index == -1) {
373                     if (Boolean.getBoolean("netbeans.debug.exceptions")) // NOI18N
374
(new Exception JavaDoc("Changed file not found")).printStackTrace(); // NOI18N
375
return;
376                 }
377                 
378                 cancelEditingInTables(new CancelSelector() {
379                     public boolean doCancelEditing(int row, int column) {
380                         if (!(row >= 0 && row < getRowCount() && column >= 0 && column < getColumnCount()))
381                             return false;
382                         return (column == index + 1);
383                     }
384                 });
385                 
386                 fireTableColumnChanged(index + 1);
387             } else if(changeType == PropertyBundleEvent.CHANGE_ITEM) {
388                 // one item changed
389
final int index2 = structure.getEntryIndexByFileName(evt.getEntryName());
390                 final int keyIndex = structure.getKeyIndexByName(evt.getItemName());
391                 
392                 if(index2 == -1 || keyIndex == -1) {
393                     if(Boolean.getBoolean("netbeans.debug.exceptions")) // NOI18N
394
(new Exception JavaDoc("Changed file not found")).printStackTrace(); // NOI18N
395

396                     return;
397                 }
398                 
399                 cancelEditingInTables(new CancelSelector() {
400                     public boolean doCancelEditing(int row, int column) {
401                         if (!(row >= 0 && row < getRowCount() && column >= 0 && column < getColumnCount()))
402                             return false;
403                         return (column == index2 + 1 && row == keyIndex);
404                     }
405                 });
406                 
407                 fireTableCellUpdated(keyIndex, index2 + 1);
408             }
409         }
410     } // End of inner class TablePropertyBundleListener.
411

412     
413     /**
414      * Object for the value for one cell in a table view.
415      * It is used to represent either (comment, value) pair of an item, or a key for an item.
416      */

417     static class StringPair implements Serializable JavaDoc {
418
419         /** Holds comment for this instance. */
420         private String JavaDoc comment;
421         
422         /** Key or value string depending on the <code>keyType</code>. */
423         private String JavaDoc value;
424         
425         /** Type of instance. */
426         private boolean keyType;
427         
428         /** Flag if comment is editable for this instance. */
429         private boolean commentEditable;
430
431         /** Generated serial version UID. */
432         static final long serialVersionUID =-463968846283787181L;
433         
434         
435         /** Constructs with empty comment and value. */
436         public StringPair() {
437             this (null, "", false); // NOI18N
438
}
439
440         /** Constructs with the given value and no comment. */
441         public StringPair(String JavaDoc v) {
442             this (null, v, true);
443         }
444
445         /** Constructs with the given comment and value. */
446         public StringPair(String JavaDoc c, String JavaDoc v) {
447             this (c, v, false);
448         }
449
450         /** Constructs with the given comment and value. */
451         public StringPair(String JavaDoc c, String JavaDoc v, boolean kt) {
452             comment = c;
453             value = v;
454             keyType = kt;
455             commentEditable = true;
456         }
457
458         
459         /** @return comment associated with this element. */
460         public String JavaDoc getComment() {
461             return comment;
462         }
463
464         /** @return the value associated with this element. */
465         public String JavaDoc getValue() {
466             return value;
467         }
468
469         /** Overrides superclass method. */
470         public boolean equals(Object JavaDoc obj) {
471             if(obj == null || !(obj instanceof StringPair))
472                 return false;
473             
474             StringPair compared = (StringPair)obj;
475
476             // PENDING compare keyTypes as well?
477

478             // Compare commnents first.
479
if(comment == null && compared.getComment() != null)
480                 return false;
481  
482             String JavaDoc str1 = comment;
483             String JavaDoc str2 = compared.getComment();
484             
485             if(!str1.equals(str2))
486                 return false;
487             
488             // Compare values.
489
if(value == null && compared.getValue() != null)
490                 return false;
491             
492             str1 = value;
493             str2 = compared.getValue();
494             
495             return str1.equals(str2);
496         }
497         
498         /** Overrides superclass method. */
499         public String JavaDoc toString() {
500             return value;
501         }
502
503         /** Returns the type key/value of the pair. */
504         public boolean isKeyType () {
505             return keyType;
506         }
507
508         /** @return true if comment should be allowed for editing. */
509         public boolean isCommentEditable() {
510             return commentEditable;
511         }
512
513         /** Sets whether the comment should be allowed to be edited. */
514         public void setCommentEditable(boolean newEditable) {
515             commentEditable = newEditable;
516         }
517     } // End of nested class StringPair.
518

519 }
520
Popular Tags