/* * This file is part of ELKI: * Environment for Developing KDD-Applications Supported by Index-Structures * * Copyright (C) 2017 * ELKI Development Team * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package de.lmu.ifi.dbs.elki.gui.util; import java.util.HashMap; import java.util.List; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreeNode; /** * Build a tree of available classes for use in Swing UIs. * * @author Erich Schubert * @since 0.7.0 * * @apiviz.has TreeNode */ public final class ClassTree { /** * Private constructor. Static methods only. */ private ClassTree() { // Do not use. } /** * Build the class tree for a given set of choices. * * @param choices Class choices * @param rootpkg Root package name (to strip / hide) * @return Root node. */ public static TreeNode build(List<Class<?>> choices, String rootpkg) { MutableTreeNode root = new PackageNode(rootpkg, rootpkg); HashMap<String, MutableTreeNode> lookup = new HashMap<>(); if(rootpkg != null) { lookup.put(rootpkg, root); } lookup.put("de.lmu.ifi.dbs.elki", root); lookup.put("", root); // Use the shorthand version of class names. String prefix = rootpkg != null ? rootpkg + "." : null; for(Class<?> impl : choices) { String name = impl.getName(); name = (prefix != null && name.startsWith(prefix)) ? name.substring(prefix.length()) : name; int plen = (impl.getPackage() != null) ? impl.getPackage().getName().length() + 1 : 0; MutableTreeNode c = new ClassNode(impl.getName().substring(plen), name); MutableTreeNode p = null; int l = name.lastIndexOf('.'); while(p == null) { if(l < 0) { p = root; break; } String pname = name.substring(0, l); p = lookup.get(pname); if(p != null) { break; } l = pname.lastIndexOf('.'); MutableTreeNode tmp = new PackageNode(l >= 0 ? pname.substring(l + 1) : pname, pname); tmp.insert(c, 0); c = tmp; lookup.put(pname, tmp); name = pname; } p.insert(c, p.getChildCount()); } // Simplify tree, except for root node for(int i = 0; i < root.getChildCount(); i++) { MutableTreeNode c = (MutableTreeNode) root.getChildAt(i); MutableTreeNode c2 = simplifyTree(c, null); if(c != c2) { root.remove(i); root.insert(c2, i); } } return root; } /** * Simplify the tree. * * @param cur Current node * @param prefix Prefix to add * @return Replacement node */ private static MutableTreeNode simplifyTree(MutableTreeNode cur, String prefix) { if(cur instanceof PackageNode) { PackageNode node = (PackageNode) cur; if(node.getChildCount() == 1) { String newprefix = (prefix != null) ? prefix + "." + (String) node.getUserObject() : (String) node.getUserObject(); cur = simplifyTree((MutableTreeNode) node.getChildAt(0), newprefix); } else { if(prefix != null) { node.setUserObject(prefix + "." + (String) node.getUserObject()); } for(int i = 0; i < node.getChildCount(); i++) { MutableTreeNode c = (MutableTreeNode) node.getChildAt(i); MutableTreeNode c2 = simplifyTree(c, null); if(c != c2) { node.remove(i); node.insert(c2, i); } } } } else if(cur instanceof ClassNode) { ClassNode node = (ClassNode) cur; if(prefix != null) { node.setUserObject(prefix + "." + (String) node.getUserObject()); } } return cur; } /** * Tree node representing a single class. * * @author Erich Schubert * * @apiviz.exclude */ public static class PackageNode extends DefaultMutableTreeNode { /** * Serial version */ private static final long serialVersionUID = 1L; /** * Class name. */ private String pkgname; /** * Current class name. * * @param display Displayed name * @param pkgname Actual class name */ public PackageNode(String display, String pkgname) { super(display); this.pkgname = pkgname; } /** * Return the package name. * * @return Package name */ public String getPackageName() { return pkgname; } } /** * Tree node representing a single class. * * @author Erich Schubert * * @apiviz.exclude */ public static class ClassNode extends DefaultMutableTreeNode { /** * Serial version */ private static final long serialVersionUID = 1L; /** * Class name. */ private String clsname; /** * Current class name. * * @param display Displayed name * @param clsname Actual class name */ public ClassNode(String display, String clsname) { super(display); this.clsname = clsname; } /** * Return the class name. * * @return Class name */ public String getClassName() { return clsname; } } }