// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.ohe.gui;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Dimension;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Map;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.plugins.ohe.ClockSystem;
import org.openstreetmap.josm.plugins.ohe.OhePlugin;
import org.openstreetmap.josm.plugins.ohe.OpeningTimeUtils;
import org.openstreetmap.josm.plugins.ohe.parser.OpeningTimeCompiler;
import org.openstreetmap.josm.plugins.ohe.parser.ParseException;
import org.openstreetmap.josm.plugins.ohe.parser.SyntaxException;
import org.openstreetmap.josm.plugins.ohe.parser.TokenMgrError;
import org.openstreetmap.josm.tools.GBC;
public class OheDialogPanel extends JPanel {
private final JTextField keyField;
// The Component for showing the Time as a Text
private final JTextField valueField;
private final JButton twentyfourSevenButton;
private final JLabel actualPostionLabel;
// The important Panel for showing/editing the Time graphical
private final OheEditor editorPanel;
private final String oldkey;
private ClockSystem clockSystem;
/**
* The Panel for editing the time-values.
*
* @param valuesToEdit
* can be a String or a Map<String, Integer> which contains
* multiple values and their number of occurences
*/
public OheDialogPanel(OhePlugin plugin, String key, Object valuesToEdit, ClockSystem clockSystem) {
this.clockSystem = clockSystem;
oldkey = key;
keyField = new JTextField(key);
String value = "";
if (valuesToEdit instanceof String)
value = (String) valuesToEdit;
else if (valuesToEdit instanceof Map<?, ?>) {
@SuppressWarnings("unchecked")
Map<String, Integer> valuesMap = (Map<String, Integer>) valuesToEdit;
if (valuesMap.size() == 1)
value = valuesMap.keySet().iterator().next();
else if (valuesMap.size() > 1) {
// TODO let the user choose which value he wants to edit (e.g. with a combobox)
int mostOccurences = 0;
for (String v : valuesMap.keySet()) {
if (valuesMap.get(v) > mostOccurences) {
value = v;
mostOccurences = valuesMap.get(v);
}
}
}
}
valueField = new JTextField(value);
valueField.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent evt) {
// on every action in the textfield the timeRects are reloaded
editorPanel.initTimeRects();
}
});
twentyfourSevenButton = new JButton(tr("apply {0}", "24/7"));
twentyfourSevenButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
valueField.setText("24/7");
editorPanel.initTimeRects();
}
});
actualPostionLabel = new JLabel("-");
JPanel toolsPanel = new JPanel(new GridBagLayout());
toolsPanel.add(twentyfourSevenButton, GBC.std());
toolsPanel.add(Box.createGlue(), GBC.std().fill(GBC.HORIZONTAL));
toolsPanel.add(actualPostionLabel, GBC.eop());
editorPanel = new OheEditor(this);
// adding all Components in a Gridbaglayout
setLayout(new GridBagLayout());
add(new JLabel(tr("Key")), GBC.std());
add(Box.createHorizontalStrut(10), GBC.std());
add(keyField, GBC.eol().fill(GBC.HORIZONTAL));
add(new JLabel(tr("Value")), GBC.std());
add(Box.createHorizontalStrut(10), GBC.std());
add(valueField, GBC.eop().fill(GBC.HORIZONTAL));
add(toolsPanel, GBC.eol().fill(GBC.HORIZONTAL));
add(editorPanel, GBC.eol().fill());
setPreferredSize(new Dimension(480, 520));
}
public String[] getChangedKeyValuePair() {
return new String[] {oldkey, keyField.getText(), valueField.getText()};
}
/**
* Returns the compiled Time from the valueField.
* @return the compiled Time from the valueField
*/
public ArrayList<int[]> getTime() throws Exception {
String value = valueField.getText();
ArrayList<int[]> time = null;
if (value.length() > 0) {
OpeningTimeCompiler compiler = new OpeningTimeCompiler(value);
try {
time = OpeningTimeUtils.convert(compiler.startCompile());
} catch (Exception | TokenMgrError t) {
Main.warn(t);
int[] tColumns = null;
String info = t.getMessage();
if (t instanceof ParseException) {
ParseException parserExc = (ParseException) t;
tColumns = new int[] {parserExc.currentToken.beginColumn - 1, parserExc.currentToken.endColumn + 1};
} else if (t instanceof SyntaxException) {
SyntaxException syntaxError = (SyntaxException) t;
tColumns = new int[] {syntaxError.getStartColumn(), syntaxError.getEndColumn()};
} else if (t instanceof TokenMgrError) {
try {
// With JavaCC 6 Message is: "Lexical error at line 1, column 20. Encountered: "P" (80), after : ""
int idx = info.indexOf("column ");
if (idx > -1) {
int col = Integer.parseInt(info.substring(idx+"column ".length(), info.indexOf('.', idx)));
tColumns = new int[] {col - 1, col + 1};
}
} catch (IndexOutOfBoundsException e) {
Main.warn(e);
} catch (NumberFormatException e) {
Main.warn(e);
}
}
// shows a Information Dialog, where the Error occurred
if (tColumns != null || info != null) {
String message = "<html>";
if (tColumns != null) {
int first = Math.max(0, tColumns[0]);
int last = Math.min(value.length(), tColumns[1]);
String begin = value.substring(0, first);
String middle = value.substring(first, last);
String end = value.substring(last);
valueField.setCaretPosition(first);
// TODO focus on the valueField
message += tr("There is something wrong in the value near:") + "<br>" + begin
+ "<span style='background-color:red;'>" + middle + "</span>" + end;
}
if (info != null) {
if (tColumns != null) {
message += "<br>";
}
message += tr("Info: {0}", tr(info));
}
message += "<br>" + tr("Correct the value manually and than press Enter.") + "</html>";
JOptionPane.showMessageDialog(this, message, tr("Error in timeformat"), JOptionPane.INFORMATION_MESSAGE);
}
throw new Exception("Error in the TimeValue", t);
}
}
return time;
}
/**
* Updates the valueField with the given timeRects.
*/
public void updateValueField(ArrayList<TimeRect> timeRects) {
if (valueField != null && timeRects != null)
valueField.setText(OpeningTimeUtils.makeStringFromRects(timeRects));
}
public void setMousePositionText(String positionText) {
actualPostionLabel.setText(positionText);
}
/**
* Returns the clock system (12 or 24 hours).
* @return the clock system
*/
public ClockSystem getHourMode() {
return clockSystem;
}
}