/* * 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.Level; 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.SendQueryException; public abstract class ParamField extends JPanel { /** */ private static final long serialVersionUID = 6025994164004985362L; /** The logger for the class ParamField. */ 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 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 { /** */ private static final long serialVersionUID = 24219488975302068L; JTextField field; public StringField(EpnTapMainView mainView, String paramName) { super(mainView, paramName); field = new JTextField(); addChangeListener(this, field); this.add(field); } @Override public void update(JTextField textField) { if ("".equals(textField.getText())) { mainView.event(Event.paramChanged, paramName, null); } else { mainView.event(Event.paramChanged, paramName, textField.getText()); } } } public static class FloatField extends ParamField implements TextFieldListener { /** */ private static final long serialVersionUID = -1880193152285564590L; JTextField field; public FloatField(EpnTapMainView mainView, String paramName) { super(mainView, paramName); field = new JTextField(); addChangeListener(this, field); this.add(field); } @Override public void update(JTextField textField) { if ("".equals(textField.getText())) { textField.setBackground(Color.WHITE); mainView.event(Event.paramRemoved, paramName); } else { try { float value = Float.parseFloat(textField.getText()); mainView.event(Event.paramChanged, paramName, value); textField.setBackground(Color.WHITE); } catch (@SuppressWarnings("unused") NumberFormatException e) { textField.setBackground(Color.PINK); } } } } public static class DateRangeField extends ParamField implements TextFieldListener { /** */ private static final long serialVersionUID = -7781309003911514777L; 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); } @Override 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 (@SuppressWarnings("unused") 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 { /** */ private static final long serialVersionUID = 7923358142882329015L; 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); } @Override 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 (@SuppressWarnings("unused") NumberFormatException e) { field.setBackground(Color.PINK); } } } } public static class TargetNameField extends ParamField implements TextFieldListener { /** */ private static final long serialVersionUID = 5136431108894677113L; 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); } static String[] getItems(String begining) throws SendQueryException { StringBuilder resolverResult = null; resolverResult = VOTableConnection.sendGet(RESOLVER_URL, "q=\"" + begining + "\""); 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(); try { for (String s : getItems(content)) { comboBox.addItem(s); } } catch (SendQueryException e) { logger.log(Level.WARNING, "Can't get table names for the resolver", e); } comboBox.getEditor().setItem(content); } if ("".equals(content)) { mainView.event(Event.paramRemoved, paramName); } else { mainView.event(Event.paramChanged, paramName, content); } } } }; @Override public void update(JTextField textField) { SwingUtilities.invokeLater(updateComboBox); } } public static class DataProductTypeField extends ParamField { /** */ private static final long serialVersionUID = -6362359909898369750L; JComboBox comboBox; public DataProductTypeField(EpnTapMainView mainView, String paramName) { super(mainView, paramName); comboBox = new JComboBox<>((String[]) getItems().keySet().toArray()); comboBox.setSelectedItem("All"); comboBox.setPreferredSize(new Dimension(MIN_FIELD_WIDTH, FIELD_HEIGHT)); comboBox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { onUpdate(); } }); this.add(comboBox); } private static 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; } 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 { /** */ private static final long serialVersionUID = 6439475087727685080L; 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 static String[] getItems() { return new String[] { "All", "Comet", "Exoplanet", "Interplanetary medium", "Ring", "Sample", "Sky", "Spacecraft", "Spacejunk", "Star" }; } 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() { @Override public void removeUpdate(DocumentEvent de) { changeListener.update(field); } @Override public void insertUpdate(DocumentEvent de) { changeListener.update(field); } @Override public void changedUpdate(DocumentEvent de) { changeListener.update(field); } }); } }