package org.mevenide.idea.repository.tree.model;
import javax.swing.event.EventListenerList;
import javax.swing.event.TreeModelEvent;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import org.mevenide.idea.Res;
import org.mevenide.repository.IRepositoryReader;
import org.mevenide.repository.RepoPathElement;
/**
* @author Arik
*/
public class RepoTreeModel implements TreeModel {
/**
* Resources
*/
private static final Res RES = Res.getInstance(RepoTreeModel.class);
private final EventListenerList listenerList = new EventListenerList();
private final RepoTreeNode root;
public RepoTreeModel(final IRepositoryReader pRepo) {
final RepoPathElement rootPathElement = new RepoPathElement(pRepo);
root = new RepoTreeNode(null, rootPathElement);
}
public RepoTreeNode getRoot() {
return root;
}
public Object getChild(Object parent, int index) {
return ((TreeNode) parent).getChildAt(index);
}
public int getChildCount(Object parent) {
return ((TreeNode) parent).getChildCount();
}
public boolean isLeaf(Object node) {
return ((TreeNode) node).isLeaf();
}
public void valueForPathChanged(TreePath path, Object newValue) {
final String className = RepoTreeModel.class.getName();
final String msg = RES.get("unsupp.op", "valueForPathChanged", className);
throw new UnsupportedOperationException(msg);
}
public int getIndexOfChild(Object parent, Object child) {
return ((TreeNode) parent).getIndex((TreeNode) child);
}
public void addTreeModelListener(TreeModelListener l) {
listenerList.add(TreeModelListener.class, l);
}
public void removeTreeModelListener(TreeModelListener l) {
listenerList.remove(TreeModelListener.class, l);
}
/**
* Invoke this method after you've changed how node is to be represented in the tree.
*/
public void nodeChanged(TreeNode node) {
if (listenerList != null && node != null) {
TreeNode parent = node.getParent();
if (parent != null) {
int anIndex = parent.getIndex(node);
if (anIndex != -1) {
int[] cIndexs = new int[1];
cIndexs[0] = anIndex;
nodesChanged(parent, cIndexs);
}
}
else if (node == getRoot()) {
nodesChanged(node, null);
}
}
}
/**
* Invoke this method after you've changed how the children identified by childIndicies are to
* be represented in the tree.
*/
public void nodesChanged(TreeNode node, int[] childIndices) {
if (node != null) {
if (childIndices != null) {
int cCount = childIndices.length;
if (cCount > 0) {
Object[] cChildren = new Object[cCount];
for (int counter = 0; counter < cCount; counter++)
cChildren[counter] = node.getChildAt
(childIndices[counter]);
fireTreeNodesChanged(this, getPathToRoot(node),
childIndices, cChildren);
}
}
else if (node == getRoot()) {
fireTreeNodesChanged(this, getPathToRoot(node), null, null);
}
}
}
/**
* Invoke this method if you've totally changed the children of node and its childrens
* children... This will post a treeStructureChanged event.
*/
public void nodeStructureChanged(TreeNode node) {
if (node != null) {
fireTreeStructureChanged(this, getPathToRoot(node), null, null);
}
}
/**
* Notifies all listeners that have registered interest for notification on this event type.
* The event instance is lazily created using the parameters passed into the fire method.
*
* @param source the node being changed
* @param path the path to the root node
* @param childIndices the indices of the changed elements
* @param children the changed elements
*
* @see EventListenerList
*/
protected void fireTreeNodesChanged(Object source, Object[] path,
int[] childIndices,
Object[] children) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
TreeModelEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == TreeModelListener.class) {
// Lazily create the event:
if (e == null)
e = new TreeModelEvent(source, path,
childIndices, children);
((TreeModelListener) listeners[i + 1]).treeNodesChanged(e);
}
}
}
/**
* Notifies all listeners that have registered interest for notification on this event type.
* The event instance is lazily created using the parameters passed into the fire method.
*
* @param source the node where new elements are being inserted
* @param path the path to the root node
* @param childIndices the indices of the new elements
* @param children the new elements
*
* @see EventListenerList
*/
protected void fireTreeNodesInserted(Object source, Object[] path,
int[] childIndices,
Object[] children) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
TreeModelEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == TreeModelListener.class) {
// Lazily create the event:
if (e == null)
e = new TreeModelEvent(source, path,
childIndices, children);
((TreeModelListener) listeners[i + 1]).treeNodesInserted(e);
}
}
}
/**
* Notifies all listeners that have registered interest for notification on this event type.
* The event instance is lazily created using the parameters passed into the fire method.
*
* @param source the node where elements are being removed
* @param path the path to the root node
* @param childIndices the indices of the removed elements
* @param children the removed elements
*
* @see EventListenerList
*/
protected void fireTreeNodesRemoved(Object source, Object[] path,
int[] childIndices,
Object[] children) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
TreeModelEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == TreeModelListener.class) {
// Lazily create the event:
if (e == null)
e = new TreeModelEvent(source, path,
childIndices, children);
((TreeModelListener) listeners[i + 1]).treeNodesRemoved(e);
}
}
}
/**
* Notifies all listeners that have registered interest for notification on this event type.
* The event instance is lazily created using the parameters passed into the fire method.
*
* @param source the node where the tree model has changed
* @param path the path to the root node
* @param childIndices the indices of the affected elements
* @param children the affected elements
*
* @see EventListenerList
*/
protected void fireTreeStructureChanged(Object source, Object[] path,
int[] childIndices,
Object[] children) {
// Guaranteed to return a non-null array
Object[] listeners = listenerList.getListenerList();
TreeModelEvent e = null;
// Process the listeners last to first, notifying
// those that are interested in this event
for (int i = listeners.length - 2; i >= 0; i -= 2) {
if (listeners[i] == TreeModelListener.class) {
// Lazily create the event:
if (e == null)
e = new TreeModelEvent(source, path,
childIndices, children);
((TreeModelListener) listeners[i + 1]).treeStructureChanged(e);
}
}
}
/**
* Builds the parents of node up to and including the root node, where the original node is the
* last element in the returned array. The length of the returned array gives the node's depth
* in the tree.
*
* @param aNode the node to get the path for
*/
public TreeNode[] getPathToRoot(TreeNode aNode) {
return getPathToRoot(aNode, 0);
}
/**
* Builds the parents of node up to and including the root node, where the original node is the
* last element in the returned array. The length of the returned array gives the node's depth
* in the tree.
*
* @param pNode the node to get the path for
* @param pDepth an int giving the number of steps already taken towards the root (on recursive
* calls), used to size the returned array
*
* @return an array of {@code RepoPathElement} giving the path from the root to the specified
* node
*/
protected TreeNode[] getPathToRoot(final TreeNode pNode, int pDepth) {
TreeNode[] retNodes;
// This method recurses, traversing towards the root in order
// size the array. On the way back, it fills in the nodes,
// starting from the root and working back to the original node.
// Check for null, in case someone passed in a null node, or
// they passed in an element that isn't rooted at root.
if (pNode == null) {
if (pDepth == 0)
return null;
else
retNodes = new TreeNode[pDepth];
}
else {
pDepth++;
if (pNode == root)
retNodes = new TreeNode[pDepth];
else
retNodes = getPathToRoot(pNode.getParent(), pDepth);
retNodes[retNodes.length - pDepth] = pNode;
}
return retNodes;
}
}