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 }