/*
* This file is a part of EpnTAPClient.
* This program aims to provide EPN-TAP support for software clients, like CASSIS spectrum analyzer.
* See draft specifications: https://voparis-confluence.obspm.fr/pages/viewpage.action?pageId=559861
* Copyright (C) 2016 Institut de Recherche en Astrophysique et Planétologie.
*
* This program 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. This program 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 this program. If not, see
* .
*/
package eu.omp.irap.vespa.epntapclient.view;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.logging.Logger;
import javax.swing.BoxLayout;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import eu.omp.irap.vespa.epntapclient.votable.controller.VOTableConnection;
import eu.omp.irap.vespa.epntapclient.votable.controller.VOTableException.BadRequestException;
import eu.omp.irap.vespa.epntapclient.votable.controller.VOTableException.HTTPRequestException;
public abstract class ParamField extends JPanel {
/** The logger for the class ParamField. */
private static final Logger logger = Logger.getLogger(ParamField.class.getName());
private static final int MIN_FIELD_WIDTH = 30;
private static final int FIELD_HEIGHT = 20;
private static final int MAX_FIELD_WIDTH = 400;
private static final int LABEL_WIDTH = 140;
private static final String RESOLVER_URL = "http://voparis-registry.obspm.fr/ssodnet/1/autocomplete";
private static final String DATE_FORMAT = "dd/MM/yyyy";
private static final String DATE_REGEX = "(^(((0[1-9]|1[0-9]|2[0-8])[\\/](0[1-9]|1[012]))|((29|30|31)[\\/](0[13578]|1[02]))|((29|30)[\\/](0[4,6,9]|11)))[\\/](19|[2-9][0-9])\\d\\d$)|(^29[\\/]02[\\/](19|[2-9][0-9])(00|04|08|12|16|20|24|28|32|36|40|44|48|52|56|60|64|68|72|76|80|84|88|92|96)$)";
private static final String MIN_SUFFIX = "min";
private static final String MAX_SUFFIX = "max";
protected static EpnTapMainView mainView;
protected String paramName;
public ParamField(EpnTapMainView mainView, String paramName) {
super();
this.mainView = mainView;
this.paramName = paramName;
this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
this.setMaximumSize(new Dimension(MAX_FIELD_WIDTH, FIELD_HEIGHT));
String strLabel = paramName.replaceAll("_", " ").trim();
JLabel label = new JLabel(strLabel.substring(0, 1).toUpperCase() + strLabel.substring(1));
label.setPreferredSize(new Dimension(LABEL_WIDTH, FIELD_HEIGHT));
this.add(label);
// TODO: Add tooltip text based on rr.table_column.column_description
}
public static class StringField extends ParamField implements TextFieldListener {
JTextField field;
public StringField(EpnTapMainView mainView, String paramName) {
super(mainView, paramName);
field = new JTextField();
addChangeListener(this, field);
this.add(field);
}
public void update(JTextField field) {
if ("".equals(field.getText())) {
mainView.event(Event.paramChanged, paramName, null);
} else {
mainView.event(Event.paramChanged, paramName, field.getText());
}
}
}
public static class FloatField extends ParamField implements TextFieldListener {
JTextField field;
public FloatField(EpnTapMainView mainView, String paramName) {
super(mainView, paramName);
field = new JTextField();
addChangeListener(this, field);
this.add(field);
}
public void update(JTextField field) {
if ("".equals(field.getText())) {
field.setBackground(Color.WHITE);
mainView.event(Event.paramRemoved, paramName);
} else {
try {
mainView.event(Event.paramChanged, paramName,
Float.parseFloat(field.getText()));
field.setBackground(Color.WHITE);
} catch (NumberFormatException e) {
field.setBackground(Color.PINK);
}
}
}
}
public static class DateRangeField extends ParamField implements TextFieldListener {
JTextField fieldMin;
JTextField fieldMax;
public DateRangeField(EpnTapMainView mainView, String paramName) {
super(mainView, paramName);
this.add(new JLabel("min "));
fieldMin = new JTextField();
fieldMin.setName(MIN_SUFFIX);
fieldMin.setPreferredSize(new Dimension(MIN_FIELD_WIDTH, FIELD_HEIGHT));
addChangeListener(this, fieldMin);
this.add(fieldMin);
this.add(new JLabel("max "));
fieldMax = new JTextField();
fieldMax.setName(MAX_SUFFIX);
fieldMax.setPreferredSize(new Dimension(MIN_FIELD_WIDTH, FIELD_HEIGHT));
addChangeListener(this, fieldMin);
this.add(fieldMax);
}
public void update(JTextField field) {
DateFormat df = new SimpleDateFormat(DATE_FORMAT, Locale.ENGLISH);
if ("".equals(field.getText())) {
field.setBackground(Color.WHITE);
mainView.event(Event.paramRemoved, paramName + field.getName());
} else if (field.getText().matches(DATE_REGEX)) {
try {
long date = df.parse(field.getText()).getTime();
date = Math.round((date / 86400000.0) + 2440587.5); // to JD
mainView.event(Event.paramChanged, paramName + field.getName(), date);
field.setBackground(Color.WHITE);
} catch (ParseException e) {
field.setBackground(Color.PINK);
}
// TODO: check if date min < date max
} else {
field.setBackground(Color.PINK);
}
}
}
public static class FloatRangeField extends ParamField implements TextFieldListener {
JTextField fieldMin;
JTextField fieldMax;
public FloatRangeField(EpnTapMainView mainView, String paramName) {
super(mainView, paramName);
fieldMin = new JTextField();
fieldMin.setName(MIN_SUFFIX);
addChangeListener(this, fieldMin);
this.add(fieldMin);
fieldMax = new JTextField();
fieldMax.setName(MAX_SUFFIX);
addChangeListener(this, fieldMax);
this.add(fieldMax);
}
public void update(JTextField field) {
if ("".equals(field.getText())) {
field.setBackground(Color.WHITE);
mainView.event(Event.paramRemoved, paramName + field.getName());
} else {
try {
mainView.event(Event.paramChanged, paramName + field.getName(),
Float.parseFloat(field.getText()));
field.setBackground(Color.WHITE);
} catch (NumberFormatException e) {
field.setBackground(Color.PINK);
}
}
}
}
public static class TargetNameField extends ParamField implements TextFieldListener {
JComboBox comboBox;
JTextField field;
String lastContent;
public TargetNameField(EpnTapMainView mainView, String paramName) {
super(mainView, paramName);
comboBox = new JComboBox();
comboBox.setPreferredSize(new Dimension(MIN_FIELD_WIDTH, FIELD_HEIGHT));
comboBox.setEditable(true);
field = (JTextField) comboBox.getEditor().getEditorComponent();
addChangeListener(this, field);
this.add(comboBox);
}
private String[] getItems(String begining) {
StringBuilder resolverResult = null;
try {
resolverResult = VOTableConnection.sendGet(RESOLVER_URL, "q=\"" + begining + "\"");
} catch (HTTPRequestException | BadRequestException e) {
logger.severe("Can not send sersolver query: " + e);
}
JsonObject root = new JsonParser().parse(resolverResult.toString()).getAsJsonObject();
int count = Integer.parseInt(root.get("count").toString());
String[] targetNames = new String[count];
JsonArray hits = root.getAsJsonArray("hits");
for (int i = 0; i < count; i++) {
JsonObject elmt = hits.get(i).getAsJsonObject();
targetNames[i] = elmt.get("name").toString().replace("\"", "");
// TODO: Display "[name] ([type])" on the JComboBox, but only "[name]" on the query.
}
return targetNames;
}
Runnable updateComboBox = new Runnable() {
@Override
public void run() {
String content = field.getText();
if (!content.equals(lastContent)) {
if (content.length() >= 2) {
lastContent = content;
comboBox.removeAllItems();
for (String s : getItems(content)) {
comboBox.addItem(s);
}
comboBox.getEditor().setItem(content);
}
if ("".equals(content)) {
mainView.event(Event.paramRemoved, paramName);
} else {
mainView.event(Event.paramChanged, paramName, content);
}
}
}
};
public void update(JTextField field) {
SwingUtilities.invokeLater(updateComboBox);
}
}
public static class DataProductTypeField extends ParamField {
JComboBox comboBox;
public DataProductTypeField(EpnTapMainView mainView, String paramName) {
super(mainView, paramName);
comboBox = new JComboBox(getItems().keySet().toArray());
comboBox.setPreferredSize(new Dimension(MIN_FIELD_WIDTH, FIELD_HEIGHT));
comboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onUpdate();
}
});
this.add(comboBox);
}
private HashMap getItems() {
HashMap items = new HashMap();
items.put("All", "all");
items.put("Image", "im");
items.put("Spectrum", "sp");
items.put("Dynamic spectrum", "ds");
items.put("Spectral cube", "sc");
items.put("Profile", "pr");
items.put("Volume", "vo");
items.put("Movie", "mo");
items.put("Cube", "cu");
items.put("Time series", "ts");
items.put("Catalog", "ca");
items.put("Spatial vector", "sv");
return items;
}
private void onUpdate() {
String key = comboBox.getSelectedItem().toString();
List item = new ArrayList();
item.add(key.replace(" ", "-").toLowerCase());
item.add(getItems().get(key));
if ("All".equals(key)) {
mainView.event(Event.paramRemoved, paramName);
} else {
mainView.event(Event.paramChanged, paramName, item);
}
}
}
public static class TargetClassField extends ParamField {
JComboBox comboBox;
public TargetClassField(EpnTapMainView mainView, String paramName) {
super(mainView, paramName);
comboBox = new JComboBox(getItems());
comboBox.setPreferredSize(new Dimension(MIN_FIELD_WIDTH, FIELD_HEIGHT));
comboBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
onUpdate();
}
});
this.add(comboBox);
}
private String[] getItems() {
return new String[] { "All", "Comet", "Exoplanet", "Interplanetary medium", "Ring",
"Sample", "Sky", "Spacecraft", "Spacejunk", "Star" };
}
private void onUpdate() {
String value = comboBox.getSelectedItem().toString().replace(" ", "_").toLowerCase();
if ("All".equals(value)) {
mainView.event(Event.paramRemoved, paramName);
} else {
mainView.event(Event.paramChanged, paramName, value);
}
}
}
interface TextFieldListener {
void update(JTextField field);
}
static void addChangeListener(final TextFieldListener changeListener, final JTextField field) {
field.getDocument().addDocumentListener(new DocumentListener() {
public void removeUpdate(DocumentEvent de) {
changeListener.update(field);
}
public void insertUpdate(DocumentEvent de) {
changeListener.update(field);
}
public void changedUpdate(DocumentEvent de) {
changeListener.update(field);
}
});
}
}