/*
* This file is part of GumTree.
*
* GumTree 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.
*
* GumTree 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 GumTree. If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2011-2015 Jean-Rémy Falleri <jr.falleri@gmail.com>
* Copyright 2011-2015 Floréal Morandat <florealm@gmail.com>
*/
package com.github.gumtreediff.client.diff.ui.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.io.FileReader;
import java.io.IOException;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTree;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreePath;
import com.github.gumtreediff.actions.TreeClassifier;
import com.github.gumtreediff.matchers.MappingStore;
import com.github.gumtreediff.actions.RootsClassifier;
import com.github.gumtreediff.actions.TreeClassifier;
import com.github.gumtreediff.matchers.MappingStore;
import com.github.gumtreediff.matchers.Matcher;
import com.github.gumtreediff.tree.ITree;
import com.github.gumtreediff.tree.TreeContext;
public class MappingsPanel extends JPanel implements TreeSelectionListener {
private static final long serialVersionUID = 1L;
private TreeContext src;
private TreeContext dst;
private TreeClassifier classifyTrees;
private MappingStore mappings;
private TreePanel panSrc;
private TreePanel panDst;
private JTextArea txtSrc;
private JTextArea txtDst;
private static final Color DEL_COLOR = new Color(190, 0, 0);
private static final Color ADD_COLOR = new Color(0, 158, 0);
private static final Color UPD_COLOR = new Color(189, 162, 0);
//private static final Color MIS_COLOR = new Color(0, 0, 128);
private static final Color MV_COLOR = new Color(128, 0, 128);
public MappingsPanel(String srcPath, String dstPath, TreeContext src, TreeContext dst, Matcher m) {
super(new GridLayout(1, 0));
this.src = src;
this.dst = dst;
this.classifyTrees = new RootsClassifier(src, dst, m);
this.mappings = new MappingStore(m.getMappingSet());
this.panSrc = new TreePanel(this.src, new MappingsCellRenderer(true));
this.panSrc.getJTree().addTreeSelectionListener(this);
this.panDst = new TreePanel(this.dst, new MappingsCellRenderer(false));
this.panDst.getJTree().addTreeSelectionListener(this);
this.txtSrc = new JTextArea();
this.txtDst = new JTextArea();
JPanel top = new JPanel();
top.setLayout(new GridLayout(1, 2));
top.add(panSrc);
top.add(panDst);
JPanel bottom = new JPanel();
bottom.setLayout(new GridLayout(1, 2));
bottom.add(new JScrollPane(txtSrc));
bottom.add(new JScrollPane(txtDst));
JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, top, bottom);
split.setDividerLocation(650);
add(split);
try {
txtSrc.getUI().getEditorKit(txtSrc).read(new FileReader(srcPath), txtSrc.getDocument(), 0);
txtDst.getUI().getEditorKit(txtDst).read(new FileReader(dstPath), txtDst.getDocument(), 0);
} catch (IOException | BadLocationException e) {
e.printStackTrace();
}
setPreferredSize(new Dimension(1024, 768));
openNodes();
}
private void openNodes() {
for (ITree t: classifyTrees.getSrcDelTrees()) openNode(panSrc, t);
for (ITree t: classifyTrees.getDstAddTrees()) openNode(panDst, t);
for (ITree t: classifyTrees.getSrcUpdTrees()) openNode(panSrc, t);
for (ITree t: classifyTrees.getDstUpdTrees()) openNode(panDst, t);
for (ITree t: classifyTrees.getSrcMvTrees()) openNode(panSrc, t);
for (ITree t: classifyTrees.getDstMvTrees()) openNode(panDst, t);
panSrc.getJTree().scrollPathToVisible(new TreePath(panSrc.getTrees().get(src.getRoot()).getPath()));
panDst.getJTree().scrollPathToVisible(new TreePath(panDst.getTrees().get(dst.getRoot()).getPath()));
}
private void openNode(TreePanel p, ITree t) {
DefaultMutableTreeNode n = p.getTrees().get(t);
p.getJTree().scrollPathToVisible(new TreePath(n.getPath()));
}
@Override
public void valueChanged(TreeSelectionEvent e) {
JTree jtree = (JTree) e.getSource();
if (jtree.getSelectionPath() == null) return;
ITree sel = (ITree) ((DefaultMutableTreeNode) jtree.getLastSelectedPathComponent()).getUserObject();
JTextArea selJTextArea = null;
boolean isMapped = false;
ITree match = null;
TreePanel matchTreePanel = null;
JTextArea matchJTextArea = null;
if (jtree == panSrc.getJTree()) {
selJTextArea = txtSrc;
matchTreePanel = panDst;
matchJTextArea = txtDst;
if (mappings.hasSrc(sel)) {
isMapped = true;
match = mappings.getDst(sel);
}
} else {
selJTextArea = txtDst;
matchTreePanel = panSrc;
matchJTextArea = txtSrc;
if (mappings.hasDst(sel)) {
isMapped = true;
match = mappings.getSrc(sel);
}
}
try {
updateJTreeAndJTextArea(sel, selJTextArea, isMapped, match, matchTreePanel, matchJTextArea);
} catch (BadLocationException ex) {
ex.printStackTrace();
}
}
private void updateJTreeAndJTextArea(ITree sel, JTextArea selJTextArea, boolean isMapped,
ITree match, TreePanel matchTreePanel,
JTextArea matchJTextArea) throws BadLocationException {
selJTextArea.getHighlighter().removeAllHighlights();
selJTextArea.getHighlighter().addHighlight(sel.getPos(), sel.getEndPos(), DefaultHighlighter.DefaultPainter);
selJTextArea.setCaretPosition(sel.getPos());
if (isMapped) {
DefaultMutableTreeNode node = matchTreePanel.getTrees().get(match);
matchTreePanel.getJTree().scrollPathToVisible(new TreePath(node.getPath()));
matchTreePanel.getJTree().setSelectionPath(new TreePath(node.getPath()));
matchJTextArea.getHighlighter().removeAllHighlights();
matchJTextArea.getHighlighter().addHighlight(
match.getPos(), match.getEndPos(), DefaultHighlighter.DefaultPainter);
matchJTextArea.setCaretPosition(match.getPos());
} else {
matchTreePanel.getJTree().clearSelection();
matchJTextArea.getHighlighter().removeAllHighlights();
}
}
private class MappingsCellRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = 1L;
private boolean isSrc;
public MappingsCellRenderer(boolean left) {
this.isSrc = left;
}
@Override
public Component getTreeCellRendererComponent(JTree jtree, Object value,
boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
super.getTreeCellRendererComponent(jtree, value, selected, expanded, leaf, row, hasFocus);
ITree tree = (ITree) ((DefaultMutableTreeNode) value).getUserObject();
if (isSrc && classifyTrees.getSrcDelTrees().contains(tree)) setForeground(DEL_COLOR);
else if (!isSrc && classifyTrees.getDstAddTrees().contains(tree)) setForeground(ADD_COLOR);
else if (isSrc && classifyTrees.getSrcUpdTrees().contains(tree)) setForeground(UPD_COLOR);
else if (!isSrc && classifyTrees.getDstUpdTrees().contains(tree)) setForeground(UPD_COLOR);
else if (isSrc && classifyTrees.getSrcMvTrees().contains(tree)) setForeground(MV_COLOR);
else if (!isSrc && classifyTrees.getDstMvTrees().contains(tree)) setForeground(MV_COLOR);
return this;
}
}
}