/*
* Freeplane - mind map editor
* Copyright (C) 2008 Joerg Mueller, Daniel Polansky, Christian Foltin, Dimitry Polivaev
*
* This file is modified by Dimitry Polivaev in 2008.
*
* 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 2 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 <http://www.gnu.org/licenses/>.
*/
package org.freeplane.view.swing.features.time.mindmapmode;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.KeyboardFocusManager;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.text.MessageFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ComboBoxEditor;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.text.JTextComponent;
import org.freeplane.core.resources.ResourceController;
import org.freeplane.core.ui.components.UITools;
import org.freeplane.core.ui.components.calendar.JCalendar;
import org.freeplane.core.ui.components.calendar.JDayChooser;
import org.freeplane.core.ui.components.calendar.JTripleCalendar;
import org.freeplane.core.util.TextUtils;
import org.freeplane.features.format.FormatController;
import org.freeplane.features.format.FormattedDate;
import org.freeplane.features.format.PatternFormat;
import org.freeplane.features.map.IMapSelectionListener;
import org.freeplane.features.map.INodeChangeListener;
import org.freeplane.features.map.INodeSelectionListener;
import org.freeplane.features.map.MapModel;
import org.freeplane.features.map.NodeChangeEvent;
import org.freeplane.features.map.NodeModel;
import org.freeplane.features.mode.Controller;
import org.freeplane.features.mode.ModeController;
import org.freeplane.features.script.IScriptEditorStarter;
import org.freeplane.features.text.TextController;
import org.freeplane.features.text.mindmapmode.MTextController;
import com.jgoodies.forms.builder.DefaultFormBuilder;
import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.FormLayout;
/**
* @author foltin
*/
class TimeManagement implements PropertyChangeListener, IMapSelectionListener {
class JTimePanel extends JPanel
{
private static final long serialVersionUID = 1L;
private JButton setReminderButton;
private JButton removeReminderButton;
private JButton remindLaterButton;
private PeriodPanel periodPanel;
private ComboBoxEditor scriptEditor;
private JCalendar calendarComponent;
private JComboBox dateFormatChooser;
public JTimePanel(boolean useTriple, int colCount) {
super();
init(useTriple, colCount);
final NodeModel selected = reminderHook.getModeController().getMapController().getSelectedNode();
update(selected);
}
public void update(NodeModel node){
if(node == null)
return;
final ReminderExtension reminder = ReminderExtension.getExtension(node);
final boolean reminderIsSet = reminder != null;
removeReminderButton.setEnabled(reminderIsSet);
if(reminderIsSet){
final long reminderTime = reminder.getRemindUserAt();
updateCalendar(reminderTime);
periodPanel.setPeriod(reminder.getPeriod());
periodPanel.setPeriodUnit(reminder.getPeriodUnit());
if(scriptEditor != null)
scriptEditor.setItem(reminder.getScript());
}
else{
if(scriptEditor != null)
scriptEditor.setItem(null);
}
}
private void updateCalendar(final long reminderTime) {
TimeManagement.this.calendar.setTimeInMillis(reminderTime);
calendarComponent.setCalendar(TimeManagement.this.calendar);
dateFormatChooser.repaint();
}
private void init(boolean useTriple, int colCount) {
final JComponent calendarContainer;
if (useTriple) {
final JTripleCalendar trippleCalendar = new JTripleCalendar();
calendarComponent = trippleCalendar.getCalendar();
calendarContainer = trippleCalendar;
}
else {
calendarComponent = new JCalendar();
calendarContainer = calendarComponent;
}
calendarComponent.setCalendar(TimeManagement.this.calendar);
if (dialog != null) {
dialog.addWindowFocusListener(new WindowAdapter() {
@Override
public void windowGainedFocus(WindowEvent e) {
calendarComponent.getDayChooser().setFocus();
}
});
}
calendarComponent.setMaximumSize(calendarComponent.getPreferredSize());
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(Box.createHorizontalGlue());
calendarComponent.getDayChooser().addPropertyChangeListener(TimeManagement.this);
calendarContainer.setAlignmentX(0.5f);
add(calendarContainer);
DefaultFormBuilder btnBuilder = new DefaultFormBuilder(new FormLayout(FormFactory.GROWING_BUTTON_COLSPEC.toString(), ""));
btnBuilder.getLayout().addGroupedColumn(btnBuilder.getColumnCount());
for(int i = 1; i< colCount; i++){
btnBuilder.appendRelatedComponentsGapColumn();
btnBuilder.appendColumn(FormFactory.GROWING_BUTTON_COLSPEC);
btnBuilder.getLayout().addGroupedColumn(btnBuilder.getColumnCount());
}
{
final JButton todayButton = new JButton(getResourceString("plugins/TimeManagement.xml_todayButton"));
todayButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent arg0) {
final Calendar currentTime = Calendar.getInstance();
currentTime.set(Calendar.SECOND, 0);
TimeManagement.this.calendar.setTimeInMillis(currentTime.getTimeInMillis());
calendarComponent.setCalendar(TimeManagement.this.calendar);
}
});
btnBuilder.append(todayButton);
}
{
dateFormatChooser = createDateFormatChooser();
btnBuilder.append(dateFormatChooser);
}
{
final JButton appendButton = new JButton(getResourceString("plugins/TimeManagement.xml_appendButton"));
if (dialog == null) {
appendButton.setFocusable(false);
}
appendButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
insertTime(dialog, appendButton);
}
});
btnBuilder.append(appendButton);
}
{
scriptEditor = null;
IScriptEditorStarter editor = (IScriptEditorStarter) reminderHook.getModeController().getExtension(IScriptEditorStarter.class);
if(editor != null){
scriptEditor = editor.createComboBoxEditor(new Dimension(600, 400));
Component scriptButton = scriptEditor.getEditorComponent();
btnBuilder.append(scriptButton);
}
}
{
setReminderButton = new JButton(getResourceString("plugins/TimeManagement.xml_reminderButton"));
setReminderButton.setToolTipText(getResourceString("plugins/TimeManagement.xml_reminderButton_tooltip"));
setReminderButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
addReminder();
}
});
btnBuilder.append(setReminderButton);
}
{
remindLaterButton = new JButton(
getResourceString("plugins/TimeManagement.xml_remindLaterButton"));
remindLaterButton.setToolTipText(getResourceString("plugins/TimeManagement.xml_remindLaterButton_tooltip"));
remindLaterButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
remindLaterReminder();
}
});
btnBuilder.append(remindLaterButton);
}
{
periodPanel = new PeriodPanel();
btnBuilder.append(periodPanel);
}
{
removeReminderButton = new JButton(
getResourceString("plugins/TimeManagement.xml_removeReminderButton"));
removeReminderButton.setToolTipText(getResourceString("plugins/TimeManagement.xml_removeReminderButton_tooltip"));
removeReminderButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
removeReminder();
}
});
btnBuilder.append(removeReminderButton);
}
if (dialog != null) {
final JButton cancelButton = new JButton(getResourceString("plugins/TimeManagement.xml_closeButton"));
cancelButton.addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
disposeDialog();
}
});
btnBuilder.append(cancelButton);
}
final JPanel btnPanel = btnBuilder.getPanel();
btnPanel.setAlignmentX(CENTER_ALIGNMENT);
add(btnPanel);
}
private void addReminder() {
final Date date = getCalendarDate();
String script = null;
if(scriptEditor != null){
script = (String) scriptEditor.getItem();
if(script != null && "".equals(script.trim()))
script = null;
}
Controller controller = Controller.getCurrentController();
for (final NodeModel node : controller.getModeController().getMapController().getSelectedNodes()) {
final ReminderExtension alreadyPresentHook = ReminderExtension.getExtension(node);
if (alreadyPresentHook != null) {
final long oldReminderTime = alreadyPresentHook.getRemindUserAt();
if(oldReminderTime > System.currentTimeMillis()){
final Object[] messageArguments = { new Date(oldReminderTime), date };
final MessageFormat formatter = new MessageFormat(
getResourceString("plugins/TimeManagement.xml_reminderNode_onlyOneDate"));
final String message = formatter.format(messageArguments);
final int result = JOptionPane.showConfirmDialog(controller.getViewController().getFrame(), message,
"Freeplane", JOptionPane.YES_NO_OPTION);
if (result == JOptionPane.NO_OPTION) {
return;
}
}
reminderHook.undoableToggleHook(node);
}
final ReminderExtension reminderExtension = new ReminderExtension(node);
reminderExtension.setRemindUserAt(date.getTime());
reminderExtension.setPeriodUnit(periodPanel.getPeriodUnit());
reminderExtension.setPeriod(periodPanel.getPeriod());
reminderExtension.setScript(script);
reminderHook.undoableActivateHook(node, reminderExtension);
}
}
private void removeReminder() {
for (final NodeModel node : getMindMapController().getMapController().getSelectedNodes()) {
final ReminderExtension alreadyPresentHook = ReminderExtension.getExtension(node);
if (alreadyPresentHook != null) {
reminderHook.undoableToggleHook(node);
}
}
}
private void remindLaterReminder(){
Date nextTime = periodPanel.calculateNextTime(calendar.getTime());
updateCalendar(nextTime.getTime());
addReminder();
}
}
private Calendar calendar;
public final static String REMINDER_HOOK_NAME = "plugins/TimeManagementReminder.xml";
private static TimeManagement sCurrentlyOpenTimeManagement = null;
private JDialog dialog;
private final ReminderHook reminderHook;
private PatternFormat dateFormat;
private INodeChangeListener nodeChangeListener;
private INodeSelectionListener nodeSelectionListener;
public TimeManagement( final ReminderHook reminderHook) {
this.reminderHook = reminderHook;
Controller.getCurrentController().getMapViewManager().addMapSelectionListener(this);
}
public void afterMapChange(final MapModel oldMap, final MapModel newMap) {
}
public void beforeMapChange(final MapModel oldMap, final MapModel newMap) {
disposeDialog();
}
/**
*
*/
private void disposeDialog() {
if (dialog == null) {
return;
}
getMindMapController().getMapController().removeNodeSelectionListener(nodeSelectionListener);
nodeSelectionListener = null;
getMindMapController().getMapController().removeNodeChangeListener(nodeChangeListener);
nodeChangeListener = null;
dialog.setVisible(false);
dialog.dispose();
dialog = null;
TimeManagement.sCurrentlyOpenTimeManagement = null;
}
private FormattedDate getCalendarDate() {
return new FormattedDate(calendar.getTime(), dateFormat.getPattern());
}
private ModeController getMindMapController() {
return Controller.getCurrentModeController();
}
private String getResourceString(final String string) {
return TextUtils.getText(string);
}
public void propertyChange(final PropertyChangeEvent event) {
if (event.getPropertyName().equals(JDayChooser.DAY_PROPERTY)) {
}
}
void showDialog() {
if (TimeManagement.sCurrentlyOpenTimeManagement != null) {
TimeManagement.sCurrentlyOpenTimeManagement.dialog.getContentPane().setVisible(true);
return;
}
TimeManagement.sCurrentlyOpenTimeManagement = this;
dialog = new JDialog(Controller.getCurrentController().getViewController().getFrame(), false /*not modal*/);
final JTimePanel timePanel =createTimePanel(dialog, true, 4);
nodeSelectionListener = new INodeSelectionListener() {
public void onSelect(NodeModel node) {
timePanel.update(node);
}
public void onDeselect(NodeModel node) {
}
};
getMindMapController().getMapController().addNodeSelectionListener(nodeSelectionListener);
nodeChangeListener = new INodeChangeListener() {
public void nodeChanged(NodeChangeEvent event) {
final NodeModel node = event.getNode();
if(event.getProperty().equals(ReminderExtension.class) && node.equals(getMindMapController().getMapController().getSelectedNode()))
timePanel.update(node);
}
};
getMindMapController().getMapController().addNodeChangeListener(nodeChangeListener);
dialog.setTitle(getResourceString("plugins/TimeManagement.xml_WindowTitle"));
dialog.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
dialog.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(final WindowEvent event) {
disposeDialog();
}
});
final Action action = new AbstractAction() {
/**
*
*/
private static final long serialVersionUID = 1L;
public void actionPerformed(final ActionEvent arg0) {
disposeDialog();
}
};
UITools.addEscapeActionToDialog(dialog, action);
dialog.setContentPane(timePanel);
dialog.pack();
UITools.setBounds(dialog, -1, -1, dialog.getWidth(), dialog.getHeight());
dialog.setVisible(true);
}
public JTimePanel createTimePanel(final Dialog dialog, boolean useTriple, int colCount) {
if (this.calendar == null) {
this.calendar = Calendar.getInstance();
this.calendar.set(Calendar.SECOND, 0);
this.calendar.set(Calendar.MILLISECOND, 0);
}
JTimePanel contentPane = new JTimePanel(useTriple, colCount);
return contentPane;
}
private JComboBox createDateFormatChooser() {
class DateFormatComboBoxElement {
private final PatternFormat dateFormat;
DateFormatComboBoxElement(PatternFormat dateFormat) {
this.dateFormat = dateFormat;
}
PatternFormat getDateFormat() {
return dateFormat;
}
public String toString() {
return dateFormat.formatObject(getCalendarDate()).toString();
}
}
final String dateFormatPattern = ResourceController.getResourceController().getProperty(
"date_format");
final Vector<DateFormatComboBoxElement> values = new Vector<DateFormatComboBoxElement>();
final List<PatternFormat> datePatterns = FormatController.getController().getDateFormats();
int selectedIndex = 0;
for (int i = 0; i < datePatterns.size(); ++i) {
final PatternFormat patternFormat = datePatterns.get(i);
values.add(new DateFormatComboBoxElement(patternFormat));
if (patternFormat.getPattern().equals(dateFormatPattern)) {
dateFormat = patternFormat;
selectedIndex = i;
}
}
final JComboBox dateFormatChooser = new JComboBox(values);
dateFormatChooser.setFocusable(false);
if (!datePatterns.isEmpty()){
dateFormatChooser.setSelectedIndex(selectedIndex);
dateFormat = ((DateFormatComboBoxElement) (dateFormatChooser.getSelectedItem())).getDateFormat();
}
dateFormatChooser.addItemListener(new ItemListener() {
public void itemStateChanged(final ItemEvent e) {
dateFormat = ((DateFormatComboBoxElement) e.getItem()).getDateFormat();
final Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
if(focusOwner instanceof JTable){
JTable table = (JTable) focusOwner;
final int[] selectedRows = table.getSelectedRows();
final int[] selectedColumns = table.getSelectedColumns();
for(int r : selectedRows)
for(int c : selectedColumns){
Object date = table.getValueAt(r, c);
if(date instanceof FormattedDate){
final FormattedDate fd = (FormattedDate) date;
if(! fd.getDateFormat().equals(dateFormat)){
table.setValueAt(new FormattedDate(fd, dateFormat.getPattern()), r, c);
}
}
}
}
else{
ModeController mController = Controller.getCurrentModeController();
for (final NodeModel node : mController.getMapController().getSelectedNodes()) {
final MTextController textController = (MTextController) TextController.getController();
Object date = node.getUserObject();
if(date instanceof FormattedDate){
final FormattedDate fd = (FormattedDate) date;
if(! fd.getDateFormat().equals(dateFormat)){
textController.setNodeObject(node, new FormattedDate(fd, dateFormat.getPattern()));
}
}
}
}
}
});
dateFormatChooser.setAlignmentX(Component.LEFT_ALIGNMENT);
return dateFormatChooser;
}
void insertTime(final Dialog dialog, final JButton appendButton) {
FormattedDate date = getCalendarDate();
final String dateAsString = dateFormat.formatObject(date).toString();
final Window parentWindow;
if (dialog != null) {
parentWindow = (Window) dialog.getParent();
}
else {
parentWindow = SwingUtilities.getWindowAncestor(appendButton);
}
final Component mostRecentFocusOwner = parentWindow.getMostRecentFocusOwner();
if (mostRecentFocusOwner instanceof JTextComponent
&& !(mostRecentFocusOwner.getClass().getName().contains("JSpinField"))) {
final JTextComponent textComponent = (JTextComponent) mostRecentFocusOwner;
textComponent.replaceSelection(dateAsString);
return;
}
if(mostRecentFocusOwner instanceof JTable){
JTable table = (JTable) mostRecentFocusOwner;
final int[] selectedRows = table.getSelectedRows();
final int[] selectedColumns = table.getSelectedColumns();
for(int r : selectedRows)
for(int c : selectedColumns)
table.setValueAt(date, r, c);
}
else{
ModeController mController = Controller.getCurrentModeController();
for (final NodeModel node : mController.getMapController().getSelectedNodes()) {
final MTextController textController = (MTextController) TextController.getController();
textController.setNodeObject(node, date);
}
}
}
}