📄 smarttree.java
字号:
*
* @param s the source of data for initialising SmartNodes etc.
*/
public void registerDataSource(DataSource s)
{
if (s == null) return; // sanity check
log.fine("registering data source for tree " + getName());
treeDataSource = s;
// Register ourselves as interested in *all* data events that pass through this data source...
treeDataSource.addDataListener(this);
//setRoot(rootDN);
}
/**
* Returns the active data source that has been registered for the tree.
*
* @return the data source used by the tree.
*/
public DataSource getDataSource()
{
return treeDataSource;
}
/**
* Register a <code>DataSink</code>.
* DataSinks are entities that are interested in
* displaying the data corresponding to a particular
* SmartNode (that is, the attributes of the node). There
* may be a number of such sinks in operation simultaneously.
* This registration method adds a new data sink to the list
* of active data sinks.
*
* @param s a new data sink to add to the list of active sinks.
*/
public void registerDataSink(DataSink s)
{
treeDataSinks.addElement(s);
if (s instanceof AttributeDisplay)
registerPluggableEditorSource((AttributeDisplay) s);
}
/**
* Quick Hack to clear out a tree preparitory to loading a new
* one. May need revisiting to do a neater data clean up.
*/
public void clearTree()
{
root.removeAllChildren();
setRoot(NODATA);
treeModel.setRoot(root);
treeModel.reload();
clearEntry();
for (int i = 0; i < treeDataSinks.size(); i++)
((DataSink) treeDataSinks.elementAt(i)).displayEntry(null, null);
}
/**
* Takes a node, and adds a bunch of children.
*
* @param parent the node to add the children too
* @param children an enumeration of NameClassPair containing
* the names of the child nodes
*/
public void addCutting(SmartNode parent, NamingEnumeration children)
{
// sanity checks
if (parent == null)
{
return;
}
if (children == null)
{
log.warning("null child list in addCutting...!");
return;
}
if (children != null)
{
// Step 1: Clear any dummy nodes prior to adding real ones.
if (parent.getChildCount() == 1 && ((SmartNode) parent.getChildAt(0)).isDummy())
{
parent.removeAllChildren();
}
// Step 2: Add new children (nb - there may be *zero* children to add, in which case parent is actually a leaf node
while (children.hasMoreElements())
{
NameClassPair np = (NameClassPair) children.nextElement();
SmartNode child;
// &(*%& pointless bloody jndi; the one time it would be useful for them
// to use 'Name' objects they use strings; in 'NameClassPair' no less. What a joke.
DN temp = new DN(np.getName());
child = new SmartNode(temp.getRDN(temp.size() - 1));
if (parent.hasChild(child.toString()) == false) // don't add a child twice!
{
parent.add(child);
//treeModel.insertNodeInto(child, parent, parent.getChildCount());
// Step 3: try to recover the object class list for the node to use.
if (np instanceof SearchResult)
{
doObjectClassSpecificHandling(child, ((SearchResult) np));
}
}
//XXX is it more efficient to work on nodes, then call nodeStructureChanged?
//XXX i.e. parent.add(child);
if (child.getAllowsChildren())
// treeModel.insertNodeInto(new SmartNode(), child, 0);
child.add(new SmartNode());
//parent.add(child);
}
parent.sort();
treeModel.nodeStructureChanged(parent);
}
}
public void registerPluggableEditorSource(AttributeDisplay display)
{
pluggableEditorSource = display;
}
/**
* HERE BE MAGIC
* <p/>
* In order for pluggable editors to truncate trees, special displays for aliases,
* object class based icons, and object class based popup menus, we need special
* handling for nodes where the object class is known.<p><
* <p/>
* This registers the object class with a node, and checks to see if any pluggable
* editors are known corresponding to these object classes that are unique, and
* have special requests (for icons/popup menus/etc.)<p>
* <p/>
* This is all optional stuff - the browser will work fine if these details are
* not available, but more complex pluggable functionality will not be possible.
*
* @param child the smart node to register the object classes with
* @param ocs a search result containing the object class attribute (we hope).
*/
protected void doObjectClassSpecificHandling(SmartNode child, SearchResult ocs)
{
if (ocs == null) return; // can't do anything.
Attributes atts = ocs.getAttributes();
if (atts == null || atts.size() == 0) return; // still can't do anything.
Attribute OC;
try // the usual fuss and bother to retrieve the object class attribute. X500 does this so much better...
{
OC = atts.get("objectClass");
if (OC == null)
OC = atts.get("objectclass");
if (OC == null) // there *may* only be one attribute, which *may* be a wierd capitalisation of object class...
{
Attribute test = (Attribute) atts.getAll().next();
if ("objectclass".equals(test.getID().toLowerCase()))
OC = test;
}
if (OC == null) // give up! It doesn't have one.
return;
if ((OC instanceof DXAttribute) == false)
OC = new DXAttribute(OC);
OC = DXAttributes.getAllObjectClasses((DXAttribute) OC); // order it...
doObjectClassSpecificHandling(child, OC);
}
catch (Exception e)
{
log.warning("Warning error doing object class specific handling for tree nodes: " + e);
}
}
/**
* HERE BE MAGIC
* <p/>
* In order for pluggable editors to truncate trees, special displays for aliases,
* object class based icons, and object class based popup menus, we need special
* handling for nodes where the object class is known.<p><
* <p/>
* This registers the object class with a node, and checks to see if any pluggable
* editors are known corresponding to these object classes that are unique, and
* have special requests (for icons/popup menus/etc.)<p>
* <p/>
* This is all optional stuff - the browser will work fine if these details are
* not available, but more complex pluggable functionality will not be possible.
*
* @param child the smart node to register the object classes with
* @param OC objectclass attribute
*/
protected void doObjectClassSpecificHandling(SmartNode child, Attribute OC)
{
if (OC instanceof DXAttribute == false)
OC = new DXAttribute(OC);
child.setTrueObjectClass((DXAttribute) OC); // and register it with smartnode
// *** TRICKYNESS ***
//
// The code below looks for, and interogates, any pluggable editors
// that are related to the node in order to determine any special
// handling requirements such as custom popup menus, icons, or
// subtree truncations.
if (pluggableEditorSource != null)
{
PluggableEditor editor = pluggableEditorSource.getUniqueEditor(OC);
if (editor != null)
{
if (editor.hideSubEntries(child.toString()))
child.setAllowsChildren(false);
ImageIcon newIcon = editor.getTreeIcon(child.toString());
if (newIcon != null)
child.setIcon(newIcon);
if (editor.getPopupMenu(child.toString()) != null)
child.setPopupMenu(editor.getPopupMenu(child.toString()));
}
}
}
/**
* Takes an entry, usually from a search result list, and adds it to
* the tree, creating parent nodes if necessary.
*
* @param newDN the new DN to create a smart Node for, and add to the tree.
*/
public SmartNode addNode(DN newDN)
{
if (newDN == null) return null;
SmartNode parent, child = null;
if (rootDN.toString().equals(NODATA))
{
setRoot(""); // the same as 'cn=World'
}
// Walk through the current newDN, creating new nodes
// as necessary until we can add a new node corresponding to
// the lowest RDN of the newDN.
parent = root;
RDN rdn;
for (int i = 0; i < newDN.size(); i++)
{
rdn = newDN.getRDN(i);
Enumeration children = parent.children();
child = null;
while (children.hasMoreElements())
{
child = (SmartNode) children.nextElement();
if (child.isDummy()) // strip any dummy nodes en passent
parent.remove(child);
else if (child.rdnEquals(rdn)) // and check if the node already exists (before overwritting it below)
break;
child = null;
}
if (child == null) // if the node doesn't exist...
{
child = new SmartNode(rdn); // ... create it
if (i < newDN.size() - 1)
{
child.setStructural(true);
}
parent.add(child); // ... add it to the parent
parent.sort();
treeModel.nodeStructureChanged(parent);
parent = child;
}
else
{
parent = child; // reset parent pointer for next turn around
if (i == newDN.size() - 1)
child.setStructural(false);
}
}
// setSelectionPath(treeModel.getPathForDN(newDN)); //TE: make sure its selected.
return parent;
}
/**
* Refresh the display of a given volatile dn or node.
*/
public void refresh(DN dn)
{
if (dn != null) //TE: make sure the dn is not null.
{
treeDataSource.getChildren(dn);
}
}
/**
* Forces a refresh of the Editor Pane. Currently is used by the tab listener in
* JXplorer for when the user changes tabs the correct entry display is updated
* depending on the entry selected in the tree of the tab that is selected.
* (see Bug 2243).
* .
*/
public void refreshEditorPane()
{
//TE: was... if(entry!=null && treeDataSource!=null)
pluggableEditorSource.refreshEditors(entry, treeDataSource);
}
/**
* Gets the DN of the currently selected tree node (or the root Node,
* if no node is selected).
*
* @return DN the distinguished name of the current SmartNode.
*/
public DN getCurrentDN()
{
return (currentDN == null) ? rootDN : currentDN;
}
/**
* Displays a null entry in the table editor and the html view.
* Intended to be used if an entry has been deleted.
*/
public void clearEntry()
{
setEntry(null);
pluggableEditorSource.displayEntry(null, treeDataSource);
}
/**
* removes everything except the root DN node(s), and
* sets things up as they were in the beginning, the
* point being to force the tree to reload from the
* data source, which has changed independantly of the
* tree...
*/
public void collapse()
{
String dn = rootDN.toString();
if (dn.equals(NODATA)) return; // don't bother!
try
{
NamingEnumeration en = treeDataSource.getChildren(rootDN).getEnumeration();
if (en != null)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -