KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > ca > directory > jxplorer > viewer > TableAttributeEditor


1 package com.ca.directory.jxplorer.viewer;
2
3 import com.ca.commons.cbutil.*;
4 import com.ca.commons.naming.*;
5 import com.ca.directory.jxplorer.*;
6 import com.ca.directory.jxplorer.tree.NewEntryWin;
7 import com.ca.directory.jxplorer.viewer.tableviewer.*;
8 import com.ca.directory.jxplorer.viewer.tableviewer.AttributeValue;
9
10 import javax.naming.NamingException JavaDoc;
11 import javax.naming.directory.Attribute JavaDoc;
12 import javax.swing.*;
13 import java.awt.*;
14 import java.awt.event.*;
15 import java.io.File JavaDoc;
16 import java.util.logging.Logger JavaDoc;
17 import java.util.logging.Level JavaDoc;
18
19 /**
20  * This class displays attributes in a table (currently string attributes only). The user can modify the table values,
21  * and submit the results, which are passed to the registered DataSource (obtained from the registered DataSource)...
22  */

23
24
25 /* PROGRAMMING NOTE:
26  *
27  * Some rather unpleasent stuff happens with object class changing. The state
28  * of the unmodified entry is maintained between displayEntry() calls using
29  * the classChangedOriginalEntry variable.
30  */

