/*
Copyright 2008-2010 Gephi
Authors : Eduardo Ramos <eduramiba@gmail.com>
Website : http://www.gephi.org
This file is part of Gephi.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright 2011 Gephi Consortium. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 3 only ("GPL") or the Common
Development and Distribution License("CDDL") (collectively, the
"License"). You may not use this file except in compliance with the
License. You can obtain a copy of the License at
http://gephi.org/about/legal/license-notice/
or /cddl-1.0.txt and /gpl-3.0.txt. See the License for the
specific language governing permissions and limitations under the
License. When distributing the software, include this License Header
Notice in each file and include the License files at
/cddl-1.0.txt and /gpl-3.0.txt. If applicable, add the following below the
License Header, with the fields enclosed by brackets [] replaced by
your own identifying information:
"Portions Copyrighted [year] [name of copyright owner]"
If you wish your version of this file to be governed by only the CDDL
or only the GPL Version 3, indicate your decision by adding
"[Contributor] elects to include this software in this distribution
under the [CDDL or GPL Version 3] license." If you do not indicate a
single choice of license, a recipient has the option to distribute
your version of this file under either the CDDL, the GPL Version 3 or
to extend the choice of license to its licensees as provided above.
However, if you add GPL Version 3 code and therefore, elected the GPL
Version 3 license, then the option applies only if the new code is
made subject to such option by the copyright holder.
Contributor(s):
Portions Copyrighted 2011 Gephi Consortium.
*/
package org.gephi.desktop.datalab.general.actions;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JList;
import javax.swing.event.ListDataEvent;
import javax.swing.event.ListDataListener;
import org.gephi.data.attributes.api.AttributeColumn;
import org.gephi.data.attributes.api.AttributeController;
import org.gephi.data.attributes.api.AttributeTable;
import org.gephi.datalab.api.DataLaboratoryHelper;
import org.gephi.datalab.spi.columns.merge.AttributeColumnsMergeStrategy;
import org.gephi.ui.components.richtooltip.RichTooltip;
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.ImageUtilities;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
/**
* UI for choosing columns to merge and a merge strategy.
* @author Eduardo Ramos <eduramiba@gmail.com>
*/
public class MergeColumnsUI extends javax.swing.JPanel {
private JButton okButton;
public enum Mode {
NODES_TABLE,
EDGES_TABLE
}
private Mode mode = Mode.NODES_TABLE;
private AttributeTable table;
private DefaultListModel availableColumnsModel;
private DefaultListModel columnsToMergeModel;
private AttributeColumnsMergeStrategy[] availableMergeStrategies;
/** Creates new form MergeColumnsUI */
public MergeColumnsUI() {
initComponents();
infoLabel.addMouseListener(new MouseAdapter() {
RichTooltip richTooltip;
@Override
public void mouseEntered(MouseEvent e) {
int index = availableStrategiesComboBox.getSelectedIndex();
if (infoLabel.isEnabled() && index != -1) {
richTooltip = buildTooltip(availableMergeStrategies[index]);
}
if (richTooltip != null) {
richTooltip.showTooltip(infoLabel);
}
}
@Override
public void mouseExited(MouseEvent e) {
if (richTooltip != null) {
richTooltip.hideTooltip();
richTooltip = null;
}
}
private RichTooltip buildTooltip(AttributeColumnsMergeStrategy strategy) {
if (strategy.getDescription() != null && !strategy.getDescription().isEmpty()) {
RichTooltip tooltip = new RichTooltip(strategy.getName(), strategy.getDescription());
if (strategy.getIcon() != null) {
tooltip.setMainImage(ImageUtilities.icon2Image(strategy.getIcon()));
}
return tooltip;
} else {
return null;
}
}
});
availableColumnsModel = new DefaultListModel();
columnsToMergeModel = new DefaultListModel();
columnsToMergeModel.addListDataListener(new ListDataListener() {
public void intervalAdded(ListDataEvent e) {
refreshAvailableMergeStrategies();
}
public void intervalRemoved(ListDataEvent e) {
refreshAvailableMergeStrategies();
}
public void contentsChanged(ListDataEvent e) {
refreshAvailableMergeStrategies();
}
});
}
private void loadColumns() {
availableColumnsModel.clear();
columnsToMergeModel.clear();
AttributeController ac = Lookup.getDefault().lookup(AttributeController.class);
AttributeColumn[] columns;
if (mode == Mode.NODES_TABLE) {
table = ac.getModel().getNodeTable();
columns = table.getColumns();
} else {
table = ac.getModel().getEdgeTable();
columns = table.getColumns();
}
for (int i = 0; i < columns.length; i++) {
availableColumnsModel.addElement(new ColumnWrapper(columns[i]));
}
availableColumnsList.setModel(availableColumnsModel);
columnsToMergeList.setModel(columnsToMergeModel);
}
private void refreshAvailableMergeStrategies() {
//Save currently selected strategy index:
int selectedStrategyIndex = availableStrategiesComboBox.getSelectedIndex();
availableStrategiesComboBox.removeAllItems();
AttributeColumn[] columnsToMerge = getColumnsToMerge();
if (columnsToMerge.length < 1) {
return;
}
AttributeColumnsMergeStrategy[] strategies = DataLaboratoryHelper.getDefault().getAttributeColumnsMergeStrategies();
ArrayList<AttributeColumnsMergeStrategy> availableStrategiesList = new ArrayList<AttributeColumnsMergeStrategy>();
for (AttributeColumnsMergeStrategy strategy : strategies) {
strategy.setup(table, columnsToMerge);
availableStrategiesList.add(strategy);//Add all but disallow executing the strategies that cannot be executed with given column
}
availableMergeStrategies = availableStrategiesList.toArray(new AttributeColumnsMergeStrategy[0]);
for (AttributeColumnsMergeStrategy s : availableMergeStrategies) {
availableStrategiesComboBox.addItem(s.getName());
}
if (selectedStrategyIndex >= 0 && selectedStrategyIndex < availableStrategiesComboBox.getItemCount()) {
availableStrategiesComboBox.setSelectedIndex(selectedStrategyIndex);
}
}
private void refreshOkButton() {
if (okButton != null) {
okButton.setEnabled(canExecuteSelectedStrategy());
}
}
public boolean canExecuteSelectedStrategy() {
int index = availableStrategiesComboBox.getSelectedIndex();
boolean result;
if (index != -1) {
result = availableMergeStrategies[index].canExecute();
} else {
result = false;
}
return result;
}
private AttributeColumn[] getColumnsToMerge() {
Object[] elements = columnsToMergeModel.toArray();
AttributeColumn[] columns = new AttributeColumn[elements.length];
for (int i = 0; i < elements.length; i++) {
columns[i] = ((ColumnWrapper) elements[i]).getColumn();
}
return columns;
}
public void setup(Mode mode) {
this.mode = mode;
loadColumns();
}
public void execute() {
int index = availableStrategiesComboBox.getSelectedIndex();
if (index != -1) {
DataLaboratoryHelper.getDefault().executeManipulator(availableMergeStrategies[index]);
}
}
public String getDisplayName() {
return NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.title");
}
public void setOkButton(JButton okButton) {
this.okButton = okButton;
refreshOkButton();
}
/**
* Class to contain a column and return its name + type with toString method.
*/
class ColumnWrapper {
private AttributeColumn column;
public ColumnWrapper(AttributeColumn column) {
this.column = column;
}
public AttributeColumn getColumn() {
return column;
}
public void setColumn(AttributeColumn column) {
this.column = column;
}
@Override
public String toString() {
return column.getTitle() + " -- " + column.getType().getTypeString();
}
}
private void moveElementsFromListToOtherList(JList sourceList, JList targetList) {
DefaultListModel sourceModel, targetModel;
sourceModel = (DefaultListModel) sourceList.getModel();
targetModel = (DefaultListModel) targetList.getModel();
Object[] selection = sourceList.getSelectedValues();
for (Object element : selection) {
sourceModel.removeElement(element);
targetModel.addElement(element);
}
}
public static ValidationPanel createValidationPanel(MergeColumnsUI innerPanel) {
ValidationPanel validationPanel = new ValidationPanel();
if (innerPanel == null) {
innerPanel = new MergeColumnsUI();
}
validationPanel.setInnerComponent(innerPanel);
ValidationGroup group = validationPanel.getValidationGroup();
group.add(innerPanel.availableStrategiesComboBox, new MergeStrategyValidator(innerPanel));
return validationPanel;
}
private static class MergeStrategyValidator implements Validator<ComboBoxModel> {
private MergeColumnsUI ui;
public MergeStrategyValidator(MergeColumnsUI ui) {
this.ui = ui;
}
public boolean validate(Problems problems, String string, ComboBoxModel t) {
if (t.getSelectedItem() != null) {
if (ui.canExecuteSelectedStrategy()) {
return true;
} else {
problems.add(NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.problems.not_executable_strategy"));
return false;
}
} else {
problems.add(NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.problems.less_than_2_columns_selected"));
return false;
}
}
}
/** 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() {
jScrollPane1 = new javax.swing.JScrollPane();
columnsToMergeList = new javax.swing.JList();
description = new javax.swing.JLabel();
addColumnButton = new javax.swing.JButton();
removeColumnButton = new javax.swing.JButton();
jScrollPane2 = new javax.swing.JScrollPane();
availableColumnsList = new javax.swing.JList();
availableColumnsLabel = new javax.swing.JLabel();
columnsToMergeLabel = new javax.swing.JLabel();
availableStrategiesLabel = new javax.swing.JLabel();
availableStrategiesComboBox = new javax.swing.JComboBox();
infoLabel = new javax.swing.JLabel();
jScrollPane1.setViewportView(columnsToMergeList);
description.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
description.setText(org.openide.util.NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.description.text")); // NOI18N
addColumnButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/gephi/desktop/datalab/resources/arrow.png"))); // NOI18N
addColumnButton.setText(org.openide.util.NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.addColumnButton.text")); // NOI18N
addColumnButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
addColumnButtonActionPerformed(evt);
}
});
removeColumnButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/gephi/desktop/datalab/resources/arrow-180.png"))); // NOI18N
removeColumnButton.setText(org.openide.util.NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.removeColumnButton.text")); // NOI18N
removeColumnButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
removeColumnButtonActionPerformed(evt);
}
});
jScrollPane2.setViewportView(availableColumnsList);
availableColumnsLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
availableColumnsLabel.setText(org.openide.util.NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.availableColumnsLabel.text")); // NOI18N
columnsToMergeLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
columnsToMergeLabel.setText(org.openide.util.NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.columnsToMergeLabel.text")); // NOI18N
availableStrategiesLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
availableStrategiesLabel.setText(org.openide.util.NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.availableStrategiesLabel.text")); // NOI18N
availableStrategiesComboBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
availableStrategiesComboBoxItemStateChanged(evt);
}
});
infoLabel.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
infoLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/gephi/desktop/datalab/resources/info.png"))); // NOI18N
infoLabel.setText(org.openide.util.NbBundle.getMessage(MergeColumnsUI.class, "MergeColumnsUI.infoLabel.text")); // NOI18N
infoLabel.setEnabled(false);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addComponent(description, javax.swing.GroupLayout.DEFAULT_SIZE, 394, Short.MAX_VALUE)
.addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(availableColumnsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jScrollPane2, 0, 0, Short.MAX_VALUE)
.addComponent(availableStrategiesLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 152, Short.MAX_VALUE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(addColumnButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(removeColumnButton, javax.swing.GroupLayout.PREFERRED_SIZE, 49, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup()
.addGap(14, 14, 14)
.addComponent(columnsToMergeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 149, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 153, javax.swing.GroupLayout.PREFERRED_SIZE))))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(availableStrategiesComboBox, 0, 218, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(infoLabel)
.addContainerGap())))))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap()
.addComponent(description, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(availableColumnsLabel)
.addComponent(columnsToMergeLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 204, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 204, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(12, 12, 12))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(addColumnButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(removeColumnButton)
.addGap(94, 94, 94)))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(availableStrategiesComboBox, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(infoLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 20, Short.MAX_VALUE)
.addComponent(availableStrategiesLabel))
.addContainerGap())
);
}// </editor-fold>//GEN-END:initComponents
private void addColumnButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_addColumnButtonActionPerformed
moveElementsFromListToOtherList(availableColumnsList, columnsToMergeList);
}//GEN-LAST:event_addColumnButtonActionPerformed
private void removeColumnButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_removeColumnButtonActionPerformed
moveElementsFromListToOtherList(columnsToMergeList, availableColumnsList);
}//GEN-LAST:event_removeColumnButtonActionPerformed
private void availableStrategiesComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_availableStrategiesComboBoxItemStateChanged
refreshOkButton();
infoLabel.setEnabled(availableStrategiesComboBox.getSelectedIndex() != -1);
}//GEN-LAST:event_availableStrategiesComboBoxItemStateChanged
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton addColumnButton;
private javax.swing.JLabel availableColumnsLabel;
private javax.swing.JList availableColumnsList;
private javax.swing.JComboBox availableStrategiesComboBox;
private javax.swing.JLabel availableStrategiesLabel;
private javax.swing.JLabel columnsToMergeLabel;
private javax.swing.JList columnsToMergeList;
private javax.swing.JLabel description;
private javax.swing.JLabel infoLabel;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JButton removeColumnButton;
// End of variables declaration//GEN-END:variables
}