Ignore:
Timestamp:
2012-07-11T15:16:48+02:00 (12 years ago)
Author:
simon04
Message:

JOSM/wikipedia: Improve wikipedia plugin.

  • fetch Wikipedia articles by category
  • display whether OSM object is already linked to Wikipedia article via tag
  • search OSM objects via double click on Wikipedia article
File:
1 edited

Legend:

Unmodified
Added
Removed
  • applications/editors/josm/plugins/wikipedia/src/org/wikipedia/WikipediaToggleDialog.java

    r28293 r28469  
    77import java.awt.event.MouseAdapter;
    88import java.awt.event.MouseEvent;
     9import java.io.IOException;
    910import java.io.UnsupportedEncodingException;
    1011import java.net.URL;
    1112import java.net.URLDecoder;
     13import java.net.URLEncoder;
     14import java.util.ArrayList;
    1215import java.util.Arrays;
     16import java.util.Collection;
    1317import java.util.Collections;
     18import java.util.HashSet;
    1419import java.util.LinkedList;
    1520import java.util.List;
     21import java.util.Map;
     22import java.util.Scanner;
     23import java.util.Set;
    1624import java.util.regex.Matcher;
    1725import java.util.regex.Pattern;
    1826import javax.swing.AbstractAction;
     27import javax.swing.DefaultListCellRenderer;
    1928import javax.swing.DefaultListModel;
     29import javax.swing.JLabel;
    2030import javax.swing.JList;
    2131import javax.swing.JOptionPane;
     
    2535import javax.xml.xpath.XPathFactory;
    2636import org.openstreetmap.josm.Main;
     37import org.openstreetmap.josm.actions.search.SearchAction;
    2738import org.openstreetmap.josm.command.ChangePropertyCommand;
    2839import org.openstreetmap.josm.data.coor.LatLon;
     40import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2941import org.openstreetmap.josm.data.osm.Tag;
     42import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
     43import org.openstreetmap.josm.data.osm.event.DataSetListenerAdapter;
     44import org.openstreetmap.josm.data.osm.event.DatasetEventManager;
     45import org.openstreetmap.josm.data.osm.event.DatasetEventManager.FireMode;
    3046import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    3147import org.openstreetmap.josm.data.preferences.StringProperty;
     48import org.openstreetmap.josm.gui.MapView;
    3249import org.openstreetmap.josm.gui.SideButton;
    3350import org.openstreetmap.josm.gui.dialogs.ToggleDialog;
     51import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    3452import org.openstreetmap.josm.tools.ImageProvider;
    3553import org.openstreetmap.josm.tools.LanguageInfo;
     
    3856import org.w3c.dom.NodeList;
    3957
    40 public class WikipediaToggleDialog extends ToggleDialog {
     58public class WikipediaToggleDialog extends ToggleDialog implements MapView.EditLayerChangeListener, DataSetListenerAdapter.Listener {
    4159
    4260    public WikipediaToggleDialog() {
    4361        super(tr("Wikipedia"), "wikipedia", tr("Fetch Wikipedia articles with coordinates"), null, 150);
    4462        createLayout(list, true, Arrays.asList(
    45                 new SideButton(new WikipediaDownloadAction()),
     63                new SideButton(new WikipediaLoadCoordinatesAction()),
     64                new SideButton(new WikipediaLoadCategoryAction()),
    4665                new SideButton(new AddWikipediaTagAction()),
    4766                new SideButton(new OpenWikipediaArticleAction()),
     
    4968    }
    5069    final StringProperty wikipediaLang = new StringProperty("wikipedia.lang", LanguageInfo.getJOSMLocaleCode().substring(0, 2));
     70    final Set<String> articles = new HashSet<String>();
    5171    final DefaultListModel model = new DefaultListModel();
    5272    final JList list = new JList(model) {
     
    5878                public void mouseClicked(MouseEvent e) {
    5979                    if (e.getClickCount() == 2 && getSelectedValue() != null) {
    60                         BoundingXYVisitor bbox = new BoundingXYVisitor();
    61                         bbox.visit(((WikipediaEntry) getSelectedValue()).coordinate);
    62                         Main.map.mapView.recalculateCenterScale(bbox);
     80                        final WikipediaEntry entry = (WikipediaEntry) getSelectedValue();
     81                        if (entry.coordinate != null) {
     82                            BoundingXYVisitor bbox = new BoundingXYVisitor();
     83                            bbox.visit(entry.coordinate);
     84                            Main.map.mapView.recalculateCenterScale(bbox);
     85                        }
     86                        SearchAction.search(entry.name.replaceAll("\\(.*\\)", ""), SearchAction.SearchMode.replace);
    6387                    }
     88                }
     89            });
     90
     91            setCellRenderer(new DefaultListCellRenderer() {
     92
     93                @Override
     94                public JLabel getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
     95                    JLabel label = (JLabel) super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
     96                    if (articles.contains(((WikipediaEntry) value).name)) {
     97                        label.setIcon(ImageProvider.getIfAvailable("misc", "green_check"));
     98                    }
     99                    return label;
    64100                }
    65101            });
     
    70106            final int index = locationToIndex(e.getPoint());
    71107            if (index >= 0) {
    72                 return "<html>" + ((WikipediaEntry) model.getElementAt(index)).description + "</html>";
     108                final String description = ((WikipediaEntry) model.getElementAt(index)).description;
     109                return description == null ? null : ("<html>" + description + "</html>");
    73110            } else {
    74111                return null;
     
    77114    };
    78115
     116    static class WikipediaLangArticle {
     117
     118        final String lang, article;
     119
     120        public WikipediaLangArticle(String lang, String article) {
     121            this.lang = lang;
     122            this.article = article;
     123        }
     124
     125        public static WikipediaLangArticle parseFromUrl(String url) {
     126            if (url == null) {
     127                return null;
     128            }
     129            // decode URL for nicer value
     130            try {
     131                url = URLDecoder.decode(url, "UTF-8");
     132            } catch (UnsupportedEncodingException ex) {
     133                throw new IllegalStateException(ex);
     134            }
     135            // extract Wikipedia language and
     136            final Matcher m = Pattern.compile("https?://(\\w*)\\.wikipedia\\.org/wiki/(.*)").matcher(url);
     137            if (!m.matches()) {
     138                return null;
     139            }
     140            return new WikipediaLangArticle(m.group(1), m.group(2));
     141        }
     142    }
     143
    79144    static class WikipediaEntry implements Comparable<WikipediaEntry> {
    80145
    81         String name, description;
    82         LatLon coordinate;
     146        final String name, description;
     147        final String wikipediaLang, wikipediaArticle;
     148        final LatLon coordinate;
    83149
    84150        public WikipediaEntry(String name, String description, LatLon coordinate) {
     
    86152            this.description = description;
    87153            this.coordinate = coordinate;
    88         }
    89 
    90         public String getHrefFromDescription() {
     154
     155            final WikipediaLangArticle wp = WikipediaLangArticle.parseFromUrl(getHrefFromDescription());
     156            if (wp == null) {
     157                System.err.println("Could not extract Wikipedia tag from: " + getHrefFromDescription());
     158            }
     159            this.wikipediaLang = wp == null ? null : wp.lang;
     160            this.wikipediaArticle = wp == null ? null : wp.article;
     161        }
     162
     163        public WikipediaEntry(String name, String wikipediaLang, String wikipediaArticle) {
     164            this.name = name;
     165            this.description = null;
     166            this.wikipediaLang = wikipediaLang;
     167            this.wikipediaArticle = wikipediaArticle;
     168            this.coordinate = null;
     169        }
     170
     171        protected final String getHrefFromDescription() {
    91172            final Matcher m = Pattern.compile(".*href=\"(.+?)\".*").matcher(description);
    92173            if (m.matches()) {
     
    98179        }
    99180
    100         public Tag createWikipediaTag() {
    101             // get URL from description
    102             String url = getHrefFromDescription();
    103             if (url == null) {
    104                 return null;
    105             }
    106             // decode URL for nicer value
    107             try {
    108                 url = URLDecoder.decode(url, "UTF-8");
    109             } catch (UnsupportedEncodingException ex) {
    110                 throw new IllegalStateException(ex);
    111             }
    112             // extract Wikipedia language and
    113             final Matcher m = Pattern.compile("https?://(\\w*)\\.wikipedia\\.org/wiki/(.*)").matcher(url);
    114             if (!m.matches()) {
    115                 System.err.println("Could not extract Wikipedia tag from: " + url);
    116                 return null;
    117             }
    118             return new Tag("wikipedia", m.group(1) + ":" + m.group(2));
     181        protected final Tag createWikipediaTag() {
     182            return new Tag("wikipedia", wikipediaLang + ":" + wikipediaArticle);
    119183        }
    120184
     
    130194    }
    131195
    132     class WikipediaDownloadAction extends AbstractAction {
    133 
    134         public WikipediaDownloadAction() {
    135             super(tr("Reload"), ImageProvider.get("dialogs", "refresh"));
     196    class WikipediaLoadCoordinatesAction extends AbstractAction {
     197
     198        public WikipediaLoadCoordinatesAction() {
     199            super(tr("Coordinates"), ImageProvider.get("dialogs", "refresh"));
    136200            putValue(SHORT_DESCRIPTION, tr("Fetches all coordinates from Wikipedia in the current view"));
    137201        }
     
    179243    }
    180244
     245    class WikipediaLoadCategoryAction extends AbstractAction {
     246
     247        public WikipediaLoadCategoryAction() {
     248            super(tr("Category"), ImageProvider.get("dialogs", "refresh"));
     249            putValue(SHORT_DESCRIPTION, tr("Fetches a list of all Wikipedia articles of a category"));
     250        }
     251
     252        @Override
     253        public void actionPerformed(ActionEvent e) {
     254            try {
     255                final String category = JOptionPane.showInputDialog(
     256                        Main.parent,
     257                        tr("Enter the Wikipedia category"));
     258                final String url = "http://toolserver.org/~daniel/WikiSense/CategoryIntersect.php?"
     259                        + "wikilang=" + wikipediaLang.get()
     260                        + "&wikifam=.wikipedia.org"
     261                        + "&basecat=" + URLEncoder.encode(category, "UTF-8")
     262                        + "&basedeep=3&templates=&mode=al&format=csv";
     263                System.out.println("Wikipedia: GET " + url);
     264                final Scanner scanner = new Scanner(new URL(url).openStream()).useDelimiter("\n");
     265                if (scanner.hasNext()) {
     266                    model.clear();
     267                }
     268                while (scanner.hasNext()) {
     269                    final String article = scanner.next().split("\t")[1].replace("_", " ");
     270                    model.addElement(new WikipediaEntry(article, wikipediaLang.get(), article));
     271                }
     272            } catch (IOException ex) {
     273                throw new RuntimeException(ex);
     274            }
     275        }
     276    }
     277
    181278    class OpenWikipediaArticleAction extends AbstractAction {
    182279
     
    189286        public void actionPerformed(ActionEvent e) {
    190287            if (list.getSelectedValue() != null) {
    191                 String url = ((WikipediaEntry) list.getSelectedValue()).getHrefFromDescription();
    192                 if (url != null) {
    193                     System.out.println("Wikipedia: opening " + url);
    194                     OpenBrowser.displayUrl(url);
    195                 }
     288                WikipediaEntry entry = (WikipediaEntry) list.getSelectedValue();
     289                final String url;
     290                if (entry.getHrefFromDescription() != null) {
     291                    url = entry.getHrefFromDescription();
     292                } else {
     293                    url = "http://" + entry.wikipediaLang + ".wikipedia.org/wiki/" + entry.wikipediaArticle.replace(" ", "_");
     294                }
     295                System.out.println("Wikipedia: opening " + url);
     296                OpenBrowser.displayUrl(url);
    196297            }
    197298        }
     
    208309        public void actionPerformed(ActionEvent e) {
    209310            String lang = JOptionPane.showInputDialog(
    210                     WikipediaToggleDialog.this,
     311                    Main.parent,
    211312                    tr("Enter the Wikipedia language"),
    212313                    wikipediaLang.get());
    213314            if (lang != null) {
    214315                wikipediaLang.put(lang);
     316                updateWikipediaArticles();
    215317            }
    216318        }
     
    237339        }
    238340    }
     341
     342    protected void updateWikipediaArticles() {
     343        articles.clear();
     344        if (Main.main != null && Main.main.getCurrentDataSet() != null) {
     345            for (final OsmPrimitive p : Main.main.getCurrentDataSet().allPrimitives()) {
     346                articles.addAll(getWikipediaArticles(p));
     347            }
     348        }
     349    }
     350
     351    protected Collection<String> getWikipediaArticles(OsmPrimitive p) {
     352        Collection<String> r = new ArrayList<String>();
     353        final Map<String, String> tags = p.getKeys();
     354        // consider wikipedia=[lang]:*
     355        final String wp = tags.get("wikipedia");
     356        if (wp != null && wp.startsWith("http")) {
     357            //wikipedia=http...
     358            final WikipediaLangArticle item = WikipediaLangArticle.parseFromUrl(wp);
     359            if (item != null && wikipediaLang.get().equals(item.lang)) {
     360                r.add(item.article.replace("_", " "));
     361            }
     362        } else if (wp != null) {
     363            //wikipedia=[lang]:[article]
     364            try {
     365                String[] item = URLDecoder.decode(wp, "UTF-8").split(":", 2);
     366                if (item.length == 2 && wikipediaLang.get().equals(item[0])) {
     367                    r.add(item[1].replace("_", " "));
     368                }
     369            } catch (UnsupportedEncodingException ex) {
     370                throw new IllegalStateException(ex);
     371            }
     372        }
     373        // consider wikipedia:[lang]=*
     374        final String wpLang = tags.get("wikipedia:" + wikipediaLang.get());
     375        if (wpLang != null && wpLang.startsWith("http")) {
     376            //wikipedia:[lang]=http...
     377            final WikipediaLangArticle item = WikipediaLangArticle.parseFromUrl(wpLang);
     378            if (wikipediaLang.get().equals(item.lang)) {
     379                r.add(item.article.replace("_", " "));
     380            }
     381        } else if (wpLang != null) {
     382            //wikipedia:[lang]=[lang]:[article]
     383            //wikipedia:[lang]=[article]
     384            try {
     385                String[] item = URLDecoder.decode(wpLang, "UTF-8").split(":", 2);
     386                r.add(item[item.length == 2 ? 1 : 0].replace("_", " "));
     387            } catch (UnsupportedEncodingException ex) {
     388                throw new IllegalStateException(ex);
     389            }
     390        }
     391        return r;
     392    }
     393
     394    private final DataSetListenerAdapter dataChangedAdapter = new DataSetListenerAdapter(this);
     395
     396    @Override
     397    public void showNotify() {
     398        DatasetEventManager.getInstance().addDatasetListener(dataChangedAdapter, FireMode.IN_EDT_CONSOLIDATED);
     399        MapView.addEditLayerChangeListener(this);
     400        updateWikipediaArticles();
     401    }
     402
     403    @Override
     404    public void hideNotify() {
     405        DatasetEventManager.getInstance().removeDatasetListener(dataChangedAdapter);
     406        MapView.removeEditLayerChangeListener(this);
     407        articles.clear();
     408    }
     409
     410    @Override
     411    public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) {
     412        updateWikipediaArticles();
     413        list.repaint();
     414    }
     415
     416    @Override
     417    public void processDatasetEvent(AbstractDatasetChangedEvent event) {
     418        updateWikipediaArticles();
     419        list.repaint();
     420    }
    239421}
Note: See TracChangeset for help on using the changeset viewer.