31 public class TableAttributeEditor extends JPanel
32         implements DataSink, PluggableEditor //, TreeEntryCreator
33
{
34     private static Logger JavaDoc log = Logger.getLogger(TableAttributeEditor.class.getName());
35
36     JTable attributeTable;
37     AttributeTableModel tableData;
38     JScrollPane tableScroller;
39     CBButton submit, reset, changeClass, opAttrs; //, help;
40
JFrame owner;
41     JDialog virtualEntryDialog = null;
42
43     /**
44      * Flag for a virtual entry.
45      */

46     boolean virtualEntry = false;
47
48     /**
49      * Copy of the current entry.
50      */

51     DXEntry currentEntry = null;
52
53     /**
54      * Copy of the current DN.
55      */

56     DN currentDN = null;
57
58     /**
59      * The data source directory data is read from.
60      */

61     public DataSource dataSource;
62
63     /**
64      * A rare operation is for the user to change the classes of an entry. This backs up the original state of that
65      * entry.
66      */

67     DXEntry classChangedOriginalEntry = null;
68
69     SmartPopupTableTool popupTableTool;
70
71     ClassLoader JavaDoc myLoader;
72
73     final AttributeValueCellEditor myEditor;
74
75     /**
76      * Constructor initialises the table and a popup tool, as well as initialising the required GUI elements. It adds
77      * action listeners for the three main buttons, which include basic user input validation checking.
78      */

79     public TableAttributeEditor(JFrame MyOwner)
80     {
81         // As usual, it is insanely hard to get the swing components to display
82
// and work properly. If JTable is not displayed in a scroll pane no headers are
83
// displayed, and you have to do it manually. (If you *do* display it
84
// in a scrollbar, in this instance, it screws up sizing)
85
// The broken header mis-feature is only mentioned in the tutorial,
86
// not in the api doco - go figure.
87

88         super();
89
90         owner = MyOwner;
91
92         // final JPanel mainPanel = (JPanel)this;
93

94         tableData = new AttributeTableModel();
95
96         attributeTable = new JTable(tableData);
97         //attributeTable.setRowHeight(20); // This may be needed, depends on how fussy people get about the bottom of letters like 'y' getting cut off when the cell is selected - bug 3013.
98

99         popupTableTool = new SmartPopupTableTool(attributeTable, tableData, (JXplorer) owner);
100
101         // Set the renderer for the attribute type...
102
final AttributeTypeCellRenderer typeRenderer = new AttributeTypeCellRenderer();
103
104         attributeTable.setDefaultRenderer(AttributeType.class, typeRenderer);
105
106         // Set the renderer for the attribute value...
107
final AttributeValueCellRenderer valueRenderer = new AttributeValueCellRenderer();
108
109         attributeTable.setDefaultRenderer(AttributeValue.class, valueRenderer);
110
111         // Set the editor for the attribute value...
112
myEditor = new AttributeValueCellEditor(owner);
113
114         attributeTable.setDefaultEditor(AttributeValue.class, myEditor);
115
116         attributeTable.getTableHeader().setReorderingAllowed(false);
117
118         currentDN = null;
119
120         JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
121         buttonPanel.add(submit = new CBButton(CBIntText.get("Submit"), CBIntText.get("Submit your changes to the Directory.")));
122         buttonPanel.add(reset = new CBButton(CBIntText.get("Reset"), CBIntText.get("Reset this entry i.e. cancels any changes.")));
123         buttonPanel.add(changeClass = new CBButton(CBIntText.get("Change Classes"), CBIntText.get("Change the Object Class of this entry.")));
124         buttonPanel.add(opAttrs = new CBButton(CBIntText.get("Properties"), CBIntText.get("View the Operational Attributes of this entry.")));
125
126         // I don't really understand why we have to do this...
127
// but without it these buttons over ride the default
128
// button (Search Bar's search button), if they have
129
// been clicked and the user hits the enter key?
130
opAttrs.setDefaultCapable(false);
131         submit.setDefaultCapable(false);
132         reset.setDefaultCapable(false);
133         changeClass.setDefaultCapable(false);
134
135         setLayout(new BorderLayout(10, 10));
136
137         tableScroller = new JScrollPane();
138         attributeTable.setBackground(Color.white);
139         tableScroller.setPreferredSize(new Dimension(300, 285));
140         tableScroller.setViewportView(attributeTable);
141         add(tableScroller, BorderLayout.CENTER);
142         add(buttonPanel, BorderLayout.SOUTH);
143
144         setVisible(true);
145
146         // Opens a dialog that displays any operational attributes of the current entry.
147
opAttrs.addActionListener(new ActionListener()
148         {
149             public void actionPerformed(ActionEvent e)
150             {
151                 displayOperationalAttributes();
152             }
153         });
154
155         reset.addActionListener(new ActionListener()
156         {
157             public void actionPerformed(ActionEvent e)
158             {
159                 myEditor.stopCellEditing();
160                 //XXX??? if (attributeTable.isEditing()) myEditor.stopCellEditing();
161
tableData.reset();
162             }
163         });
164
165         submit.addActionListener(new ActionListener()
166         {
167             public void actionPerformed(ActionEvent e)
168             {
169                 doSubmit();
170             }
171         });
172
173         // This allows the user to change the objectclass attribute.
174
// This is pretty tricky, because it changes what attributes are available.
175
changeClass.addActionListener(new ActionListener()
176         {
177             public void actionPerformed(ActionEvent e)
178             {
179                 changeClass();
180             }
181         });
182
183         attributeTable.addMouseListener(new MouseAdapter()
184         {
185             public void mousePressed(MouseEvent e)
186             {
187                 if (!doPopupStuff(e)) super.mousePressed(e);
188             }
189
190             public void mouseReleased(MouseEvent e)
191             {
192                 if (!doPopupStuff(e)) super.mouseReleased(e);
193             }
194
195             //TODO need to have a way to call this from a keystroke...
196
public boolean doPopupStuff(MouseEvent e)
197             {
198                 if (e.isPopupTrigger() == false) return false;
199
200                 int row = attributeTable.rowAtPoint(new Point(e.getX(), e.getY()));
201
202                 attributeTable.clearSelection();
203                 attributeTable.addRowSelectionInterval(row, row);
204                 attributeTable.repaint();
205
206                 popupTableTool.registerCurrentRow((AttributeType) attributeTable.getValueAt(row, 0), (AttributeValue) attributeTable.getValueAt(row, 1), row, tableData.getRDN()); // active path also set by valueChanged
207
popupTableTool.show(attributeTable, e.getX(), e.getY());
208                 popupTableTool.registerCellEditor(myEditor); //TE: for bug fix 3107.
209
return true;
210             }
211         });
212     }
213
214     /**
215      * Opens the change class dialog.
216      */

217     public void changeClass()
218     { //JPanel mainPanel
219
/*
220          * MINOR MAGIC
221          *
222          * This code reuses the 'new entry window'. In order to make things
223          * sane, we prompt the user to save any serious changes before continuing.
224          * (Things can get really wierd if the user changes the name and then
225          * tries to change the objectclass - best to avoid the whole issue.)
226          */

227         myEditor.stopCellEditing();
228
229         if (virtualEntry)
230         {
231             doVirtualEntryDisplay();
232             return;
233         }
234
235         /*
236          * classChangedOriginalEntry saves the original state of the entry
237          * between visits to NewEntryWin. (- I wonder if it would be neater
238          * to just reset the 'oldEntry' state of the table every time? ).
239          * Check it's not been set already (i.e. Pathological User is paying
240          * multiple visits to the NewEntryWin.)
241          */

242         if (classChangedOriginalEntry == null)
243             classChangedOriginalEntry = tableData.getOldEntry();
244
245         DXEntry newEntry = tableData.getNewEntry();
246         DN newDN = newEntry.getDN();
247
248         /*
249          * Pathalogical user has messed with the name, *and* wants to
250          * change the object classes...
251          */

252         if (newDN.equals(classChangedOriginalEntry.getDN()) == false)
253         {
254             if (promptForSave(false) == false) // we may need to reset the 'newEntry' data
255
{ // if the user discards their changes.
256

257                 tableData.reset(); // resets the table before going on.
258

259                 newEntry = tableData.getNewEntry();
260                 newDN = newEntry.getDN();
261             }
262             else // user has saved data - so now we need to reset the 'classChangedOriginalEntry'
263
{ // to the changed (and hopefully saved!) data.
264
// NB: If the directory write fails, then the change classes will also fail...
265
classChangedOriginalEntry = tableData.getNewEntry();
266             }
267         }
268
269         /*
270          * Open NewEntryWin, allowing the user to reset the objectclass attribute.
271          */

272
273 /*
274         NewEntryWin userData = new NewEntryWin(newDN.parentDN(), newDN,
275                                 dataSource,
276                                 newEntry.getAsNonNullAttributes(),
277                                 newDN.getLowestRDN().toString(), TableAttributeEditor.this,
278                                 CBUtility.getParentFrame(mainPanel));
279 */

280         if (dataSource.getSchemaOps() == null)
281         {
282             JOptionPane.showMessageDialog(owner, CBIntText.get("Because there is no schema currently published by the\ndirectory, changing an entry's object class is unavailable."), CBIntText.get("No Schema"), JOptionPane.INFORMATION_MESSAGE);
283             return;
284         }
285         else
286         {
287             NewEntryWin userData = new NewEntryWin(dataSource, newDN, newEntry.getAsNonNullAttributes(),
288                     this, CBUtility.getParentFrame(this));
289             userData.setSize(400, 250);
290             CBUtility.center(userData, owner); // TE: centres window.
291
userData.setVisible(true);
292         }
293     }
294
295     /**
296      * Kicks off the entry modify/update & checks for manditory attributes.
297      */

298     public void doSubmit()
299     {
300         if (dataSource == null)
301         {
302             CBUtility.error("No dataSource available to write changes to in Table Attribute Editor");
303             return;
304         }
305
306         myEditor.stopCellEditing();
307
308         // If schema checking is on, make sure that all mandatory attributes are filled in.
309
if ("false".equalsIgnoreCase(JXplorer.getProperty("option.ignoreSchemaOnSubmission"))
310                 && (tableData.checkMandatoryAttributesSet() == false))
311         {
312             CBUtility.error(TableAttributeEditor.this, CBIntText.get("All Mandatory Attributes must have values!"), null);
313             return;
314         }
315
316         writeTableData();
317     }
318
319     /**
320      * Opens a dialog that displays the operational attributes of the current entry.
321      */

322     public void displayOperationalAttributes()
323     {
324         JXplorer jx = null;
325
326         if (owner instanceof JXplorer)
327             jx = (JXplorer) owner;
328         else
329             return;
330
331         String JavaDoc[] opAttrs = new String JavaDoc[]{"createTimestamp", "modifyTimestamp", "creatorsName", "modifiersName", "subschemaSubentry"};
332         int size = opAttrs.length;
333         DXEntry entry = null;
334         try
335         {
336             entry = (jx.getSearchBroker()).unthreadedReadEntry(currentDN, opAttrs);
337         }
338         catch (NamingException JavaDoc e)
339         {
340             CBUtility.error(TableAttributeEditor.this, CBIntText.get("Unable to read entry " + currentDN), e);
341         }
342         StringBuffer JavaDoc buffy = new StringBuffer JavaDoc("DN: " + currentDN.toString() + "\n\n");
343
344         // Get the attribute values...
345
for (int i = 0; i < size; i++)
346         {
347             DXAttribute att = (DXAttribute) entry.get(opAttrs[i]);
348
349             try
350             {
351                 if (att != null)
352                 {
353                     buffy.append(opAttrs[i] + ": " + att.get().toString() + "\n\n");
354                 }
355             }
356             catch (NamingException JavaDoc ee)
357             {
358                 log.log(Level.WARNING, "Problem accessing Operational Attributes via Table Editor\n", ee);
359             }
360         }
361
362         // Dialog setup...
363
JTextArea area = new JTextArea(buffy.toString());
364         area.setFont(new Font("SansSerif", Font.PLAIN, 11));
365         area.setLineWrap(true);
366         area.setWrapStyleWord(true);
367         JScrollPane scrollPane = new JScrollPane(area);
368         scrollPane.setPreferredSize(new Dimension(300, 125));
369         scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
370         JOptionPane.showMessageDialog(jx, scrollPane, CBIntText.get("Properties (Operational Attributes)"), JOptionPane.INFORMATION_MESSAGE);
371     }
372
373     /**
374      * This notifies the user that they are about to lose entered data (i.e. they've made changes and are about to a)
375      * change classes or b) go to another entry).
376      * @param reset usually prompt for save keeps an internal check to prevent the user being prompted twice for the
377      * same entry. If this parameter is true, that prompt is reset.
378      * @return true if data is saved, false if discarded.
379      */

380     public boolean promptForSave(boolean reset)
381     {
382         return false;
383 /* TEMPORARY REMOVAL
384         if (dataSource == null || dataSource.isActive() == false)
385         {
386             return false; // no point prompting - nothing to save with!
387         }
388 */

389         /*
390          * Only ever check the entry once (sometimes promptForSave can be called
391          * multiple time - remember that the 'save' function gets called by a
392          * separate thread).
393          */

394 /* TEMPORARY REMOVAL
395         if (reset)
396             checkedDN = null; // force the prompt to be used.
397
398         if (checkedDN == null || checkedDN.equals(tableData.getOldEntry().getDN()) == false)
399         {
400             checkedDN = tableData.getOldEntry().getDN();
401
402             //Thread.currentThread().dumpStack();
403
404             String save = CBIntText.get("Save");
405             String discard = CBIntText.get("Discard");
406
407             int result = JOptionPane.showOptionDialog(CBUtility.getDefaultDisplay(),
408                                                  CBIntText.get("Submit changes to the Directory?"),
409                                                  CBIntText.get("Save Data"), JOptionPane.DEFAULT_OPTION,
410                                                  JOptionPane.QUESTION_MESSAGE, null,
411                                                  new Object[] {save, discard}, save);
412             if (result == 0)
413             {
414                 writeTableData(); // nb - this queues a request to the directory
415                 return true;
416             }
417         }
418         else
419         {
420             // do nothing - don't prompt, don't save...
421         }
422         return false;
423 */

424     }
425
426     /**
427      * Opens a dialog that asks the user if they want to make a virtual entry a non virtual entry. If the user clicks
428      * 'Yes' the 'change class' dialog opens.
429      */

430     public void doVirtualEntryDisplay()
431     {
432         virtualEntryDialog = new JDialog(owner, CBIntText.get("Virtual Entry"), true);
433
434         CBButton btnYes = new CBButton(CBIntText.get("Yes"), CBIntText.get("Click yes to make a Virtual Entry."));
435         CBButton btnNo = new CBButton(CBIntText.get("No"), CBIntText.get("Click no to cancel without making a Virtual Entry."));
436
437         //TE: layout stuff...
438
Container pane = virtualEntryDialog.getContentPane();
439         pane.setLayout(new BorderLayout());
440         CBPanel panel1 = new CBPanel();
441         CBPanel panel2 = new CBPanel();
442         CBPanel panel3 = new CBPanel();
443
444         panel1.add(new JLabel(CBIntText.get("This entry is a Virtual Entry. Are you sure you want to give this entry an object class?")));
445         panel2.add(btnYes);
446         panel2.add(btnNo);
447
448         panel3.makeWide();
449         panel3.addln(panel1);
450         panel3.addln(panel2);
451
452         pane.add(panel3);
453
454         btnYes.addActionListener(new ActionListener()
455         {
456             public void actionPerformed(ActionEvent e)
457             {
458                 processVirtualEntry();
459             }
460         });
461
462         btnNo.addActionListener(new ActionListener()
463         {
464             public void actionPerformed(ActionEvent e)
465             {
466                 shutVirtualEntryDialog();
467             }
468         });
469         virtualEntryDialog.setSize(475, 125);
470         CBUtility.center(virtualEntryDialog, owner);
471         virtualEntryDialog.setVisible(true);
472     }
473
474     /**
475      * Normally called by the 'Yes' button listener of the virtual entry dialog. This method opens the New Entry dialog
476      * in simple mode (or Change Classes dialog). If the user selects one or more object classes they are added to the
477      * entry and displayed in the table editor.
478      */

479     public void processVirtualEntry()
480     {
481
482         NewEntryWin userData = null;
483         if (dataSource.getSchemaOps() == null)
484         {
485             JOptionPane.showMessageDialog(owner, CBIntText.get("Because there is no schema currently published by the\ndirectory, changing an entry's object class is unavailable."), CBIntText.get("No Schema"), JOptionPane.INFORMATION_MESSAGE);
486             return;
487         }
488         else
489         {
490             shutVirtualEntryDialog(); //TE: kill the prompt window.
491
userData = new NewEntryWin(dataSource, currentEntry.getDN(), this, owner, true);
492             userData.setSize(400, 250);
493             CBUtility.center(userData, owner); //TE: centres window.
494
userData.setVisible(true);
495
496             while (userData.isVisible()) //TE: don't do anything until the New Entry window is closed.
497
{
498                 try
499                 {
500                     wait();
501                 }
502                 catch (Exception JavaDoc e)
503                 {
504                     userData.dispose();
505                 }
506             }
507         }
508
509         if (userData.newObjectClasses != null) //TE: if the user has selected one or more object classes - add them to the entry in the directory.
510
{
511             try
512             {
513                 DXOps dxOps = new DXOps(dataSource.getDirContext());
514                 dxOps.addAttribute(currentEntry.getDN(), userData.newObjectClasses);
515                 dataSource.getEntry(currentEntry.getDN()); //TE: hack?? forces the entry to be read again - otherwise we don't display the naming value.
516
}
517             catch (NamingException JavaDoc e)
518             {
519                 CBUtility.error(TableAttributeEditor.this, CBIntText.get("Unable to add new object classes to {0}.", new String JavaDoc[]{currentEntry.getDN().toString()}), e);
520             }
521         }
522     }
523
524     /**
525      * Disposes of the virtual entry dialog that is opened as a prompt when the user may want to edit a virtual entry.
526      */

527     public void shutVirtualEntryDialog()
528     {
529         if (virtualEntryDialog != null)
530         {
531             virtualEntryDialog.setVisible(false);
532             virtualEntryDialog.dispose();
533         }
534     }
535
536     //
537
// DN checkedDN;
538

539     /**
540      * <p>Displays data that can be modified by the user in a table.</p>
541      * @param entry the entry to be displayed by all the editors
542      * @param ds the datasource the editors may use for more info
543      */

544     public void displayEntry(DXEntry entry, DataSource ds)
545     {
546 // checkedDN = null; // hack - resets promptForSave.
547

548         // Set the globals...
549
currentEntry = entry;
550         dataSource = ds;
551
552         if (entry != null && entry.size() == 0)
553         {
554 // If there is an entry and it's size is zero - it's probably is a virtual entry.
555
// We need to give the user the option of adding an object class to it i.e. so that
556
// it can be added to the directory as a real entry.
557
//
558
// Disable all the buttons except the 'Change Class' button - but rename this button
559
// to 'Add Class' so the user hopefully has a bit more of an idea about what is going on.
560

561 // Sets editor to a blank screen...
562
tableData.clear();
563
564 // Disable all buttons except the 'Change Class' button - rename this one...
565
submit.setEnabled(false);
566             reset.setEnabled(false);
567             changeClass.setText(CBIntText.get("Add Class"));
568             changeClass.setEnabled(true);
569             opAttrs.setEnabled(false);
570
571             virtualEntry = true;
572
573             return;
574         }
575
576         virtualEntry = false;
577
578         // Isn't a virtual entry...
579
if (entry != null)
580             currentDN = entry.getDN();
581
582         // May have been changed to 'Add Class'...
583
changeClass.setText(CBIntText.get("Change Class"));
584
585         // Some quick faffing around, to see if we're coming back from a
586
// change classes operation.
587
if (classChangedOriginalEntry != null)
588         {
589             // If they have the same name, then we're reviewing the same entry - otherwise we've moved on
590
if (entry == null || entry.getDN().equals(classChangedOriginalEntry.getDN()) == false)
591                 classChangedOriginalEntry = null;
592         }
593
594         /*
595          * Check that we're not displaying a new entry, and leaving unsaved changes
596          * behind.
597          *
598          * This turns out to be quite tricky, and involves a bunch 'o special cases.
599          *
600          * First check whether the table data has changed (if not, do nothing)
601          * -> if the new entry is null, prompt user to save
602          * -> OR if the DN has changed, and it wasn't due to a rename, prompt user to save
603          *
604          */

605         if (tableData.changedByUser()) // user made changes - were they saved? (i.e., are we
606
{ // displaying the result of those changes?)
607
boolean prompt = false;
608
609             DXEntry oldEntry = tableData.getOldEntry();
610
611             if (oldEntry != null)
612             {
613                 /*
614                  * The code below is simply checking to see if the name of the
615                  * new entry is different from the old entry, and if it is,
616                  * whether that's due to the old entry being renamed.
617                  */

618                 if (entry == null)
619                 {
620                     prompt = true;
621                 }
622                 //TE: added the isEmpty check see bug: 3194.
623
else if (!oldEntry.getDN().isEmpty() && entry.getDN().equals(oldEntry.getDN()) == false)
624                 {
625                     DN oldParent = oldEntry.getDN().parentDN();
626
627                     DN newParent = entry.getDN().parentDN();
628
629                     if (oldParent.equals(newParent) == false)
630                     {
631                         prompt = true;
632                     }
633                     else
634                     {
635                         if (entry.getDN().getLowestRDN().equals(tableData.getRDN()) == false)
636                         {
637                             prompt = true;
638                         }
639                     }
640                 }
641
642                 if (prompt) // yes, there is a risk of data loss - prompt the user.
643
{
644                     if (promptForSave(false)) // see if the user wants to save their data
645
{
646                         //dataSource.getEntry(entry.getDN()); // queue a request to redisplay
647
return; // this entry (but don't show it this time around).
648
}
649                 }
650             }
651         }
652
653         myEditor.setDataSource(ds); // Sets the DataSource in AttributeValueCellEditor used to get the syntax of attributes.
654

655         // only enable buttons if DataSource
656
// is valid *and* we can modify data...
657

658         if (dataSource == null || entry == null)
659         {
660             submit.setEnabled(false);
661             reset.setEnabled(false);
662             changeClass.setEnabled(false);
663             opAttrs.setEnabled(false);
664         }
665         else
666         {
667             submit.setEnabled(true);
668             reset.setEnabled(true);
669             opAttrs.setEnabled(true);
670
671             if (entry.get("objectclass") != null) // only allow class changes if we can find
672
changeClass.setEnabled(true); // some to start with!
673
}
674
675         myEditor.stopCellEditing();
676
677         if (entry != null)
678         {
679             entry.expandAllAttributes();
680             currentDN = entry.getDN();
681
682             tableData.insertAttributes(entry);
683             popupTableTool.setDN(currentDN); // Sets the DN in SmartPopupTableTool.
684
myEditor.setDN(currentDN); // Sets the DN in the attributeValueCellEditor which can be used to identify the entry that is being modified/
685
}
686         else
687         {
688             tableData.clear(); // Sets editor to a blank screen.
689
}
690
691         tableScroller.getVerticalScrollBar().setValue(0); // Sets the scroll bar back to the top.
692
}
693
694     public JComponent getDisplayComponent()
695     {
696         validate();
697         repaint();
698         return this;
699     }
700
701     public String JavaDoc[] getAttributeValuesAsStringArray(Attribute JavaDoc a)
702             throws NamingException JavaDoc
703     {
704         if (a == null) return new String JavaDoc[0];
705         DXNamingEnumeration e = new DXNamingEnumeration(a.getAll());
706         if (e == null) return new String JavaDoc[0];
707         return e.toStringArray();
708     }
709
710     /**
711      * Test whether the (unordered) object class lists of two attributes contain the same
712      */

713     public boolean objectClassesChanged(DXAttributes a, DXAttributes b)
714     {
715         boolean result = false;
716         try
717         {
718             String JavaDoc[] A = getAttributeValuesAsStringArray(a.getAllObjectClasses());
719             String JavaDoc[] B = getAttributeValuesAsStringArray(b.getAllObjectClasses());
720
721             Object JavaDoc[] test = CBArray.difference(A, B);
722             if (test.length > 0) result = true;
723             test = CBArray.difference(B, A);
724             if (test.length > 0) result = true;
725
726
727             return result;
728         }
729         catch (NamingException JavaDoc e)
730         {
731             log.log(Level.WARNING, "Error in TableAttributeEditor:objectClassesChanged ", e);
732             return true;
733         }
734     }
735
736     /**
737      * Writes the data currently in the table editor to the directory.
738      */

739     public void writeTableData()
740     {
741
742         myEditor.stopCellEditing();
743
744         if (dataSource == null) // if ds is null, data is not modifiable...
745
{
746             CBUtility.error("no datasource to write data to in writeTableData()");
747             return;
748         } // shouldn't happen
749

750         DXEntry oldEntry = tableData.getOldEntry();
751
752         DXEntry newEntry = tableData.getNewEntry();
753
754         /* Check to see if major surgery is needed - whether the user has been
755          * messing with the object class list. */

756
757         if (classChangedOriginalEntry != null)
758         {
759
760             // use the saved state of the pre-class-changed entry as the 'old entry'
761
// state.
762
oldEntry = classChangedOriginalEntry;
763             classChangedOriginalEntry = null; // this is only used once! (either the object class change will
764
// now succeed, or fail - either way, the entry state is reset to
765
// match what's in the directory.)
766

767             if (objectClassesChanged(oldEntry, newEntry))
768             {
769                 oldEntry.removeEmptyAttributes();
770
771                 newEntry.setStatus(oldEntry.getStatus());
772
773                 Object JavaDoc[] delSet = CBArray.difference(oldEntry.toIDStringArray(), newEntry.toIDStringArray());
774
775                 /* if there *are* attributes that should no longer exist, delete them by adding them (blanked)
776                  * to the complete 'newAtts' set of *all* known attributes. */

777
778                 if ((delSet != null) && (delSet.length > 0))
779                 {
780                     for (int i = 0; i < delSet.length; i++)
781                     {
782                         newEntry.put(new DXAttribute(delSet[i].toString())); // overwrite old values with an empty attribute
783
}
784                 }
785             }
786         }
787
788         dataSource.modifyEntry(oldEntry, newEntry);
789     }
790
791     /**
792      * Return the thingumy that should be printed.
793      */

794     public Component getPrintComponent()
795     {
796         return attributeTable;
797     }
798
799     /**
800      * This editor is happy to be used in conjunction with other editors...
801      */

802     public boolean isUnique()
803     {
804         return false;
805     }
806
807     public String JavaDoc getName()
808     {
809         return CBIntText.get("Table Editor");
810     }
811
812     public ImageIcon getIcon()
813     {
814         return new ImageIcon("images" + File.separator + "table.gif");
815     } //TE: returns an icon.
816

817     public String JavaDoc getToolTip()
818     {
819         return CBIntText.get("The table editor is generally used for editing data, it also functions perfectly well as a simple, but robust, entry viewer.");
820     } //TE: returns a tool tip.
821

822     public DataSink getDataSink()
823     {
824         return this;
825     }
826
827     public boolean canCreateEntry()
828     {
829         return true;
830     }
831
832     public void registerComponents(JMenuBar menu, JToolBar buttons, JTree tree, JPopupMenu treeMenu, JFrame jx)
833     {
834     }
835
836     public void unload()
837     {
838     }
839
840     /**
841      * Use the default tree icon system based on naming value or object class.
842      */

843     public ImageIcon getTreeIcon(String JavaDoc rdn)
844     {
845         return null;
846     }
847
848     /**
849      * Use the default popupmenu.
850      */

851     public JPopupMenu getPopupMenu(String JavaDoc rdn)
852     {
853         return null;
854     }
855
856     /**
857      * Don't hide sub entries.
858      */

859     public boolean hideSubEntries(String JavaDoc rdn)
860     {
861         return false;
862     }
863
864     /**
865      * Optionally register a new class loader for atribute value viewers to use.
866      */

867     public void registerClassLoader(ClassLoader JavaDoc loader)
868     {
869         myLoader = loader;
870         myEditor.registerClassLoader(loader);
871     }
872
873     public void setVisible(boolean state)
874     {
875         super.setVisible(state);
876
877         // has to be *after* previous call for SwingMagic reasons.
878
if (state == false && tableData.changedByUser()) // user made changes - were they saved? (i.e., are we
879
{
880             /*
881              * The setVisible() method may be called multiple time. Only prompt
882              * the user the first time.
883              */

884             promptForSave(false);
885         }
886     }
887 }
Popular Tags