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