package org.incha.ui.dependency;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.eclipse.jdt.core.IInitializer;
import org.incha.core.JavaProject;
import org.incha.core.jswingripples.eig.JSwingRipplesEIG;
import org.incha.core.jswingripples.eig.JSwingRipplesEIGEdge;
import org.incha.core.jswingripples.eig.JSwingRipplesEIGNode;
public class DependencyViewer extends JFrame {
private static final String CAN_NOT_ADD_DEPENDENCY_TEXT = "Can not add a dependency to the current tab";
private static final String ADD_DEPENDENCY_TEXT = "^ Add a dependency to the [Calling - direct] tab ^";
private static final long serialVersionUID = 113666502784036828L;
private static final int CALLING_DIRECT = 0;
private static final int CALLED_DIRECT = 1;
private final JLabel topLevelInfo = new JLabel();
private final JButton addDependency = new JButton(ADD_DEPENDENCY_TEXT);
private final ClassDependencyView callingDirectView;
private final ClassDependencyView calledDirectView;
private final ClassDependencyView callingIncludeTransitive;
private final ClassDependencyView calledIncludeTransitive;
private final ClassDependencyView allDependencies;
private final AllClassesView allClassesView;
private JSwingRipplesEIGNode node;
/**
* Default constructor.
*/
public DependencyViewer(final JavaProject project) {
super("Dependency manager");
callingDirectView = new ClassDependencyView(project, 0);
calledDirectView = new ClassDependencyView(project, 1);
callingIncludeTransitive = new ClassDependencyView(project, 0);
calledIncludeTransitive = new ClassDependencyView(project, 1);
allDependencies = new ClassDependencyView(project, 2);
allClassesView = new AllClassesView(project);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
final JPanel contentPane = new JPanel(new BorderLayout(0, 5));
setContentPane(contentPane);
topLevelInfo.setHorizontalAlignment(JLabel.CENTER);
contentPane.add(topLevelInfo, BorderLayout.NORTH);
final JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
contentPane.add(splitPane, BorderLayout.CENTER);
//top panel
final JTabbedPane top = new JTabbedPane(JTabbedPane.TOP,
JTabbedPane.WRAP_TAB_LAYOUT);
top.add("Calling - direct",
new JScrollPane(callingDirectView));
top.add("Called - direct",
new JScrollPane(calledDirectView));
top.add("Calling, including transitive through members",
new JScrollPane(callingIncludeTransitive));
top.add("Called, including transitive through members",
new JScrollPane(calledIncludeTransitive));
top.add("All dependencies",
new JScrollPane(allDependencies));
splitPane.setLeftComponent(top);
//bottom panel
final JPanel bottom = new JPanel(new BorderLayout(0, 5));
bottom.add(addDependency, BorderLayout.NORTH);
bottom.add(new JScrollPane(allClassesView), BorderLayout.CENTER);
splitPane.setRightComponent(bottom);
//add listeners
top.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(final ChangeEvent e) {
final int index = top.getSelectedIndex();
final boolean allowAddDependency = index == CALLING_DIRECT || index == CALLED_DIRECT;
addDependency.setEnabled(allowAddDependency);
addDependency.setText(allowAddDependency
? ADD_DEPENDENCY_TEXT : CAN_NOT_ADD_DEPENDENCY_TEXT);
}
});
addComponentListener(new ComponentAdapter() {
/* (non-Javadoc)
* @see java.awt.event.ComponentAdapter#componentShown(java.awt.event.ComponentEvent)
*/
@Override
public void componentShown(final ComponentEvent e) {
removeComponentListener(this);
splitPane.setDividerLocation(0.5);
}
});
addDependency.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
addDependency(top.getSelectedIndex());
}
});
//remove dependency listener
final MouseListener dependencyListener = new MouseAdapter() {
/* (non-Javadoc)
* @see java.awt.event.MouseAdapter#mousePressed(java.awt.event.MouseEvent)
*/
@Override
public void mousePressed(final MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
removeDependency((ClassDependencyView) e.getSource(),
top.getSelectedIndex(), e.getX(), e.getY());
}
}
};
callingDirectView.addMouseListener(dependencyListener);
calledDirectView.addMouseListener(dependencyListener);
}
/**
*
*/
protected void removeDependency(final ClassDependencyView view,
final int selectedTab, final int x, final int y) {
final int row = view.getSelectedRow();
final JSwingRipplesEIGNode s = row < 0 ? null : view.getClassHierarchyModel().getValueAt(row);
if (s != null) {
final JSwingRipplesEIGNode node1;
final JSwingRipplesEIGNode node2;
if (selectedTab == CALLING_DIRECT) {
node1 = s;
node2 = node;
} else {
node1 = node;
node2 = s;
}
final JSwingRipplesEIGEdge edge = node.getEig().getEdge(node1, node2);
if (edge != null) {
final JPopupMenu popup = new JPopupMenu();
popup.add(new AbstractAction("Remove the dependency") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(final ActionEvent e) {
node.getEig().removeEdge(edge);
//refresh all views
setNode(node);
}
});
popup.show(view, x, y);
}
}
}
/**
* @param selectedTab
*/
protected void addDependency(final int selectedTab) {
final int row = allClassesView.getSelectedRow();
final JSwingRipplesEIGNode s = row < 0 ? null : allClassesView.getClassHierarchyModel().getValueAt(row);
if (s != null && !(s.getNodeIMember() instanceof IInitializer)) {
final JSwingRipplesEIGNode node1;
final JSwingRipplesEIGNode node2;
if (selectedTab == CALLING_DIRECT) {
node1 = s;
node2 = node;
} else {
node1 = node;
node2 = s;
}
final JSwingRipplesEIGEdge edge = node.getEig().addEdge(node1, node2);
if (edge != null) {
edge.setMark("Custom");
//refresh all views
setNode(node);
}
}
}
/**
* @param node the node.
*/
public void setNode(final JSwingRipplesEIGNode node) {
this.node = node;
allClassesView.setData(getAllNodesExcludeGiven(node));
topLevelInfo.setText("Dependencies of the [" + this.node.getFullName() + "] node: ");
callingDirectView.setDependencies(node, getCallingDirectDependencies(this.node));
calledDirectView.setDependencies(node, getCalledDirectDependencies(this.node));
callingIncludeTransitive.setDependencies(node, getCallingIncludeTransitiveDependencies(this.node));
calledIncludeTransitive.setDependencies(node, getCalledIncludeTransitiveDependencies(this.node));
allDependencies.setDependencies(node, getAllDependencies(node));
}
/**
* @param node2
* @return
*/
private List<JSwingRipplesEIGNode> getAllNodesExcludeGiven(
final JSwingRipplesEIGNode node) {
final List<JSwingRipplesEIGNode> nodes = new LinkedList<JSwingRipplesEIGNode>();
for (final JSwingRipplesEIGNode n : node.getEig().getAllNodes()) {
if (!n.equals(node)) {
nodes.add(n);
}
}
return nodes;
}
/**
* @param node
* @return
*/
private Set<JSwingRipplesEIGNode> getAllDependencies(
final JSwingRipplesEIGNode node) {
final JSwingRipplesEIG eig = node.getEig();
final HashSet<JSwingRipplesEIGNode> nodes=new HashSet<JSwingRipplesEIGNode>();
nodes.add(node);
return eig.edgesToNeigbors(
nodes,
JSwingRipplesEIG.DIRECTION_CONSIDERED_BOTH_CALLING_AND_CALLED,
JSwingRipplesEIG.NESTING_CONSIDERED_BOTH_TOP_AND_MEMBER_NODES);
}
/**
* @param node
* @return
*/
private Set<JSwingRipplesEIGNode> getCalledIncludeTransitiveDependencies(
final JSwingRipplesEIGNode node) {
final JSwingRipplesEIG eig = node.getEig();
final HashSet<JSwingRipplesEIGNode> nodes=new HashSet<JSwingRipplesEIGNode>();
nodes.add(node);
return eig.edgesToNeigbors(
nodes,
JSwingRipplesEIG.DIRECTION_CONSIDERED_CALLED_NODES_ONLY,
JSwingRipplesEIG.NESTING_CONSIDERED_BOTH_TOP_AND_MEMBER_NODES);
}
/**
* @param node
* @return
*/
private Set<JSwingRipplesEIGNode> getCallingIncludeTransitiveDependencies(
final JSwingRipplesEIGNode node) {
final JSwingRipplesEIG eig = node.getEig();
final HashSet<JSwingRipplesEIGNode> nodes=new HashSet<JSwingRipplesEIGNode>();
nodes.add(node);
return eig.edgesToNeigbors(
nodes,
JSwingRipplesEIG.DIRECTION_CONSIDERED_CALLING_NODES_ONLY,
JSwingRipplesEIG.NESTING_CONSIDERED_BOTH_TOP_AND_MEMBER_NODES);
}
/**
* @param node
* @return
*/
private Set<JSwingRipplesEIGNode> getCalledDirectDependencies(
final JSwingRipplesEIGNode node) {
final JSwingRipplesEIG eig = node.getEig();
final HashSet<JSwingRipplesEIGNode> nodes=new HashSet<JSwingRipplesEIGNode>();
nodes.add(node);
return eig.edgesToNeigbors(
nodes,
JSwingRipplesEIG.DIRECTION_CONSIDERED_CALLED_NODES_ONLY,
JSwingRipplesEIG.NESTING_CONSIDERED_BOTH_TOP_AND_MEMBER_NODES);
}
/**
* @param node
* @return
*/
private Set<JSwingRipplesEIGNode> getCallingDirectDependencies(
final JSwingRipplesEIGNode node) {
final JSwingRipplesEIG eig = node.getEig();
final HashSet<JSwingRipplesEIGNode> nodes=new HashSet<JSwingRipplesEIGNode>();
nodes.add(node);
return eig.edgesToNeigbors(
nodes,
JSwingRipplesEIG.DIRECTION_CONSIDERED_CALLING_NODES_ONLY,
JSwingRipplesEIG.NESTING_CONSIDERED_BOTH_TOP_AND_MEMBER_NODES);
}
}