X-Git-Url: http://git.nikiroo.be/?p=fanfix.git;a=blobdiff_plain;f=src%2Fbe%2Fnikiroo%2Futils%2Fui%2FTreeCellSpanner.java;fp=src%2Fbe%2Fnikiroo%2Futils%2Fui%2FTreeCellSpanner.java;h=703bfa1c99d91b00bd19de0cbaf281caf9ab444c;hp=0000000000000000000000000000000000000000;hb=f19b48e27a56ebab18687debd9ef52581a03f06d;hpb=dfa4091ccd9f46687c7326aa6bf2eaf588a7cb83 diff --git a/src/be/nikiroo/utils/ui/TreeCellSpanner.java b/src/be/nikiroo/utils/ui/TreeCellSpanner.java new file mode 100644 index 0000000..703bfa1 --- /dev/null +++ b/src/be/nikiroo/utils/ui/TreeCellSpanner.java @@ -0,0 +1,169 @@ +/* + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program. If not, see . + */ +// Can be found at: https://code.google.com/archive/p/aephyr/source/default/source +// package aephyr.swing; +package be.nikiroo.utils.ui; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.tree.*; + +import java.util.*; + +public class TreeCellSpanner extends Container implements TreeCellRenderer, ComponentListener { + + public TreeCellSpanner(JTree tree, TreeCellRenderer renderer) { + if (tree == null || renderer == null) + throw new NullPointerException(); + this.tree = tree; + this.renderer = renderer; + treeParent = tree.getParent(); + if (treeParent != null && treeParent instanceof JViewport) { + treeParent.addComponentListener(this); + } else { + treeParent = null; + tree.addComponentListener(this); + } + } + + protected final JTree tree; + + private TreeCellRenderer renderer; + + private Component rendererComponent; + + private Container treeParent; + + private Map offsets = new HashMap(); + + private TreePath path; + + public TreeCellRenderer getRenderer() { + return renderer; + } + + @Override + public Component getTreeCellRendererComponent(JTree tree, Object value, + boolean selected, boolean expanded, boolean leaf, int row, + boolean hasFocus) { + path = tree.getPathForRow(row); + if (path != null && path.getLastPathComponent() != value) + path = null; + rendererComponent = renderer.getTreeCellRendererComponent( + tree, value, selected, expanded, leaf, row, hasFocus); + if (getComponentCount() < 1 || getComponent(0) != rendererComponent) { + removeAll(); + add(rendererComponent); + } + return this; + } + + @Override + public void doLayout() { + int x = getX(); + if (x < 0) + return; + if (path != null) { + Integer offset = offsets.get(path); + if (offset == null || offset.intValue() != x) { + offsets.put(path, x); + fireTreePathChanged(path); + } + } + rendererComponent.setBounds(getX(), getY(), getWidth(), getHeight()); + } + + @Override + public void paint(Graphics g) { + if (rendererComponent != null) + rendererComponent.paint(g); + } + + @Override + public Dimension getPreferredSize() { + Dimension s = rendererComponent.getPreferredSize(); + // check if path count is greater than 1 to exclude the root + if (path != null && path.getPathCount() > 1) { + Integer offset = offsets.get(path); + if (offset != null) { + int width; + if (tree.getParent() == treeParent) { + width = treeParent.getWidth(); + } else { + if (treeParent != null) { + treeParent.removeComponentListener(this); + tree.addComponentListener(this); + treeParent = null; + } + if (tree.getParent() instanceof JViewport) { + treeParent = tree.getParent(); + tree.removeComponentListener(this); + treeParent.addComponentListener(this); + width = treeParent.getWidth(); + } else { + width = tree.getWidth(); + } + } + s.width = width - offset; + } + } + return s; + } + + + protected void fireTreePathChanged(TreePath path) { + if (path.getPathCount() > 1) { + // this cannot be used for the root node or else + // the entire tree will keep being revalidated ad infinitum + TreeModel model = tree.getModel(); + Object node = path.getLastPathComponent(); + if (node instanceof TreeNode && (model instanceof DefaultTreeModel + || (model instanceof TreeModelTransformer && + (model=((TreeModelTransformer)model).getModel()) instanceof DefaultTreeModel))) { + ((DefaultTreeModel)model).nodeChanged((TreeNode)node); + } else { + model.valueForPathChanged(path, node.toString()); + } + } else { + // root! + + } + } + + + private int lastWidth; + + @Override + public void componentHidden(ComponentEvent e) {} + + @Override + public void componentMoved(ComponentEvent e) {} + + @Override + public void componentResized(ComponentEvent e) { + if (e.getComponent().getWidth() != lastWidth) { + lastWidth = e.getComponent().getWidth(); + for (int row=tree.getRowCount(); --row>=0;) { + fireTreePathChanged(tree.getPathForRow(row)); + } + } + } + + @Override + public void componentShown(ComponentEvent e) {} + +}