/* 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.datalab.api.DataLaboratoryHelper; import org.gephi.datalab.spi.columns.merge.AttributeColumnsMergeStrategy; import org.gephi.graph.api.Column; import org.gephi.graph.api.GraphController; import org.gephi.graph.api.GraphModel; import org.gephi.graph.api.Table; 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 */ public class MergeColumnsUI extends javax.swing.JPanel { private JButton okButton; public enum Mode { NODES_TABLE, EDGES_TABLE } private Mode mode = Mode.NODES_TABLE; private Table table; private final DefaultListModel availableColumnsModel; private final 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() { @Override public void intervalAdded(ListDataEvent e) { refreshAvailableMergeStrategies(); } @Override public void intervalRemoved(ListDataEvent e) { refreshAvailableMergeStrategies(); } @Override public void contentsChanged(ListDataEvent e) { refreshAvailableMergeStrategies(); } }); } private void loadColumns() { availableColumnsModel.clear(); columnsToMergeModel.clear(); GraphModel am = Lookup.getDefault().lookup(GraphController.class).getGraphModel(); Column[] columns; if (mode == Mode.NODES_TABLE) { table = am.getNodeTable(); columns = table.toArray(); } else { table = am.getEdgeTable(); columns = table.toArray(); } for (Column column : columns) { availableColumnsModel.addElement(new ColumnWrapper(column)); } availableColumnsList.setModel(availableColumnsModel); columnsToMergeList.setModel(columnsToMergeModel); } private void refreshAvailableMergeStrategies() { //Save currently selected strategy index: int selectedStrategyIndex = availableStrategiesComboBox.getSelectedIndex(); availableStrategiesComboBox.removeAllItems(); Column[] columnsToMerge = getColumnsToMerge(); if (columnsToMerge.length < 1) { return; } AttributeColumnsMergeStrategy[] strategies = DataLaboratoryHelper.getDefault().getAttributeColumnsMergeStrategies(); ArrayList<AttributeColumnsMergeStrategy> availableStrategiesList = new ArrayList<>(); 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 Column[] getColumnsToMerge() { Object[] elements = columnsToMergeModel.toArray(); Column[] columns = new Column[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 Column column; public ColumnWrapper(Column column) { this.column = column; } public Column getColumn() { return column; } public void setColumn(Column column) { this.column = column; } @Override public String toString() { return column.getTitle() + " -- " + column.getTypeClass().getSimpleName(); } } 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; } @Override 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(); columnsToMergeList.addMouseListener(new java.awt.event.MouseAdapter() { @Override public void mouseClicked(java.awt.event.MouseEvent evt) { columnsToMergeListMouseClicked(evt); } }); 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() { @Override 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() { @Override public void actionPerformed(java.awt.event.ActionEvent evt) { removeColumnButtonActionPerformed(evt); } }); availableColumnsList.addMouseListener(new java.awt.event.MouseAdapter() { @Override public void mouseClicked(java.awt.event.MouseEvent evt) { availableColumnsListMouseClicked(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() { @Override 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) .addComponent(availableColumnsLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 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) .addComponent(addColumnButton) .addComponent(removeColumnButton)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup() .addGap(14, 14, 14) .addComponent(columnsToMergeLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 149, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 153, Short.MAX_VALUE))) .addGap(30, 30, 30)) .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.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE) .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 private void availableColumnsListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_availableColumnsListMouseClicked if (evt.getClickCount() == 2) { int index = availableColumnsList.locationToIndex(evt.getPoint()); availableColumnsList.setSelectedIndex(index); moveElementsFromListToOtherList(availableColumnsList, columnsToMergeList); } }//GEN-LAST:event_availableColumnsListMouseClicked private void columnsToMergeListMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_columnsToMergeListMouseClicked if (evt.getClickCount() == 2) { int index = columnsToMergeList.locationToIndex(evt.getPoint()); columnsToMergeList.setSelectedIndex(index); moveElementsFromListToOtherList(columnsToMergeList, availableColumnsList); } }//GEN-LAST:event_columnsToMergeListMouseClicked // 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 }