KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > directory > jxplorer > viewer > tableviewer > AttributeValueCellEditor


1 package com.ca.directory.jxplorer.viewer.tableviewer;
2
3 import com.ca.commons.cbutil.CBIntText;
4 import com.ca.commons.cbutil.CBJComboBox;
5 import com.ca.commons.cbutil.CBUtility;
6 import com.ca.commons.jndi.SchemaOps;
7 import com.ca.commons.naming.DN;
8 import com.ca.commons.security.cert.CertViewer;
9 import com.ca.directory.jxplorer.DataSource;
10 import com.ca.directory.jxplorer.editor.*;
11
12 import javax.naming.NamingException JavaDoc;
13 import javax.naming.directory.Attribute JavaDoc;
14 import javax.naming.directory.Attributes JavaDoc;
15 import javax.swing.*;
16 import java.awt.*;
17 import java.awt.event.MouseAdapter JavaDoc;
18 import java.awt.event.MouseEvent JavaDoc;
19 import java.lang.reflect.Constructor JavaDoc;
20 import java.security.cert.X509Certificate JavaDoc;
21 import java.util.Arrays JavaDoc;
22 import java.util.EventObject JavaDoc;
23 import java.util.logging.Logger JavaDoc;
24 import java.util.logging.Level JavaDoc;
25
26 /**
27  * The cell editor that brings up the dialog.
28  * We inherit from AbstractCellEditor,
29  * even though it means we have to create a dummy
30  * check box. Attribute Value Editor uses schema
31  * info to validate the user's input before submission...
32  */

