/*
* Copyright (c) 2005-2016 Flamingo 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 Flamingo 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 org.pushingpixels.flamingo.api.bcb.core;
import java.awt.Component;
import java.io.InputStream;
import java.util.LinkedList;
import java.util.List;
import javax.swing.Icon;
import javax.swing.JLabel;
import javax.swing.JTree;
import javax.swing.tree.TreeModel;
import org.pushingpixels.flamingo.api.bcb.BreadcrumbBarCallBack;
import org.pushingpixels.flamingo.api.bcb.BreadcrumbItem;
import org.pushingpixels.flamingo.api.bcb.JBreadcrumbBar;
import org.pushingpixels.flamingo.api.common.StringValuePair;
/**
* Breadcrumb bar that allows wrapping an existing {@link JTree} or a
* {@link TreeModel}.
*
* <ul>
* <li>Use
* {@link BreadcrumbTreeAdapterSelector#BreadcrumbTreeAdapterSelector(JTree)} to
* wrap an existing tree that has a {@link JLabel} based renderer.</li>
* <li>Use a
* {@link BreadcrumbTreeAdapterSelector#BreadcrumbTreeAdapterSelector(JTree, TreeAdapter)}
* to wrap an existing tree and provide a custom breadcrumb bar path renderer.</li>
* <li>Use
* {@link BreadcrumbTreeAdapterSelector#BreadcrumbTreeAdapterSelector(TreeModel, TreeAdapter, boolean)}
* to wrap an existing tree model.</li>
* </ul>
*
* @author Kirill Grouchnikov
*/
public class BreadcrumbTreeAdapterSelector extends JBreadcrumbBar<Object> {
/**
* Tree adapter that allows plugging a custom rendering logic.
*
* @author Kirill Grouchnikov
*/
public static abstract class TreeAdapter {
/**
* Returns the caption for the specified tree node. Note that the
* extending class <strong>must</strong> override this method in an
* EDT-safe fashion.
*
* @param node
* Tree node.
* @return The caption for the specified tree node.
*/
public abstract String toString(final Object node);
/**
* Returns the icon for the specified tree node.
*
* @param node
* Tree node.
* @return The icon for the specified tree node.
*/
public Icon getIcon(Object node) {
return null;
}
}
/**
* Tree-adapter specific implementation of the {@link BreadcrumbBarCallBack}
* .
*
* @author Kirill Grouchnikov
*/
public static class TreeCallback extends BreadcrumbBarCallBack<Object> {
/**
* The corresponding tree model.
*/
protected TreeModel treeModel;
/**
* The corresponding tree adapter. Can not be <code>null</code>.
*/
protected TreeAdapter treeAdapter;
/**
* If <code>true</code>, the first selector shows the tree root node. If
* <code>false</code>, the first selector shows the tree root child
* nodes.
*/
protected boolean isRootVisible;
/**
* Creates the callback.
*
* @param treeModel
* The corresponding tree model.
* @param treeAdapter
* The corresponding tree adapter. Can not be
* <code>null</code>.
* @param isRootVisible
* If <code>true</code>, the first selector shows the tree
* root node. If <code>false</code>, the first selector shows
* the tree root child nodes.
*/
public TreeCallback(TreeModel treeModel, TreeAdapter treeAdapter,
boolean isRootVisible) {
this.treeModel = treeModel;
this.treeAdapter = treeAdapter;
this.isRootVisible = isRootVisible;
}
/*
* (non-Javadoc)
*
* @see
* org.jvnet.flamingo.bcb.BreadcrumbBarCallBack#getPathChoices(java.
* util.List)
*/
@Override
public List<StringValuePair<Object>> getPathChoices(
List<BreadcrumbItem<Object>> path) {
if (path == null) {
Object root = this.treeModel.getRoot();
List<StringValuePair<Object>> bRoots = new LinkedList<StringValuePair<Object>>();
if (isRootVisible) {
StringValuePair<Object> rootPair = new StringValuePair<Object>(
this.treeAdapter.toString(root), root);
rootPair.set("icon", this.treeAdapter.getIcon(root));
bRoots.add(rootPair);
} else {
for (int i = 0; i < this.treeModel.getChildCount(root); i++) {
Object rootChild = this.treeModel.getChild(root, i);
StringValuePair<Object> rootPair = new StringValuePair<Object>(
this.treeAdapter.toString(rootChild), rootChild);
rootPair.set("icon", this.treeAdapter
.getIcon(rootChild));
bRoots.add(rootPair);
}
}
return bRoots;
}
if (path.size() == 0)
return null;
Object lastInPath = path.get(path.size() - 1).getData();
if (this.treeModel.isLeaf(lastInPath))
return null;
LinkedList<StringValuePair<Object>> lResult = new LinkedList<StringValuePair<Object>>();
for (int i = 0; i < this.treeModel.getChildCount(lastInPath); i++) {
Object child = this.treeModel.getChild(lastInPath, i);
if (this.treeModel.isLeaf(child))
continue;
StringValuePair<Object> pair = new StringValuePair<Object>(
this.treeAdapter.toString(child), child);
pair.set("icon", this.treeAdapter.getIcon(child));
lResult.add(pair);
}
return lResult;
}
/*
* (non-Javadoc)
*
* @see
* org.jvnet.flamingo.bcb.BreadcrumbBarCallBack#getLeafs(java.util.List)
*/
@Override
public List<StringValuePair<Object>> getLeafs(
List<BreadcrumbItem<Object>> path) {
Object lastInPath = path.get(path.size() - 1).getData();
if (this.treeModel.isLeaf(lastInPath))
return null;
LinkedList<StringValuePair<Object>> lResult = new LinkedList<StringValuePair<Object>>();
for (int i = 0; i < this.treeModel.getChildCount(lastInPath); i++) {
Object child = this.treeModel.getChild(lastInPath, i);
if (!this.treeModel.isLeaf(child))
continue;
StringValuePair<Object> pair = new StringValuePair<Object>(
this.treeAdapter.toString(child), child);
pair.set("icon", this.treeAdapter.getIcon(child));
lResult.add(pair);
}
return lResult;
}
/*
* (non-Javadoc)
*
* @see
* org.jvnet.flamingo.bcb.BreadcrumbBarCallBack#getLeafContent(java.
* lang.Object)
*/
@Override
public InputStream getLeafContent(Object leaf) {
return null;
}
}
/**
* Creates an adapter for the specified tree model.
*
* @param treeModel
* Tree model.
* @param treeAdapter
* Tree adapter. Can not be <code>null</code>.
* @param isRootVisible
* If <code>true</code>, the first selector shows the tree root
* node. If <code>false</code>, the first selector shows the tree
* root child nodes.
*/
public BreadcrumbTreeAdapterSelector(TreeModel treeModel,
TreeAdapter treeAdapter, boolean isRootVisible) {
super(new TreeCallback(treeModel, treeAdapter, isRootVisible));
// SwingWorker<List<StringValuePair<Object>>, Void> worker = new
// SwingWorker<List<StringValuePair<Object>>, Void>() {
// @Override
// protected List<StringValuePair<Object>> doInBackground()
// throws Exception {
// return callback.getPathChoices(null);
// }
//
// @Override
// protected void done() {
// try {
// pushChoices(new BreadcrumbItemChoices<Object>(get()));
// } catch (Exception exc) {
// }
// }
// };
// worker.execute();
}
/**
* Creates an adapter for the specified tree.
*
* @param tree
* Tree.
* @param treeAdapter
* Tree adapter. Can not be <code>null</code>.
*/
public BreadcrumbTreeAdapterSelector(JTree tree, TreeAdapter treeAdapter) {
this(tree.getModel(), treeAdapter, tree.isRootVisible());
}
/**
* Creates an adapter for the specified tree. Assumes that the tree renderer
* extends a {@link JLabel}. Otherwise, the path selectors will have no
* captions and no icons.
*
* @param tree
* Tree.
*/
public BreadcrumbTreeAdapterSelector(final JTree tree) {
this(tree, new TreeAdapter() {
private JLabel getRenderer(Object node) {
Component renderer = tree.getCellRenderer()
.getTreeCellRendererComponent(tree, node, false, false,
tree.getModel().isLeaf(node), 0, false);
if (renderer instanceof JLabel)
return (JLabel) renderer;
return null;
}
@Override
public String toString(Object node) {
JLabel label = getRenderer(node);
if (label != null)
return label.getText();
return null;
}
@Override
public Icon getIcon(Object node) {
JLabel label = getRenderer(node);
if (label != null)
return label.getIcon();
return null;
}
});
}
}