// License: GPL. For details, see LICENSE file. package org.wikipedia.actions; import static org.openstreetmap.josm.tools.I18n.tr; import static org.openstreetmap.josm.tools.I18n.trn; import java.awt.event.ActionEvent; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JOptionPane; import org.openstreetmap.josm.Main; import org.openstreetmap.josm.actions.JosmAction; import org.openstreetmap.josm.command.ChangePropertyCommand; import org.openstreetmap.josm.command.Command; import org.openstreetmap.josm.command.SequenceCommand; import org.openstreetmap.josm.data.osm.DataSet; import org.openstreetmap.josm.data.osm.OsmPrimitive; import org.openstreetmap.josm.gui.ConditionalOptionPaneUtil; import org.openstreetmap.josm.gui.Notification; import org.openstreetmap.josm.gui.PleaseWaitRunnable; import org.openstreetmap.josm.gui.progress.ProgressMonitor; import org.openstreetmap.josm.tools.MultiMap; import org.openstreetmap.josm.tools.Utils; import org.wikipedia.WikipediaApp; import org.wikipedia.data.WikipediaEntry; import org.wikipedia.gui.GuiUtils; public class FetchWikidataAction extends JosmAction { public FetchWikidataAction() { super(tr("Fetch Wikidata IDs"), "dialogs/wikidata", tr("Fetch Wikidata IDs using the ''wikipedia'' tag"), null, true); } @Override public void actionPerformed(ActionEvent e) { DataSet ds = getLayerManager().getEditDataSet(); if (ds == null) { return; } Main.worker.submit(new Fetcher(ds.getSelected())); } public static class Fetcher extends PleaseWaitRunnable { private final Collection<? extends OsmPrimitive> selection; private boolean canceled = false; private final List<Command> commands = new ArrayList<>(); private final Collection<WikipediaEntry> notFound = new ArrayList<>(); public Fetcher(Collection<? extends OsmPrimitive> selection) { super(tr("Fetching Wikidata IDs")); this.selection = selection; } @Override protected void cancel() { canceled = true; } @Override protected void realRun() { final Map<String, PrimitivesWithWikipedia> wikipediaByLanguage = getLanguageToArticlesMap(selection); getProgressMonitor().setTicksCount(wikipediaByLanguage.keySet().size()); for (final Map.Entry<String, PrimitivesWithWikipedia> i : wikipediaByLanguage.entrySet()) { if (canceled) { break; } final PrimitivesWithWikipedia fetcher = i.getValue(); fetcher.updateWikidataIds(getProgressMonitor().createSubTaskMonitor(1, false)); final Command command = fetcher.getCommand(); if (command != null) { commands.add(command); } notFound.addAll(fetcher.getNotFound()); } } static Map<String, PrimitivesWithWikipedia> getLanguageToArticlesMap(final Iterable<? extends OsmPrimitive> selection) { final Map<String, PrimitivesWithWikipedia> r = new HashMap<>(); for (final OsmPrimitive i : selection) { final WikipediaEntry tag = WikipediaEntry.parseTag("wikipedia", i.get("wikipedia")); if (tag != null) { if (!r.containsKey(tag.lang)) { r.put(tag.lang, new PrimitivesWithWikipedia(tag.lang)); } r.get(tag.lang).put(i, tag.article); } } return r; } @Override protected void finish() { if (!canceled && !commands.isEmpty()) { Main.main.undoRedo.add(commands.size() == 1 ? commands.get(0) : new SequenceCommand(tr("Add Wikidata"), commands)); } if (!canceled && !notFound.isEmpty()) { new Notification(tr("No Wikidata ID found for: {0}", Utils.joinAsHtmlUnorderedList(notFound))) .setIcon(JOptionPane.WARNING_MESSAGE) .setDuration(Notification.TIME_LONG) .show(); } } } private static class PrimitivesWithWikipedia { final String lang; final MultiMap<String, OsmPrimitive> byArticle = new MultiMap<>(); final List<Command> commands = new ArrayList<>(); final List<WikipediaEntry> notFound = new ArrayList<>(); PrimitivesWithWikipedia(String lang) { this.lang = lang; } public void put(OsmPrimitive key, String wikipedia) { byArticle.put(wikipedia, key); } void updateWikidataIds(ProgressMonitor monitor) { final int size = byArticle.keySet().size(); monitor.beginTask(trn( "Fetching {0} Wikidata ID for language ''{1}''", "Fetching {0} Wikidata IDs for language ''{1}''", size, size, lang)); final Map<String, String> wikidataByWikipedia = WikipediaApp.forLanguage(lang).getWikidataForArticles(byArticle.keySet()); ConditionalOptionPaneUtil.startBulkOperation(GuiUtils.PREF_OVERWRITE); for (Map.Entry<String, Set<OsmPrimitive>> i : byArticle.entrySet()) { final String wikipedia = i.getKey(); final String wikidata = wikidataByWikipedia.get(wikipedia); if (wikidata != null) { if (GuiUtils.confirmOverwrite("wikidata", wikidata, i.getValue())) { commands.add(new ChangePropertyCommand(i.getValue(), "wikidata", wikidata)); } } else { final WikipediaEntry article = new WikipediaEntry(lang, wikipedia); Main.warn(tr("No Wikidata ID found for: {0}", article)); notFound.add(article); } } ConditionalOptionPaneUtil.endBulkOperation(GuiUtils.PREF_OVERWRITE); monitor.finishTask(); } public Command getCommand() { return commands.isEmpty() ? null : new SequenceCommand(tr("Add Wikidata for language ''{0}''", lang), commands); } List<WikipediaEntry> getNotFound() { return notFound; } } @Override protected void updateEnabledState() { updateEnabledStateOnCurrentSelection(); } @Override protected void updateEnabledState(Collection<? extends OsmPrimitive> selection) { for (final OsmPrimitive i : selection) { if (i.hasKey("wikipedia")) { setEnabled(true); return; } } setEnabled(false); } }