// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.dataprofiler.core.ui.chart.jung;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.MenuItem;
import java.awt.PopupMenu;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.IOException;
import java.util.List;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.apache.log4j.Logger;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.talend.dataprofiler.core.i18n.internal.DefaultMessagesImpl;
import org.talend.dataquality.PluginConstant;
import org.talend.dq.indicators.graph.EdgeDisplayPredicate;
import org.talend.dq.indicators.graph.GraphBuilder;
import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.decorators.DefaultToolTipFunction;
import edu.uci.ics.jung.visualization.DefaultVisualizationModel;
import edu.uci.ics.jung.visualization.GraphZoomScrollPane;
import edu.uci.ics.jung.visualization.ISOMLayout;
import edu.uci.ics.jung.visualization.PersistentLayout;
import edu.uci.ics.jung.visualization.PersistentLayoutImpl;
import edu.uci.ics.jung.visualization.PluggableRenderer;
import edu.uci.ics.jung.visualization.ShapePickSupport;
import edu.uci.ics.jung.visualization.VisualizationModel;
import edu.uci.ics.jung.visualization.VisualizationViewer;
import edu.uci.ics.jung.visualization.VisualizationViewer.GraphMouse;
import edu.uci.ics.jung.visualization.control.CrossoverScalingControl;
import edu.uci.ics.jung.visualization.control.DefaultModalGraphMouse;
import edu.uci.ics.jung.visualization.control.ModalGraphMouse.Mode;
import edu.uci.ics.jung.visualization.control.SatelliteVisualizationViewer;
import edu.uci.ics.jung.visualization.control.ScalingControl;
/**
* DOC bZhou class global comment. Detailled comment
*/
public class JungGraphGenerator {
protected static Logger log = Logger.getLogger(JungGraphGenerator.class);
private static final int DOUBLE_CLICK_COUNT = 2;
private static final String PERSIST_LAYOUT_FILE_NAME = "persistLayout.out"; //$NON-NLS-1$
private Graph graph;
private GraphBuilder graphbuilder;
private PluggableRenderer pr, sr;
private VisualizationViewer vv, sv;
private Frame frame;
private JFrame helpDialog;
private boolean isPreview = false;
/**
* DOC bzhou JungGraphGenerator constructor comment.
*/
public JungGraphGenerator(GraphBuilder graphbuilder, List<Object[]> listRows) {
this.graphbuilder = graphbuilder;
graph = graphbuilder.createMultiGraph(listRows);
}
// ADD yyi 2009-09-09 feature 8834
public Composite generate(Composite parent, boolean isWithHelp, boolean isPreview) {
this.isPreview = isPreview;
return generate(parent, isWithHelp);
}
public Composite generate(Composite parent, boolean isWithHelp) {
Composite frameComp = createAWTSWTComposite(parent);
frame = SWT_AWT.new_Frame(frameComp);
frame.setTitle(DefaultMessagesImpl.getString("JungGraphGenerator.NominalAnalysis")); //$NON-NLS-1$
pr = new LineRender(graphbuilder);
sr = new LineRender(graphbuilder);
PersistentLayout layout = new PersistentLayoutImpl(new ISOMLayout(graph));
VisualizationModel vm = new DefaultVisualizationModel(layout);
vv = new VisualizationViewer(vm, pr);
sv = new SatelliteVisualizationViewer(vv, vm, sr, new Dimension(200, 200));
configureVViewer(vv);
// create contollers
JPanel controllers = createToolControllers(vv);
// MOD yyi 2009-09-09 feature 8834
if (this.isPreview)
controllers.setVisible(false);
JPanel panel = new GraphZoomScrollPane(vv);
if (isWithHelp) {
helpDialog = createSatelliteDialog(vv, sv);
controllers.add(createShowSatelliteCheck(helpDialog));
}
frame.add(panel);
frame.add(controllers, BorderLayout.SOUTH);
frame.validate();
addListeners();
return frameComp;
}
/**
* DOC bZhou Comment method "createShowSatelliteCheck".
*
* @param dialog
* @return
*/
private JCheckBox createShowSatelliteCheck(final JFrame dialog) {
final JCheckBox showSatellite = new JCheckBox(DefaultMessagesImpl.getString("JungGraphGenerator.SatelliteView")); //$NON-NLS-1$
showSatellite.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
dialog.pack();
dialog.setAlwaysOnTop(true);
dialog.setVisible(showSatellite.isSelected());
}
});
return showSatellite;
}
/**
* DOC bZhou Comment method "createToolControllers".
*
* @param vv
* @return
*/
private JPanel createToolControllers(final VisualizationViewer vv) {
final GraphMouse graphMouse = new DefaultModalGraphMouse();
vv.setGraphMouse(graphMouse);
JPanel pSlider = createSlider();
JCheckBox inverse = createInverseCheck(vv);
ScalingControl scaler = new CrossoverScalingControl();
JButton plus = createPlusScaler(vv, scaler);
JButton minus = createMinusScaler(vv, scaler);
JButton reset = createResetBTN(vv);
// set mode seleciton box
JCheckBox checkBox = createModeSwitcher(graphMouse);
final PersistentLayout pl = (PersistentLayout) vv.getGraphLayout();
JButton persist = createPersistBTN(pl, PERSIST_LAYOUT_FILE_NAME);
JButton restore = createRestoreBTN(vv, pl, PERSIST_LAYOUT_FILE_NAME);
JPanel jp2 = new JPanel();
jp2.setLayout(new java.awt.GridLayout(2, 1));
jp2.add(inverse);
jp2.add(checkBox);
JPanel jp3 = new JPanel();
jp3.setLayout(new java.awt.GridLayout(2, 1));
jp3.add(persist);
jp3.add(restore);
JPanel controls = new JPanel();
controls.add(pSlider);
controls.add(plus);
controls.add(minus);
controls.add(reset);
controls.add(jp2);
controls.add(jp3);
return controls;
}
/**
* DOC bZhou Comment method "createRestoreBTN".
*
* @param vv
* @param pl
* @param fileName
* @return
*/
private JButton createRestoreBTN(final VisualizationViewer vv, final PersistentLayout pl, final String fileName) {
JButton restore = new JButton(DefaultMessagesImpl.getString("JungGraphGenerator.RestoreLayout")); //$NON-NLS-1$
restore.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
pl.restore(fileName);
vv.repaint();
} catch (Exception e1) {
log.error(e1, e1);
}
}
});
return restore;
}
/**
* DOC bZhou Comment method "createPersistBTN".
*
* @param pl
* @param fileName
* @return
*/
private JButton createPersistBTN(final PersistentLayout pl, final String fileName) {
JButton persist = new JButton(DefaultMessagesImpl.getString("JungGraphGenerator.SaveLayout")); //$NON-NLS-1$
persist.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// open file select dialog.
// JFileChooser fileChooser = new JFileChooser();
// fileChooser.setDialogTitle("Choose a file");
// int result = fileChooser.showOpenDialog((JButton) e.getSource());
//
// if (result == JFileChooser.APPROVE_OPTION) {
// File file = fileChooser.getSelectedFile();
// }
try {
pl.persist(fileName);
} catch (IOException e1) {
log.error(e1, e1);
}
}
});
return persist;
}
/**
* DOC bZhou Comment method "createModeSwitcher".
*
* @param graphMouse
* @return
*/
private JCheckBox createModeSwitcher(final GraphMouse graphMouse) {
final JCheckBox checkBox = new JCheckBox(DefaultMessagesImpl.getString("JungGraphGenerator.Pick")); //$NON-NLS-1$
checkBox.addActionListener(new ActionListener() {
/*
* (non-Javadoc)
*
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
DefaultModalGraphMouse modalGraphMouse = (DefaultModalGraphMouse) graphMouse;
if (checkBox.isSelected()) {
modalGraphMouse.setMode(Mode.PICKING);
} else {
modalGraphMouse.setMode(Mode.TRANSFORMING);
}
}
});
return checkBox;
}
/**
* DOC bZhou Comment method "createResetBTN".
*
* @param vv
* @return
*/
private JButton createResetBTN(final VisualizationViewer vv) {
JButton reset = new JButton(DefaultMessagesImpl.getString("JungGraphGenerator.Reset")); //$NON-NLS-1$
reset.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
vv.getLayoutTransformer().setToIdentity();
vv.getViewTransformer().setToIdentity();
}
});
return reset;
}
/**
* DOC bZhou Comment method "createMinusScaler".
*
* @param vv
* @param scaler
* @return
*/
private JButton createMinusScaler(final VisualizationViewer vv, final ScalingControl scaler) {
JButton minus = new JButton("-");//$NON-NLS-1$
minus.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
scaler.scale(vv, 1 / 1.1f, vv.getCenter());
}
});
return minus;
}
/**
* DOC bZhou Comment method "createPlusScaler".
*
* @param vv
* @param scaler
* @return
*/
private JButton createPlusScaler(final VisualizationViewer vv, final ScalingControl scaler) {
JButton plus = new JButton("+"); //$NON-NLS-1$
plus.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
scaler.scale(vv, 1.1f, vv.getCenter());
}
});
return plus;
}
/**
* DOC bZhou Comment method "createInverseCheck".
*
* @param vv
* @return
*/
private JCheckBox createInverseCheck(final VisualizationViewer vv) {
final JCheckBox inverse = new JCheckBox(DefaultMessagesImpl.getString("JungGraphGenerator.InverseEdgeWeight")); //$NON-NLS-1$
inverse.addActionListener(new ActionListener() {
/*
* (non-Javadoc)
*
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
public void actionPerformed(ActionEvent e) {
graphbuilder.setProportionalWidth(inverse.isSelected());
vv.repaint();
log.info(DefaultMessagesImpl.getString("JungGraphGenerator.Inverse")); //$NON-NLS-1$
}
});
return inverse;
}
/**
* DOC bZhou Comment method "createSlider".
*
* @return
*/
private JPanel createSlider() {
JPanel pSlider = new JPanel();
pSlider.setLayout(new BoxLayout(pSlider, BoxLayout.Y_AXIS));
pSlider.setBorder(new TitledBorder(DefaultMessagesImpl.getString("JungGraphGenerator.FilterEdgeWeight"))); //$NON-NLS-1$
final JSlider slider = new JSlider(0, 10, 0);
slider.setMajorTickSpacing(2);
slider.setMinorTickSpacing(1);
slider.setPaintTicks(false);
slider.setPaintLabels(false);
slider.setSnapToTicks(true);
slider.addChangeListener(new ChangeListener() {
/*
* (non-Javadoc)
*
* @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
*/
public void stateChanged(ChangeEvent e) {
int weight = slider.getValue();
EdgeDisplayPredicate edgePredicate = (EdgeDisplayPredicate) pr.getEdgeIncludePredicate();
edgePredicate.filterSmall(weight);
// ((VertexDisplayPredicate) pr.getVertexIncludePredicate()).filterSmall(true, weight);
// log.info("sliding..." + degree);
}
});
pSlider.add(slider);
return pSlider;
}
/**
* DOC bZhou Comment method "configureVViewer".
*
* @param vv
*/
private void configureVViewer(final VisualizationViewer vv) {
// vv = new VisualizationViewer(new CircleLayout(graph), pr);
// vv = new VisualizationViewer(new SpringLayout(graph), pr);
// vv = new VisualizationViewer(new KKLayout(graph), pr);
vv.setBackground(Color.white);
vv.setPickSupport(new ShapePickSupport());
vv.addPostRenderPaintable(new VisualizationViewer.Paintable() {
int x;
int y;
Font font;
FontMetrics metrics;
int swidth;
int sheight;
String str = PluginConstant.EMPTY_STRING; //$NON-NLS-1$
public void paint(Graphics g) {
Dimension d = vv.getSize();
if (font == null) {
font = new Font(g.getFont().getName(), Font.BOLD, 30);
metrics = g.getFontMetrics(font);
swidth = metrics.stringWidth(str);
sheight = metrics.getMaxAscent() + metrics.getMaxDescent();
x = (d.width - swidth) / 2;
y = (int) (d.height - sheight * 1.5);
}
g.setFont(font);
Color oldColor = g.getColor();
g.setColor(Color.DARK_GRAY);
g.drawString(str, x, y);
g.setColor(oldColor);
}
public boolean useTransform() {
return false;
}
});
// vv.addGraphMouseListener(new TestGraphMouseListener());
// add my listener for ToolTips
vv.setToolTipFunction(new DefaultToolTipFunction());
}
/**
* DOC bZhou Comment method "createSatelliteView".
*
* @param vv
* @param sv
* @return
*/
private JFrame createSatelliteDialog(final VisualizationViewer vv, VisualizationViewer sv) {
final JFrame dialog = new JFrame();
dialog.setTitle(DefaultMessagesImpl.getString("JungGraphGenerator.Satellite")); //$NON-NLS-1$
ScalingControl scaler = new CrossoverScalingControl();
JButton plus = createPlusScaler(vv, scaler);
JButton minus = createMinusScaler(vv, scaler);
JButton reset = createResetBTN(vv);
JButton help = createHelpBTN();
JPanel controls = new JPanel(new java.awt.GridLayout(2, 2));
controls.add(plus);
controls.add(minus);
controls.add(reset);
controls.add(help);
dialog.add(sv);
dialog.add(controls, BorderLayout.SOUTH);
return dialog;
}
/**
* DOC bZhou Comment method "createHelpBTN".
*
* @return
*/
private JButton createHelpBTN() {
final JButton help = new JButton(DefaultMessagesImpl.getString("JungGraphGenerator.Help")); //$NON-NLS-1$
help.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String title = DefaultMessagesImpl.getString("JungGraphGenerator.Instruction");
String message = DefaultMessagesImpl.getString("JungGraphGenerator.Instructions");
showHelpMessage(null, title, message);
}
private void showHelpMessage(Component parent, String title, String message) {
JOptionPane.showMessageDialog(null, title, message, JOptionPane.PLAIN_MESSAGE);
}
});
return help;
}
private Composite createAWTSWTComposite(Composite parent) {
Composite frameComp = new Composite(parent, SWT.EMBEDDED);
frameComp.setLayout(new GridLayout());
frameComp.setLayoutData(new GridData(GridData.FILL_BOTH));
frameComp.setBackground(Display.getDefault().getSystemColor(SWT.COLOR_GRAY));
return frameComp;
}
/**
* DOC BZhou Comment method "addListeners".
*/
private void addListeners() {
vv.addMouseListener(new MouseAdapter() {
/*
* (non-Javadoc)
*
* @see java.awt.event.MouseAdapter#mouseClicked(java.awt.event.MouseEvent)
*/
@Override
public void mouseClicked(MouseEvent e) {
if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == DOUBLE_CLICK_COUNT) {
// show in full screem.
showFullDialog();
}
if (e.getButton() == MouseEvent.BUTTON3) {
// show menu.
PopupMenu menu = new PopupMenu();
MenuItem item = new MenuItem(DefaultMessagesImpl.getString("JungGraphGenerator.ShowFullscreen")); //$NON-NLS-1$
menu.add(item);
vv.add(menu);
menu.show(vv, e.getX(), e.getY());
item.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
showFullDialog();
}
});
}
}
/**
* DOC BZhou Comment method "showFullDialog".
*/
private void showFullDialog() {
Display.getDefault().asyncExec(new Runnable() {
public void run() {
new JungGraphChartDialog(JungGraphGenerator.this).open();
}
});
}
});
}
}