Allow users to modify tags (hidden in non-expert mode)

Signed-off-by: Taylor Smock <taylor.smock@kaart.com>
pull/1/head
Taylor Smock 2019-10-29 09:40:15 -06:00
rodzic df70ac4d4e
commit f3035d89f2
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 625F6A74A3E4311A
4 zmienionych plików z 183 dodań i 30 usunięć

Wyświetl plik

@ -3,28 +3,43 @@ package org.openstreetmap.josm.plugins.mapwithai;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import org.openstreetmap.josm.actions.ExpertToggleAction;
import org.openstreetmap.josm.gui.preferences.PreferenceTabbedPane;
import org.openstreetmap.josm.gui.preferences.SubPreferenceSetting;
import org.openstreetmap.josm.gui.preferences.TabPreferenceSetting;
import org.openstreetmap.josm.gui.preferences.advanced.PrefEntry;
import org.openstreetmap.josm.plugins.mapwithai.backend.MapWithAIPreferenceHelper;
import org.openstreetmap.josm.spi.preferences.StringSetting;
import org.openstreetmap.josm.tools.GBC;
public class MapWithAIPreferences implements SubPreferenceSetting {
private final JComboBox<String> possibleMapWithAIApiUrl;
private final JCheckBox switchLayerCheckBox;
private final JCheckBox mergeBuildingAddressCheckBox;
private final JSpinner maximumAdditionSpinner;
private final ReplacementPreferenceTable table;
private final List<PrefEntry> displayData;
public MapWithAIPreferences() {
possibleMapWithAIApiUrl = new JComboBox<>();
@ -32,6 +47,16 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
maximumAdditionSpinner = new JSpinner(
new SpinnerNumberModel(MapWithAIPreferenceHelper.getMaximumAddition(), 0, 100, 1));
mergeBuildingAddressCheckBox = new JCheckBox();
displayData = new ArrayList<>();
fillDisplayData(displayData);
table = new ReplacementPreferenceTable(displayData);
}
private static void fillDisplayData(List<PrefEntry> list) {
Map<String, String> current = new TreeMap<>(MapWithAIPreferenceHelper.getReplacementTags());
for (Entry<String, String> entry : current.entrySet()) {
list.add(new PrefEntry(entry.getKey(), new StringSetting(entry.getValue()), new StringSetting(null), false));
}
}
@Override
@ -40,9 +65,9 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
final JLabel switchLayer = new JLabel(tr("Automatically switch layers"));
final JLabel maximumAddition = new JLabel(tr("Maximum features (add)"));
final JLabel mergeBuildingWithAddress = new JLabel(tr("Merge address nodes and buildings"));
final JPanel container = new JPanel(new GridBagLayout());
container.setAlignmentY(Component.TOP_ALIGNMENT);
final GridBagConstraints constraints = new GridBagConstraints();
final JPanel nonExpert = new JPanel(new GridBagLayout());
nonExpert.setAlignmentY(Component.TOP_ALIGNMENT);
nonExpert.setAlignmentX(Component.LEFT_ALIGNMENT);
possibleMapWithAIApiUrl.setEditable(true);
possibleMapWithAIApiUrl.setPrototypeDisplayValue("https://example.url/some/end/point");
@ -58,38 +83,64 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
switchLayerCheckBox.setSelected(MapWithAIPreferenceHelper.isSwitchLayers());
mergeBuildingAddressCheckBox.setSelected(MapWithAIPreferenceHelper.isMergeBuildingAddress());
constraints.gridx = 0;
constraints.gridy = 0;
constraints.weightx = .1;
constraints.weighty = 0;
constraints.insets = new Insets(5, 10, 5, 10);
constraints.anchor = GridBagConstraints.EAST;
constraints.fill = GridBagConstraints.HORIZONTAL;
container.add(mapWithAIApiUrl, constraints);
nonExpert.add(mapWithAIApiUrl);
constraints.gridx++;
container.add(possibleMapWithAIApiUrl, constraints);
nonExpert.add(possibleMapWithAIApiUrl, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
constraints.gridx--;
constraints.gridy++;
container.add(switchLayer, constraints);
nonExpert.add(switchLayer);
constraints.gridx++;
container.add(switchLayerCheckBox, constraints);
nonExpert.add(switchLayerCheckBox, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
constraints.gridx--;
constraints.gridy++;
container.add(maximumAddition, constraints);
constraints.gridx++;
container.add(maximumAdditionSpinner, constraints);
nonExpert.add(maximumAddition);
nonExpert.add(maximumAdditionSpinner, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
constraints.gridx--;
constraints.gridy++;
container.add(mergeBuildingWithAddress, constraints);
constraints.gridx++;
container.add(mergeBuildingAddressCheckBox, constraints);
nonExpert.add(mergeBuildingWithAddress);
nonExpert.add(mergeBuildingAddressCheckBox, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
getTabPreferenceSetting(gui).addSubTab(this, MapWithAIPlugin.NAME, container);
final JPanel expert = new JPanel(new GridBagLayout());
expert.add(Box.createHorizontalGlue(), GBC.std().fill(GridBagConstraints.HORIZONTAL));
JScrollPane scroll = new JScrollPane(table);
expert.add(scroll, GBC.eol().fill(GridBagConstraints.BOTH));
scroll.setPreferredSize(new Dimension(400, 200));
JButton add = new JButton(tr("Add"));
expert.add(Box.createHorizontalGlue(), GBC.std().fill(GridBagConstraints.HORIZONTAL));
expert.add(add, GBC.std().insets(0, 5, 0, 0));
add.addActionListener(e -> {
PrefEntry pe = table.addPreference(gui);
if (pe != null && pe.getValue() instanceof StringSetting) {
displayData.add(pe);
Collections.sort(displayData);
table.fireDataChanged();
}
});
JButton edit = new JButton(tr("Edit"));
expert.add(edit, GBC.std().insets(5, 5, 0, 0));
edit.addActionListener(e -> {
List<PrefEntry> toEdit = table.getSelectedItems();
if (toEdit.size() == 1) {
table.editPreference(gui);
}
});
JButton delete = new JButton(tr("Delete"));
expert.add(delete, GBC.std().insets(5, 5, 0, 0));
delete.addActionListener(e -> {
List<PrefEntry> toRemove = table.getSelectedItems();
if (!toRemove.isEmpty()) {
displayData.removeAll(toRemove);
}
table.fireDataChanged();
});
ExpertToggleAction.addVisibilitySwitcher(expert);
JPanel pane = new JPanel(new GridBagLayout());
pane.add(nonExpert, GBC.eol().fill(GridBagConstraints.HORIZONTAL));
pane.add(expert);
getTabPreferenceSetting(gui).addSubTab(this, MapWithAIPlugin.NAME, pane);
}
@Override
@ -100,9 +151,16 @@ public class MapWithAIPreferences implements SubPreferenceSetting {
if (value instanceof Number) {
MapWithAIPreferenceHelper.setMaximumAddition(((Number) value).intValue(), true);
}
MapWithAIPreferenceHelper.setReplacementTags(convertPrefToMap(displayData));
return false;
}
private static Map<String, String> convertPrefToMap(List<PrefEntry> displayData) {
Map<String, String> returnMap = displayData.isEmpty() ? Collections.emptyMap() : new TreeMap<>();
displayData.forEach(entry -> returnMap.put(entry.getKey(), entry.getValue().getValue().toString()));
return returnMap;
}
@Override
public boolean isExpert() {
return false;

Wyświetl plik

@ -0,0 +1,52 @@
// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.mapwithai;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import org.openstreetmap.josm.gui.ExtendedDialog;
import org.openstreetmap.josm.gui.preferences.advanced.PrefEntry;
import org.openstreetmap.josm.gui.preferences.advanced.PreferencesTable;
import org.openstreetmap.josm.gui.widgets.JosmTextField;
import org.openstreetmap.josm.spi.preferences.StringSetting;
import org.openstreetmap.josm.tools.GBC;
/**
* @author Taylor Smock
*/
public class ReplacementPreferenceTable extends PreferencesTable {
private static final long serialVersionUID = 8057277761625324262L;
public ReplacementPreferenceTable(List<PrefEntry> displayData) {
super(displayData);
}
@Override
public PrefEntry addPreference(final JComponent gui) {
JPanel p = new JPanel(new GridBagLayout());
p.add(new JLabel(tr("Original Tag")), GBC.std().insets(0, 0, 5, 0));
JosmTextField tkey = new JosmTextField("", 50);
p.add(tkey, GBC.eop().insets(5, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
p.add(new JLabel(tr("Replacement Tag")), GBC.std().insets(0, 0, 5, 0));
JosmTextField tValue = new JosmTextField("", 50);
p.add(tValue, GBC.eop().insets(5, 0, 0, 0).fill(GridBagConstraints.HORIZONTAL));
PrefEntry pe = null;
if (askAddSetting(gui, p)) {
pe = new PrefEntry(tkey.getText(), new StringSetting(tValue.getText()), new StringSetting(null), false);
}
return pe;
}
private static boolean askAddSetting(JComponent gui, JPanel p) {
return new ExtendedDialog(gui, tr("Add setting"), tr("OK"), tr("Cancel")).setContent(p)
.setButtonIcons("ok", "cancel").showDialog().getValue() == 1;
}
}

Wyświetl plik

@ -22,6 +22,7 @@ import org.openstreetmap.josm.data.osm.BBox;
import org.openstreetmap.josm.data.osm.DataSet;
import org.openstreetmap.josm.data.osm.Node;
import org.openstreetmap.josm.data.osm.OsmPrimitive;
import org.openstreetmap.josm.data.osm.Tag;
import org.openstreetmap.josm.data.osm.UploadPolicy;
import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
@ -31,6 +32,7 @@ import org.openstreetmap.josm.plugins.mapwithai.commands.MergeDuplicateWays;
import org.openstreetmap.josm.tools.HttpClient;
import org.openstreetmap.josm.tools.HttpClient.Response;
import org.openstreetmap.josm.tools.Logging;
import org.openstreetmap.josm.tools.Pair;
/**
* Get data in a parallel manner
@ -92,6 +94,7 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
synchronized (LOCK) {
/* Microsoft buildings don't have a source, so we add one */
MapWithAIDataUtils.addSourceTags(dataSet, "building", "Microsoft");
replaceTags(dataSet);
removeCommonTags(dataSet);
mergeNodes(dataSet);
// filterDataSet(dataSet);
@ -103,6 +106,19 @@ public class GetDataRunnable extends RecursiveTask<DataSet> {
return dataSet;
}
/**
* Replace tags in a dataset with a set of replacement tags
*
* @param dataSet The dataset with primitives to change
*/
public static void replaceTags(DataSet dataSet) {
Map<Tag, Tag> replaceTags = MapWithAIPreferenceHelper.getReplacementTags().entrySet().parallelStream()
.map(entry -> new Pair<>(Tag.ofString(entry.getKey()), Tag.ofString(entry.getValue())))
.collect(Collectors.toMap(pair -> pair.a, pair -> pair.b));
replaceTags.forEach((orig, replace) -> dataSet.allNonDeletedPrimitives().parallelStream()
.filter(prim -> prim.hasTag(orig.getKey(), orig.getValue())).forEach(prim -> prim.put(replace)));
}
private static void cleanupDataSet(DataSet dataSet) {
Map<OsmPrimitive, String> origIds = dataSet.allPrimitives().parallelStream()
.filter(prim -> prim.hasKey("orig_id")).distinct()

Wyświetl plik

@ -3,8 +3,12 @@ package org.openstreetmap.josm.plugins.mapwithai.backend;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.openstreetmap.josm.data.osm.Tag;
import org.openstreetmap.josm.plugins.mapwithai.MapWithAIPlugin;
import org.openstreetmap.josm.spi.preferences.Config;
@ -183,7 +187,30 @@ public final class MapWithAIPreferenceHelper {
}
}
/**
* Get the maximum distance for a node to be considered a duplicate
*
* @return The max distance between nodes for duplicates
*/
public static double getMaxNodeDistance() {
return Config.getPref().getDouble(MapWithAIPlugin.NAME.concat(".duplicatenodedistance"), 0.6);
}
/**
* @return A map of tags to replacement tags (use {@link Tag.ofString} to parse)
*/
public static Map<String, String> getReplacementTags() {
Map<String, String> defaultMap = Collections.emptyMap();
List<Map<String, String>> listOfMaps = Config.getPref()
.getListOfMaps(MapWithAIPlugin.NAME.concat(".replacementtags"), Arrays.asList(defaultMap));
return listOfMaps.isEmpty() ? defaultMap : listOfMaps.get(0);
}
/**
* @param tagsToReplace set the tags to replace
*/
public static void setReplacementTags(Map<String, String> tagsToReplace) {
List<Map<String, String>> tags = tagsToReplace.isEmpty() ? null : Arrays.asList(new TreeMap<>(tagsToReplace));
Config.getPref().putListOfMaps(MapWithAIPlugin.NAME.concat(".replacementtags"), tags);
}
}