Ticket #16572: ConvertToDataLayerAction.patch

File ConvertToDataLayerAction.patch, 12.8 KB (added by Bjoeni, 6 years ago)
  • src/org/openstreetmap/josm/gui/layer/gpx/ConvertToDataLayerAction.java

     
    66
    77import java.awt.GridBagLayout;
    88import java.awt.event.ActionEvent;
     9import java.awt.event.ActionListener;
    910import java.io.File;
    1011import java.text.DateFormat;
    1112import java.util.ArrayList;
     
    1819import java.util.Optional;
    1920
    2021import javax.swing.AbstractAction;
     22import javax.swing.BorderFactory;
     23import javax.swing.ButtonGroup;
     24import javax.swing.JCheckBox;
    2125import javax.swing.JLabel;
    2226import javax.swing.JOptionPane;
    2327import javax.swing.JPanel;
     28import javax.swing.JRadioButton;
    2429
    2530import org.openstreetmap.josm.Main;
    2631import org.openstreetmap.josm.data.gpx.GpxConstants;
     
    3136import org.openstreetmap.josm.data.osm.Node;
    3237import org.openstreetmap.josm.data.osm.Way;
    3338import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil;
     39import org.openstreetmap.josm.gui.ExtendedDialog;
    3440import org.openstreetmap.josm.gui.MainApplication;
    3541import org.openstreetmap.josm.gui.layer.GpxLayer;
    3642import org.openstreetmap.josm.gui.layer.Layer;
     
    8187
    8288        @Override
    8389        public DataSet convert() {
    84             final DataSet ds = new DataSet();
     90            DataSet ds = new DataSet();
     91
     92            List<String> keys = new ArrayList<>();
     93            String convertTags = Config.getPref().get("gpx.convert-tags", "ask");
     94            boolean check = convertTags.equals("list") || convertTags.equals("ask");
     95            boolean none = convertTags.equals("no"); // no need to convert tags when no dialog will be shown anyways
     96
    8597            for (GpxTrack trk : layer.data.getTracks()) {
    8698                for (GpxTrackSegment segment : trk.getSegments()) {
    8799                    List<Node> nodes = new ArrayList<>();
     
    89101                        Node n = new Node(p.getCoor());
    90102                        for (Entry<String, Object> entry : p.attr.entrySet()) {
    91103                            String key = entry.getKey();
    92                             String str = p.getString(key);
    93                             if (str != null) {
    94                                 n.put(key, str);
     104                            Object obj = p.get(key);
     105                            if (check && !keys.contains(key) && (obj instanceof String || obj instanceof Date)) {
     106                                keys.add(key);
     107                            }
     108                            if (obj instanceof String) {
     109                                String str = (String) obj;
     110                                if (!none) {
     111                                    // only convert when required
     112                                    n.put(key, str);
     113                                }
    95114                                if (GpxConstants.PT_TIME.equals(key)) {
     115                                    // timestamps should always be converted
    96116                                    try {
    97117                                        n.setTimestamp(DateUtils.fromString(str));
    98118                                    } catch (UncheckedParseException e) {
     
    99119                                        Logging.log(Logging.LEVEL_WARN, e);
    100120                                    }
    101121                                }
    102                             } else {
    103                                 Object obj = p.get(key);
    104                                 if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
    105                                     Date date = (Date) obj;
     122                            } else if (obj instanceof Date && GpxConstants.PT_TIME.equals(key)) {
     123                                // timestamps should always be converted
     124                                Date date = (Date) obj;
     125                                if (!none) { //... but the tag will only be set when required
    106126                                    n.put(key, timeFormatter.format(date));
    107                                     n.setTimestamp(date);
    108127                                }
     128                                n.setTimestamp(date);
    109129                            }
    110130                        }
    111131                        ds.addPrimitive(n);
     
    116136                    ds.addPrimitive(w);
    117137                }
    118138            }
     139            //gpx.convert-tags: all, list, *ask, no
     140            //gpx.convert-tags.last: *all, list, no
     141            //gpx.convert-tags.list.yes
     142            //gpx.convert-tags.list.no
     143            List<String> listPos = Config.getPref().getList("gpx.convert-tags.list.yes");
     144            List<String> listNeg = Config.getPref().getList("gpx.convert-tags.list.no");
     145            if (check && !keys.isEmpty()) {
     146                // Either "list" or "ask" was stored in the settings, so the nodes have to be filtered after all tags have been processed
     147                List<String> allTags = new ArrayList<>(listPos);
     148                allTags.addAll(listNeg);
     149                if (!allTags.containsAll(keys) || convertTags.equals("ask")) {
     150                    // not all keys are in positive/negative list, so we have to ask the user
     151                    TagConversionDialogResponse res = showTagConversionDialog(keys, listPos, listNeg);
     152                    if (res.sel == null) {
     153                        return null;
     154                    }
     155                    listPos = res.listPos;
     156
     157                    if (res.sel.equals("no")) {
     158                        // User just chose not to convert any tags, but that was unknown before the initial conversion
     159                        return filterDataSet(ds, null);
     160                    } else if (res.sel.equals("all")) {
     161                        return ds;
     162                    }
     163                }
     164                if (!listPos.containsAll(keys)) {
     165                    ds = filterDataSet(ds, listPos);
     166                }
     167            }
    119168            return ds;
    120169        }
     170
     171        /**
     172         * Filters the tags of the given {@link DataSet}
     173         * @param ds The {@link DataSet}
     174         * @param listPos A {@code List<String>} containing the tags to be kept, can be {@code null} if all tags are to be removed
     175         * @return The {@link DataSet}
     176         * @since xxx
     177         */
     178        public DataSet filterDataSet(DataSet ds, List<String> listPos) {
     179            Collection<Node> nodes = ds.getNodes();
     180            for (Node n : nodes) {
     181                for (String key : n.keySet()) {
     182                    if (listPos == null || !listPos.contains(key)) {
     183                        n.put(key, null);
     184                    }
     185                }
     186            }
     187            return ds;
     188        }
     189
     190        /**
     191         * Shows the TagConversionDialog asking the user whether to keep all, some or no tags
     192         * @param keys The keys present during the current conversion
     193         * @param listPos The keys that were previously selected
     194         * @param listNeg The keys that were previously unselected
     195         * @return {@link TagConversionDialogResponse} containing the selection
     196         */
     197        private TagConversionDialogResponse showTagConversionDialog(List<String> keys, List<String> listPos,
     198                List<String> listNeg) {
     199            TagConversionDialogResponse res = new TagConversionDialogResponse(listPos, listNeg);
     200            String lSel = Config.getPref().get("gpx.convert-tags.last", "all");
     201
     202            JPanel p = new JPanel(new GridBagLayout());
     203            ButtonGroup r = new ButtonGroup();
     204
     205            p.add(new JLabel(tr(
     206                    "The GPX layer contains fields that can be converted to OSM tags. How would you like to proceed?")),
     207                    GBC.eol());
     208            JRadioButton rAll = new JRadioButton(tr("Convert all fields"), lSel.equals("all"));
     209            r.add(rAll);
     210            p.add(rAll, GBC.eol());
     211
     212            JRadioButton rList = new JRadioButton(tr("Only convert the following fields:"), lSel.equals("list"));
     213            r.add(rList);
     214            p.add(rList, GBC.eol());
     215
     216            JPanel q = new JPanel();
     217
     218            List<JCheckBox> checkList = new ArrayList<>();
     219            for (String key : keys) {
     220                JCheckBox cTmp = new JCheckBox(key, !listNeg.contains(key));
     221                checkList.add(cTmp);
     222                q.add(cTmp);
     223            }
     224
     225            q.setBorder(BorderFactory.createEmptyBorder(0, 20, 5, 0));
     226            p.add(q, GBC.eol());
     227
     228            JRadioButton rNone = new JRadioButton(tr("Do not convert any fields"), lSel.equals("no"));
     229            r.add(rNone);
     230            p.add(rNone, GBC.eol());
     231
     232            ActionListener enabler = new TagConversionDialogRadioButtonActionListener(checkList, true);
     233            ActionListener disabler = new TagConversionDialogRadioButtonActionListener(checkList, false);
     234
     235            if (!lSel.equals("list")) {
     236                disabler.actionPerformed(null);
     237            }
     238
     239            rAll.addActionListener(disabler);
     240            rList.addActionListener(enabler);
     241            rNone.addActionListener(disabler);
     242
     243            ExtendedDialog ed = new ExtendedDialog(Main.parent, tr("Options"), tr("Convert"),
     244                    tr("Convert and remember selection"), tr("Cancel"))
     245                            .setButtonIcons("exportgpx", "exportgpx", "cancel").setContent(p);
     246            int ret = ed.showDialog().getValue();
     247
     248            if (ret == 1 || ret == 2) {
     249                for (JCheckBox cItem : checkList) {
     250                    String key = cItem.getText();
     251                    if (cItem.isSelected()) {
     252                        if (!listPos.contains(key)) {
     253                            res.listPos.add(key);
     254                        }
     255                        res.listNeg.remove(key);
     256                    } else {
     257                        if (!listNeg.contains(key)) {
     258                            res.listNeg.add(key);
     259                        }
     260                        res.listPos.remove(key);
     261                    }
     262                }
     263                if (rAll.isSelected()) {
     264                    res.sel = "all";
     265                } else if (rNone.isSelected()) {
     266                    res.sel = "no";
     267                }
     268                Config.getPref().put("gpx.convert-tags.last", res.sel);
     269                if (ret == 2) {
     270                    Config.getPref().put("gpx.convert-tags", res.sel);
     271                } else {
     272                    Config.getPref().put("gpx.convert-tags", "ask");
     273                }
     274                Config.getPref().putList("gpx.convert-tags.list.yes", res.listPos);
     275                Config.getPref().putList("gpx.convert-tags.list.no", res.listNeg);
     276            } else {
     277                res.sel = null;
     278            }
     279            return res;
     280        }
     281
     282        private class TagConversionDialogResponse {
     283            public TagConversionDialogResponse(List<String> p, List<String> n) {
     284                listPos = new ArrayList<>(p);
     285                listNeg = new ArrayList<>(n);
     286            }
     287
     288            List<String> listPos;
     289            List<String> listNeg;
     290            String sel = "list";
     291        }
     292
     293        private class TagConversionDialogRadioButtonActionListener implements ActionListener {
     294
     295            private boolean enable;
     296            private List<JCheckBox> checkList;
     297
     298            public TagConversionDialogRadioButtonActionListener(List<JCheckBox> chks, boolean en) {
     299                enable = en;
     300                checkList = chks;
     301            }
     302
     303            @Override
     304            public void actionPerformed(ActionEvent arg0) {
     305                for (JCheckBox ch : checkList) {
     306                    ch.setEnabled(enable);
     307                }
     308            }
     309        }
    121310    }
    122311
    123312    /**
     
    181370            return;
    182371        }
    183372        final DataSet ds = convert();
    184         final OsmDataLayer osmLayer = new OsmDataLayer(ds, tr("Converted from: {0}", layer.getName()), null);
    185         if (layer.getAssociatedFile() != null) {
    186             osmLayer.setAssociatedFile(new File(layer.getAssociatedFile().getParentFile(), layer.getAssociatedFile().getName() + ".osm"));
     373        if (ds != null) {
     374            final OsmDataLayer osmLayer = new OsmDataLayer(ds, tr("Converted from: {0}", layer.getName()), null);
     375            if (layer.getAssociatedFile() != null) {
     376                osmLayer.setAssociatedFile(new File(layer.getAssociatedFile().getParentFile(),
     377                        layer.getAssociatedFile().getName() + ".osm"));
     378            }
     379            osmLayer.setUploadDiscouraged(true);
     380            MainApplication.getLayerManager().addLayer(osmLayer, false);
     381            MainApplication.getLayerManager().removeLayer(layer);
    187382        }
    188         osmLayer.setUploadDiscouraged(true);
    189         MainApplication.getLayerManager().addLayer(osmLayer, false);
    190         MainApplication.getLayerManager().removeLayer(layer);
    191383    }
    192384}