// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.gui.io;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.KeyStroke;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import org.openstreetmap.josm.Main;
import org.openstreetmap.josm.data.osm.Changeset;
import org.openstreetmap.josm.gui.SideButton;
import org.openstreetmap.josm.tools.ImageProvider;
import org.openstreetmap.josm.tools.InputMapUtils;
import org.openstreetmap.josm.tools.WindowGeometry;
/**
* This dialog lets the user select changesets from a list of changesets.
* @since 2115
*/
public class CloseChangesetDialog extends JDialog {
/** the list */
private JList<Changeset> lstOpenChangesets;
/** true if the user canceled the dialog */
private boolean canceled;
/** the list model */
private DefaultListModel<Changeset> model;
private SideButton btnCloseChangesets;
protected JPanel buildTopPanel() {
JPanel pnl = new JPanel();
pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
pnl.setLayout(new BorderLayout());
pnl.add(new JLabel(tr("<html>Please select the changesets you want to close</html>")), BorderLayout.CENTER);
return pnl;
}
protected JPanel buildCenterPanel() {
JPanel pnl = new JPanel();
pnl.setLayout(new BorderLayout());
model = new DefaultListModel<>();
pnl.add(new JScrollPane(lstOpenChangesets = new JList<>(model)), BorderLayout.CENTER);
lstOpenChangesets.setCellRenderer(new ChangesetCellRenderer());
return pnl;
}
protected JPanel buildSouthPanel() {
JPanel pnl = new JPanel();
pnl.setLayout(new FlowLayout(FlowLayout.CENTER));
// -- close action
CloseAction closeAction = new CloseAction();
lstOpenChangesets.addListSelectionListener(closeAction);
pnl.add(btnCloseChangesets = new SideButton(closeAction));
InputMapUtils.enableEnter(btnCloseChangesets);
// -- cancel action
SideButton btn;
pnl.add(btn = new SideButton(new CancelAction()));
btn.setFocusable(true);
return pnl;
}
protected void build() {
setTitle(tr("Open changesets"));
getContentPane().setLayout(new BorderLayout());
getContentPane().add(buildTopPanel(), BorderLayout.NORTH);
getContentPane().add(buildCenterPanel(), BorderLayout.CENTER);
getContentPane().add(buildSouthPanel(), BorderLayout.SOUTH);
getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0), "escape");
getRootPane().getActionMap().put("escape", new CancelAction());
addWindowListener(new WindowEventHandler());
}
@Override
public void setVisible(boolean visible) {
if (visible) {
new WindowGeometry(
getClass().getName() + ".geometry",
WindowGeometry.centerInWindow(Main.parent, new Dimension(300,300))
).applySafe(this);
} else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775
new WindowGeometry(this).remember(getClass().getName() + ".geometry");
}
super.setVisible(visible);
}
/**
* Constructs a new {@code CloseChangesetDialog}.
*/
public CloseChangesetDialog() {
super(JOptionPane.getFrameForComponent(Main.parent), ModalityType.DOCUMENT_MODAL);
build();
}
class CloseAction extends AbstractAction implements ListSelectionListener {
public CloseAction() {
putValue(NAME, tr("Close changesets"));
putValue(SMALL_ICON, ImageProvider.get("closechangeset"));
putValue(SHORT_DESCRIPTION, tr("Close the selected open changesets"));
refreshEnabledState();
}
@Override
public void actionPerformed(ActionEvent e) {
setCanceled(false);
setVisible(false);
}
protected void refreshEnabledState() {
List<Changeset> list = lstOpenChangesets.getSelectedValuesList();
setEnabled(list != null && !list.isEmpty());
}
@Override
public void valueChanged(ListSelectionEvent e) {
refreshEnabledState();
}
}
class CancelAction extends AbstractAction {
public CancelAction() {
putValue(NAME, tr("Cancel"));
putValue(SMALL_ICON, ImageProvider.get("cancel"));
putValue(SHORT_DESCRIPTION, tr("Cancel closing of changesets"));
}
public void cancel() {
setCanceled(true);
setVisible(false);
}
@Override
public void actionPerformed(ActionEvent e) {
cancel();
}
}
class WindowEventHandler extends WindowAdapter {
@Override
public void windowActivated(WindowEvent arg0) {
btnCloseChangesets.requestFocusInWindow();
}
@Override
public void windowClosing(WindowEvent arg0) {
new CancelAction().cancel();
}
}
/**
* Replies true if this dialog was canceled
* @return true if this dialog was canceled
*/
public boolean isCanceled() {
return canceled;
}
/**
* Sets whether this dialog is canceled
*
* @param canceled true, if this dialog is canceld
*/
protected void setCanceled(boolean canceled) {
this.canceled = canceled;
}
/**
* Sets the collection of changesets to be displayed
*
* @param changesets the collection of changesets. Assumes an empty collection if null
*/
public void setChangesets(Collection<Changeset> changesets) {
if (changesets == null) {
changesets = new ArrayList<>();
}
model.removeAllElements();
for (Changeset cs: changesets) {
model.addElement(cs);
}
if (!changesets.isEmpty()) {
lstOpenChangesets.getSelectionModel().setSelectionInterval(0, changesets.size()-1);
}
}
/**
* Replies a collection with the changesets the user selected.
* Never null, but may be empty.
*
* @return a collection with the changesets the user selected.
*/
public Collection<Changeset> getSelectedChangesets() {
return lstOpenChangesets.getSelectedValuesList();
}
}