/* * Copyright (c) 2005-2008 Substance Kirill Grouchnikov. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * o Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * o Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * o Neither the name of Substance Kirill Grouchnikov nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package test.check; import java.awt.BorderLayout; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Enumeration; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import javax.swing.Icon; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JScrollPane; import javax.swing.JTree; import javax.swing.UIManager; import javax.swing.border.EmptyBorder; import javax.swing.filechooser.FileSystemView; import javax.swing.tree.DefaultTreeCellRenderer; import javax.swing.tree.TreeNode; import org.pushingpixels.lafwidget.animation.AnimationConfigurationManager; import org.pushingpixels.substance.api.SubstanceLookAndFeel; import org.pushingpixels.substance.api.renderers.SubstanceDefaultTreeCellRenderer; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.layout.FormLayout; /** * Test application panel for testing {@link JTree} component and * {@link SubstanceLookAndFeel#TREE_SMART_SCROLL_ANIMATION_KIND}. * * @author Kirill Grouchnikov */ public class FileTreePanel extends ControllablePanel implements Deferrable { private boolean isInitialized; @Override public boolean isInitialized() { return this.isInitialized; } /** * File system view. */ protected static FileSystemView fsv = FileSystemView.getFileSystemView(); /** * Renderer for the file tree. * * @author Kirill Grouchnikov */ private static class SubstanceFileTreeCellRenderer extends SubstanceDefaultTreeCellRenderer { /** * Icon cache to speed the rendering. */ private Map<String, Icon> iconCache = new HashMap<String, Icon>(); /** * Root name cache to speed the rendering. */ private Map<File, String> rootNameCache = new HashMap<File, String>(); /* * (non-Javadoc) * * @seeorg.pushingpixels.substance.SubstanceDefaultTreeCellRenderer# * getTreeCellRendererComponent(javax.swing.JTree, java.lang.Object, * boolean, boolean, boolean, int, boolean) */ @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { FileTreeNode ftn = (FileTreeNode) value; File file = ftn.file; String filename = ""; if (file != null) { if (ftn.isFileSystemRoot) { // long start = System.currentTimeMillis(); filename = rootNameCache.get(file); if (filename == null) { filename = fsv.getSystemDisplayName(file); rootNameCache.put(file, filename); } // long end = System.currentTimeMillis(); // System.out.println(filename + ":" + (end - start)); } else { filename = file.getName(); } } JLabel result = (JLabel) super.getTreeCellRendererComponent(tree, filename, sel, expanded, leaf, row, hasFocus); if (file != null) { Icon icon = iconCache.get(filename); if (icon == null) { // System.out.println("Getting icon of " + filename); icon = fsv.getSystemIcon(file); iconCache.put(filename, icon); } result.setIcon(icon); } return result; } } /** * Renderer for the file tree. * * @author Kirill Grouchnikov */ private static class FileTreeCellRenderer extends DefaultTreeCellRenderer { /** * Icon cache to speed the rendering. */ private Map<String, Icon> iconCache = new HashMap<String, Icon>(); /** * Root name cache to speed the rendering. */ private Map<File, String> rootNameCache = new HashMap<File, String>(); /* * (non-Javadoc) * * @seeorg.pushingpixels.substance.SubstanceDefaultTreeCellRenderer# * getTreeCellRendererComponent(javax.swing.JTree, java.lang.Object, * boolean, boolean, boolean, int, boolean) */ @Override public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row, boolean hasFocus) { FileTreeNode ftn = (FileTreeNode) value; File file = ftn.file; String filename = ""; if (file != null) { if (ftn.isFileSystemRoot) { // long start = System.currentTimeMillis(); filename = rootNameCache.get(file); if (filename == null) { filename = fsv.getSystemDisplayName(file); rootNameCache.put(file, filename); } // long end = System.currentTimeMillis(); // System.out.println(filename + ":" + (end - start)); } else { filename = file.getName(); } } JLabel result = (JLabel) super.getTreeCellRendererComponent(tree, filename, sel, expanded, leaf, row, hasFocus); if (file != null) { Icon icon = iconCache.get(filename); if (icon == null) { // System.out.println("Getting icon of " + filename); icon = fsv.getSystemIcon(file); iconCache.put(filename, icon); } result.setIcon(icon); } return result; } } /** * A node in the file tree. * * @author Kirill Grouchnikov */ private static class FileTreeNode implements TreeNode { /** * Node file. */ private File file; /** * Children of the node file. */ private List<File> children; /** * Parent node. */ private TreeNode parent; /** * Indication whether this node corresponds to a file system root. */ private boolean isFileSystemRoot; /** * Creates a new file tree node. * * @param file * Node file * @param isFileSystemRoot * Indicates whether the file is a file system root. * @param parent * Parent node. */ public FileTreeNode(File file, boolean isFileSystemRoot, TreeNode parent) { this.file = file; this.isFileSystemRoot = isFileSystemRoot; this.parent = parent; this.children = new ArrayList<File>(); File[] children = file.listFiles(); if (children != null) { for (File child : file.listFiles()) { if (fsv.isHiddenFile(child)) continue; this.children.add(child); } Collections.sort(this.children, new Comparator<File>() { @Override public int compare(File o1, File o2) { if (o1.equals(o2)) return 0; if (o1.isDirectory() && o2.isFile()) return -1; if (o1.isFile() && o2.isDirectory()) return 1; int result = fsv.getSystemDisplayName(o1).toLowerCase() .compareTo( fsv.getSystemDisplayName(o2) .toLowerCase()); if (result != 0) return result; return o1.compareTo(o2); } }); } } /** * Creates a new file tree node. * * @param children * Children files. */ public FileTreeNode(List<File> children) { this.file = null; this.parent = null; this.children = children; } /* * (non-Javadoc) * * @see javax.swing.tree.TreeNode#children() */ public Enumeration children() { final int elementCount = this.children.size(); return new Enumeration<File>() { int count = 0; /* * (non-Javadoc) * * @see java.util.Enumeration#hasMoreElements() */ public boolean hasMoreElements() { return count < elementCount; } /* * (non-Javadoc) * * @see java.util.Enumeration#nextElement() */ public File nextElement() { if (count < elementCount) { return children.get(count++); } throw new NoSuchElementException("Vector Enumeration"); } }; } /* * (non-Javadoc) * * @see javax.swing.tree.TreeNode#getAllowsChildren() */ public boolean getAllowsChildren() { return true; } /* * (non-Javadoc) * * @see javax.swing.tree.TreeNode#getChildAt(int) */ public TreeNode getChildAt(int childIndex) { return new FileTreeNode(this.children.get(childIndex), this.parent == null, this); } /* * (non-Javadoc) * * @see javax.swing.tree.TreeNode#getChildCount() */ public int getChildCount() { return this.children.size(); } /* * (non-Javadoc) * * @see javax.swing.tree.TreeNode#getIndex(javax.swing.tree.TreeNode) */ public int getIndex(TreeNode node) { FileTreeNode ftn = (FileTreeNode) node; for (int i = 0; i < this.children.size(); i++) { if (ftn.file.equals(this.children.get(i))) return i; } return -1; } /* * (non-Javadoc) * * @see javax.swing.tree.TreeNode#getParent() */ public TreeNode getParent() { return this.parent; } /* * (non-Javadoc) * * @see javax.swing.tree.TreeNode#isLeaf() */ public boolean isLeaf() { return (this.getChildCount() == 0); } } /** * The file tree. */ private JTree tree; /** * Creates the file tree panel. */ public FileTreePanel() { this.setLayout(new BorderLayout()); } public synchronized void initialize() { List<File> rootsList = new ArrayList<File>(); for (File child : File.listRoots()) { rootsList.add(child); } FileTreeNode rootTreeNode = new FileTreeNode(rootsList); this.tree = new JTree(rootTreeNode); this.tree.setCellRenderer((UIManager.getLookAndFeel() instanceof SubstanceLookAndFeel) ? new SubstanceFileTreeCellRenderer() : new FileTreeCellRenderer()); this.tree.setRootVisible(false); final JScrollPane jsp = new JScrollPane(this.tree); jsp.setBorder(new EmptyBorder(0, 0, 0, 0)); this.add(jsp, BorderLayout.CENTER); FormLayout lm = new FormLayout("right:pref, 4dlu, fill:pref:grow", ""); DefaultFormBuilder builder = new DefaultFormBuilder(lm, new ScrollablePanel()); builder.appendSeparator("General"); final JCheckBox isEnabled = new JCheckBox("is enabled"); isEnabled.setSelected(tree.isEnabled()); isEnabled.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { tree.setEnabled(isEnabled.isSelected()); } }); builder.append("Enabled", isEnabled); final JCheckBox watermarkBleed = new JCheckBox("is bleeding"); watermarkBleed.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { tree.putClientProperty(SubstanceLookAndFeel.WATERMARK_VISIBLE, Boolean.valueOf(watermarkBleed.isSelected())); jsp.putClientProperty(SubstanceLookAndFeel.WATERMARK_VISIBLE, Boolean.valueOf(watermarkBleed.isSelected())); tree.repaint(); } }); builder.append("Watermark", watermarkBleed); final JCheckBox cbTreeSmartScroll = new JCheckBox("smart tree scroll"); cbTreeSmartScroll.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (cbTreeSmartScroll.isSelected()) { AnimationConfigurationManager .getInstance() .allowAnimations( SubstanceLookAndFeel.TREE_SMART_SCROLL_ANIMATION_KIND, tree); } else { AnimationConfigurationManager .getInstance() .disallowAnimations( SubstanceLookAndFeel.TREE_SMART_SCROLL_ANIMATION_KIND, tree); } tree.repaint(); } }); builder.append("Decorations", cbTreeSmartScroll); this.controlPanel = builder.getPanel(); this.isInitialized = true; } }