⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 smartnode.java

📁 JAVA开源LDAP浏览器jxplorer的源码!
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
package com.ca.directory.jxplorer.tree;

import com.ca.commons.cbutil.CBResourceLoader;
import com.ca.commons.cbutil.CBUtility;
import com.ca.commons.naming.*;
import com.ca.directory.jxplorer.JXplorer;

import javax.naming.NamingEnumeration;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import java.awt.datatransfer.*;
import java.io.File;
import java.io.IOException;
import java.text.CollationKey;
import java.text.Collator;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/*
 *    SmartNode is a utility class for storing class/value/icon combinations, as
 *    well as the standard MutableTreeNode information from the swing.tree package. 
 *    combinations.  Takes arguments of form 'cn=Fred+sn=Nurk: ...'
 *    and parses them to:
 *       distinguishedValue = 'Fred+Nurk'
 *
 *    The class also tries to work out an appropriate icon for displaying the node.
 *    It uses the objectClass attributes, when these are known, or a default icon
 *    keyed to the ldap RDN attribute (i.e. 'c','o','cn' etc.)
 *
 *    WARNING: At present, this only works for <b>single</b> valued RDNs!
 */
 
 // Mmmm... wonder if it's worth trying to include an explicit DN for every node,
 // rather than generating it from the tree?
 // ans. Yes it would be DAMN useful, but there might be some stress keeping them
 // all updated when parent nodes changed... better to have them able to work it 
 // out dynamically...

 
public class SmartNode extends DefaultMutableTreeNode implements  Transferable, Comparable
{
    private static RDN emptyRDN = new RDN(); 

    public RDN rdn = emptyRDN;
    
    /*
     *  A misnomer - this is actually the naming attribute of the RDN.
     */
    String nodeObjectClass = null;

    boolean dummy = false;
    boolean root = false;
    boolean alwaysRefresh = false;
    boolean blankRoot = false;                       // if root is blank, use ROOTNAME or blank depending on context
    //boolean objectClassSet = false;                  // whether a true object class is known.
    boolean structural = false;                      // whether this is just to fill the tree out, but doesn't represent an entry... (i.e. in a search tree response)


    static Hashtable icons = new Hashtable(16);      // the icons displayed in the tree
    static boolean useIcons;

    public static final String ROOTNAME = "World";
    public static final String DUMMYMESSAGE = "reading...";

    ImageIcon icon = null;

    JPopupMenu menu = null;  // an optional popup menu.

	private static boolean initialised = false;

  	final public static DataFlavor UNICODETEXT = DataFlavor.getTextPlainUnicodeFlavor();

	DataFlavor[] flavours = { UNICODETEXT };

    // get a single platform specific language collator for use in sorting.
    private static Collator myCollator = Collator.getInstance();

    // the collation key of the node, used for sorting.
    private CollationKey collationKey;

    private static Logger log = Logger.getLogger(SmartNode.class.getName());

/**
 *   Pre load the image icons, we'll be using them a lot.
 *
 *   Image icons are stored in the 'icons' hashtable, keyed on their
 *   file name stem. (i.e. person.gif is stored with key 'person')
 */
 
 
// XXX Rewrite to use resource loader as well...!
// XXX (and possibly only create icons when needed?)
 
