/**
* Copyright (C) 2001-2017 by RapidMiner and the contributors
*
* Complete list of developers available at our web site:
*
* http://rapidminer.com
*
* This program is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero 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
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License along with this program.
* If not, see http://www.gnu.org/licenses/.
*/
package com.rapidminer.gui.properties.tablepanel.cells.implementations;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import javax.swing.AbstractAction;
import javax.swing.JFormattedTextField;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import org.jdesktop.swingx.prompt.PromptSupport;
import org.jdesktop.swingx.prompt.PromptSupport.FocusBehavior;
import com.michaelbaranov.microba.calendar.DatePicker;
import com.rapidminer.example.set.CustomFilter.CustomFilters;
import com.rapidminer.gui.properties.tablepanel.TablePanel;
import com.rapidminer.gui.properties.tablepanel.cells.interfaces.CellType;
import com.rapidminer.gui.properties.tablepanel.cells.interfaces.CellTypeDate;
import com.rapidminer.gui.properties.tablepanel.cells.interfaces.CellTypeDateTime;
import com.rapidminer.gui.properties.tablepanel.model.TablePanelModel;
import com.rapidminer.tools.I18N;
/**
* GUI component for the {@link TablePanel} for {@link CellTypeDate} and {@link CellTypeDateTime}.
*
* @author Marco Boeck
*
*/
public class CellTypeDateImpl extends JPanel implements CellTypeDate, CellTypeDateTime {
private static final long serialVersionUID = 2280442691332299994L;
// ThreadLocal because DateFormat is NOT threadsafe and creating a new DateFormat is
// EXTREMELY expensive
/** the format for date_time */
private static final ThreadLocal<DateFormat> FORMAT_DATE_TIME = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(CustomFilters.DATE_TIME_FORMAT_STRING, Locale.ENGLISH);
}
};
private static final ThreadLocal<DateFormat> FORMAT_DATE_TIME_OLD = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(CustomFilters.DATE_TIME_FORMAT_STRING_OLD, Locale.ENGLISH);
}
};
// ThreadLocal because DateFormat is NOT threadsafe and creating a new DateFormat is
// EXTREMELY expensive
/** the format for date */
private static final ThreadLocal<DateFormat> FORMAT_DATE = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(CustomFilters.DATE_FORMAT_STRING, Locale.ENGLISH);
}
};
private static final ThreadLocal<DateFormat> FORMAT_DATE_OLD = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat(CustomFilters.DATE_FORMAT_STRING_OLD, Locale.ENGLISH);
}
};
/**
* Creates a panel for date/date_time cells. Adds a date picker next to the field. Does not
* validate the model, so make sure this call works!
*
* @param model
* @param rowIndex
* @param columnIndex
* @param cellClass
*/
public CellTypeDateImpl(final TablePanelModel model, final int rowIndex, final int columnIndex,
final Class<? extends CellType> cellClass) {
super();
setLayout(new BorderLayout());
// get date from model if possible
String text = String.valueOf(model.getValueAt(rowIndex, columnIndex));
Date date = new Date();
if (text != null && !"".equals(text.trim())) {
try {
// keep compatibility with processes from versions prior to 6.0.004
int yearIndex = text.lastIndexOf("/") + 1;
int firstWhitespaceIndex = text.indexOf(" ");
String yearString = null;
if (yearIndex > 0 && firstWhitespaceIndex > 0 && yearIndex < firstWhitespaceIndex) {
yearString = text.substring(yearIndex, text.indexOf(" "));
}
// if year consists of 2 chars, use old (bugged) version
if (CellTypeDate.class.isAssignableFrom(cellClass)) {
if (yearString != null && yearString.length() == 2) {
date = FORMAT_DATE_OLD.get().parse(text);
} else {
date = FORMAT_DATE.get().parse(text);
}
} else {
if (yearString != null && yearString.length() == 2) {
date = FORMAT_DATE_TIME_OLD.get().parse(text);
} else {
date = FORMAT_DATE_TIME.get().parse(text);
}
}
} catch (ParseException e) {
date = null;
}
}
// create and add the date picker
final DatePicker datePicker;
if (CellTypeDate.class.isAssignableFrom(cellClass)) {
datePicker = new DatePicker(date, FORMAT_DATE.get());
} else {
datePicker = new DatePicker(date, FORMAT_DATE_TIME.get());
}
// add ctrl+space shortcut for date picker (to surrounding panel [for tab focus reasons] and
// to input field)
AbstractAction caAction = new AbstractAction() {
private static final long serialVersionUID = 5092311623220201432L;
@Override
public void actionPerformed(final ActionEvent e) {
datePicker.showPopup();
}
};
datePicker.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
"contentAssistAction");
datePicker.getActionMap().put("contentAssistAction", caAction);
final JFormattedTextField field = CellTypeImplHelper.createFormattedTextField(model, rowIndex, columnIndex);
field.getInputMap().put(
KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()),
"contentAssistAction");
field.getActionMap().put("contentAssistAction", caAction);
// set syntax assist if available
String syntaxHelp = model.getSyntaxHelpAt(rowIndex, columnIndex);
if (syntaxHelp != null && !"".equals(syntaxHelp.trim())) {
PromptSupport.setForeground(Color.LIGHT_GRAY, field);
PromptSupport.setPrompt(syntaxHelp, field);
PromptSupport.setFontStyle(Font.ITALIC, field);
PromptSupport.setFocusBehavior(FocusBehavior.SHOW_PROMPT, field);
}
// misc settings
datePicker.setToolTipText(I18N.getMessageOrNull(I18N.getGUIBundle(), "gui.action.date_picker.tip"));
datePicker.showButtonOnly(true);
datePicker.setShowNoneButton(false);
datePicker.addActionListener(new ActionListener() {
@Override
public void actionPerformed(final ActionEvent e) {
// empty date, no need to convert
if (datePicker.getDate() == null) {
field.setText("");
return;
}
if (CellTypeDate.class.isAssignableFrom(cellClass)) {
field.setText(FORMAT_DATE.get().format(datePicker.getDate()));
} else {
field.setText(FORMAT_DATE_TIME.get().format(datePicker.getDate()));
}
}
});
add(datePicker, BorderLayout.EAST);
// set text to model value
field.setText(text);
if (CellTypeDate.class.isAssignableFrom(cellClass)) {
field.setToolTipText(field.getToolTipText() + " (" + CustomFilters.DATE_FORMAT_STRING + ")");
} else {
field.setToolTipText(field.getToolTipText() + " (" + CustomFilters.DATE_TIME_FORMAT_STRING + ")");
}
add(field, BorderLayout.CENTER);
// set size so panels don't grow larger when they get the chance
setPreferredSize(new Dimension(300, 20));
setMinimumSize(new Dimension(100, 15));
setMaximumSize(new Dimension(1600, 30));
}
}