001package jmri.jmrit.catalog;
002
003import java.io.File;
004import javax.swing.tree.DefaultMutableTreeNode;
005import javax.swing.tree.DefaultTreeModel;
006import jmri.InstanceManagerAutoDefault;
007import jmri.util.FileUtil;
008
009/**
010 * TreeModel used by CatalogPane to create a tree of resources.
011 * <p>
012 * Accessed via the instance() member, as we expect to have only one of these
013 * models.
014 * <p>
015 * The tree has two top-level visible nodes. One, "icons", represents the
016 * contents of the icons directory in the resources tree in the .jar file. The
017 * other, "files", is all files found in the "resources" filetree in the
018 * preferences directory. Note that this means that files in the distribution
019 * directory are _not_ included.
020 * <p>
021 * As a special case "simplification", the catalog tree will not contain CVS
022 * directories, or files whose name starts with a "."
023 *
024 * @author Bob Jacobsen Copyright 2002
025 */
026public class CatalogTreeModel extends DefaultTreeModel implements InstanceManagerAutoDefault {
027
028    public CatalogTreeModel() {
029
030        super(new DefaultMutableTreeNode("Root"));
031        dRoot = (DefaultMutableTreeNode) super.getRoot();  // this is used because we can't store the DMTN we just made during the super() call
032
033        // we manually create the first node, rather than use
034        // the routine, so we can name it.
035        CatalogTreeModel.this.insertResourceNodes(resourceRoot, resourceRoot, dRoot);
036        FileUtil.createDirectory(FileUtil.getUserResourcePath());
037        CatalogTreeModel.this.insertFileNodes("files", fileRoot, dRoot);
038
039    }
040
041    /**
042     * Recursively add a representation of the resources below a particular
043     * resource
044     *
045     * @param pName   Name of the resource to be scanned; this is only used for
046     *                the human-readable tree
047     * @param pPath   Path to this resource, including the pName part
048     * @param pParent Node for the parent of the resource to be scanned, e.g.
049     *                where in the tree to insert it.
050     */
051    void insertResourceNodes(String pName, String pPath, DefaultMutableTreeNode pParent) {
052        File fp = new File(pPath);
053        if (!fp.exists()) {
054            return;
055        }
056
057        // suppress overhead files
058        if (fp.getName().startsWith(".")) {
059            return;
060        }
061        if (fp.getName().equals("CVS")) {
062            return;
063        }
064
065        // first, represent this one
066        DefaultMutableTreeNode newElement = new DefaultMutableTreeNode(pName);
067        insertNodeInto(newElement, pParent, pParent.getChildCount());
068        // then look for children and recurse
069        if (fp.isDirectory()) {
070            // work on the kids
071            String[] sp = fp.list();
072
073            if (sp == null) {
074                log.warn("unexpected null list() in insertResourceNodes from \"{}\"", pPath);
075                return;
076            }
077
078            for (String item : sp) {
079                log.trace("Descend into resource: {}", item);
080                insertResourceNodes(item, pPath + "/" + item, newElement);
081            }
082        }
083    }
084
085    /**
086     * Recursively add a representation of the files below a particular file
087     *
088     * @param name   Name of the file to be scanned
089     * @param path   the path to the file
090     * @param parent Node for the parent of the file to be scanned
091     */
092    void insertFileNodes(String name, String path, DefaultMutableTreeNode parent) {
093        File fp = new File(path);
094        if (!fp.exists()) {
095            return;
096        }
097
098        // suppress overhead files
099        if (fp.getName().startsWith(".")) {
100            return;
101        }
102        if (fp.getName().equals("CVS")) {
103            return;
104        }
105
106        // represent this one
107        DefaultMutableTreeNode newElement = new DefaultMutableTreeNode(name);
108        insertNodeInto(newElement, parent, parent.getChildCount());
109        // then look for childrent and recurse
110        // getSystemResource is a URL, getFile is the filename string
111        if (fp.isDirectory()) {
112            // work on the kids
113            String[] sp = fp.list();
114            if (sp!=null) {
115                for (String sp1 : sp) {
116                    log.debug("Descend into file: {}",sp1);
117                    insertFileNodes(sp1, path + "/" + sp1, newElement);
118                }
119            }
120        }
121    }
122
123    DefaultMutableTreeNode dRoot;
124
125    /**
126     * Starting point in the .jar file for the "icons" part of the tree
127     */
128    static final String resourceRoot = "resources";
129    static final String fileRoot = FileUtil.getUserResourcePath();
130
131    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(CatalogTreeModel.class);
132
133}