/*
Copyright 2008 WebAtlas
Authors : Mathieu Bastian, Mathieu Jacomy, Julian Bilcke, Eduardo Ramos
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.datalab.plugin.manipulators.general.ui;
import com.csvreader.CsvReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableModel;
import org.gephi.ui.utils.DialogFileFilter;
import org.netbeans.validation.api.Problems;
import org.netbeans.validation.api.Validator;
import org.netbeans.validation.api.ui.ValidationGroup;
import org.netbeans.validation.api.ui.ValidationPanel;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.NbPreferences;
/**
*
* @author Eduardo Ramos <eduramiba@gmail.com>
*/
public class ImportCSVUIVisualPanel1 extends javax.swing.JPanel {
private static final String CHARSET_SAVED_PREFERENCES = "ImportCSVUIVisualPanel1_Charset";
private static final String SEPARATOR_SAVED_PREFERENCES = "ImportCSVUIVisualPanel1_Separator";
private static final String TABLE_SAVED_PREFERENCES = "ImportCSVUIVisualPanel1_Table";
private static final int MAX_ROWS_PREVIEW = 25;
private File selectedFile = null;
private ImportCSVUIWizardPanel1 wizard1;
private int columnCount = 0;
private boolean hasSourceNodeColumn = false;
private boolean hasTargetNodeColumn = false;
private boolean columnNamesRepeated = false;
private ValidationPanel validationPanel;
/** Creates new form ImportCSVUIVisualPanel1 */
public ImportCSVUIVisualPanel1(ImportCSVUIWizardPanel1 wizard1) {
initComponents();
this.wizard1 = wizard1;
separatorComboBox.addItem(new SeparatorWrapper((','), getMessage("ImportCSVUIVisualPanel1.comma")));
separatorComboBox.addItem(new SeparatorWrapper((';'), getMessage("ImportCSVUIVisualPanel1.semicolon")));
separatorComboBox.addItem(new SeparatorWrapper(('\t'), getMessage("ImportCSVUIVisualPanel1.tab")));
separatorComboBox.addItem(new SeparatorWrapper((' '), getMessage("ImportCSVUIVisualPanel1.space")));
separatorComboBox.setSelectedIndex(NbPreferences.forModule(ImportCSVUIVisualPanel1.class).getInt(SEPARATOR_SAVED_PREFERENCES, 0));//Use saved separator or comma if not saved yet
tableComboBox.addItem(getMessage("ImportCSVUIVisualPanel1.nodes-table"));
tableComboBox.addItem(getMessage("ImportCSVUIVisualPanel1.edges-table"));
tableComboBox.setSelectedIndex(NbPreferences.forModule(ImportCSVUIVisualPanel1.class).getInt(TABLE_SAVED_PREFERENCES, 0));//Use saved table or nodes table if not saved yet
for (String charset : Charset.availableCharsets().keySet()) {
charsetComboBox.addItem(charset);
}
String savedCharset = NbPreferences.forModule(ImportCSVUIVisualPanel1.class).get(CHARSET_SAVED_PREFERENCES, null);
if (savedCharset != null) {
charsetComboBox.setSelectedItem(savedCharset);
}else{
charsetComboBox.setSelectedItem(Charset.forName("UTF-8").name());//UTF-8 by default, not system default charset
}
}
public void unSetup(){
NbPreferences.forModule(ImportCSVUIVisualPanel1.class).put(CHARSET_SAVED_PREFERENCES, charsetComboBox.getSelectedItem().toString());
NbPreferences.forModule(ImportCSVUIVisualPanel1.class).putInt(SEPARATOR_SAVED_PREFERENCES, separatorComboBox.getSelectedIndex());
NbPreferences.forModule(ImportCSVUIVisualPanel1.class).putInt(TABLE_SAVED_PREFERENCES, tableComboBox.getSelectedIndex());
}
public ValidationPanel getValidationPanel() {
if (validationPanel != null) {
return validationPanel;
}
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
validationPanel = new ValidationPanel();
validationPanel.setInnerComponent(ImportCSVUIVisualPanel1.this);
ValidationGroup validationGroup = validationPanel.getValidationGroup();
validationGroup.add(pathTextField, new Validator<String>() {
public boolean validate(Problems prblms, String string, String t) {
if (!isValidFile()) {
prblms.add(getMessage("ImportCSVUIVisualPanel1.validation.invalid-file"));
return false;
}
if (!hasColumns()) {
prblms.add(getMessage("ImportCSVUIVisualPanel1.validation.no-columns"));
return false;
}
if (columnNamesRepeated) {
prblms.add(getMessage("ImportCSVUIVisualPanel1.validation.repeated-columns"));
return false;
}
if (!areValidColumnsForTable()) {
prblms.add(getMessage("ImportCSVUIVisualPanel1.validation.edges.no-source-target-columns"));
return false;
}
return true;
}
});
}
});
validationPanel.setName(getName());
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (InvocationTargetException ex) {
Exceptions.printStackTrace(ex);
}
return validationPanel;
}
public void refreshPreviewTable() {
if (selectedFile != null && selectedFile.exists()) {
try {
CsvReader reader = new CsvReader(new FileInputStream(selectedFile), getSelectedSeparator(), getSelectedCharset());
reader.setTrimWhitespace(false);
String[] headers;
try {
reader.readHeaders();
headers = reader.getHeaders();
} catch (Exception ex) {
headers = new String[0];//Some charsets can be problematic with unreal columns lenght. Don't show table when there are problems
}
columnCount = headers.length;
//Check for repeated column names:
Set<String> columnNamesSet = new HashSet<String>();
columnNamesRepeated = false;
hasSourceNodeColumn = false;
hasTargetNodeColumn = false;
for (String header : headers) {
if (header.equalsIgnoreCase("source")) {
hasSourceNodeColumn = true;
}
if (header.equalsIgnoreCase("target")) {
hasTargetNodeColumn = true;
}
if (columnNamesSet.contains(header)) {
columnNamesRepeated = true;
break;
}
columnNamesSet.add(header);
}
ArrayList<String[]> records = new ArrayList<String[]>();
if (columnCount > 0) {
String[] currentRecord;
while (reader.readRecord() && records.size() < MAX_ROWS_PREVIEW) {
currentRecord = new String[reader.getColumnCount()];
for (int i = 0; i < currentRecord.length; i++) {
currentRecord[i] = reader.get(i);
}
records.add(currentRecord);
}
}
reader.close();
final String[] columnNames = headers;
final String[][] values = records.toArray(new String[0][]);
previewTable.setModel(new TableModel() {
public int getRowCount() {
return values.length;
}
public int getColumnCount() {
return columnNames.length;
}
public String getColumnName(int columnIndex) {
return columnNames[columnIndex];
}
public Class<?> getColumnClass(int columnIndex) {
return String.class;
}
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
public Object getValueAt(int rowIndex, int columnIndex) {
if (values[rowIndex].length > columnIndex) {
return values[rowIndex][columnIndex];
} else {
return null;
}
}
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
}
public void addTableModelListener(TableModelListener l) {
}
public void removeTableModelListener(TableModelListener l) {
}
});
} catch (FileNotFoundException ex) {
Exceptions.printStackTrace(ex);
} catch (IOException ex) {
JOptionPane.showMessageDialog(this, getMessage("ImportCSVUIVisualPanel1.validation.error"), getMessage("ImportCSVUIVisualPanel1.validation.file-permissions-error"), JOptionPane.ERROR_MESSAGE);
}
}
wizard1.fireChangeEvent();
pathTextField.setText(pathTextField.getText());//To fire validation panel messages.
}
@Override
public String getName() {
return getMessage("ImportCSVUIVisualPanel1.name");
}
public Character getSelectedSeparator() {
Object item = separatorComboBox.getSelectedItem();
if (item instanceof SeparatorWrapper) {
return ((SeparatorWrapper) item).separator;
} else {
return item.toString().charAt(0);
}
}
public File getSelectedFile() {
return selectedFile;
}
public ImportCSVUIWizardAction.Mode getMode() {
switch (tableComboBox.getSelectedIndex()) {
case 0:
return ImportCSVUIWizardAction.Mode.NODES_TABLE;
case 1:
return ImportCSVUIWizardAction.Mode.EDGES_TABLE;
default:
return ImportCSVUIWizardAction.Mode.NODES_TABLE;//Not going to happen.
}
}
public Charset getSelectedCharset() {
return Charset.forName(charsetComboBox.getSelectedItem().toString());
}
public int getColumnCount() {
return columnCount;
}
public boolean isColumnNamesRepeated() {
return columnNamesRepeated;
}
public boolean isValidFile() {
return selectedFile != null && selectedFile.exists();
}
public boolean hasColumns() {
return columnCount > 0;
}
public boolean areValidColumnsForTable() {
switch (getMode()) {
case NODES_TABLE:
return true;
case EDGES_TABLE:
return hasSourceNodeColumn && hasTargetNodeColumn;
default:
return false;
}
}
public boolean isCSVValid() {
return isValidFile() && hasColumns() && !columnNamesRepeated && areValidColumnsForTable();
}
class SeparatorWrapper {
private Character separator;
private String displayText;
public SeparatorWrapper(Character separator) {
this.separator = separator;
}
public SeparatorWrapper(Character separator, String displayText) {
this.separator = separator;
this.displayText = displayText;
}
@Override
public String toString() {
if (displayText != null) {
return displayText;
} else {
return String.valueOf(separator);
}
}
}
private String getMessage(String resName) {
return NbBundle.getMessage(ImportCSVUIVisualPanel1.class, resName);
}
/** 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() {
descriptionLabel = new javax.swing.JLabel();
pathTextField = new javax.swing.JTextField();
fileButton = new javax.swing.JButton();
separatorLabel = new javax.swing.JLabel();
separatorComboBox = new javax.swing.JComboBox();
tableLabel = new javax.swing.JLabel();
tableComboBox = new javax.swing.JComboBox();
previewLabel = new javax.swing.JLabel();
scroll = new javax.swing.JScrollPane();
previewTable = new javax.swing.JTable();
charsetLabel = new javax.swing.JLabel();
charsetComboBox = new javax.swing.JComboBox();
descriptionLabel.setText(org.openide.util.NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.descriptionLabel.text")); // NOI18N
pathTextField.setEditable(false);
pathTextField.setText(org.openide.util.NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.pathTextField.text")); // NOI18N
fileButton.setText(org.openide.util.NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.fileButton.text")); // NOI18N
fileButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
fileButtonActionPerformed(evt);
}
});
separatorLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
separatorLabel.setText(org.openide.util.NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.separatorLabel.text")); // NOI18N
separatorComboBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
separatorComboBoxItemStateChanged(evt);
}
});
tableLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
tableLabel.setText(org.openide.util.NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.tableLabel.text")); // NOI18N
tableComboBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
tableComboBoxItemStateChanged(evt);
}
});
previewLabel.setText(org.openide.util.NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.previewLabel.text")); // NOI18N
scroll.setViewportView(previewTable);
charsetLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
charsetLabel.setText(org.openide.util.NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.charsetLabel.text")); // NOI18N
charsetComboBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
charsetComboBoxItemStateChanged(evt);
}
});
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(scroll, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 325, Short.MAX_VALUE)
.addComponent(descriptionLabel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 325, Short.MAX_VALUE)
.addGroup(layout.createSequentialGroup()
.addComponent(pathTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 274, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(fileButton))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(separatorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(separatorComboBox, 0, 90, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(tableLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(tableComboBox, 0, 123, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(charsetLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 96, Short.MAX_VALUE)
.addComponent(charsetComboBox, 0, 96, Short.MAX_VALUE)))
.addComponent(previewLabel, javax.swing.GroupLayout.Alignment.LEADING))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(descriptionLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(pathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(fileButton))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addComponent(separatorLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(separatorComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(tableLabel)
.addComponent(charsetLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(tableComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(charsetComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGap(18, 18, 18)
.addComponent(previewLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(scroll, javax.swing.GroupLayout.DEFAULT_SIZE, 147, Short.MAX_VALUE)
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void fileButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileButtonActionPerformed
String lastPath = NbPreferences.forModule(ImportCSVUIVisualPanel1.class).get(LAST_PATH, null);
final JFileChooser chooser = new JFileChooser(lastPath);
chooser.setAcceptAllFileFilterUsed(false);
DialogFileFilter dialogFileFilter = new DialogFileFilter(NbBundle.getMessage(ImportCSVUIVisualPanel1.class, "ImportCSVUIVisualPanel1.filechooser.csvDescription"));
dialogFileFilter.addExtension("csv");
chooser.addChoosableFileFilter(dialogFileFilter);
chooser.setSelectedFile(selectedFile);
int returnFile = chooser.showOpenDialog(null);
if (returnFile != JFileChooser.APPROVE_OPTION) {
return;
}
selectedFile = chooser.getSelectedFile();
String path = selectedFile.getAbsolutePath();
pathTextField.setText(path);
//Save last path
String defaultDirectory = selectedFile.getParentFile().getAbsolutePath();
NbPreferences.forModule(ImportCSVUIVisualPanel1.class).put(LAST_PATH, defaultDirectory);
refreshPreviewTable();
}//GEN-LAST:event_fileButtonActionPerformed
private void separatorComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_separatorComboBoxItemStateChanged
refreshPreviewTable();
}//GEN-LAST:event_separatorComboBoxItemStateChanged
private void charsetComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_charsetComboBoxItemStateChanged
refreshPreviewTable();
}//GEN-LAST:event_charsetComboBoxItemStateChanged
private void tableComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_tableComboBoxItemStateChanged
refreshPreviewTable();
}//GEN-LAST:event_tableComboBoxItemStateChanged
private static final String LAST_PATH = "ImportCSVUIVisualPanel1_Save_Last_Path";
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JComboBox charsetComboBox;
private javax.swing.JLabel charsetLabel;
private javax.swing.JLabel descriptionLabel;
private javax.swing.JButton fileButton;
private javax.swing.JTextField pathTextField;
private javax.swing.JLabel previewLabel;
private javax.swing.JTable previewTable;
private javax.swing.JScrollPane scroll;
private javax.swing.JComboBox separatorComboBox;
private javax.swing.JLabel separatorLabel;
private javax.swing.JComboBox tableComboBox;
private javax.swing.JLabel tableLabel;
// End of variables declaration//GEN-END:variables
}