33 public class AttributeValueCellEditor extends AbstractCellEditor
34 {
35     Frame owner;
36
37     JTextField textField = new JTextField();
38     JLabel label = new JLabel("");
39
40     CBJComboBox combobox = new CBJComboBox();
41
42     JComponent editorComponent = textField;
43
44     abstractbinaryeditor abstractEditor = null; // this is the display editor for binary data - e.g. the audio player, or photo viewer
45

46     Object JavaDoc value;
47     boolean binaryEditFlag = false; // handle binary editing separately
48
boolean specialStringEditor = false; // handle special string stuff like postal address
49
protected ClassLoader JavaDoc myLoader = null; // optional extended class loader
50
public DataSource datasource = null; //TE: The syntax of the attribute.
51
public DN currentDN = null; //TE: The dn of the entry being modified.
52

53     int lastSelectedRow = 0; //TE: The last selected row - which is used to set the height back to normal (16).
54

55     public static final String JavaDoc BINARY_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.5";
56     public static final String JavaDoc BOOLEAN_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.7";
57     public static final String JavaDoc CERTIFICATE_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.8";
58     public static final String JavaDoc GENERALIZED_TIME_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.24";
59     public static final String JavaDoc POSTAL_ADDRESS_SYNTAX = "1.3.6.1.4.1.1466.115.121.1.41";
60
61     private static Logger JavaDoc log = Logger.getLogger(AttributeValueCellEditor.class.getName());
62
63    /**
64     * A basic constructor, which does little except add a
65     * mouse listener to the default text field, setting the
66     * click count for 'cancel editing' to two.
67     */

68     public AttributeValueCellEditor(Frame parent)
69     {
70         owner = parent;
71
72     // textField.setFont(new Font("Tahoma", Font.PLAIN,11)); //TE: makes the textField same as the label - bug 3013.
73

74         editorComponent.addMouseListener(new MouseAdapter JavaDoc()
75         {
76             public void mousePressed(MouseEvent JavaDoc e)
77             {
78 //TE: I've commented this out because a double click makes the value in the cell disappear?? Bug - 3007.
79
// if (e.getClickCount() == 2)
80
// cancelCellEditing();
81
}
82         });
83     }
84
85     //
86
// Implementing the CellEditor Interface
87
//
88

89     // implements javax.swing.table.TableCellEditor
90

91     /**
92      * Returns an awt.Component that acts as a cell editor.
93      * Checks, in the following order, for a Certificate, binary syntax,
94      * postalAddress, GeneralizedTime, if there are options. If none of these
95      * syntax' match then the default string editor is set.
96      * This method also increases the size of the row selected so that the value
97      * is easier to read.
98      * @param table
99      * @param value
100      * @param isSelected
101      * @param row
102      * @param column
103      * @return
104      */

105     public Component getTableCellEditorComponent(JTable table,
106                          Object JavaDoc value, boolean isSelected,
107                          int row, int column)
108     {
109         binaryEditFlag = false;
110         specialStringEditor = false;
111
112         table.setRowHeight(lastSelectedRow, 16);
113         table.setRowHeight(row, 24);
114
115         lastSelectedRow = row;
116
117         if (value instanceof AttributeValue)
118         {
119             AttributeValue att = (AttributeValue) value;
120
121             if (hasSyntax(att, CERTIFICATE_SYNTAX)) //TE: a syntax check for Certificate.
122
setCertificateEditor(att);
123             else if (att.isBinary()) //TE: binary check.
124
setBinaryEditor(att);
125             else if (hasSyntax(att, POSTAL_ADDRESS_SYNTAX)) //TE: postalAddress syntax check.
126
setPostalAddressEditor(att);
127             else if (hasSyntax(att, GENERALIZED_TIME_SYNTAX)) //TE: generalizedTime syntax check.
128
setGeneralizedTimeEditor(att);
129             else if (hasSyntax(att, BOOLEAN_SYNTAX)) //TE: boolean syntax check.
130
setBooleanEditor(att);
131             else if (att.hasOptions()) // there are suggested possible values
132
setOptions(att);
133             else
134                 setString(att);
135
136             setCellEditorValue(att);
137         }
138         return editorComponent;
139     }
140
141    /**
142     * Checks if the attribute value's syntax matches the given syntax.
143     * @param att the attribute value for example, 'Fred' from 'cn=Fred'.
144     * @param syntax the syntax to check against for example, '1.3.6.1.4.1.1466.115.121.1.8'.
145     * @return true if the syntaxes match false otherwise.
146     */

147     public boolean hasSyntax(AttributeValue att, String JavaDoc syntax)
148     {
149         String JavaDoc attSyntax = getAttributeSyntax(att);
150         return (attSyntax != null && attSyntax.indexOf(syntax) > -1);
151     }
152
153    /**
154     * Sets the certificate editor in the table cell whose attribute is
155     * a certificate ["1.3.6.1.4.1.1466.115.121.1.8"].
156     * @param att the attribute value to be set in the editor.
157     */

158     private void setCertificateEditor(AttributeValue att)
159     {
160         CertViewer.CertAndFileName returnVal = CertViewer.editCertificate(owner, att.getValue());
161         X509Certificate JavaDoc cert = returnVal.cert;
162         if (cert != null)
163         {
164             try
165             {
166                 byte[] newData = cert.getEncoded();
167                 if (Arrays.equals(newData, att.getValue()) == false)
168                     att.setValue(newData);
169             }
170             catch(Exception JavaDoc e)
171             {
172                 CBUtility.error(CBIntText.get("Error: unable to modify certificate."), e);
173             }
174         }
175
176         binaryEditFlag = true;
177
178         if (att.isEmpty())
179         {
180             label.setText(" ");
181         }
182         else
183         {
184             label.setText(CBIntText.get("(non string data)"));
185         }
186
187         editorComponent = label;
188     }
189
190    /**
191     * Sets the string in the table cell whose attribute is
192     * a string (does a check for the length of a string also and if
193     * the string is longer than 100 it sets the large string editor).
194     * @param att the attribute value to be set in the editor.
195     */

196     private void setString(AttributeValue att)
197     {
198         String JavaDoc textValue = att.toString();
199         if (textValue.length() > 100) // arbitrary long display limit...
200
{
201             setLargeStringEditor(att);
202         }
203         else
204         {
205             textValue = textValue.trim(); // XXX trim off extra space that may be there for swing printing hack...
206

207             textField.setText(textValue);
208
209             editorComponent = textField;
210         }
211     }
212
213    /**
214     * Sets the large string editor in the table cell whose attribute value is
215     * a string longer than 100 chars.
216     * @param att the attribute value to be set in the editor.
217     */

218     private void setLargeStringEditor(AttributeValue att)
219     {
220         largestringeditor lse = new largestringeditor(owner, att);
221         specialStringEditor = true;
222         CBUtility.center(lse, owner);
223         lse.setVisible(true);
224         label.setText(att.getStringValue().substring(0,100));
225         editorComponent = label;
226     }
227
228    /**
229     * Sets a combo box in the table cell whose attribute could have
230     * suggested possible values.
231     * @param att the attribute value to be set in the editor.
232     */

233     private void setOptions(AttributeValue att)
234     {
235         combobox.removeAllItems();
236         String JavaDoc[] ops = att.getOptions();
237         for (int i=0; i<ops.length; i++)
238             combobox.addItem(ops[i]);
239         editorComponent = combobox;
240     }
241
242    /**
243     * Sets the binary editor in the table cell whose attribute is
244     * a binary.
245     * @param att the attribute value to be set in the editor.
246     */

247     private void setBinaryEditor(AttributeValue att)
248     {
249         startBinaryEditor(att); // runs modal dialog binary editor
250
binaryEditFlag = true;
251
252         if (att.isEmpty())
253         {
254             label.setText(" ");
255         }
256         else
257         {
258             label.setText(CBIntText.get("(non string data)"));
259         }
260
261         editorComponent = label;
262     }
263
264    /**
265     * Sets the generalized time editor in the table cell whose attribute is
266     * a generalizedTime ["1.3.6.1.4.1.1466.115.121.1.24"].
267     * @param att the attribute value to be set in the editor.
268     */

269     private void setGeneralizedTimeEditor(AttributeValue att)
270     {
271         generalizedtimeeditor timeEditor = null;
272
273         if (att==null)
274         {
275             timeEditor = new generalizedtimeeditor(owner,"", true);
276         }
277         else
278         {
279             timeEditor = new generalizedtimeeditor(owner, att.toString(), true);
280         }
281
282         specialStringEditor = true;
283         CBUtility.center(timeEditor, owner); //TE: centres the attribute editor.
284
timeEditor.setStringValue(att);
285         timeEditor.setVisible(true);
286
287         if (att.isEmpty())
288         {
289             label.setText(" ");
290         }
291         else
292         {
293             label.setText(att.getStringValue()); //TE: sets the table label to reflect the changes.
294
}
295
296         editorComponent = label;
297     }
298
299    /**
300     * Sets the postal address editor in the table cell whose attribute is
301     * a postalAddress ["1.3.6.1.4.1.1466.115.121.1.41"].
302     * @param att the attribute value to be set in the editor.
303     */

304     private void setPostalAddressEditor(AttributeValue att)
305     {
306         postaladdresseditor postalEditor = new postaladdresseditor(owner, att);
307         specialStringEditor = true;
308         CBUtility.center(postalEditor, owner); //TE: centres the attribute editor.
309
postalEditor.setStringValue(att);
310         postalEditor.setVisible(true);
311
312         if (att.isEmpty())
313         {
314             label.setText(" ");
315         }
316         else
317         {
318             label.setText(att.getStringValue()); //TE: sets the table label to reflect the changes.
319
}
320
321         editorComponent = label;
322     }
323
324    /**
325     * Sets the postal address editor in the table cell whose attribute is
326     * a postalAddress ["1.3.6.1.4.1.1466.115.121.1.7"].
327     * @param att the attribute value to be set in the editor.
328     */

329     private void setBooleanEditor(AttributeValue att)
330     {
331         booleaneditor booleanEditor = new booleaneditor(owner, att);
332         specialStringEditor = true;
333         CBUtility.center(booleanEditor, owner); //TE: centres the attribute editor.
334
booleanEditor.setStringValue(att);
335         booleanEditor.setVisible(true);
336
337         if (att.isEmpty())
338         {
339             label.setText(" ");
340         }
341         else
342         {
343             label.setText(att.getStringValue()); //TE: sets the table label to reflect the changes.
344
}
345
346         editorComponent = label;
347     }
348
349    /**
350     * Returns the syntax of the attribute value that is supplied
351     * @param att the attribute value for example 'Fred' from 'cn=Fred'.
352     * @return the syntax of the attribute for example for postalAddress the return string would be:
353     * 'SYNTAX: 1.3.6.1.4.1.1466.115.121.1.41'. If it fails to find the schema, it returns
354     * '1.3.6.1.4.1.1466.115.121.1.15' (DirectoryString) as a default.
355     */

356     public String JavaDoc getAttributeSyntax(AttributeValue att)
357     {
358         String JavaDoc attID = att.getID();
359         return getAttributeSyntaxFromName(attID);
360     }
361
362     /**
363      * This looks up the attribute syntax using the name of the attribute.
364      * If none is found, it also checks to see if it is a 'SUP' of another
365      * attribute, and tries to recursively get the schema from that.
366      * @param attID the name of the attribute to look up; e.g. 'cn'
367      * @return the syntax of the attribute (usually an OID, e.g. "1.3.6.1.4.1.1466.115.121.1.15")
368      */

369     private String JavaDoc getAttributeSyntaxFromName(String JavaDoc attID)
370     {
371         if (attID.indexOf(';') > 0)
372             attID = attID.substring(0, attID.indexOf(';')); //TE: for example: userCertificate;binary.
373

374         try
375         {
376             if (datasource == null)
377                 throw new NamingException JavaDoc("No datasource!");
378
379             SchemaOps schema = datasource.getSchemaOps();
380             if (schema == null)
381                 throw new NamingException JavaDoc("No schema!");
382                                                //TE: gets the schema.
383
Attributes JavaDoc attSchema = schema.getAttributes("AttributeDefinition/" + attID); //TE: gets the attribute definition.
384

385             if (attSchema == null)
386                 throw new NamingException JavaDoc("No schema for AttributeDefinition/"+attID);
387
388             Attribute JavaDoc attSyntax = attSchema.get("SYNTAX"); //TE: gets the Syntax of the attribute .
389

390             if (attSyntax == null) // maybe it's a 'SUP' entry...
391
{
392                 Attribute JavaDoc supSchema = attSchema.get("SUP");
393                 if (supSchema == null)
394                     throw new NamingException JavaDoc("Error processing attribute definition for " + attID + " no schema and no sup entry found");
395
396                 if (supSchema.get().toString().equals(attID)) // 'SUP' is always single valued
397
throw new NamingException JavaDoc("recursive schema definition: " + attID + " sup of itself");
398
399                 return getAttributeSyntaxFromName(supSchema.get().toString()); // recursively find the syntax of the sup entry
400
}
401             else
402             {
403                 String JavaDoc syntax = attSyntax.toString();
404                 if (syntax.startsWith("SYNTAX: "))
405                     syntax = syntax.substring(8);
406                 return syntax;
407             }
408         }
409         catch (NamingException JavaDoc e)
410         {
411             log.log(Level.WARNING, "Problem processing attribute definition: ", e);
412             return "1.3.6.1.4.1.1466.115.121.1.15"; // default to 'DirectoryString'
413
}
414     }
415
416    /**
417     * Does a quick check to make the binary handling sane (if necessary)
418     * before calling the super class stopCellEditing.
419     */

420      // Enough casts to fill a hindu temple.
421
public boolean stopCellEditing()
422     {
423         if (binaryEditFlag)
424         {
425             return super.stopCellEditing();
426         }
427         else if (specialStringEditor)
428         {
429             return super.stopCellEditing();
430         }
431
432         Object JavaDoc o = getCellEditorValue();
433         if (o == null) return true; // not actually editing - redundant call.
434

435         if (o instanceof AttributeValue)
436         {
437             AttributeValue v = (AttributeValue)o;
438
439             if (editorComponent instanceof JTextField)
440             {
441                 String JavaDoc userData = ((JTextField)editorComponent).getText();
442                 // Bug 4891 - limit the user to entering only a single space.
443
int len = userData.length();
444                 if (len > 0)
445                 {
446                     userData.trim();
447                     if (userData.length() == 0)
448                         userData = " "; // multiple spaces are shortened to a single space. Technically we should
449

450                     if (userData.length() != len)
451                         ((JTextField)editorComponent).setText(userData);
452                 }
453                 v.update(userData);
454             }
455             else if (editorComponent instanceof CBJComboBox)
456                 v.update(((CBJComboBox)editorComponent).getSelectedItem());
457             else
458                 log.warning("unknown editorComponent = " + editorComponent.getClass());
459         }
460         else
461             log.warning("(AttValCellEdit) Not an Att Val: is " + o.getClass());
462
463         setCellEditorValue(o);
464
465         return super.stopCellEditing();
466     }
467
468    /**
469     * Checks if the user has clicked sufficient times to make the cell
470     * editable.
471     */

472     public boolean isCellEditable(EventObject JavaDoc e)
473     {
474         boolean editable = true;
475         if (e instanceof MouseEvent JavaDoc)
476         {
477             editable = ((MouseEvent JavaDoc)e).getClickCount() >= clickCountToStart;
478         }
479         return editable;
480     }
481
482    /**
483     * Kicks of a separate binary editor by looking for a Java class with
484     * name of the attribute, plus the word 'Editor', and starting that
485     * up if it can be found. (Otherwise it uses the default editor).
486     */

487     public void startBinaryEditor(AttributeValue att)
488     {
489         if (abstractEditor != null &&
490             (abstractEditor instanceof Component) &&
491             ((Component)abstractEditor).isVisible() ) //TE: checks if an editor is already open (i.e. if multiple clicks on a value in the table editor).
492
{
493             return; //TE: do nothing...there is already an editor open.
494
}
495
496         if (att.isBinary()==false) // should never happen!
497
{log.warning("Error: non binary value passed to binary editor!"); return; }
498
499         String JavaDoc attName = att.getID();
500         int trim = attName.indexOf(";binary");
501         if (trim>0)
502             attName = attName.substring(0,trim);
503
504         String JavaDoc className = "com.ca.directory.jxplorer.editor." + attName + "editor";
505
506         try
507         {
508             Class JavaDoc c = null;
509             if (myLoader == null)
510             {
511                 System.out.println("using default loader for "+className );
512                 c = Class.forName(className);
513             }
514             else
515             {
516                 System.out.println("looking for: " + className.toLowerCase());
517                 c = myLoader.loadClass(className.toLowerCase());
518             }
519             if (abstractbinaryeditor.class.isAssignableFrom(c))
520             {
521                 Constructor JavaDoc constructor;
522                 if (owner instanceof Frame)
523                 {
524                     constructor = c.getConstructor(new Class JavaDoc[] {java.awt.Frame JavaDoc.class});
525                     abstractEditor = (abstractbinaryeditor) constructor.newInstance(new Object JavaDoc[] {owner});
526                 }
527                 else
528                 {
529                     constructor = c.getConstructor(new Class JavaDoc[0]);
530                     abstractEditor = (abstractbinaryeditor) constructor.newInstance(new Object JavaDoc[0]);
531                 }
532
533                 abstractEditor.setValue(att);
534                 if(abstractEditor instanceof basicbinaryeditor) //TE: set the current DN in the editor.
535
((basicbinaryeditor)abstractEditor).setDN(currentDN);
536                 else if(abstractEditor instanceof defaultbinaryeditor) //TE: set the current DN in the editor.
537
((defaultbinaryeditor)abstractEditor).setDN(currentDN);
538
539                 if (abstractEditor instanceof defaultbinaryeditor)
540                 {
541                     ((defaultbinaryeditor)abstractEditor).showDialog(); //todo: TE:seems that the abstractEditor doesn't get set to null after it is closed...
542
abstractEditor = null; //todo: TE: so this is a hack to kill the dialog so that it opens the next time a user clicks on that attribute value. It would be nice to fix this!
543
}
544                 else if (abstractEditor instanceof Component)
545                 {
546                     ((Component)abstractEditor).setVisible(true);
547                 }
548
549                 fireEditingStopped(); // everything is now being done by the separate binary editor window...
550
return; // ...and don't load default editor (below)
551
}
552             else
553             {
554                 log.warning("error: can't load editor class " + className + " since it is not inherited from AbstractBinaryEditor\n");
555             }
556
557         }
558         catch (NoSuchMethodException JavaDoc e)
559         {
560             log.log(Level.WARNING, "coding error in editor " + className+ " - using default binary editor instead.", e);
561         }
562         catch (ClassNotFoundException JavaDoc e)
563         {
564             log.info("(expected) can not find editor " + className + "\n" + e.toString()); // 'expected' error
565
try
566             {
567                 defaultbinaryeditor dbe = new defaultbinaryeditor(owner); // kick off the default editor (creates an option dialog)
568
dbe.setDN(currentDN);
569                 CBUtility.center(dbe, owner); //TE: centers the window.
570
dbe.setValue(att);
571                 dbe.showDialog();
572             }
573             catch (Exception JavaDoc e2)
574             {
575                 log.log(Level.WARNING, "unable to start backup editor", e2);
576                 e2.printStackTrace();
577             }
578         }
579         catch (Exception JavaDoc e3)
580         {
581             log.log(Level.WARNING, "error loading editor " + className, e3);
582             e3.printStackTrace();
583         }
584     }
585
586    /**
587     * Optionally register a new class loader for atribute value viewers to use.
588     */

589     public void registerClassLoader(ClassLoader JavaDoc loader)
590     {
591         myLoader = loader;
592     }
593
594    /**
595     * Returns the datasource.
596     * @param ds the datasource.
597     */

598     public void setDataSource(DataSource ds)
599     {
600         datasource = ds;
601     }
602
603    /**
604     * Sets the dn of the entry being modified.
605     * @param dn the DN of the entry being modified.
606     */

607     public void setDN(DN dn)
608     {
609         currentDN = dn;
610     }
611
612    /**
613     * Sets the the abstract editor (display editor for binary data - e.g. the audio player, or photo viewer), to null.
614     */

615     public void cleanupEditor()
616     {
617          abstractEditor = null;
618     }
619 }
620
Popular Tags