    static public void init(CBResourceLoader resourceLoader)
    {
    	if (initialised) return;	// we only need to run this method once, but
    	initialised = true;			// it's not an error to call it multiple times.
    
        String iconPath = JXplorer.getProperty("dir.icons");

        if (iconPath == null) 
        {
            useIcons = false;
            return;
        }
        
        String[] extensions = {"jpg","gif","jpeg"};
        
        String[] iconFiles = CBUtility.readFilteredDirectory(iconPath, extensions);
        
        /*
         *    Emergency BackUp : If the icon directory is bad, try to
         *    find a working one, and if successfull, save it as new 
         *    default value.
         */
        if (iconFiles == null)
        {
            log.warning("can't find icon directory " + iconPath + " trying to find /icons directory");
            iconPath = JXplorer.localDir + "icons" + File.separator;
            iconFiles = CBUtility.readFilteredDirectory(iconPath, extensions);
            if (iconFiles == null)
            {
                log.warning("Can't find icon directory; check 'dir.icons=' line in dxconfig.txt.");
                return;
            }
            log.warning("Recovered!  - iconPath reset to " + iconPath);
            JXplorer.myProperties.setProperty("dir.icons", iconPath);
        }
         
        for (int i=0; i<iconFiles.length; i++)
        {
            String stem = iconFiles[i].substring(0,iconFiles[i].lastIndexOf('.'));
            // save icon names *in lower case*
            icons.put(stem.toLowerCase(), new ImageIcon(iconPath + iconFiles[i]));
        }
        
        // get any extra icons available in resource files...
        
        try
        {

	        String[] extraIcons = resourceLoader.getPrefixedResources("icons/");
	        for (int i=0; i<extraIcons.length; i++)
	        {
	        	String iconName = extraIcons[i];
	        	String stem = iconName.substring(6);
	        	int endpos = stem.lastIndexOf('.');
				if (stem.length() > 0 && endpos != -1)
				{
            // save icon names *in lower case*
					stem = stem.substring(0,endpos).toLowerCase();
		        	byte[] b = resourceLoader.getResource(iconName);
		        	icons.put(stem, new ImageIcon(b));
	        	}
	        }
        }
		catch (Exception e)
		{     
			log.warning("Error trying to load icons from resource files: " + e);
		}
        useIcons = icons.containsKey("default"); // only use icons if we have a fallback default

    }
    
    /**
     *    Constructor for dummy nodes; used to flag possibly expandable nodes 
     *    when their children status is unknown (due to not having been read 
     *    from the directory yet.)
     */
    
    public SmartNode() 
    { 
        super(); 
        log.finer("created null SmartNode (I)");
        dummy = true; 
        nodeObjectClass="default"; 
        //distinguishedValue = "null"; 
    }
    
    /**
     * Simple constructor, for when objectClass attributes are not known
     * @param rdnString the relative distinguished name, e.g. 'cn=fnord'
     */
     
    public SmartNode(String rdnString) 
    { 
        super(); 
        log.finer("created SmartNode (II) :" + rdnString);
        update(rdnString); 
    }
    
    /**
     * Simple constructor, for when objectClass attributes are not known
     * @param rdn the relative distinguished name, e.g. 'cn=fnord'
     */
     
    public SmartNode(RDN rdn) 
    { 
        super(); 
        log.finer("created SmartNode (IIb) :" + rdn);
        update(rdn); 
    }
    
    /**
     * Copy constructor, for when an RDN is the same, but the tree position
     * (and hence the full DN) is different.  <b>Does Not</b> makes copies of children:
     * use copyChildren() separately if you want this.
     *
     *  @param S the node to copy for initial values.
     */
     
     public SmartNode(SmartNode S) 
     { 
         super(); 
         log.finer("created SmartNode (III) :" + S.toString());
         //distinguishedValue = new String(S.distinguishedValue);
         nodeObjectClass = new String(S.nodeObjectClass);
         icon = S.icon;
         update(S.getRDN());
         dummy = S.dummy;
     }
    
    /** 
     *  When objectClass attributes are known, we try to be cleverer getting
     *  the icon for this node.
     * 
     *  @param RDN the RDN of the new node (e.g. 'cn=fnord')
     *  @param objectClasses a javax.naming.directory Attribute containing
     *         a list of the node's ldap objectClasses.
     */

    // XXX how to choose between conflicting object classes?  At the moment
    // XXX this picks up the first one that it can match an icon to...

    public SmartNode(String RDN, DXAttribute objectClasses) 
    {
        super();
        log.finer("created SmartNode (IV) :" + RDN);
        
        update(RDN);
        
        setTrueObjectClass(objectClasses);
        
    }        

