001 // License: GPL. For details, see LICENSE file.
002 package org.openstreetmap.josm.gui.dialogs.changeset.query;
003
004 import static org.openstreetmap.josm.tools.I18n.tr;
005
006 import java.awt.Dimension;
007 import java.awt.GridBagConstraints;
008 import java.awt.GridBagLayout;
009 import java.awt.Insets;
010 import java.awt.event.FocusAdapter;
011 import java.awt.event.FocusEvent;
012 import java.net.MalformedURLException;
013 import java.net.URL;
014
015 import javax.swing.BorderFactory;
016 import javax.swing.JLabel;
017 import javax.swing.JPanel;
018 import javax.swing.JTextField;
019 import javax.swing.event.DocumentEvent;
020 import javax.swing.event.DocumentListener;
021 import javax.swing.event.HyperlinkEvent;
022 import javax.swing.event.HyperlinkListener;
023
024 import org.openstreetmap.josm.gui.widgets.HtmlPanel;
025 import org.openstreetmap.josm.io.ChangesetQuery;
026 import org.openstreetmap.josm.io.OsmApi;
027 import org.openstreetmap.josm.io.ChangesetQuery.ChangesetQueryUrlException;
028 import org.openstreetmap.josm.tools.ImageProvider;
029
030
031 public class UrlBasedQueryPanel extends JPanel {
032
033 private JTextField tfUrl;
034 private JLabel lblValid;
035
036 protected JPanel buildURLPanel() {
037 JPanel pnl = new JPanel(new GridBagLayout());
038 GridBagConstraints gc = new GridBagConstraints();
039 gc.weightx = 0.0;
040 gc.fill = GridBagConstraints.HORIZONTAL;
041 gc.insets = new Insets(0,0,0,5);
042 pnl.add(new JLabel(tr("URL: ")), gc);
043
044 gc.gridx = 1;
045 gc.weightx = 1.0;
046 gc.fill = GridBagConstraints.HORIZONTAL;
047 pnl.add(tfUrl = new JTextField(), gc);
048 tfUrl.getDocument().addDocumentListener(new ChangetQueryUrlValidator());
049 tfUrl.addFocusListener(
050 new FocusAdapter() {
051 @Override
052 public void focusGained(FocusEvent e) {
053 tfUrl.selectAll();
054 }
055 }
056 );
057
058 gc.gridx = 2;
059 gc.weightx = 0.0;
060 gc.fill = GridBagConstraints.HORIZONTAL;
061 pnl.add(lblValid = new JLabel(), gc);
062 lblValid.setPreferredSize(new Dimension(20,20));
063 return pnl;
064 }
065
066 protected JPanel buildHelpPanel() {
067 HtmlPanel pnl = new HtmlPanel();
068 pnl.setText(
069 "<html><body>"
070 + tr("Please enter or paste an URL to retrieve changesets from the OSM API.")
071 + "<p><strong>" + tr("Examples") + "</strong></p>"
072 + "<ul>"
073 + "<li><a href=\"http://www.openstreetmap.org/browse/changesets?open=true\">http://www.openstreetmap.org/browse/changesets?open=true</a></li>"
074 + "<li><a href=\"http://api.openstreetmap.org/api/0.6/changesets?open=true\">http://api.openstreetmap.org/api/0.6/changesets?open=true</a></li>"
075 + "</ul>"
076 + tr("Note that changeset queries are currently always submitted to ''{0}'', regardless of the "
077 + "host, port and path of the URL entered below.", OsmApi.getOsmApi().getBaseUrl())
078 + "</body></html>"
079 );
080 pnl.getEditorPane().addHyperlinkListener(
081 new HyperlinkListener() {
082 public void hyperlinkUpdate(HyperlinkEvent e) {
083 if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
084 tfUrl.setText(e.getDescription());
085 tfUrl.requestFocusInWindow();
086 }
087 }
088 }
089 );
090 return pnl;
091 }
092
093 protected void build() {
094 setLayout(new GridBagLayout());
095 setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
096
097 GridBagConstraints gc = new GridBagConstraints();
098 gc.weightx = 1.0;
099 gc.fill = GridBagConstraints.HORIZONTAL;
100 gc.insets = new Insets(0,0,10,0);
101 add(buildHelpPanel(),gc);
102
103 gc.gridy = 1;
104 gc.weightx = 1.0;
105 gc.fill = GridBagConstraints.HORIZONTAL;
106 add(buildURLPanel(),gc);
107
108 gc.gridy = 2;
109 gc.weightx = 1.0;
110 gc.weighty = 1.0;
111 gc.fill = GridBagConstraints.BOTH;
112 add(new JPanel(),gc);
113
114 }
115 public UrlBasedQueryPanel() {
116 build();
117 }
118
119 protected boolean isValidChangesetQueryUrl(String text) {
120 return buildChangesetQuery(text) != null;
121 }
122
123 protected ChangesetQuery buildChangesetQuery(String text) {
124 URL url = null;
125 try {
126 url = new URL(text);
127 } catch(MalformedURLException e) {
128 return null;
129 }
130 String path = url.getPath();
131 String query = url.getQuery();
132 if (path == null || ! path.endsWith("/changesets")) return null;
133
134 try {
135 return ChangesetQuery.buildFromUrlQuery(query);
136 } catch(ChangesetQueryUrlException e) {
137 return null;
138 }
139 }
140
141 /**
142 * Replies the {@link ChangesetQuery} specified in this panel. null, if no valid changeset query
143 * is specified.
144 *
145 * @return the changeset query
146 */
147 public ChangesetQuery buildChangesetQuery() {
148 String value = tfUrl.getText().trim();
149 return buildChangesetQuery(value);
150 }
151
152 public void startUserInput() {
153 tfUrl.requestFocusInWindow();
154 }
155
156 /**
157 * Validates text entered in the changeset query URL field on the fly
158 */
159 class ChangetQueryUrlValidator implements DocumentListener {
160 protected String getCurrentFeedback() {
161 String fb = (String)lblValid.getClientProperty("valid");
162 return fb == null ? "none" : fb;
163 }
164 protected void feedbackValid() {
165 if (getCurrentFeedback().equals("valid")) return;
166 lblValid.setIcon(ImageProvider.get("dialogs/changeset", "valid"));
167 lblValid.setToolTipText("");
168 lblValid.putClientProperty("valid", "valid");
169 }
170
171 protected void feedbackInvalid() {
172 if (getCurrentFeedback().equals("invalid")) return;
173 lblValid.setIcon(ImageProvider.get("warning-small"));
174 lblValid.setToolTipText(tr("This changeset query URL is invalid"));
175 lblValid.putClientProperty("valid", "invalid");
176 }
177
178 protected void feedbackNone() {
179 lblValid.setIcon(null);
180 lblValid.putClientProperty("valid", "none");
181 }
182
183 protected void validate() {
184 String value = tfUrl.getText();
185 if (value.trim().equals("")) {
186 feedbackNone();
187 return;
188 }
189 value = value.trim();
190 if (isValidChangesetQueryUrl(value)) {
191 feedbackValid();
192 } else {
193 feedbackInvalid();
194 }
195 }
196 public void changedUpdate(DocumentEvent e) {
197 validate();
198 }
199
200 public void insertUpdate(DocumentEvent e) {
201 validate();
202 }
203
204 public void removeUpdate(DocumentEvent e) {
205 validate();
206 }
207 }
208 }