001 // License: GPL. For details, see LICENSE file. 002 package org.openstreetmap.josm.gui.io; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.awt.BorderLayout; 007 import java.awt.Dimension; 008 import java.awt.FlowLayout; 009 import java.awt.event.ActionEvent; 010 import java.awt.event.WindowAdapter; 011 import java.awt.event.WindowEvent; 012 import java.util.ArrayList; 013 import java.util.Collection; 014 import java.util.Collections; 015 import java.util.Comparator; 016 import java.util.List; 017 018 import javax.swing.AbstractAction; 019 import javax.swing.AbstractListModel; 020 import javax.swing.Action; 021 import javax.swing.BorderFactory; 022 import javax.swing.JComponent; 023 import javax.swing.JDialog; 024 import javax.swing.JLabel; 025 import javax.swing.JList; 026 import javax.swing.JOptionPane; 027 import javax.swing.JPanel; 028 import javax.swing.JScrollPane; 029 import javax.swing.JSplitPane; 030 import javax.swing.KeyStroke; 031 import javax.swing.ListSelectionModel; 032 import javax.swing.event.ListSelectionEvent; 033 import javax.swing.event.ListSelectionListener; 034 035 import org.openstreetmap.josm.Main; 036 import org.openstreetmap.josm.data.osm.OsmPrimitive; 037 import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 038 import org.openstreetmap.josm.gui.DefaultNameFormatter; 039 import org.openstreetmap.josm.gui.OsmPrimitivRenderer; 040 import org.openstreetmap.josm.gui.SideButton; 041 import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction; 042 import org.openstreetmap.josm.gui.help.HelpUtil; 043 import org.openstreetmap.josm.tools.ImageProvider; 044 import org.openstreetmap.josm.tools.WindowGeometry; 045 046 /** 047 * This dialog can be used to select individual object for uploading. 048 * 049 * 050 */ 051 public class UploadSelectionDialog extends JDialog { 052 053 private OsmPrimitiveList lstSelectedPrimitives; 054 private OsmPrimitiveList lstDeletedPrimitives; 055 private JSplitPane spLists; 056 private boolean canceled; 057 private SideButton btnContinue; 058 059 protected JPanel buildSelectedPrimitivesPanel() { 060 JPanel pnl = new JPanel(); 061 pnl.setLayout(new BorderLayout()); 062 JLabel lbl = new JLabel(tr("<html>Mark modified objects <strong>from the current selection</strong> to be uploaded to the server.</html>")); 063 lbl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 064 pnl.add(lbl, BorderLayout.NORTH); 065 pnl.add(new JScrollPane(lstSelectedPrimitives = new OsmPrimitiveList()), BorderLayout.CENTER); 066 return pnl; 067 } 068 069 protected JPanel buildDeletedPrimitivesPanel() { 070 JPanel pnl = new JPanel(); 071 pnl.setLayout(new BorderLayout()); 072 JLabel lbl = new JLabel(tr("<html>Mark <strong>locally deleted objects</strong> to be deleted on the server.</html>")); 073 lbl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5)); 074 pnl.add(lbl, BorderLayout.NORTH); 075 pnl.add(new JScrollPane(lstDeletedPrimitives = new OsmPrimitiveList()), BorderLayout.CENTER); 076 return pnl; 077 } 078 079 protected JPanel buildButtonPanel() { 080 JPanel pnl = new JPanel(); 081 pnl.setLayout(new FlowLayout()); 082 ContinueAction continueAction = new ContinueAction(); 083 pnl.add(btnContinue = new SideButton(continueAction)); 084 btnContinue.setFocusable(true); 085 lstDeletedPrimitives.getSelectionModel().addListSelectionListener(continueAction); 086 lstSelectedPrimitives.getSelectionModel().addListSelectionListener(continueAction); 087 088 pnl.add(new SideButton(new CancelAction())); 089 pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Dialog/UploadSelection")))); 090 return pnl; 091 } 092 093 protected void build() { 094 setLayout(new BorderLayout()); 095 spLists = new JSplitPane(JSplitPane.VERTICAL_SPLIT); 096 spLists.setTopComponent(buildSelectedPrimitivesPanel()); 097 spLists.setBottomComponent(buildDeletedPrimitivesPanel()); 098 add(spLists, BorderLayout.CENTER); 099 add(buildButtonPanel(), BorderLayout.SOUTH); 100 addWindowListener( 101 new WindowAdapter() { 102 @Override 103 public void windowOpened(WindowEvent e) { 104 spLists.setDividerLocation(0.5); 105 btnContinue.requestFocusInWindow(); 106 } 107 108 @Override 109 public void windowClosing(WindowEvent e) { 110 setCanceled(true); 111 } 112 } 113 ); 114 setTitle(tr("Select objects to upload")); 115 HelpUtil.setHelpContext(getRootPane(), HelpUtil.ht("/Dialog/UploadSelection")); 116 } 117 118 public UploadSelectionDialog() { 119 super(JOptionPane.getFrameForComponent(Main.parent), ModalityType.DOCUMENT_MODAL); 120 build(); 121 } 122 123 public void populate(Collection<OsmPrimitive> selected, Collection<OsmPrimitive> deleted) { 124 if (selected != null) { 125 lstSelectedPrimitives.getOsmPrimitiveListModel().setPrimitives(new ArrayList<OsmPrimitive>(selected)); 126 if (!selected.isEmpty()) { 127 lstSelectedPrimitives.getSelectionModel().setSelectionInterval(0, selected.size()-1); 128 } else { 129 lstSelectedPrimitives.getSelectionModel().clearSelection(); 130 } 131 } else { 132 lstSelectedPrimitives.getOsmPrimitiveListModel().setPrimitives(null); 133 lstSelectedPrimitives.getSelectionModel().clearSelection(); 134 } 135 136 if (deleted != null) { 137 lstDeletedPrimitives.getOsmPrimitiveListModel().setPrimitives(new ArrayList<OsmPrimitive>(deleted)); 138 } else { 139 lstDeletedPrimitives.getOsmPrimitiveListModel().setPrimitives(null); 140 } 141 } 142 143 public boolean isCanceled() { 144 return canceled; 145 } 146 147 protected void setCanceled(boolean canceled) { 148 this.canceled = canceled; 149 } 150 151 public List<OsmPrimitive> getSelectedPrimitives() { 152 ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>(); 153 System.out.println("selected length:" +lstSelectedPrimitives.getSelectedIndices().length); 154 for (int i=0; i< lstSelectedPrimitives.getSelectedIndices().length;i++) { 155 System.out.println("selected:" +lstSelectedPrimitives.getSelectedIndices()[i]); 156 } 157 ret.addAll(lstSelectedPrimitives.getOsmPrimitiveListModel().getPrimitives(lstSelectedPrimitives.getSelectedIndices())); 158 ret.addAll(lstDeletedPrimitives.getOsmPrimitiveListModel().getPrimitives(lstDeletedPrimitives.getSelectedIndices())); 159 return ret; 160 } 161 162 @Override 163 public void setVisible(boolean visible) { 164 if (visible) { 165 new WindowGeometry( 166 getClass().getName() + ".geometry", 167 WindowGeometry.centerInWindow( 168 Main.parent, 169 new Dimension(200,400) 170 ) 171 ).applySafe(this); 172 } else if (!visible && isShowing()){ 173 new WindowGeometry(this).remember(getClass().getName() + ".geometry"); 174 } 175 super.setVisible(visible); 176 } 177 178 static class OsmPrimitiveList extends JList { 179 protected void init() { 180 setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 181 setCellRenderer(new OsmPrimitivRenderer()); 182 } 183 184 public OsmPrimitiveList() { 185 super(new OsmPrimitiveListModel()); 186 init(); 187 } 188 189 public OsmPrimitiveList(OsmPrimitiveListModel model) { 190 super(model); 191 init(); 192 } 193 194 public OsmPrimitiveListModel getOsmPrimitiveListModel() { 195 return (OsmPrimitiveListModel)getModel(); 196 } 197 } 198 199 static class OsmPrimitiveListModel extends AbstractListModel { 200 private List<OsmPrimitive> data; 201 202 public OsmPrimitiveListModel() { 203 } 204 205 protected void sort() { 206 if (data == null) 207 return; 208 Collections.sort( 209 data, 210 new Comparator<OsmPrimitive>() { 211 private DefaultNameFormatter formatter = DefaultNameFormatter.getInstance(); 212 public int compare(OsmPrimitive o1, OsmPrimitive o2) { 213 int ret = OsmPrimitiveType.from(o1).compareTo(OsmPrimitiveType.from(o2)); 214 if (ret != 0) return ret; 215 return o1.getDisplayName(formatter).compareTo(o1.getDisplayName(formatter)); 216 } 217 } 218 ); 219 } 220 221 public OsmPrimitiveListModel(List<OsmPrimitive> data) { 222 setPrimitives(data); 223 } 224 225 public void setPrimitives(List<OsmPrimitive> data) { 226 this.data = data; 227 sort(); 228 if (data != null) { 229 fireContentsChanged(this,0, data.size()); 230 } else { 231 fireContentsChanged(this, 0,0); 232 } 233 } 234 235 public Object getElementAt(int index) { 236 if (data == null) 237 return null; 238 return data.get(index); 239 } 240 241 public int getSize() { 242 if (data == null) 243 return 0; 244 return data.size(); 245 } 246 247 public List<OsmPrimitive> getPrimitives(int [] indices) { 248 if (indices == null || indices.length == 0) 249 return Collections.emptyList(); 250 ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>(indices.length); 251 for (int i: indices) { 252 if (i < 0) { 253 continue; 254 } 255 ret.add(data.get(i)); 256 } 257 return ret; 258 } 259 } 260 261 class CancelAction extends AbstractAction { 262 public CancelAction() { 263 putValue(Action.SHORT_DESCRIPTION, tr("Cancel uploading")); 264 putValue(Action.NAME, tr("Cancel")); 265 putValue(Action.SMALL_ICON, ImageProvider.get("", "cancel")); 266 getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) 267 .put(KeyStroke.getKeyStroke("ESCAPE"), "ESCAPE"); 268 getRootPane().getActionMap().put("ESCAPE", this); 269 setEnabled(true); 270 } 271 272 public void actionPerformed(ActionEvent e) { 273 setCanceled(true); 274 setVisible(false); 275 } 276 } 277 278 class ContinueAction extends AbstractAction implements ListSelectionListener { 279 public ContinueAction() { 280 putValue(Action.SHORT_DESCRIPTION, tr("Continue uploading")); 281 putValue(Action.NAME, tr("Continue")); 282 putValue(Action.SMALL_ICON, ImageProvider.get("", "upload")); 283 updateEnabledState(); 284 } 285 286 public void actionPerformed(ActionEvent e) { 287 setCanceled(false); 288 setVisible(false); 289 } 290 291 protected void updateEnabledState() { 292 setEnabled(lstSelectedPrimitives.getSelectedIndex() >=0 293 || lstDeletedPrimitives.getSelectedIndex() >= 0); 294 } 295 296 public void valueChanged(ListSelectionEvent e) { 297 updateEnabledState(); 298 } 299 } 300 }