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; 014 015import javax.swing.AbstractAction; 016import javax.swing.BorderFactory; 017import javax.swing.DefaultListModel; 018import javax.swing.JDialog; 019import javax.swing.JLabel; 020import javax.swing.JList; 021import javax.swing.JPanel; 022import javax.swing.JScrollPane; 023import javax.swing.event.ListSelectionEvent; 024import javax.swing.event.ListSelectionListener; 025 026import org.openstreetmap.josm.data.osm.Changeset; 027import org.openstreetmap.josm.gui.MainApplication; 028import org.openstreetmap.josm.gui.SideButton; 029import org.openstreetmap.josm.gui.util.GuiHelper; 030import org.openstreetmap.josm.gui.util.WindowGeometry; 031import org.openstreetmap.josm.tools.ImageProvider; 032import org.openstreetmap.josm.tools.InputMapUtils; 033import org.openstreetmap.josm.tools.Utils; 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(MainApplication.getMainFrame(), 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(MainApplication.getMainFrame()), 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 setEnabled(!Utils.isEmpty(lstOpenChangesets.getSelectedValuesList())); 131 } 132 133 @Override 134 public void valueChanged(ListSelectionEvent e) { 135 refreshEnabledState(); 136 } 137 } 138 139 class CancelAction extends AbstractAction { 140 141 CancelAction() { 142 putValue(NAME, tr("Cancel")); 143 new ImageProvider("cancel").getResource().attachImageIcon(this, true); 144 putValue(SHORT_DESCRIPTION, tr("Cancel closing of changesets")); 145 } 146 147 public void cancel() { 148 setCanceled(true); 149 setVisible(false); 150 } 151 152 @Override 153 public void actionPerformed(ActionEvent e) { 154 cancel(); 155 } 156 } 157 158 class WindowEventHandler extends WindowAdapter { 159 160 @Override 161 public void windowActivated(WindowEvent arg0) { 162 btnCloseChangesets.requestFocusInWindow(); 163 } 164 165 @Override 166 public void windowClosing(WindowEvent arg0) { 167 new CancelAction().cancel(); 168 } 169 170 } 171 172 /** 173 * Replies true if this dialog was canceled 174 * @return true if this dialog was canceled 175 */ 176 public boolean isCanceled() { 177 return canceled; 178 } 179 180 /** 181 * Sets whether this dialog is canceled 182 * 183 * @param canceled true, if this dialog is canceld 184 */ 185 protected void setCanceled(boolean canceled) { 186 this.canceled = canceled; 187 } 188 189 /** 190 * Sets the collection of changesets to be displayed 191 * 192 * @param changesets the collection of changesets. Assumes an empty collection if null 193 */ 194 public void setChangesets(Collection<Changeset> changesets) { 195 if (changesets == null) { 196 changesets = new ArrayList<>(); 197 } 198 model.removeAllElements(); 199 for (Changeset cs: changesets) { 200 model.addElement(cs); 201 } 202 if (!changesets.isEmpty()) { 203 lstOpenChangesets.getSelectionModel().setSelectionInterval(0, changesets.size()-1); 204 } 205 } 206 207 /** 208 * Replies a collection with the changesets the user selected. 209 * Never null, but may be empty. 210 * 211 * @return a collection with the changesets the user selected. 212 */ 213 public Collection<Changeset> getSelectedChangesets() { 214 return lstOpenChangesets.getSelectedValuesList(); 215 } 216}