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    }