001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.gui.io; 003 004import static org.openstreetmap.josm.tools.I18n.tr; 005 006import java.awt.BorderLayout; 007import java.awt.Dimension; 008import java.awt.FlowLayout; 009import java.awt.event.ActionEvent; 010import java.awt.event.WindowAdapter; 011import java.awt.event.WindowEvent; 012import java.util.ArrayList; 013import java.util.Collection; 014import java.util.List; 015 016import javax.swing.AbstractAction; 017import javax.swing.BorderFactory; 018import javax.swing.DefaultListModel; 019import javax.swing.JDialog; 020import javax.swing.JLabel; 021import javax.swing.JList; 022import javax.swing.JPanel; 023import javax.swing.JScrollPane; 024import javax.swing.event.ListSelectionEvent; 025import javax.swing.event.ListSelectionListener; 026 027import org.openstreetmap.josm.Main; 028import org.openstreetmap.josm.data.osm.Changeset; 029import org.openstreetmap.josm.gui.SideButton; 030import org.openstreetmap.josm.gui.util.GuiHelper; 031import org.openstreetmap.josm.gui.util.WindowGeometry; 032import org.openstreetmap.josm.tools.ImageProvider; 033import org.openstreetmap.josm.tools.InputMapUtils; 034 035/** 036 * This dialog lets the user select changesets from a list of changesets. 037 * @since 2115 038 */ 039public class CloseChangesetDialog extends JDialog { 040 041 /** the list */ 042 private JList<Changeset> lstOpenChangesets; 043 /** true if the user canceled the dialog */ 044 private boolean canceled; 045 /** the list model */ 046 private DefaultListModel<Changeset> model; 047 048 private SideButton btnCloseChangesets; 049 050 protected JPanel buildTopPanel() { 051 JPanel pnl = new JPanel(new BorderLayout()); 052 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 053 pnl.add(new JLabel(tr("<html>Please select the changesets you want to close</html>")), BorderLayout.CENTER); 054 return pnl; 055 } 056 057 protected JPanel buildCenterPanel() { 058 JPanel pnl = new JPanel(new BorderLayout()); 059 model = new DefaultListModel<>(); 060 lstOpenChangesets = new JList<>(model); 061 pnl.add(new JScrollPane(lstOpenChangesets), BorderLayout.CENTER); 062 lstOpenChangesets.setCellRenderer(new ChangesetCellRenderer()); 063 return pnl; 064 } 065 066 protected JPanel buildSouthPanel() { 067 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.CENTER)); 068 069 // -- close action 070 CloseAction closeAction = new CloseAction(); 071 lstOpenChangesets.addListSelectionListener(closeAction); 072 btnCloseChangesets = new SideButton(closeAction); 073 pnl.add(btnCloseChangesets); 074 InputMapUtils.enableEnter(btnCloseChangesets); 075 076 // -- cancel action 077 SideButton btn = new SideButton(new CancelAction()); 078 pnl.add(btn); 079 btn.setFocusable(true); 080 return pnl; 081 } 082 083 protected void build() { 084 setTitle(tr("Open changesets")); 085 getContentPane().setLayout(new BorderLayout()); 086 getContentPane().add(buildTopPanel(), BorderLayout.NORTH); 087 getContentPane().add(buildCenterPanel(), BorderLayout.CENTER); 088 getContentPane().add(buildSouthPanel(), BorderLayout.SOUTH); 089 090 InputMapUtils.addEscapeAction(getRootPane(), new CancelAction()); 091 addWindowListener(new WindowEventHandler()); 092 } 093 094 @Override 095 public void setVisible(boolean visible) { 096 if (visible) { 097 new WindowGeometry( 098 getClass().getName() + ".geometry", 099 WindowGeometry.centerInWindow(Main.parent, new Dimension(300, 300)) 100 ).applySafe(this); 101 } else if (isShowing()) { // Avoid IllegalComponentStateException like in #8775 102 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 103 } 104 super.setVisible(visible); 105 } 106 107 /** 108 * Constructs a new {@code CloseChangesetDialog}. 109 */ 110 public CloseChangesetDialog() { 111 super(GuiHelper.getFrameForComponent(Main.parent), ModalityType.DOCUMENT_MODAL); 112 build(); 113 } 114 115 class CloseAction extends AbstractAction implements ListSelectionListener { 116 CloseAction() { 117 putValue(NAME, tr("Close changesets")); 118 new ImageProvider("closechangeset").getResource().attachImageIcon(this, true); 119 putValue(SHORT_DESCRIPTION, tr("Close the selected open changesets")); 120 refreshEnabledState(); 121 } 122 123 @Override 124 public void actionPerformed(ActionEvent e) { 125 setCanceled(false); 126 setVisible(false); 127 } 128 129 protected void refreshEnabledState() { 130 List<Changeset> list = lstOpenChangesets.getSelectedValuesList(); 131 setEnabled(list != null && !list.isEmpty()); 132 } 133 134 @Override 135 public void valueChanged(ListSelectionEvent e) { 136 refreshEnabledState(); 137 } 138 } 139 140 class CancelAction extends AbstractAction { 141 142 CancelAction() { 143 putValue(NAME, tr("Cancel")); 144 new ImageProvider("cancel").getResource().attachImageIcon(this, true); 145 putValue(SHORT_DESCRIPTION, tr("Cancel closing of changesets")); 146 } 147 148 public void cancel() { 149 setCanceled(true); 150 setVisible(false); 151 } 152 153 @Override 154 public void actionPerformed(ActionEvent e) { 155 cancel(); 156 } 157 } 158 159 class WindowEventHandler extends WindowAdapter { 160 161 @Override 162 public void windowActivated(WindowEvent arg0) { 163 btnCloseChangesets.requestFocusInWindow(); 164 } 165 166 @Override 167 public void windowClosing(WindowEvent arg0) { 168 new CancelAction().cancel(); 169 } 170 171 } 172 173 /** 174 * Replies true if this dialog was canceled 175 * @return true if this dialog was canceled 176 */ 177 public boolean isCanceled() { 178 return canceled; 179 } 180 181 /** 182 * Sets whether this dialog is canceled 183 * 184 * @param canceled true, if this dialog is canceld 185 */ 186 protected void setCanceled(boolean canceled) { 187 this.canceled = canceled; 188 } 189 190 /** 191 * Sets the collection of changesets to be displayed 192 * 193 * @param changesets the collection of changesets. Assumes an empty collection if null 194 */ 195 public void setChangesets(Collection<Changeset> changesets) { 196 if (changesets == null) { 197 changesets = new ArrayList<>(); 198 } 199 model.removeAllElements(); 200 for (Changeset cs: changesets) { 201 model.addElement(cs); 202 } 203 if (!changesets.isEmpty()) { 204 lstOpenChangesets.getSelectionModel().setSelectionInterval(0, changesets.size()-1); 205 } 206 } 207 208 /** 209 * Replies a collection with the changesets the user selected. 210 * Never null, but may be empty. 211 * 212 * @return a collection with the changesets the user selected. 213 */ 214 public Collection<Changeset> getSelectedChangesets() { 215 return lstOpenChangesets.getSelectedValuesList(); 216 } 217}