    /**
     *    If available, it is best to use the object class of the 
     *    entry (to determine which icon to display 'n stuff).  This
     *    does a quick 'n dirty search if the object class attribute
     *    is known.  Better is to manually set the deepest object class,
     *    but this requires knowledge of the schema 'n stuff...
     */
             
    public void setTrueObjectClass(DXAttribute objectClasses)
    {        
        try
        { 
            NamingEnumeration obClasses = objectClasses.getAll();        
            while (obClasses.hasMoreElements())  // use non-error-checking form
            {
                String value = obClasses.nextElement().toString();
                if (setTrueObjectClass(value)) 
                    break;
            }                    
        }
        catch (javax.naming.NamingException e)
        {
            log.log(Level.WARNING, "Naming Exception parsing " + rdn +"\n", e);
        }
    }

    /** 
     *    This attempts to set the object class of the node to a particular
     *    value.  It returns true if an icon is available for that object
     *    class, false otherwise.
     */
     
    public boolean setTrueObjectClass(String value)
    {
        value = value.toLowerCase();
        if (icons.containsKey(value))
        {
            nodeObjectClass = value;
            icon = (ImageIcon) icons.get(nodeObjectClass);
            
            return true;
        }
        else
            return false;    
    }

    /**
     *    Takes an ldap RDN string such as 'ou=DemoCorp', and breaks it into
     *    a nodeObjectClass ('ou') and a distinguished value ('DemoCorp'),
     *    and replaces the existing values of these variables.
     *
     *    @param rdn the new RDN to replace the nodes current value.
     */

    public void update(String rdn)
    {
        try 
        { 
            update(new RDN(rdn)); 
        } 
        catch (Exception e) 
        {
            log.warning("unexpected error in SmartNode:update() " + e.toString());
            e.printStackTrace();
        } // should never throw an exception...
    }
    
    public void update(RDN newRDN)
    {

        if (newRDN==null) 
            setRdn(emptyRDN);
        else    
            setRdn(newRDN);

        if (rdn.isEmpty())            // probably a root entry
        {
            nodeObjectClass="default"; 
        }

        if (nodeObjectClass == null)  // in extremis, grab the ldap rdn attribute and use that for icons...
            nodeObjectClass = rdn.getAtt(0);  // use root 'cause DN has only one element...

        // create a collation key for fast language-sensitive sorting...
        // (note toLowerCase() for case insensitive sorting - remove for case sensitive...

        // XXX this is where features such as sorting by object class, or sorting by naming attribute, can be
        // XXX put...

        // 'false' is the default
        boolean sortByNamingAttribute = ("true".equals(JXplorer.getProperty("sort.by.naming.attribute")));

        if (rdn.isMultiValued())
        {
            StringBuffer key = new StringBuffer(rdn.toString().length());
            for (int i=0; i<rdn.size(); i++)
            {
                if (sortByNamingAttribute)
                    key.append(rdn.getRawVal(i)).append(rdn.getAtt(i));
                else
                    key.append(rdn.getAtt(i)).append(rdn.getRawVal(i));
            }
            collationKey = myCollator.getCollationKey(key.toString().toLowerCase());
        }
        else
        {
            if (sortByNamingAttribute)
                collationKey = myCollator.getCollationKey(nodeObjectClass + getDistinguishedValue().toLowerCase());
            else
                collationKey = myCollator.getCollationKey(getDistinguishedValue().toLowerCase() + nodeObjectClass);
        }
    }

    /**
     *    A utility ftn that makes copies of all the child nodes
     *    given to it, and adds the copies to the current node.
     *    @param children an enumeration of SmartNode(s), to copy
     *           and add.
     */
     
    public void copyChildren(Enumeration children)
    {
        while (children.hasMoreElements())
        {
            SmartNode A = new SmartNode((SmartNode)children.nextElement());
            add(A);
        }
    }
    
    /**
     *    Returns the RDN of the tree node as a String.
     *    @return the RDN as a string.
     */
     
    public RDN getRDN() {
        return (blankRoot==true)?emptyRDN:rdn; }
    

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -