/* 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.ui.processor.plugin; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.text.SimpleDateFormat; import java.util.Date; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.gephi.dynamic.DynamicUtilities; import org.gephi.dynamic.api.DynamicController; import org.gephi.dynamic.api.DynamicModel; import org.gephi.io.processor.plugin.DynamicProcessor; 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.ValidationListener; import org.netbeans.validation.api.ui.ValidationPanel; import org.openide.util.Lookup; /** * * @author Mathieu Bastian */ public class DynamicProcessorPanel extends javax.swing.JPanel { private double lastFrame = Double.POSITIVE_INFINITY; public DynamicProcessorPanel() { initComponents(); } public void setup(DynamicProcessor processor) { DynamicController dynamicController = Lookup.getDefault().lookup(DynamicController.class); DynamicModel dynamicModel = dynamicController.getModel(); if (dynamicModel != null) { lastFrame = dynamicModel.getMax(); } lastFrameLabel.setText("None"); if (dynamicModel != null && !(dynamicModel.getMin() == Double.NEGATIVE_INFINITY && dynamicModel.getMax() == Double.POSITIVE_INFINITY)) { //Select only the current time format DynamicModel.TimeFormat timeFormat = dynamicModel.getTimeFormat(); if (timeFormat.equals(DynamicModel.TimeFormat.DATE)) { dateRadio.setSelected(true); timeStampRadio.setEnabled(false); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { datePicker.setDate(sdf.parse(processor.getDate())); } catch (Exception e) { datePicker.setDate(new Date()); } lastFrameLabel.setText(DynamicUtilities.getXMLDateStringFromDouble(lastFrame)); } else { timeStampRadio.setSelected(true); dateRadio.setEnabled(false); lastFrameLabel.setText(Double.toString(lastFrame)); } } labelMatchingCheckbox.setSelected(processor.isLabelmatching()); } public void unsetup(DynamicProcessor processor) { processor.setDateMode(dateRadio.isSelected()); if (dateRadio.isSelected()) { try { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String begin = sdf.format(datePicker.getDate()); processor.setDate(begin); } catch (Exception e) { //Exception catched later in processor } } else { processor.setDate(timestampField.getText()); } processor.setLabelmatching(labelMatchingCheckbox.isSelected()); } public static ValidationPanel createValidationPanel(DynamicProcessorPanel innerPanel) { ValidationPanel validationPanel = new ValidationPanel(); validationPanel.setInnerComponent(innerPanel); ValidationGroup group = validationPanel.getValidationGroup(); final FullValidationListener fullValidationListener = new FullValidationListener(innerPanel); group.add(fullValidationListener); PropertyChangeListener listener = new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent e) { if ("date".equals(e.getPropertyName())) { fullValidationListener.event(); } } }; innerPanel.datePicker.addPropertyChangeListener(listener); innerPanel.timestampField.getDocument().addDocumentListener(new DocumentListener() { public void insertUpdate(DocumentEvent e) { fullValidationListener.event(); } public void removeUpdate(DocumentEvent e) { fullValidationListener.event(); } public void changedUpdate(DocumentEvent e) { } }); innerPanel.dateRadio.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fullValidationListener.event(); } }); innerPanel.timeStampRadio.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { fullValidationListener.event(); } }); return validationPanel; } private static class FullValidationListener extends ValidationListener { FullValidator lastFrameValidator; public FullValidationListener(DynamicProcessorPanel panel) { lastFrameValidator = new FullValidator((panel)); } @Override protected boolean validate(Problems problems) { return lastFrameValidator.validate(problems, "", ""); } public void event() { this.validate(); } } private static class FullValidator implements Validator<String> { private DynamicProcessorPanel panel; public FullValidator(DynamicProcessorPanel panel) { this.panel = panel; } @Override public boolean validate(Problems problems, String compName, String model) { if (panel.dateRadio.isSelected()) { if (panel.datePicker.getDate() == null) { problems.add("The date can't be empty"); return false; } else if (!Double.isInfinite(panel.lastFrame)) { //Date SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); String begin = sdf.format(panel.datePicker.getDate()); double d = DynamicUtilities.getDoubleFromXMLDateString(begin); if (d <= panel.lastFrame) { problems.add("The new date must be later than the last current date"); return false; } } } else { String t = panel.timestampField.getText(); if (t.isEmpty()) { problems.add("The time stamp can't be empty"); return false; } try { Double.parseDouble(panel.timestampField.getText()); } catch (Exception e) { problems.add("The time stamp must be a number"); return false; } if (!Double.isInfinite(panel.lastFrame) && Double.parseDouble(panel.timestampField.getText()) <= panel.lastFrame) { problems.add("The new time stamp must be greater than the last frame"); return false; } } return true; } } /** 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() { bindingGroup = new org.jdesktop.beansbinding.BindingGroup(); buttongroup = new javax.swing.ButtonGroup(); header = new org.jdesktop.swingx.JXHeader(); dateRadio = new javax.swing.JRadioButton(); labelDate = new javax.swing.JLabel(); datePicker = new org.jdesktop.swingx.JXDatePicker(); timeStampRadio = new javax.swing.JRadioButton(); labelTime = new javax.swing.JLabel(); timestampField = new javax.swing.JTextField(); labelLastFrame = new javax.swing.JLabel(); lastFrameLabel = new javax.swing.JLabel(); labelMatchingCheckbox = new javax.swing.JCheckBox(); header.setDescription(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.header.description")); // NOI18N header.setTitle(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.header.title")); // NOI18N buttongroup.add(dateRadio); dateRadio.setSelected(true); dateRadio.setText(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.dateRadio.text")); // NOI18N labelDate.setText(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.labelDate.text")); // NOI18N org.jdesktop.beansbinding.Binding binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, dateRadio, org.jdesktop.beansbinding.ELProperty.create("${selected}"), labelDate, org.jdesktop.beansbinding.BeanProperty.create("enabled")); bindingGroup.addBinding(binding); binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, dateRadio, org.jdesktop.beansbinding.ELProperty.create("${selected}"), datePicker, org.jdesktop.beansbinding.BeanProperty.create("enabled")); bindingGroup.addBinding(binding); buttongroup.add(timeStampRadio); timeStampRadio.setText(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.timeStampRadio.text")); // NOI18N labelTime.setText(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.labelTime.text")); // NOI18N binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, timeStampRadio, org.jdesktop.beansbinding.ELProperty.create("${selected}"), labelTime, org.jdesktop.beansbinding.BeanProperty.create("enabled")); bindingGroup.addBinding(binding); binding = org.jdesktop.beansbinding.Bindings.createAutoBinding(org.jdesktop.beansbinding.AutoBinding.UpdateStrategy.READ_WRITE, timeStampRadio, org.jdesktop.beansbinding.ELProperty.create("${selected}"), timestampField, org.jdesktop.beansbinding.BeanProperty.create("enabled")); bindingGroup.addBinding(binding); labelLastFrame.setFont(labelLastFrame.getFont().deriveFont(labelLastFrame.getFont().getStyle() | java.awt.Font.BOLD)); labelLastFrame.setText(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.labelLastFrame.text")); // NOI18N labelMatchingCheckbox.setText(org.openide.util.NbBundle.getMessage(DynamicProcessorPanel.class, "DynamicProcessorPanel.labelMatchingCheckbox.text")); // NOI18N 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() .addComponent(labelMatchingCheckbox) .addContainerGap(285, Short.MAX_VALUE)) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(labelLastFrame) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(lastFrameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 243, Short.MAX_VALUE) .addGap(136, 136, 136)) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(21, 21, 21) .addComponent(labelDate) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(dateRadio) .addGroup(layout.createSequentialGroup() .addGap(21, 21, 21) .addComponent(labelTime) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(timestampField, javax.swing.GroupLayout.PREFERRED_SIZE, 117, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(timeStampRadio)) .addContainerGap(205, Short.MAX_VALUE)) .addComponent(header, javax.swing.GroupLayout.DEFAULT_SIZE, 498, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(header, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addComponent(labelMatchingCheckbox) .addGap(18, 18, 18) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addComponent(labelLastFrame) .addGap(18, 18, 18) .addComponent(dateRadio)) .addComponent(lastFrameLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(labelDate) .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGap(18, 18, 18) .addComponent(timeStampRadio) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(labelTime) .addComponent(timestampField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap(30, Short.MAX_VALUE)) ); bindingGroup.bind(); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttongroup; private org.jdesktop.swingx.JXDatePicker datePicker; private javax.swing.JRadioButton dateRadio; private org.jdesktop.swingx.JXHeader header; private javax.swing.JLabel labelDate; private javax.swing.JLabel labelLastFrame; private javax.swing.JCheckBox labelMatchingCheckbox; private javax.swing.JLabel labelTime; private javax.swing.JLabel lastFrameLabel; private javax.swing.JRadioButton timeStampRadio; private javax.swing.JTextField timestampField; private org.jdesktop.beansbinding.BindingGroup bindingGroup; // End of variables declaration//GEN-END:variables }