/*
* (c) Copyright 2010-2011 AgileBirds
*
* This file is part of OpenFlexo.
*
* OpenFlexo is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* OpenFlexo 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>.
*
*/
package org.openflexo.fib.utils;
/**
* Widget allowing to edit a file with a popup
*
* @author sguerin
*
*/
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.DefaultListCellRenderer;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.openflexo.fib.controller.FIBController;
import org.openflexo.fib.model.FIBCustom;
import org.openflexo.fib.model.FIBCustom.FIBCustomComponent;
import org.openflexo.swing.ButtonsControlPanel;
import org.openflexo.swing.TextFieldCustomPopup;
import org.openflexo.toolbox.Duration;
import org.openflexo.toolbox.Duration.DurationUnit;
public class DurationSelector extends TextFieldCustomPopup<Duration> implements FIBCustomComponent<Duration, DurationSelector> {
public static final Font NORMAL_FONT = new Font("SansSerif", Font.PLAIN, 11);
private static final String EMPTY_STRING = "";
private Duration _revertValue;
protected DurationChooserPanel durationChooserPanel;
public DurationSelector() {
this((Duration) null);
}
public DurationSelector(Duration aDuration) {
super(aDuration);
if (aDuration != null) {
_revertValue = aDuration.clone();
}
}
public DurationSelector(int col) {
this((Duration) null, col);
}
public DurationSelector(Duration aDuration, int col) {
super(aDuration, col);
if (aDuration != null) {
_revertValue = aDuration.clone();
}
}
@Override
protected ResizablePanel createCustomPanel(Duration editedObject) {
durationChooserPanel = new DurationChooserPanel(editedObject);
return durationChooserPanel;
}
@Override
public void updateCustomPanel(Duration editedObject) {
if (durationChooserPanel != null) {
durationChooserPanel.update(editedObject);
}
}
@Override
public String renderedString(Duration editedObject) {
if (editedObject != null) {
return getLocalizedStringRepresentation(editedObject);
} else {
return EMPTY_STRING;
}
}
public String getLocalizedStringRepresentation(Duration duration) {
if (duration.getUnit() == null) {
return "";
}
return duration.getValue() + " " + localizedForKey(duration.getUnit().getLocalizedKey() + (duration.getValue() > 1 ? "s" : ""));
}
protected class DurationChooserPanel extends ResizablePanel {
ButtonsControlPanel controlPanel;
JSpinner valueChooser;
JComboBox unitChooser;
private Dimension defaultDimension = new Dimension(320, 90);
void update(Duration aDuration) {
if (aDuration != null) {
valueChooser.setValue((int) aDuration.getValue());
}
unitChooser.setSelectedItem(aDuration != null ? aDuration.getUnit() : null);
}
protected DurationChooserPanel(Duration aDuration) {
super();
unitChooser = new JComboBox(Duration.DurationUnit.values());
unitChooser.setSelectedItem(DurationUnit.DAYS);
unitChooser.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == unitChooser) {
if (getEditedObject() == null) {
setEditedObject(new Duration((Integer) valueChooser.getValue(), (DurationUnit) unitChooser.getSelectedItem()));
} else {
getEditedObject().setUnit((DurationUnit) unitChooser.getSelectedItem());
}
}
fireEditedObjectChanged();
}
});
unitChooser.setRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component returned = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if (returned != null && returned instanceof JLabel && value != null) {
boolean isMultiple = getEditedObject() != null ? getEditedObject().getValue() > 1 : false;
((JLabel) returned).setText(localizedForKey(((DurationUnit) value).getLocalizedKey() + (isMultiple ? "s" : "")));
}
return returned;
}
});
SpinnerNumberModel valueModel = new SpinnerNumberModel(1, Integer.MIN_VALUE, Integer.MAX_VALUE, 1);
valueChooser = new JSpinner(valueModel);
valueChooser.setEditor(new JSpinner.NumberEditor(valueChooser, "#"));
valueChooser.setMinimumSize(valueChooser.getPreferredSize());
valueChooser.setValue(1);
valueChooser.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
if (e.getSource() == valueChooser) {
if (getEditedObject() == null) {
setEditedObject(new Duration((Integer) valueChooser.getValue(), (DurationUnit) unitChooser.getSelectedItem()));
} else {
getEditedObject().setValue((Integer) valueChooser.getValue());
}
}
fireEditedObjectChanged();
}
});
JPanel valuesPanel = new JPanel();
valuesPanel.setLayout(new FlowLayout());
valuesPanel.add(valueChooser);
valuesPanel.add(unitChooser);
controlPanel = new ButtonsControlPanel() {
@Override
public String localizedForKeyAndButton(String key, JButton component) {
return DurationSelector.this.localizedForKeyAndButton(key, component);
}
};
controlPanel.addButton("apply", new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
apply();
}
});
controlPanel.addButton("cancel", new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
cancel();
}
});
controlPanel.addButton("reset", new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
setEditedObject(null);
apply();
}
});
controlPanel.applyFocusTraversablePolicyTo(this, true);
setLayout(new BorderLayout());
add(valuesPanel, BorderLayout.CENTER);
add(controlPanel, BorderLayout.SOUTH);
durationChooserPanel = this;
durationChooserPanel.setSize(defaultDimension);
durationChooserPanel.setMinimumSize(defaultDimension);
durationChooserPanel.setMaximumSize(defaultDimension);
update(aDuration);
}
@Override
public Dimension getDefaultSize() {
return defaultDimension;
}
@Override
public void setPreferredSize(Dimension aDimension) {
// durationChooserPanel.setPreferredSize(aDimension);
super.setPreferredSize(aDimension);
}
}
@Override
public void apply() {
setRevertValue(getEditedObject() != null ? getEditedObject().clone() : getEditedObject());
closePopup();
super.apply();
}
@Override
public void cancel() {
setEditedObject(_revertValue);
closePopup();
super.cancel();
}
@Override
public void setRevertValue(Duration oldValue) {
_revertValue = oldValue;
}
@Override
public Duration getRevertValue() {
return _revertValue;
}
@Override
public void setEditedObject(Duration object) {
if (object != null && object.getValue() == 0) {
super.setEditedObject(null);
} else {
super.setEditedObject(object);
}
// GPO: We update the field programmatically but without using invokeLater because in the context of table cell rendering it will
// cause all cells to display the same value.
String val = renderedString(getEditedObject());
if (val == null && getTextField().getText() == null) {
return;
}
if (getTextField().getText() != null && getTextField().getText().equals(val)) {
return;
}
_isProgrammaticalySet = true;
getTextField().setText(val);
_isProgrammaticalySet = false;
}
// Override if required
public String localizedForKeyAndButton(String key, JButton component) {
return key;
}
@Override
protected void openPopup() {
super.openPopup();
if (durationChooserPanel != null) {
durationChooserPanel.controlPanel.applyFocusTraversablePolicyTo(durationChooserPanel, true);
}
}
@Override
public DurationSelector getJComponent() {
return this;
}
@Override
public Class<Duration> getRepresentedType() {
return Duration.class;
}
@Override
public void init(FIBCustom component, FIBController controller) {
}
}