1 | // License: GPL. For details, see LICENSE file.
|
---|
2 | package org.openstreetmap.josm.gui.dialogs.properties;
|
---|
3 |
|
---|
4 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
5 |
|
---|
6 | import java.awt.event.ActionEvent;
|
---|
7 | import java.awt.event.KeyEvent;
|
---|
8 | import java.io.IOException;
|
---|
9 | import java.net.URI;
|
---|
10 | import java.net.URISyntaxException;
|
---|
11 | import java.util.ArrayList;
|
---|
12 | import java.util.List;
|
---|
13 | import java.util.Map;
|
---|
14 | import java.util.Objects;
|
---|
15 | import java.util.function.Function;
|
---|
16 |
|
---|
17 | import javax.swing.AbstractAction;
|
---|
18 | import javax.swing.JTable;
|
---|
19 | import javax.swing.KeyStroke;
|
---|
20 |
|
---|
21 | import org.openstreetmap.josm.data.osm.Relation;
|
---|
22 | import org.openstreetmap.josm.gui.MainApplication;
|
---|
23 | import org.openstreetmap.josm.spi.preferences.Config;
|
---|
24 | import org.openstreetmap.josm.tools.HttpClient;
|
---|
25 | import org.openstreetmap.josm.tools.ImageProvider;
|
---|
26 | import org.openstreetmap.josm.tools.LanguageInfo;
|
---|
27 | import org.openstreetmap.josm.tools.Logging;
|
---|
28 | import org.openstreetmap.josm.tools.OpenBrowser;
|
---|
29 | import org.openstreetmap.josm.tools.Utils;
|
---|
30 |
|
---|
31 | /**
|
---|
32 | * Launch browser with wiki help for selected object.
|
---|
33 | * @since 13521
|
---|
34 | */
|
---|
35 | public class HelpAction extends AbstractAction {
|
---|
36 | private final JTable tagTable;
|
---|
37 | private final Function<Integer, String> tagKeySupplier;
|
---|
38 | private final Function<Integer, Map<String, Integer>> tagValuesSupplier;
|
---|
39 |
|
---|
40 | private final JTable membershipTable;
|
---|
41 | private final Function<Integer, Relation> memberValueSupplier;
|
---|
42 |
|
---|
43 | /**
|
---|
44 | * Constructs a new {@code HelpAction}.
|
---|
45 | * @param tagTable The tag table. Cannot be null
|
---|
46 | * @param tagKeySupplier Finds the key from given row of tag table. Cannot be null
|
---|
47 | * @param tagValuesSupplier Finds the values from given row of tag table (map of values and number of occurrences). Cannot be null
|
---|
48 | * @param membershipTable The membership table. Can be null
|
---|
49 | * @param memberValueSupplier Finds the parent relation from given row of membership table. Can be null
|
---|
50 | */
|
---|
51 | public HelpAction(JTable tagTable, Function<Integer, String> tagKeySupplier, Function<Integer, Map<String, Integer>> tagValuesSupplier,
|
---|
52 | JTable membershipTable, Function<Integer, Relation> memberValueSupplier) {
|
---|
53 | this.tagTable = Objects.requireNonNull(tagTable);
|
---|
54 | this.tagKeySupplier = Objects.requireNonNull(tagKeySupplier);
|
---|
55 | this.tagValuesSupplier = Objects.requireNonNull(tagValuesSupplier);
|
---|
56 | this.membershipTable = membershipTable;
|
---|
57 | this.memberValueSupplier = memberValueSupplier;
|
---|
58 | putValue(NAME, tr("Go to OSM wiki for tag help"));
|
---|
59 | putValue(SHORT_DESCRIPTION, tr("Launch browser with wiki help for selected object"));
|
---|
60 | new ImageProvider("dialogs", "search").getResource().attachImageIcon(this, true);
|
---|
61 | putValue(ACCELERATOR_KEY, getKeyStroke());
|
---|
62 | }
|
---|
63 |
|
---|
64 | /**
|
---|
65 | * Returns the keystroke launching this action (F1).
|
---|
66 | * @return the keystroke launching this action
|
---|
67 | */
|
---|
68 | public KeyStroke getKeyStroke() {
|
---|
69 | return KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0);
|
---|
70 | }
|
---|
71 |
|
---|
72 | @Override
|
---|
73 | public void actionPerformed(ActionEvent e) {
|
---|
74 | try {
|
---|
75 | String base = Config.getPref().get("url.openstreetmap-wiki", "https://wiki.openstreetmap.org/wiki/");
|
---|
76 | String lang = LanguageInfo.getWikiLanguagePrefix();
|
---|
77 | final List<URI> uris = new ArrayList<>();
|
---|
78 | int row;
|
---|
79 | if (tagTable.getSelectedRowCount() == 1) {
|
---|
80 | row = tagTable.getSelectedRow();
|
---|
81 | String key = Utils.encodeUrl(tagKeySupplier.apply(row));
|
---|
82 | Map<String, Integer> m = tagValuesSupplier.apply(row);
|
---|
83 | if (!m.isEmpty()) {
|
---|
84 | String val = Utils.encodeUrl(m.entrySet().iterator().next().getKey());
|
---|
85 |
|
---|
86 | uris.add(new URI(String.format("%s%sTag:%s=%s", base, lang, key, val)));
|
---|
87 | uris.add(new URI(String.format("%sTag:%s=%s", base, key, val)));
|
---|
88 | uris.add(new URI(String.format("%s%sKey:%s", base, lang, key)));
|
---|
89 | uris.add(new URI(String.format("%sKey:%s", base, key)));
|
---|
90 | uris.add(new URI(String.format("%s%sMap_Features", base, lang)));
|
---|
91 | uris.add(new URI(String.format("%sMap_Features", base)));
|
---|
92 | }
|
---|
93 | } else if (membershipTable != null && membershipTable.getSelectedRowCount() == 1) {
|
---|
94 | row = membershipTable.getSelectedRow();
|
---|
95 | String type = (memberValueSupplier.apply(row)).get("type");
|
---|
96 | if (type != null) {
|
---|
97 | type = Utils.encodeUrl(type);
|
---|
98 | }
|
---|
99 |
|
---|
100 | if (type != null && !type.isEmpty()) {
|
---|
101 | uris.add(new URI(String.format("%s%sRelation:%s", base, lang, type)));
|
---|
102 | uris.add(new URI(String.format("%sRelation:%s", base, type)));
|
---|
103 | }
|
---|
104 |
|
---|
105 | uris.add(new URI(String.format("%s%sRelations", base, lang)));
|
---|
106 | uris.add(new URI(String.format("%sRelations", base)));
|
---|
107 | } else {
|
---|
108 | // give the generic help page, if more than one element is selected
|
---|
109 | uris.add(new URI(String.format("%s%sMap_Features", base, lang)));
|
---|
110 | uris.add(new URI(String.format("%sMap_Features", base)));
|
---|
111 | }
|
---|
112 |
|
---|
113 | MainApplication.worker.execute(() -> displayHelp(uris));
|
---|
114 | } catch (URISyntaxException e1) {
|
---|
115 | Logging.error(e1);
|
---|
116 | }
|
---|
117 | }
|
---|
118 |
|
---|
119 | private void displayHelp(final List<URI> uris) {
|
---|
120 | try {
|
---|
121 | // find a page that actually exists in the wiki
|
---|
122 | HttpClient.Response conn;
|
---|
123 | for (URI u : uris) {
|
---|
124 | conn = HttpClient.create(u.toURL(), "HEAD").connect();
|
---|
125 |
|
---|
126 | if (conn.getResponseCode() != 200) {
|
---|
127 | conn.disconnect();
|
---|
128 | } else {
|
---|
129 | long osize = conn.getContentLength();
|
---|
130 | if (osize > -1) {
|
---|
131 | conn.disconnect();
|
---|
132 |
|
---|
133 | final URI newURI = new URI(u.toString()
|
---|
134 | .replace("=", "%3D") /* do not URLencode whole string! */
|
---|
135 | .replaceFirst("/wiki/", "/w/index.php?redirect=no&title=")
|
---|
136 | );
|
---|
137 | conn = HttpClient.create(newURI.toURL(), "HEAD").connect();
|
---|
138 | }
|
---|
139 |
|
---|
140 | /* redirect pages have different content length, but retrieving a "nonredirect"
|
---|
141 | * page using index.php and the direct-link method gives slightly different
|
---|
142 | * content lengths, so we have to be fuzzy.. (this is UGLY, recode if u know better)
|
---|
143 | */
|
---|
144 | if (osize > -1 && conn.getContentLength() != -1 && Math.abs(conn.getContentLength() - osize) > 200) {
|
---|
145 | Logging.info("{0} is a mediawiki redirect", u);
|
---|
146 | conn.disconnect();
|
---|
147 | } else {
|
---|
148 | conn.disconnect();
|
---|
149 |
|
---|
150 | OpenBrowser.displayUrl(u.toString());
|
---|
151 | break;
|
---|
152 | }
|
---|
153 | }
|
---|
154 | }
|
---|
155 | } catch (URISyntaxException | IOException e1) {
|
---|
156 | Logging.error(e1);
|
---|
157 | }
|
---|
158 | }
|
---|
159 | }
|
---|