source: josm/trunk/src/org/openstreetmap/josm/gui/layer/gpx/ConvertFromGpxLayerAction.java@ 14446

Last change on this file since 14446 was 14446, checked in by Don-vip, 5 years ago

see #16995 - use_Date exclusively for PT_TIME attribute (patch by cmuelle8)

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer.gpx;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.GridBagLayout;
7import java.awt.event.ActionEvent;
8import java.awt.event.ActionListener;
9import java.text.DateFormat;
10import java.util.ArrayList;
11import java.util.Collection;
12import java.util.Date;
13import java.util.List;
14import java.util.Map.Entry;
15
16import javax.swing.BorderFactory;
17import javax.swing.ButtonGroup;
18import javax.swing.JCheckBox;
19import javax.swing.JLabel;
20import javax.swing.JPanel;
21import javax.swing.JRadioButton;
22
23import org.openstreetmap.josm.data.gpx.GpxConstants;
24import org.openstreetmap.josm.data.gpx.GpxTrack;
25import org.openstreetmap.josm.data.gpx.GpxTrackSegment;
26import org.openstreetmap.josm.data.gpx.WayPoint;
27import org.openstreetmap.josm.data.osm.DataSet;
28import org.openstreetmap.josm.data.osm.Node;
29import org.openstreetmap.josm.data.osm.Way;
30import org.openstreetmap.josm.gui.ExtendedDialog;
31import org.openstreetmap.josm.gui.MainApplication;
32import org.openstreetmap.josm.gui.layer.GpxLayer;
33import org.openstreetmap.josm.gui.layer.OsmDataLayer;
34import org.openstreetmap.josm.spi.preferences.Config;
35import org.openstreetmap.josm.tools.GBC;
36import org.openstreetmap.josm.tools.date.DateUtils;
37
38/**
39 * Converts a {@link GpxLayer} to a {@link OsmDataLayer}.
40 * @since 14129 (extracted from {@link ConvertToDataLayerAction})
41 */
42public class ConvertFromGpxLayerAction extends ConvertToDataLayerAction<GpxLayer> {
43
44 private static final String GPX_SETTING = "gpx.convert-tags";
45 private final DateFormat timeFormatter = DateUtils.getGpxFormat();
46
47 /**
48 * Creates a new {@code FromGpxLayer}.
49 * @param layer the source layer
50 */
51 public ConvertFromGpxLayerAction(GpxLayer layer) {
52 super(layer);
53 }
54
55 @Override
56 public DataSet convert() {
57 final DataSet ds = new DataSet();
58
59 List<String> keys = new ArrayList<>();
60 String convertTags = Config.getPref().get(GPX_SETTING, "ask");
61 boolean check = "list".equals(convertTags) || "ask".equals(convertTags);
62 boolean none = "no".equals(convertTags); // no need to convert tags when no dialog will be shown anyways
63
64 for (GpxTrack trk : layer.data.getTracks()) {
65 for (GpxTrackSegment segment : trk.getSegments()) {
66 List<Node> nodes = new ArrayList<>();
67 for (WayPoint p : segment.getWayPoints()) {
68 Node n = new Node(p.getCoor());
69 for (Entry<String, Object> entry : p.attr.entrySet()) {
70 String key = entry.getKey();
71 Object obj = p.get(key);
72 if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Date)) {
73 keys.add(key);
74 }
75 if (obj instanceof String) {
76 String str = (String) obj;
77 if (!none) {
78 // only convert when required
79 n.put(key, str);
80 }
81 } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
82 // timestamps should always be converted
83 Date date = (Date) obj;
84 if (!none) { //... but the tag will only be set when required
85 n.put(key, timeFormatter.format(date));
86 }
87 n.setTimestamp(date);
88 }
89 }
90 ds.addPrimitive(n);
91 nodes.add(n);
92 }
93 Way w = new Way();
94 w.setNodes(nodes);
95 ds.addPrimitive(w);
96 }
97 }
98 //gpx.convert-tags: all, list, *ask, no
99 //gpx.convert-tags.last: *all, list, no
100 //gpx.convert-tags.list.yes
101 //gpx.convert-tags.list.no
102 List<String> listPos = Config.getPref().getList(GPX_SETTING + ".list.yes");
103 List<String> listNeg = Config.getPref().getList(GPX_SETTING + ".list.no");
104 if (check && !keys.isEmpty()) {
105 // Either "list" or "ask" was stored in the settings, so the Nodes have to be filtered after all tags have been processed
106 List<String> allTags = new ArrayList<>(listPos);
107 allTags.addAll(listNeg);
108 if (!allTags.containsAll(keys) || "ask".equals(convertTags)) {
109 // not all keys are in positive/negative list, so we have to ask the user
110 TagConversionDialogResponse res = showTagConversionDialog(keys, listPos, listNeg);
111 if (res.sel == null) {
112 return null;
113 }
114 listPos = res.listPos;
115
116 if ("no".equals(res.sel)) {
117 // User just chose not to convert any tags, but that was unknown before the initial conversion
118 return filterDataSet(ds, null);
119 } else if ("all".equals(res.sel)) {
120 return ds;
121 }
122 }
123 if (!listPos.containsAll(keys)) {
124 return filterDataSet(ds, listPos);
125 }
126 }
127 return ds;
128 }
129
130 /**
131 * Filters the tags of the given {@link DataSet}
132 * @param ds The {@link DataSet}
133 * @param listPos A {@code List<String>} containing the tags to be kept, can be {@code null} if all tags are to be removed
134 * @return The {@link DataSet}
135 * @since 14103
136 */
137 public DataSet filterDataSet(DataSet ds, List<String> listPos) {
138 Collection<Node> nodes = ds.getNodes();
139 for (Node n : nodes) {
140 for (String key : n.keySet()) {
141 if (listPos == null || !listPos.contains(key)) {
142 n.put(key, null);
143 }
144 }
145 }
146 return ds;
147 }
148
149 /**
150 * Shows the TagConversionDialog asking the user whether to keep all, some or no tags
151 * @param keys The keys present during the current conversion
152 * @param listPos The keys that were previously selected
153 * @param listNeg The keys that were previously unselected
154 * @return {@link TagConversionDialogResponse} containing the selection
155 */
156 private static TagConversionDialogResponse showTagConversionDialog(List<String> keys, List<String> listPos, List<String> listNeg) {
157 TagConversionDialogResponse res = new TagConversionDialogResponse(listPos, listNeg);
158 String lSel = Config.getPref().get(GPX_SETTING + ".last", "all");
159
160 JPanel p = new JPanel(new GridBagLayout());
161 ButtonGroup r = new ButtonGroup();
162
163 p.add(new JLabel(
164 tr("The GPX layer contains fields that can be converted to OSM tags. How would you like to proceed?")),
165 GBC.eol());
166 JRadioButton rAll = new JRadioButton(tr("Convert all fields"), "all".equals(lSel));
167 r.add(rAll);
168 p.add(rAll, GBC.eol());
169
170 JRadioButton rList = new JRadioButton(tr("Only convert the following fields:"), "list".equals(lSel));
171 r.add(rList);
172 p.add(rList, GBC.eol());
173
174 JPanel q = new JPanel();
175
176 List<JCheckBox> checkList = new ArrayList<>();
177 for (String key : keys) {
178 JCheckBox cTmp = new JCheckBox(key, !listNeg.contains(key));
179 checkList.add(cTmp);
180 q.add(cTmp);
181 }
182
183 q.setBorder(BorderFactory.createEmptyBorder(0, 20, 5, 0));
184 p.add(q, GBC.eol());
185
186 JRadioButton rNone = new JRadioButton(tr("Do not convert any fields"), "no".equals(lSel));
187 r.add(rNone);
188 p.add(rNone, GBC.eol());
189
190 ActionListener enabler = new TagConversionDialogRadioButtonActionListener(checkList, true);
191 ActionListener disabler = new TagConversionDialogRadioButtonActionListener(checkList, false);
192
193 if (!"list".equals(lSel)) {
194 disabler.actionPerformed(null);
195 }
196
197 rAll.addActionListener(disabler);
198 rList.addActionListener(enabler);
199 rNone.addActionListener(disabler);
200
201 ExtendedDialog ed = new ExtendedDialog(MainApplication.getMainFrame(), tr("Options"),
202 tr("Convert"), tr("Convert and remember selection"), tr("Cancel"))
203 .setButtonIcons("exportgpx", "exportgpx", "cancel").setContent(p);
204 int ret = ed.showDialog().getValue();
205
206 if (ret == 1 || ret == 2) {
207 for (JCheckBox cItem : checkList) {
208 String key = cItem.getText();
209 if (cItem.isSelected()) {
210 if (!res.listPos.contains(key)) {
211 res.listPos.add(key);
212 }
213 res.listNeg.remove(key);
214 } else {
215 if (!res.listNeg.contains(key)) {
216 res.listNeg.add(key);
217 }
218 res.listPos.remove(key);
219 }
220 }
221 if (rAll.isSelected()) {
222 res.sel = "all";
223 } else if (rNone.isSelected()) {
224 res.sel = "no";
225 }
226 Config.getPref().put(GPX_SETTING + ".last", res.sel);
227 if (ret == 2) {
228 Config.getPref().put(GPX_SETTING, res.sel);
229 } else {
230 Config.getPref().put(GPX_SETTING, "ask");
231 }
232 Config.getPref().putList(GPX_SETTING + ".list.yes", res.listPos);
233 Config.getPref().putList(GPX_SETTING + ".list.no", res.listNeg);
234 } else {
235 res.sel = null;
236 }
237 return res;
238 }
239
240 private static class TagConversionDialogResponse {
241
242 final List<String> listPos;
243 final List<String> listNeg;
244 String sel = "list";
245
246 TagConversionDialogResponse(List<String> p, List<String> n) {
247 listPos = new ArrayList<>(p);
248 listNeg = new ArrayList<>(n);
249 }
250 }
251
252 private static class TagConversionDialogRadioButtonActionListener implements ActionListener {
253
254 private final boolean enable;
255 private final List<JCheckBox> checkList;
256
257 TagConversionDialogRadioButtonActionListener(List<JCheckBox> chks, boolean en) {
258 enable = en;
259 checkList = chks;
260 }
261
262 @Override
263 public void actionPerformed(ActionEvent arg0) {
264 for (JCheckBox ch : checkList) {
265 ch.setEnabled(enable);
266 }
267 }
268 }
269}
Note: See TracBrowser for help on using the repository browser.