/*
* Freeplane - mind map editor
* Copyright (C) 2010 Volker Boerchers
*
* This file author is Volker Boerchers
*
* 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.features.url.mindmapmode;
import java.awt.Color;
import java.awt.Component;
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.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Comparator;
import java.util.TreeSet;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.WindowConstants;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.DefaultTableCellRenderer;
import org.freeplane.core.ui.MenuBuilder;
import org.freeplane.core.ui.components.UITools;
import org.freeplane.core.util.HtmlUtils;
import org.freeplane.core.util.TextUtils;
import org.freeplane.features.url.mindmapmode.MFileManager.AlternativeFileMode;
/**
* @author vboerchers
*/
class FileRevisionsDialog extends JDialog {
public static class FileWrapper {
private final File file;
public FileWrapper(final File file) {
this.file = file;
}
public File getFile() {
return file;
}
@Override
public String toString() {
return file.getName();
}
}
private class RevisionTable extends JTable {
private static final long serialVersionUID = 1L;
public RevisionTable(final Object[][] data, int selectedRow) {
super(data, new Object[] { TextUtils.getText(key("file_name")),
TextUtils.getText(key("file_size")),
TextUtils.getText(key("file_last_modified")) });
int width = Toolkit.getDefaultToolkit().getScreenSize().width * 2 / 3;
getColumnModel().getColumn(0).setPreferredWidth((int) (width * 0.7));
getColumnModel().getColumn(1).setPreferredWidth((int) (width * 0.1));
getColumnModel().getColumn(2).setPreferredWidth((int) (width * 0.2));
setRowHeight(20);
setRowSelectionAllowed(true);
setFocusable(false);
setDefaultRenderer(Object.class, renderer);
setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
setRowSelectionInterval(selectedRow, selectedRow);
getSelectionModel().addListSelectionListener(new ListSelectionListener() {
public void valueChanged(final ListSelectionEvent event) {
// Update the word field if a suggestion is click
if (!event.getValueIsAdjusting()) {
final ListSelectionModel lsm = (ListSelectionModel) event.getSource();
final boolean enable = !(lsm.isSelectionEmpty());
if (enable) {
final FileWrapper fileWrapper = (FileWrapper) getModel().getValueAt(getSelectedRow(), 0);
if (file.equals(fileWrapper.getFile())) {
setButtonOpenDefault();
}
else {
setButtonOpenRestore(fileWrapper);
}
setSelectedFile(fileWrapper.getFile());
}
else {
setButtonOpenDefault();
}
}
}
});
addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
if (e.getClickCount() >= 2) {
final FileWrapper fileWrapper = (FileWrapper) getModel().getValueAt(getSelectedRow(), 0);
setSelectedFile(fileWrapper.getFile());
if (fileWrapper != null)
btnRestore.doClick();
}
}
});
}
private void setButtonOpenDefault() {
MenuBuilder.setLabelAndMnemonic(btnRestore, TextUtils.getRawText(key("open")));
btnRestore.setToolTipText(TextUtils.format(key("open.tooltip")));
}
private void setButtonOpenRestore(final FileWrapper fileWrapper) {
MenuBuilder.setLabelAndMnemonic(btnRestore, TextUtils.getRawText(key("restore")));
btnRestore.setToolTipText(TextUtils.format(key("restore.tooltip"),
file.getName(), fileWrapper.toString()));
}
private final DefaultTableCellRenderer renderer = new DefaultTableCellRenderer() {
private static final long serialVersionUID = 1L;
@Override
public Component getTableCellRendererComponent(final JTable table, final Object value,
final boolean isSelected, final boolean hasFocus,
final int row, final int column) {
final Component c = super
.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
// change the font of the first line which contains the original file
if (containsOriginalFile(table, row))
c.setFont(getFont().deriveFont(Font.BOLD));
return c;
}
private boolean containsOriginalFile(JTable table, int row) {
FileWrapper fileHolder = (FileWrapper) table.getValueAt(row, 0);
return fileHolder.getFile().equals(file);
}
};
@Override
public boolean isCellEditable(final int row, final int column) {
return false;
}
}
private static final long serialVersionUID = 1L;
private final static String ALL_KEY_BASE = "FileRevisionsDialog";
private final static String AUTOSAVE_KEY_BASE = "NewerFileRevisionsFoundDialog";
private String keyBase;
private JButton btnRestore;
private JButton btnSkip;
private boolean cancelled;
private final File file;
private File selectedFile;
private final SimpleDateFormat dateFormat = new SimpleDateFormat();
private final NumberFormat fileSizeFormat = NumberFormat.getIntegerInstance();
private class CloseAction implements ActionListener {
public void actionPerformed(final ActionEvent e) {
final Object source = e.getSource();
cancelled = (source == btnSkip);
dispose();
}
}
public FileRevisionsDialog(final File file, final File[] revisions, AlternativeFileMode mode) {
super(UITools.getFrame(), true);
if(mode == AlternativeFileMode.ALL)
keyBase = ALL_KEY_BASE;
else if(mode == AlternativeFileMode.AUTOSAVE)
keyBase = AUTOSAVE_KEY_BASE;
setTitle(TextUtils.getText(key("title")));
UITools.backOtherWindows();
this.selectedFile = this.file = file;
setBackground(Color.white);
setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
UITools.addEscapeActionToDialog(this);
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
final JTable table = createTable(revisions);
final JScrollPane scrollPane = new JScrollPane(table);
scrollPane.getViewport().setBackground(Color.white);
final Dimension tablePreferredSize = table.getPreferredSize();
int maxHeight = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight() * 2 / 3;
scrollPane.getViewport().setPreferredSize(new Dimension(tablePreferredSize.width, Math.min(maxHeight, tablePreferredSize.height)));
add(scrollPane);
add(createQuestion());
add(createButtonBar());
getRootPane().setDefaultButton(btnRestore);
getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
getRootPane().getActionMap().put("up", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
int newSelectedRow = table.getSelectedRow() - 1;
if(newSelectedRow >= 0)
table.setRowSelectionInterval(newSelectedRow, newSelectedRow);
}
});
getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");
getRootPane().getActionMap().put("down", new AbstractAction() {
public void actionPerformed(ActionEvent e) {
int newSelectedRow = table.getSelectedRow() + 1;
if(newSelectedRow < table.getRowCount())
table.setRowSelectionInterval(newSelectedRow, newSelectedRow);
}
});
pack();
UITools.showFrame();
setLocationRelativeTo(UITools.getFrame());
setVisible(true);
}
private Component createQuestion() {
final String text = TextUtils.format(key("question"), file.getName());
final String html = HtmlUtils.plainToHTML(text);
final JLabel textArea = new JLabel(html);
textArea.setAlignmentX(0.5f);
textArea.setFont(new Font("Dialog", Font.BOLD, 12));
textArea.setBorder(BorderFactory.createLineBorder(Color.BLACK));
return textArea;
}
private String key(final String appendix) {
return keyBase + "." + appendix;
}
private JTable createTable(final File[] revisions) {
final TreeSet<File> sortedRevisions = new TreeSet<File>(new Comparator<File>() {
public int compare(final File f1, final File f2) {
final long diff = f1.lastModified() - f2.lastModified();
if (diff == 0)
return f1.getName().compareTo(f2.getName());
return diff < 0 ? -1 : (diff > 0 ? 1 : 0);
}
});
sortedRevisions.add(file);
sortedRevisions.addAll(Arrays.asList(revisions));
final Object[][] data = new Object[sortedRevisions.size()][];
int i = 0;
int selectedRow = 0;
for (final File f : sortedRevisions) {
data[i] = createRow(f);
if(f == file)
selectedRow = i;
i++;
}
final RevisionTable revisionTable = new RevisionTable(data, selectedRow);
return revisionTable;
}
private Object[] createRow(final File file) {
return new Object[] { new FileWrapper(file), fileSizeFormat.format(file.length()),
dateFormat.format(file.lastModified()) };
}
private Box createButtonBar() {
final Box controllerBox = Box.createHorizontalBox();
controllerBox.setBorder(new EmptyBorder(5, 0, 5, 0));
final CloseAction closeAction = new CloseAction();
controllerBox.add(Box.createHorizontalGlue());
btnSkip = createButton(key("cancel"), null, closeAction);
btnRestore = createButton(key("open"), key("open.tooltip"), closeAction);
controllerBox.add(btnRestore);
controllerBox.add(Box.createHorizontalStrut(10));
controllerBox.add(btnSkip);
controllerBox.add(Box.createHorizontalStrut(10));
return controllerBox;
}
private JButton createButton(final String key, final String tooltipKey, final ActionListener closeAction) {
final JButton button = new JButton();
MenuBuilder.setLabelAndMnemonic(button, TextUtils.getRawText(key));
button.addActionListener(closeAction);
button.setMaximumSize(new Dimension(1000, 1000));
final String selectedFileName = getSelectedFile() == null ? null : getSelectedFile().getName();
// arguments are only used for one button but they don't hurt for the other
if (tooltipKey != null)
button.setToolTipText(TextUtils.format(tooltipKey, file.getName(), selectedFileName));
return button;
}
/** returns null on cancel */
public File getSelectedFile() {
if(cancelled)
return null;
return selectedFile;
}
private void setSelectedFile(final File selectedFile) {
this.selectedFile = selectedFile;
}
}