// 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 lstOpenChangesets; /** true if the user canceled the dialog */ private boolean canceled; /** the list model */ private DefaultListModel 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("Please select the changesets you want to close")), 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 { 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 list = lstOpenChangesets.getSelectedValuesList(); setEnabled(list != null && !list.isEmpty()); } @Override public void valueChanged(ListSelectionEvent e) { refreshEnabledState(); } } class CancelAction extends AbstractAction { 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 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 getSelectedChangesets() { return lstOpenChangesets.getSelectedValuesList(); } }