Changeset 2361 in josm


Ignore:
Timestamp:
2009-10-31T17:06:05+01:00 (14 years ago)
Author:
Gubaer
Message:

Improved tab "Places" in download dialog (download on double click, progress dialog, line wrap in tooltip text, etc.)

Location:
trunk/src/org/openstreetmap/josm
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/gui/download/BoundingBoxSelection.java

    r2334 r2361  
    3939
    4040    private JTextField[] latlon = null;
    41     final JTextArea osmUrl = new JTextArea();
    42     final JTextArea showUrl = new JTextArea();
     41    private final JTextArea osmUrl = new JTextArea();
     42    private final JTextArea showUrl = new JTextArea();
     43    private DownloadDialog parent;
    4344
    4445   
     
    5455        latlon[0].addActionListener(latChecker);
    5556
    56         latChecker = new LatValueChecker(latlon[3]);
     57        latChecker = new LatValueChecker(latlon[2]);
    5758        latlon[2].addFocusListener(latChecker);
    5859        latlon[2].addActionListener(latChecker);
     
    7273        JPanel dlg = new JPanel(new GridBagLayout());
    7374
    74         class osmUrlRefresher implements DocumentListener {
    75             public void changedUpdate(DocumentEvent e) { parseURL(gui); }
    76             public void insertUpdate(DocumentEvent e) { parseURL(gui); }
    77             public void removeUpdate(DocumentEvent e) { parseURL(gui); }
    78         }
    79 
    80         osmUrl.getDocument().addDocumentListener(new osmUrlRefresher());
     75        osmUrl.getDocument().addDocumentListener(new OsmUrlRefresher());
    8176
    8277        // select content on receiving focus. this seems to be the default in the
     
    10499
    105100        gui.addDownloadAreaSelector(dlg, tr("Bounding Box"));
     101        this.parent = gui;
    106102    }
    107103
     
    184180                return;           
    185181            }
     182            setErrorMessage(null);
    186183        }
    187184       
     
    225222                return;
    226223            }
     224            setErrorMessage(null);
    227225        }
    228226       
     
    248246        }       
    249247    }
     248   
     249    class OsmUrlRefresher implements DocumentListener {
     250        public void changedUpdate(DocumentEvent e) { parseURL(parent); }
     251        public void insertUpdate(DocumentEvent e) { parseURL(parent); }
     252        public void removeUpdate(DocumentEvent e) { parseURL(parent); }
     253    }
    250254}
  • trunk/src/org/openstreetmap/josm/gui/download/PlaceSelection.java

    r2332 r2361  
    33import static org.openstreetmap.josm.tools.I18n.tr;
    44
     5import java.awt.BorderLayout;
    56import java.awt.Component;
    6 import java.awt.Cursor;
    77import java.awt.Dimension;
     8import java.awt.GridBagConstraints;
    89import java.awt.GridBagLayout;
     10import java.awt.Insets;
    911import java.awt.event.ActionEvent;
    10 import java.awt.event.ActionListener;
    1112import java.awt.event.MouseAdapter;
    1213import java.awt.event.MouseEvent;
     14import java.io.IOException;
    1315import java.io.InputStream;
    1416import java.io.InputStreamReader;
    1517import java.net.HttpURLConnection;
    1618import java.net.URL;
    17 
     19import java.util.ArrayList;
     20import java.util.LinkedList;
     21import java.util.List;
     22import java.util.StringTokenizer;
     23
     24import javax.swing.AbstractAction;
     25import javax.swing.BorderFactory;
     26import javax.swing.DefaultListSelectionModel;
    1827import javax.swing.JButton;
    19 import javax.swing.JComponent;
    2028import javax.swing.JLabel;
    21 import javax.swing.JOptionPane;
    2229import javax.swing.JPanel;
    2330import javax.swing.JScrollPane;
     
    2532import javax.swing.JTextField;
    2633import javax.swing.ListSelectionModel;
     34import javax.swing.UIManager;
     35import javax.swing.event.DocumentEvent;
     36import javax.swing.event.DocumentListener;
    2737import javax.swing.event.ListSelectionEvent;
    2838import javax.swing.event.ListSelectionListener;
    29 import javax.swing.table.DefaultTableCellRenderer;
     39import javax.swing.table.DefaultTableColumnModel;
    3040import javax.swing.table.DefaultTableModel;
     41import javax.swing.table.TableCellRenderer;
     42import javax.swing.table.TableColumn;
    3143import javax.xml.parsers.SAXParserFactory;
    3244
     
    3446import org.openstreetmap.josm.data.Bounds;
    3547import org.openstreetmap.josm.data.coor.LatLon;
    36 import org.openstreetmap.josm.tools.GBC;
     48import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
     49import org.openstreetmap.josm.gui.ExceptionDialogUtil;
     50import org.openstreetmap.josm.gui.PleaseWaitRunnable;
     51import org.openstreetmap.josm.io.OsmTransferException;
     52import org.openstreetmap.josm.tools.ImageProvider;
    3753import org.xml.sax.Attributes;
    3854import org.xml.sax.InputSource;
     
    4258public class PlaceSelection implements DownloadSelection {
    4359
    44     private JTextField searchTerm = new JTextField();
    45     private JButton submitSearch = new JButton(tr("Search..."));
    46     private DefaultTableModel searchResults = new DefaultTableModel() {
    47         @Override public boolean isCellEditable(int row, int col) { return false; }
    48     };
    49     private JTable searchResultDisplay = new JTable(searchResults);
    50     private boolean updatingSelf;
    51 
    52     /**
    53      * Data storage for search results.
    54      */
    55     class SearchResult
    56     {
    57         public String name;
    58         public String type;
    59         public String nearestPlace;
    60         public String description;
    61         public double lat;
    62         public double lon;
    63         public int zoom;
    64     }
    65 
    66     /**
    67      * A very primitive parser for the name finder's output.
    68      * Structure of xml described here:  http://wiki.openstreetmap.org/index.php/Name_finder
    69      *
    70      */
    71     private class Parser extends DefaultHandler
    72     {
    73         private SearchResult currentResult = null;
    74         private StringBuffer description = null;
    75         private int depth = 0;
    76         /**
    77          * Detect starting elements.
    78          *
    79          */
    80         @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException
    81         {
    82             depth++;
    83             try
    84             {
    85                 if (qName.equals("searchresults"))
    86                 {
    87                     searchResults.setRowCount(0);
    88                 }
    89                 else if (qName.equals("named") && (depth == 2))
    90                 {
    91                     currentResult = new PlaceSelection.SearchResult();
    92                     currentResult.name = atts.getValue("name");
    93                     currentResult.type = atts.getValue("info");
    94                     currentResult.lat = Double.parseDouble(atts.getValue("lat"));
    95                     currentResult.lon = Double.parseDouble(atts.getValue("lon"));
    96                     currentResult.zoom = Integer.parseInt(atts.getValue("zoom"));
    97                     searchResults.addRow(new Object[] { currentResult, currentResult, currentResult, currentResult });
    98                 }
    99                 else if (qName.equals("description") && (depth == 3))
    100                 {
    101                     description = new StringBuffer();
    102                 }
    103                 else if (qName.equals("named") && (depth == 4))
    104                 {
    105                     // this is a "named" place in the nearest places list.
    106                     String info = atts.getValue("info");
    107                     if ("city".equals(info) || "town".equals(info) || "village".equals(info)) {
    108                         currentResult.nearestPlace = atts.getValue("name");
    109                     }
    110                 }
    111             }
    112             catch (NumberFormatException x)
    113             {
    114                 x.printStackTrace(); // SAXException does not chain correctly
    115                 throw new SAXException(x.getMessage(), x);
    116             }
    117             catch (NullPointerException x)
    118             {
    119                 x.printStackTrace(); // SAXException does not chain correctly
    120                 throw new SAXException(tr("Null pointer exception, possibly some missing tags."), x);
    121             }
    122         }
    123         /**
    124          * Detect ending elements.
    125          */
    126         @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException
    127         {
    128 
    129             if (qName.equals("searchresults"))
    130             {
    131             }
    132             else if (qName.equals("description") && description != null)
    133             {
    134                 currentResult.description = description.toString();
    135                 description = null;
    136             }
    137             depth--;
    138 
    139         }
    140         /**
    141          * Read characters for description.
    142          */
    143         @Override public void characters(char[] data, int start, int length) throws org.xml.sax.SAXException
    144         {
    145             if (description != null)
    146             {
    147                 description.append(data, start, length);
    148             }
    149         }
    150     }
    151 
    152     /**
    153      * This queries David Earl's server. Needless to say, stuff should be configurable, and
    154      * error handling improved.
    155      */
    156     public void queryServer(final JComponent component)
    157     {
    158         final Cursor oldCursor = component.getCursor();
    159 
    160         // had to put this in a thread as it wouldn't update the cursor properly before.
    161         Runnable r = new Runnable() {
    162             public void run() {
    163                 try
    164                 {
    165                     String searchtext = searchTerm.getText();
    166                     if(searchtext.length()==0)
    167                     {
    168                         JOptionPane.showMessageDialog(
    169                                 Main.parent,
    170                                 tr("Please enter a search string"),
    171                                 tr("Information"),
    172                                 JOptionPane.INFORMATION_MESSAGE
    173                         );
    174                     }
    175                     else
    176                     {
    177                         component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
    178                         component.repaint();
    179                         URL url = new URL("http://gazetteer.openstreetmap.org/namefinder/search.xml?find="
    180                                 +java.net.URLEncoder.encode(searchTerm.getText(), "UTF-8"));
    181                         HttpURLConnection activeConnection = (HttpURLConnection)url.openConnection();
    182                         //System.out.println("got return: "+activeConnection.getResponseCode());
    183                         activeConnection.setConnectTimeout(15000);
    184                         InputStream inputStream = activeConnection.getInputStream();
    185                         InputSource inputSource = new InputSource(new InputStreamReader(inputStream, "UTF-8"));
    186                         SAXParserFactory.newInstance().newSAXParser().parse(inputSource, new Parser());
    187                     }
    188                 }
    189                 catch (Exception x)
    190                 {
    191                     x.printStackTrace();
    192                     JOptionPane.showMessageDialog(
    193                             Main.parent,
    194                             tr("Cannot read place search results from server"),
    195                             tr("Error"),
    196                             JOptionPane.ERROR_MESSAGE
    197                     );
    198                 }
    199                 component.setCursor(oldCursor);
    200             }
    201         };
    202         new Thread(r).start();
     60    private JTextField tfSearchExpression;
     61    private JButton btnSearch;
     62    private NamedResultTableModel model;
     63    private JTable tblSearchResults;
     64    private DownloadDialog parent;
     65 
     66    protected JPanel buildSearchPanel() {
     67        JPanel panel = new JPanel();
     68        panel.setLayout(new GridBagLayout());
     69        GridBagConstraints gc = new GridBagConstraints();
     70       
     71        // the label for the search field
     72        //
     73        gc.gridwidth = 2;
     74        gc.fill = GridBagConstraints.HORIZONTAL;
     75        gc.weightx  =1.0;
     76        gc.insets = new Insets(5, 5, 0, 5);
     77        panel.add(new JLabel(tr("Enter a place name to search for:")), gc);
     78       
     79        // the search expression field
     80        //
     81        tfSearchExpression = new JTextField();
     82        tfSearchExpression.setToolTipText(tr("Enter a place name to search for"));
     83        gc.gridx = 0;
     84        gc.gridy = 1;
     85        gc.gridwidth = 1;
     86        panel.add(tfSearchExpression,  gc);
     87
     88        // the search button
     89        //
     90        SearchAction searchAction = new SearchAction();
     91        btnSearch = new JButton(searchAction);
     92        tfSearchExpression.getDocument().addDocumentListener(searchAction);
     93        tfSearchExpression.addActionListener(searchAction);
     94
     95        gc.gridx = 1;
     96        gc.gridy = 1;
     97        gc.fill = GridBagConstraints.HORIZONTAL;
     98        gc.weightx = 0.0;
     99        panel.add(btnSearch,  gc);
     100   
     101        return panel;   
    203102    }
    204103
     
    210109    public void addGui(final DownloadDialog gui) {
    211110        JPanel panel = new JPanel();
    212         panel.setLayout(new GridBagLayout());
    213 
    214         // this is manually tuned so that it looks nice on a GNOME
    215         // desktop - maybe needs some cross platform proofing.
    216         panel.add(new JLabel(tr("Enter a place name to search for:")), GBC.eol().insets(5, 5, 5, 5));
    217         panel.add(searchTerm, GBC.std().fill(GBC.HORIZONTAL).insets(5, 0, 5, 4));
    218         panel.add(submitSearch, GBC.eol().insets(5, 0, 5, 5));
    219         Dimension btnSize = submitSearch.getPreferredSize();
    220         btnSize.setSize(btnSize.width, btnSize.height * 0.8);
    221         submitSearch.setPreferredSize(btnSize);
    222 
    223         GBC c = GBC.std().fill().insets(5, 0, 5, 5);
    224         c.gridwidth = 2;
    225         JScrollPane scrollPane = new JScrollPane(searchResultDisplay);
     111        panel.setLayout(new BorderLayout());
     112        panel.add(buildSearchPanel(), BorderLayout.NORTH);
     113
     114        DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
     115        model = new NamedResultTableModel(selectionModel);
     116        tblSearchResults = new JTable(model, new NamedResultTableColumnModel());
     117        tblSearchResults.setSelectionModel(selectionModel);
     118        JScrollPane scrollPane = new JScrollPane(tblSearchResults);
    226119        scrollPane.setPreferredSize(new Dimension(200,200));
    227         panel.add(scrollPane, c);
    228         gui.addDownloadAreaSelector(panel, tr("Places"));
    229 
    230         scrollPane.setPreferredSize(scrollPane.getPreferredSize());
    231 
    232         // when the button is clicked
    233         submitSearch.addActionListener(new ActionListener() {
    234             public void actionPerformed(ActionEvent e) {
    235                 queryServer(gui.getRootPane());
    236             }
    237         });
    238 
    239         searchTerm.addActionListener(new ActionListener() {
    240             public void actionPerformed(ActionEvent e) {
    241                 queryServer(gui.getRootPane());
    242             }
    243         });
    244 
    245         searchResults.addColumn(tr("name"));
    246         searchResults.addColumn(tr("type"));
    247         searchResults.addColumn(tr("near"));
    248         searchResults.addColumn(tr("zoom"));
    249 
    250         // TODO - this is probably not the coolest way to set relative sizes?
    251         searchResultDisplay.getColumn(tr("name")).setPreferredWidth(200);
    252         searchResultDisplay.getColumn(tr("type")).setPreferredWidth(100);
    253         searchResultDisplay.getColumn(tr("near")).setPreferredWidth(100);
    254         searchResultDisplay.getColumn(tr("zoom")).setPreferredWidth(50);
    255         searchResultDisplay.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    256 
    257         // display search results in a table. for simplicity, the table contains
    258         // the same SearchResult object in each of the four columns, but it is rendered
    259         // differently depending on the column.
    260         searchResultDisplay.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
    261             @Override public Component getTableCellRendererComponent(JTable table, Object value,
    262                     boolean isSelected, boolean hasFocus, int row, int column) {
    263                 super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    264                 if (value != null) {
    265                     SearchResult sr = (SearchResult) value;
    266                     switch(column) {
    267                     case 0:
    268                         setText(sr.name);
    269                         break;
    270                     case 1:
    271                         setText(sr.type);
    272                         break;
    273                     case 2:
    274                         setText(sr.nearestPlace);
    275                         break;
    276                     case 3:
    277                         setText(Integer.toString(sr.zoom));
    278                         break;
    279                     }
    280                     setToolTipText("<html>"+((SearchResult)value).description+"</html>");
    281                 }
    282                 return this;
    283             }
    284         });
    285 
    286         // if item is selected in list, notify dialog
    287         searchResultDisplay.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
    288             public void valueChanged(ListSelectionEvent lse) {
    289                 if (lse.getValueIsAdjusting()) return;
    290                 SearchResult r = null;
    291                 try
    292                 {
    293                     r = (SearchResult) searchResults.getValueAt(lse.getFirstIndex(), 0);
    294                 }
    295                 catch (Exception x)
    296                 {
    297                     // Ignore
    298                 }
    299                 if (r != null)
    300                 {
    301                     double size = 180.0 / Math.pow(2, r.zoom);
    302                     Bounds b = new Bounds(
    303                         new LatLon(
    304                             r.lat - size / 2,
    305                             r.lat + size / 2
    306                          ),
    307                          new LatLon(
    308                             r.lon - size,
    309                             r.lon + size
    310                          )
    311                     );
    312                     gui.boundingBoxChanged(b,null);
    313                 }
    314             }
    315         });
    316 
    317         // TODO - we'd like to finish the download dialog upon double-click but
    318         // don't know how to bypass the JOptionPane in which the whole thing is
    319         // displayed.
    320         searchResultDisplay.addMouseListener(new MouseAdapter() {
     120        panel.add(scrollPane, BorderLayout.CENTER);
     121       
     122        gui.addDownloadAreaSelector(panel, tr("Areas around Places"));
     123
     124        scrollPane.setPreferredSize(scrollPane.getPreferredSize());       
     125        tblSearchResults.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
     126        tblSearchResults.getSelectionModel().addListSelectionListener(new ListSelectionHandler());
     127        tblSearchResults.addMouseListener(new MouseAdapter() {
    321128            @Override public void mouseClicked(MouseEvent e) {
    322129                if (e.getClickCount() > 1) {
    323                     if (searchResultDisplay.getSelectionModel().getMinSelectionIndex() > -1) {
    324                         // add sensible action here.
     130                    SearchResult sr = model.getSelectedSearchResult();
     131                    if (sr == null) return;
     132                    parent.startDownload(sr.getDownloadArea());
     133                }
     134            }
     135        });       
     136        parent = gui;
     137    }
     138
     139    public void setDownloadArea(Bounds area) {
     140       tblSearchResults.clearSelection();
     141    }
     142       
     143    /**
     144     * Data storage for search results.
     145     */
     146    static private class SearchResult {
     147        public String name;
     148        public String info;
     149        public String nearestPlace;
     150        public String description;
     151        public double lat;
     152        public double lon;
     153        public int zoom;
     154        public int osmId;
     155        public OsmPrimitiveType type;
     156       
     157        public Bounds getDownloadArea() {
     158            double size = 180.0 / Math.pow(2, zoom);
     159            Bounds b = new Bounds(
     160                    new LatLon(lat - size / 2, lon - size),
     161                    new LatLon(lat + size / 2, lon+ size)
     162                    );
     163            return b;
     164        }
     165    }
     166   
     167   
     168    /**
     169     * A very primitive parser for the name finder's output.
     170     * Structure of xml described here:  http://wiki.openstreetmap.org/index.php/Name_finder
     171     *
     172     */
     173    private class NameFinderResultParser extends DefaultHandler {
     174        private SearchResult currentResult = null;
     175        private StringBuffer description = null;
     176        private int depth = 0;
     177        private List<SearchResult> data = new LinkedList<SearchResult>();
     178
     179        /**
     180         * Detect starting elements.
     181         *
     182         */
     183        @Override
     184        public void startElement(String namespaceURI, String localName, String qName, Attributes atts)
     185                throws SAXException {
     186            depth++;
     187            try {
     188                if (qName.equals("searchresults")) {
     189                    // do nothing
     190                } else if (qName.equals("named") && (depth == 2)) {
     191                    currentResult = new PlaceSelection.SearchResult();
     192                    currentResult.name = atts.getValue("name");
     193                    currentResult.info = atts.getValue("info");
     194                    currentResult.lat = Double.parseDouble(atts.getValue("lat"));
     195                    currentResult.lon = Double.parseDouble(atts.getValue("lon"));
     196                    currentResult.zoom = Integer.parseInt(atts.getValue("zoom"));
     197                    currentResult.osmId = Integer.parseInt(atts.getValue("id"));
     198                    currentResult.type = OsmPrimitiveType.from(atts.getValue("type"));
     199                    data.add(currentResult);
     200                } else if (qName.equals("description") && (depth == 3)) {
     201                    description = new StringBuffer();
     202                } else if (qName.equals("named") && (depth == 4)) {
     203                    // this is a "named" place in the nearest places list.
     204                    String info = atts.getValue("info");
     205                    if ("city".equals(info) || "town".equals(info) || "village".equals(info)) {
     206                        currentResult.nearestPlace = atts.getValue("name");
    325207                    }
    326208                }
    327             }
    328         });
    329 
    330     }
    331 
    332     public void setDownloadArea(Bounds area) {
    333        searchResultDisplay.clearSelection();
     209            } catch (NumberFormatException x) {
     210                x.printStackTrace(); // SAXException does not chain correctly
     211                throw new SAXException(x.getMessage(), x);
     212            } catch (NullPointerException x) {
     213                x.printStackTrace(); // SAXException does not chain correctly
     214                throw new SAXException(tr("Null pointer exception, possibly some missing tags."), x);
     215            }
     216        }
     217
     218        /**
     219         * Detect ending elements.
     220         */
     221        @Override
     222        public void endElement(String namespaceURI, String localName, String qName) throws SAXException {
     223            if (qName.equals("searchresults")) {
     224            } else if (qName.equals("description") && description != null) {
     225                currentResult.description = description.toString();
     226                description = null;
     227            }
     228            depth--;
     229
     230        }
     231
     232        /**
     233         * Read characters for description.
     234         */
     235        @Override
     236        public void characters(char[] data, int start, int length) throws org.xml.sax.SAXException {
     237            if (description != null) {
     238                description.append(data, start, length);
     239            }
     240        }
     241       
     242        public List<SearchResult> getResult() {
     243            return data;
     244        }
     245    }
     246   
     247    class SearchAction extends AbstractAction implements DocumentListener {
     248
     249        public SearchAction() {
     250            putValue(NAME, tr("Search ..."));
     251            putValue(SMALL_ICON, ImageProvider.get("dialogs","search"));
     252            putValue(SHORT_DESCRIPTION, tr("Click to start searching for places"));
     253            updateEnabledState();
     254        }
     255       
     256        public void actionPerformed(ActionEvent e) {
     257            if (!isEnabled() || tfSearchExpression.getText().trim().length() == 0)
     258                return;
     259            NameQueryTask task = new NameQueryTask(tfSearchExpression.getText());
     260            Main.worker.submit(task);
     261        }
     262       
     263        protected void updateEnabledState() {
     264            setEnabled(tfSearchExpression.getText().trim().length() > 0);
     265        }
     266
     267        public void changedUpdate(DocumentEvent e) {
     268            updateEnabledState();
     269        }
     270
     271        public void insertUpdate(DocumentEvent e) {
     272            updateEnabledState();
     273        }
     274
     275        public void removeUpdate(DocumentEvent e) {
     276            updateEnabledState();
     277        }
     278    }
     279   
     280   
     281    class NameQueryTask extends PleaseWaitRunnable {
     282       
     283        private String searchExpression;
     284        private HttpURLConnection connection;
     285        private List<SearchResult> data;
     286        private boolean canceled = false;
     287        private Exception lastException;
     288       
     289        public NameQueryTask(String searchExpression) {
     290            super(tr("Querying name server"),false /* don't ignore exceptions */);
     291            this.searchExpression = searchExpression;
     292        }
     293       
     294       
     295        @Override
     296        protected void cancel() {
     297            this.canceled = true;
     298            synchronized (this) {
     299                if (connection != null) {
     300                    connection.disconnect();                   
     301                }               
     302            }           
     303        }
     304
     305        @Override
     306        protected void finish() {
     307            if (canceled)
     308                return;
     309            if (lastException != null) {
     310                ExceptionDialogUtil.explainException(lastException);
     311                return;
     312            }
     313            model.setData(this.data);           
     314        }
     315
     316        @Override
     317        protected void realRun() throws SAXException, IOException, OsmTransferException {           
     318            try {
     319                getProgressMonitor().indeterminateSubTask(tr("Querying name server ..."));
     320                    URL url = new URL("http://gazetteer.openstreetmap.org/namefinder/search.xml?find="
     321                            +java.net.URLEncoder.encode(searchExpression, "UTF-8"));
     322                    synchronized(this) {
     323                        connection = (HttpURLConnection)url.openConnection();
     324                    }
     325                    connection.setConnectTimeout(15000);
     326                    InputStream inputStream = connection.getInputStream();
     327                    InputSource inputSource = new InputSource(new InputStreamReader(inputStream, "UTF-8"));
     328                    NameFinderResultParser parser = new NameFinderResultParser();
     329                    SAXParserFactory.newInstance().newSAXParser().parse(inputSource, parser);
     330                    this.data = parser.getResult();
     331            } catch(Exception e) {
     332                if (canceled) {
     333                    // ignore exception
     334                    return;
     335                }
     336                lastException = e;
     337            }
     338        }
     339    }
     340   
     341    class NamedResultTableModel extends DefaultTableModel {
     342        private ArrayList<SearchResult> data;
     343        private ListSelectionModel selectionModel;
     344       
     345        public NamedResultTableModel(ListSelectionModel selectionModel) {
     346            data = new ArrayList<SearchResult>();
     347            this.selectionModel = selectionModel;
     348        }
     349        @Override
     350        public int getRowCount() {
     351            if (data == null) return 0;
     352            return data.size();
     353        }
     354
     355        @Override
     356        public Object getValueAt(int row, int column) {
     357            if (data == null) return null;
     358            return data.get(row);
     359        }
     360       
     361        public void setData(List<SearchResult> data) {
     362            if (data == null) {
     363                this.data.clear();
     364            } else {
     365                this.data  =new ArrayList<SearchResult>(data);
     366            }
     367            fireTableDataChanged();
     368        }
     369        @Override
     370        public boolean isCellEditable(int row, int column) {
     371            return false;
     372        }
     373       
     374        public SearchResult getSelectedSearchResult() {
     375            if (selectionModel.getMinSelectionIndex() < 0) {
     376                return null;
     377            }
     378            return data.get(selectionModel.getMinSelectionIndex());
     379        }
     380    }
     381   
     382    class NamedResultTableColumnModel extends DefaultTableColumnModel {
     383        protected void createColumns() {
     384            TableColumn col = null;
     385            NamedResultCellRenderer renderer = new NamedResultCellRenderer();
     386
     387            // column 0 - Name
     388            col = new TableColumn(0);
     389            col.setHeaderValue(tr("Name"));
     390            col.setResizable(true);
     391            col.setPreferredWidth(200);
     392            col.setCellRenderer(renderer);
     393            addColumn(col);
     394           
     395            // column 1 - Version
     396            col = new TableColumn(1);
     397            col.setHeaderValue(tr("Type"));
     398            col.setResizable(true);
     399            col.setPreferredWidth(100);
     400            col.setCellRenderer(renderer);
     401            addColumn(col);
     402           
     403            // column 2 - Near
     404            col = new TableColumn(2);
     405            col.setHeaderValue(tr("Near"));
     406            col.setResizable(true);
     407            col.setPreferredWidth(100);
     408            col.setCellRenderer(renderer);
     409            addColumn(col);
     410           
     411
     412            // column 3 - Zoom
     413            col = new TableColumn(3);
     414            col.setHeaderValue(tr("Zoom"));
     415            col.setResizable(true);
     416            col.setPreferredWidth(50);
     417            col.setCellRenderer(renderer);
     418            addColumn(col);
     419        }
     420
     421        public NamedResultTableColumnModel() {
     422            createColumns();
     423        }
     424    }
     425   
     426    class ListSelectionHandler implements ListSelectionListener {
     427        public void valueChanged(ListSelectionEvent lse) {
     428            SearchResult r = null;
     429            try {
     430                r = (SearchResult) model.getValueAt(lse.getFirstIndex(), 0);
     431            } catch (Exception x) {
     432                // Ignore
     433            }
     434            if (r != null) {
     435                parent.boundingBoxChanged(r.getDownloadArea(), PlaceSelection.this);
     436            }
     437        }
     438    }
     439   
     440    class NamedResultCellRenderer extends JLabel implements TableCellRenderer {
     441        public NamedResultCellRenderer() {
     442            setOpaque(true);
     443            setBorder(BorderFactory.createEmptyBorder(2,2,2,2));
     444        }
     445       
     446        protected void reset() {
     447            setText("");
     448            setIcon(null);
     449        }
     450       
     451        protected void renderColor(boolean selected) {
     452            if (selected) {
     453                setForeground(UIManager.getColor("Table.selectionForeground"));
     454                setBackground(UIManager.getColor("Table.selectionBackground"));
     455            } else {
     456                setForeground(UIManager.getColor("Table.foreground"));
     457                setBackground(UIManager.getColor("Table.background"));               
     458            }
     459        }
     460       
     461        protected String lineWrapDescription(String description) {
     462            StringBuffer ret = new StringBuffer();
     463            StringBuffer line = new StringBuffer();
     464            StringTokenizer tok = new StringTokenizer(description, " ");
     465            while(tok.hasMoreElements()) {
     466                String t = tok.nextToken();
     467                if (line.length() == 0) {
     468                    line.append(t);
     469                } else if (line.length() < 80) {
     470                    line.append(" ").append(t);
     471                } else {
     472                    line.append(" ").append(t).append("<br>");
     473                    ret.append(line);
     474                    line = new StringBuffer();
     475                }
     476            }
     477            ret.insert(0, "<html>");
     478            ret.append("</html>");
     479            return ret.toString();
     480        }
     481       
     482        public Component getTableCellRendererComponent(JTable table, Object value,
     483                boolean isSelected, boolean hasFocus, int row, int column) {
     484           
     485            reset();
     486            renderColor(isSelected);
     487           
     488            if (value == null) return this;
     489            SearchResult sr = (SearchResult) value;
     490            switch(column) {
     491            case 0:
     492                setText(sr.name);
     493                break;
     494            case 1:
     495                setText(sr.info);
     496                break;
     497            case 2:
     498                setText(sr.nearestPlace);
     499                break;
     500            case 3:
     501                setText(Integer.toString(sr.zoom));
     502                break;
     503            }
     504            setToolTipText(lineWrapDescription(sr.description));
     505            return this;
     506        }
    334507    }
    335508}
  • trunk/src/org/openstreetmap/josm/io/OsmServerBackreferenceReader.java

    r2303 r2361  
    8383     *
    8484     * @param id  the id of the primitive. > 0 expected
    85      * @param type the type of the primitive. Must not be null.
    8685     * @param readFull true, if referers should be read fully (i.e. including their immediate children)
    8786     *
Note: See TracChangeset for help on using the changeset viewer.