/*
Copyright 2008-2010 Gephi
Authors : Mathieu Bastian <mathieu.bastian@gephi.org>
Website : http://www.gephi.org
This file is part of Gephi.
Gephi is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
Gephi 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Gephi. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gephi.desktop.context;
import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import javax.swing.SwingUtilities;
import org.gephi.graph.api.DirectedGraph;
import org.gephi.graph.api.GraphEvent;
import org.gephi.graph.api.GraphListener;
import org.gephi.graph.api.GraphModel;
import org.gephi.graph.api.HierarchicalGraph;
import org.gephi.graph.api.UndirectedGraph;
import org.openide.util.NbBundle;
/**
*
* @author Mathieu Bastian
*/
public class ContextPanel extends javax.swing.JPanel implements GraphListener {
private enum GraphType {
DIRECTED(NbBundle.getMessage(ContextPanel.class, "ContextPanel.graphType.directed")),
UNDIRECTED(NbBundle.getMessage(ContextPanel.class, "ContextPanel.graphType.undirected")),
MIXED(NbBundle.getMessage(ContextPanel.class, "ContextPanel.graphType.mixed"));
protected final String type;
GraphType(String type) {
this.type = type;
}
}
private GraphModel model;
private ContextPieChart pieChart;
private NumberFormat formatter;
private boolean showPie = true;
private ThreadPoolExecutor consumerThread;
public ContextPanel() {
initComponents();
initDesign();
refreshModel(null);
pieButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
pieChart.setChartVisible(pieButton.isSelected());
}
});
pieChart.setChartVisible(pieButton.isSelected());
//Event manager
consumerThread = new ThreadPoolExecutor(0, 1, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(5), new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "Context Panel consumer thread");
t.setDaemon(true);
return t;
}
}, new ThreadPoolExecutor.DiscardOldestPolicy());
}
private void initDesign() {
pieChart = new ContextPieChart();
piePanel.add(pieChart.getChartPanel(), BorderLayout.CENTER);
labelNodes.setFont(labelNodes.getFont().deriveFont(Font.BOLD));
labelEdges.setFont(labelEdges.getFont().deriveFont(Font.BOLD));
formatter = NumberFormat.getPercentInstance();
formatter.setMaximumFractionDigits(2);
}
public void refreshModel(GraphModel model) {
if (this.model != null) {
this.model.removeGraphListener(this);
}
this.model = model;
setEnable(model != null);
if (this.model != null) {
model.addGraphListener(this);
refreshModelData();
}
}
private void refreshModelData() {
if (consumerThread.getQueue().remainingCapacity() > 0) {
consumerThread.execute(new RefreshRunnable());
}
}
private class RefreshRunnable implements Runnable {
public void run() {
HierarchicalGraph visibleGraph = model.getHierarchicalGraphVisible();
HierarchicalGraph fullGraph = model.getHierarchicalGraph();
final int nodesFull = fullGraph.getNodeCount();
final int nodesVisible = visibleGraph.getNodeCount();
final int edgesFull = fullGraph.getTotalEdgeCount();
final int edgesVisible = visibleGraph.getTotalEdgeCount();
final GraphType graphType = visibleGraph instanceof DirectedGraph ? GraphType.DIRECTED : visibleGraph instanceof UndirectedGraph ? GraphType.UNDIRECTED : GraphType.MIXED;
SwingUtilities.invokeLater(new Runnable() {
public void run() {
String visible = NbBundle.getMessage(ContextPanel.class, "ContextPanel.visible");
String nodeText = String.valueOf(nodesVisible);
String edgeText = String.valueOf(edgesVisible);
if (nodesFull != nodesVisible || edgesFull != edgesVisible) {
nodeText += nodesFull > 0 ? " (" + formatter.format(nodesVisible / (double) nodesFull) + " " + visible + ")" : "";
edgeText += edgesFull > 0 ? " (" + formatter.format(edgesVisible / (double) edgesFull) + " " + visible + ")" : "";
}
nodeLabel.setText(nodeText);
edgeLabel.setText(edgeText);
graphTypeLabel.setText(graphType.type);
double percentage = 0.5 * nodesVisible / (double) nodesFull + 0.5 * edgesVisible / (double) edgesFull;
pieChart.refreshChart(percentage);
}
});
}
}
public void graphChanged(GraphEvent event) {
refreshModelData();
}
private void setEnable(boolean enable) {
labelNodes.setEnabled(enable);
labelEdges.setEnabled(enable);
nodeLabel.setEnabled(enable);
edgeLabel.setEnabled(enable);
if (!enable) {
nodeLabel.setText("NaN");
edgeLabel.setText("NaN");
graphTypeLabel.setText("");
}
pieButton.setEnabled(enable);
piePanel.setVisible(showPie);
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
commandToolbar = new javax.swing.JToolBar();
pieButton = new javax.swing.JToggleButton();
piePanel = new javax.swing.JPanel();
labelNodes = new javax.swing.JLabel();
nodeLabel = new javax.swing.JLabel();
labelEdges = new javax.swing.JLabel();
edgeLabel = new javax.swing.JLabel();
graphTypeLabel = new javax.swing.JLabel();
setOpaque(false);
setLayout(new java.awt.GridBagLayout());
commandToolbar.setFloatable(false);
commandToolbar.setOrientation(1);
commandToolbar.setRollover(true);
commandToolbar.setOpaque(false);
pieButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/gephi/desktop/context/resources/pie.png"))); // NOI18N
pieButton.setFocusable(false);
pieButton.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER);
pieButton.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM);
commandToolbar.add(pieButton);
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 2;
gridBagConstraints.gridy = 0;
gridBagConstraints.gridheight = 4;
gridBagConstraints.fill = java.awt.GridBagConstraints.VERTICAL;
gridBagConstraints.weighty = 1.0;
add(commandToolbar, gridBagConstraints);
piePanel.setOpaque(false);
piePanel.setLayout(new java.awt.BorderLayout());
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.gridwidth = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.weighty = 1.0;
add(piePanel, gridBagConstraints);
labelNodes.setText(org.openide.util.NbBundle.getMessage(ContextPanel.class, "ContextPanel.labelNodes.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
gridBagConstraints.insets = new java.awt.Insets(7, 7, 0, 5);
add(labelNodes, gridBagConstraints);
nodeLabel.setText(org.openide.util.NbBundle.getMessage(ContextPanel.class, "ContextPanel.nodeLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(7, 4, 0, 3);
add(nodeLabel, gridBagConstraints);
labelEdges.setText(org.openide.util.NbBundle.getMessage(ContextPanel.class, "ContextPanel.labelEdges.text")); // NOI18N
labelEdges.setToolTipText("Number of edges, without meta-edges"); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(6, 7, 0, 5);
add(labelEdges, gridBagConstraints);
edgeLabel.setText(org.openide.util.NbBundle.getMessage(ContextPanel.class, "ContextPanel.edgeLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 1;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(6, 4, 0, 3);
add(edgeLabel, gridBagConstraints);
graphTypeLabel.setText(org.openide.util.NbBundle.getMessage(ContextPanel.class, "ContextPanel.graphTypeLabel.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.gridwidth = 2;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.insets = new java.awt.Insets(6, 7, 5, 5);
add(graphTypeLabel, gridBagConstraints);
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JToolBar commandToolbar;
private javax.swing.JLabel edgeLabel;
private javax.swing.JLabel graphTypeLabel;
private javax.swing.JLabel labelEdges;
private javax.swing.JLabel labelNodes;
private javax.swing.JLabel nodeLabel;
private javax.swing.JToggleButton pieButton;
private javax.swing.JPanel piePanel;
// End of variables declaration//GEN-END:variables
}