package eu.doppel_helix.netbeans.mantisintegration.issue;
import biz.futureware.mantisconnect.CustomFieldDefinitionData;
import biz.futureware.mantisconnect.UserData;
import com.clutch.dates.StringToTime;
import eu.doppel_helix.netbeans.mantisintegration.swing.DelegatingBaseLineJPanel;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.DefaultListModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListModel;
import javax.swing.ListSelectionModel;
import org.jdesktop.swingx.JXDatePicker;
import org.jdesktop.swingx.WrapLayout;
public abstract class CustomFieldComponent extends DelegatingBaseLineJPanel implements ActionListener {
private enum Type {
DisplayOnly, // Added value
String,
Numeric,
Float,
Enumeration,
Email,
Checkbox,
List,
MultiselectionList,
Date,
Radio
}
public static CustomFieldComponent create(CustomFieldDefinitionData cfdd, UserData ud) {
// typeId is zero based - but more values are introduced (-1 for DisplayOnly)
Type type = Type.values()[cfdd.getType().intValue() + 1];
if (ud != null
&& ud.getAccess_level().compareTo(cfdd.getAccess_level_rw()) < 0) {
return new CustomFieldComponentDisplay(cfdd, type);
} else {
switch (type) {
case Date:
return new CustomFieldComponentDate(cfdd);
case String:
case Email:
return new CustomFieldComponentLine(cfdd);
case List:
return new CustomFieldComponentList(cfdd, false);
case MultiselectionList:
return new CustomFieldComponentList(cfdd, true);
case Checkbox:
return new CustomFieldComponentCheckbox(cfdd);
case Radio:
return new CustomFieldComponentRadio(cfdd);
case Numeric:
return new CustomFieldComponentNumeric(cfdd, false);
case Float:
return new CustomFieldComponentNumeric(cfdd, true);
case Enumeration:
return new CustomFieldComponentEnum(cfdd);
default:
return new CustomFieldComponentDisplay(cfdd, type);
}
}
}
private final CustomFieldDefinitionData cfdd;
private JLabel label;
protected JPopupMenu popup = new JPopupMenu();
private CustomFieldComponent(CustomFieldDefinitionData cfdd) {
this.cfdd = cfdd;
setOpaque(false);
JMenuItem mi = new JMenuItem("Reset");
mi.addActionListener(this);
mi.setActionCommand("reset");
popup.add(mi);
this.setComponentPopupMenu(popup);
}
abstract public String getValue();
abstract public void setValue(String value);
public CustomFieldDefinitionData getCustomFieldDefinitionData() {
return cfdd;
}
public void setDefaultValue() {
setValue(cfdd.getDefault_value());
}
public JLabel getLabel() {
if (label == null) {
label = new JLabel(cfdd.getField().getName() + ":");
}
return label;
}
@Override
public void actionPerformed(ActionEvent e) {
switch (e.getActionCommand()) {
case "reset":
this.setDefaultValue();
break;
}
}
private static class CustomFieldComponentDisplay extends CustomFieldComponent {
private static DateFormat dateFormat = DateFormat.getDateInstance(DateFormat.SHORT);
private String value;
private JLabel outputLabel;
private Type type;
public CustomFieldComponentDisplay(CustomFieldDefinitionData cfdd, Type type) {
super(cfdd);
this.type = type;
this.outputLabel = new JLabel();
this.setLayout(new BorderLayout());
this.add(outputLabel);
this.setComponentPopupMenu(null);
}
@Override
public void setValue(String value) {
this.value = value;
outputLabel.setText(this.toDisplay(value));
}
@Override
public java.lang.String getValue() {
return value;
}
private String toDisplay(String value) {
if (value == null) {
return " ";
}
switch (type) {
case Checkbox:
case MultiselectionList:
return value.replace("|", ", ");
case Date:
synchronized (dateFormat) {
Date d = new Date(Integer.valueOf(value) * 1000l);
return dateFormat.format(d);
}
case Email:
case Enumeration:
case Float:
case Numeric:
case Radio:
case String:
case List:
default:
return value;
}
}
}
private static class CustomFieldComponentDate extends CustomFieldComponent {
private final JXDatePicker datePicker = new JXDatePicker();
public CustomFieldComponentDate(CustomFieldDefinitionData cfdd) {
super(cfdd);
this.setLayout(new WrapLayout(WrapLayout.LEADING));
this.add(datePicker);
datePicker.setComponentPopupMenu(popup);
}
@Override
public void setValue(String value) {
if (value != null) {
value = value.trim();
}
if (value.trim().startsWith("{") && value.endsWith("}")) {
Object date = StringToTime.date(value.substring(1, value.length()
- 1));
if (date instanceof Date) {
datePicker.setDate((Date) date);
} else {
datePicker.setDate(null);
}
} else {
try {
Long unixtimestamp = Long.valueOf(value);
datePicker.setDate(new Date(unixtimestamp * 1000));
} catch (NullPointerException | NumberFormatException ex) {
datePicker.setDate(null);
}
}
}
@Override
public java.lang.String getValue() {
if (datePicker.getDate() != null) {
return Long.toString(datePicker.getDate().getTime() / 1000);
} else {
return "";
}
}
}
private static class CustomFieldComponentLine extends CustomFieldComponent {
private final JTextField line = new JTextField();
public CustomFieldComponentLine(CustomFieldDefinitionData cfdd) {
super(cfdd);
this.setLayout(new BorderLayout());
this.add(line);
line.setComponentPopupMenu(popup);
}
@Override
public void setValue(String value) {
if(value == null) {
value = "";
}
line.setText(value);
}
@Override
public java.lang.String getValue() {
return line.getText();
}
}
private static class CustomFieldComponentList extends CustomFieldComponent {
private final JList<String> list = new JList<>();
public CustomFieldComponentList(CustomFieldDefinitionData cfdd, boolean multiselect) {
super(cfdd);
this.setLayout(new BorderLayout());
this.add(new JScrollPane(list));
this.setMinimumSize(new Dimension(0, 75));
DefaultListModel<String> dlm = new DefaultListModel<>();
String[] possibleValues = cfdd.getPossible_values().split("\\|");
for(int i = 0; i < possibleValues.length; i++) {
dlm.add(i, possibleValues[i]);
}
list.setModel(dlm);
if(multiselect) {
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
} else {
list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
}
list.setComponentPopupMenu(popup);
}
@Override
public void setValue(String value) {
List<String> selectedValues = Arrays.asList(value.split("\\|"));
List<Integer> selectIndices = new ArrayList<>();
ListModel<String> lm = list.getModel();
for(int i = 0; i < lm.getSize(); i++) {
if(selectedValues.contains(lm.getElementAt(i))) {
selectIndices.add(i);
}
}
int selectedIndicesArray[] = new int[selectIndices.size()];
for(int i = 0; i < selectIndices.size(); i++) {
selectedIndicesArray[i] = selectIndices.get(i);
}
list.setSelectedIndices(selectedIndicesArray);
}
@Override
public java.lang.String getValue() {
StringBuilder result = new StringBuilder();
for(int index: list.getSelectedIndices()) {
if(result.length() != 0) {
result.append("|");
}
result.append(list.getModel().getElementAt(index));
}
return result.toString();
}
}
private static class CustomFieldComponentCheckbox extends CustomFieldComponent {
private final Map<String,JCheckBox> checkboxes = new HashMap<>();
public CustomFieldComponentCheckbox(CustomFieldDefinitionData cfdd) {
super(cfdd);
this.setLayout(new WrapLayout(WrapLayout.LEADING));
for(String value: cfdd.getPossible_values().split("\\|")) {
JCheckBox checkbox = new JCheckBox(value);
checkbox.setOpaque(false);
checkbox.setComponentPopupMenu(popup);
checkboxes.put(value, checkbox);
this.add(checkbox);
}
}
@Override
public void setValue(String value) {
List<String> selectedValues = Arrays.asList(value.split("\\|"));
for(Entry<String,JCheckBox> entry: checkboxes.entrySet()) {
entry.getValue().setSelected(selectedValues.contains(entry.getKey()));
}
}
@Override
public java.lang.String getValue() {
StringBuilder result = new StringBuilder();
for(Entry<String,JCheckBox> entry: checkboxes.entrySet()) {
if (entry.getValue().isSelected()) {
if (result.length() != 0) {
result.append("|");
}
result.append(entry.getKey());
}
}
return result.toString();
}
}
private static class CustomFieldComponentRadio extends CustomFieldComponent {
private final Map<String,JRadioButton> radiobuttons = new HashMap<>();
public CustomFieldComponentRadio(CustomFieldDefinitionData cfdd) {
super(cfdd);
this.setLayout(new WrapLayout(WrapLayout.LEADING));
ButtonGroup buttonGroup = new ButtonGroup();
for(String value: cfdd.getPossible_values().split("\\|")) {
JRadioButton radiobutton = new JRadioButton(value);
radiobutton.setOpaque(false);
radiobutton.setComponentPopupMenu(popup);
radiobuttons.put(value, radiobutton);
this.add(radiobutton);
buttonGroup.add(radiobutton);
}
}
@Override
public void setValue(String value) {
List<String> selectedValues = Arrays.asList(value.split("\\|"));
for(Entry<String,JRadioButton> entry: radiobuttons.entrySet()) {
entry.getValue().setSelected(selectedValues.contains(entry.getKey()));
}
}
@Override
public java.lang.String getValue() {
StringBuilder result = new StringBuilder();
for(Entry<String,JRadioButton> entry: radiobuttons.entrySet()) {
if (entry.getValue().isSelected()) {
if (result.length() != 0) {
result.append("|");
}
result.append(entry.getKey());
}
}
return result.toString();
}
}
private static class CustomFieldComponentEnum extends CustomFieldComponent {
private final JComboBox<String> combobox = new JComboBox<>();
public CustomFieldComponentEnum(CustomFieldDefinitionData cfdd) {
super(cfdd);
this.setLayout(new WrapLayout(WrapLayout.LEADING));
DefaultComboBoxModel<String> dcbm = new DefaultComboBoxModel<>();
for(String value: cfdd.getPossible_values().split("\\|")) {
dcbm.addElement(value);
}
combobox.setModel(dcbm);
this.add(combobox);
combobox.setComponentPopupMenu(popup);
}
@Override
public void setValue(String value) {
combobox.setSelectedItem(value);
}
@Override
public java.lang.String getValue() {
if(combobox.getSelectedIndex() != -1) {
return (String) combobox.getSelectedItem();
} else {
return "";
}
}
}
private static class CustomFieldComponentNumeric extends CustomFieldComponent implements FocusListener {
private final JTextField line = new JTextField();
private final boolean floating;
private String oldValue = null;
public CustomFieldComponentNumeric(CustomFieldDefinitionData cfdd, boolean floating) {
super(cfdd);
this.setLayout(new BorderLayout());
this.add(line);
this.floating = floating;
line.setComponentPopupMenu(popup);
}
@Override
public void setValue(String value) {
if(value == null) {
value = "";
}
line.setText(value);
}
@Override
public java.lang.String getValue() {
return line.getText();
}
@Override
public void focusGained(FocusEvent e) {
oldValue = line.getText();
}
@Override
public void focusLost(FocusEvent e) {
String newValue = line.getText();
if("".equals(newValue)) {
return;
}
try {
if (floating) {
Double.parseDouble(newValue);
} else {
Integer.parseInt(newValue);
}
} catch (NumberFormatException ne) {
line.setText(oldValue);
}
}
}
}