Changeset 2034 in josm


Ignore:
Timestamp:
2009-09-03T11:58:15+02:00 (15 years ago)
Author:
Gubaer
Message:

refactored UserListDialog
fixed #3379: Add a link to http://openstreetmap.org/user/$user in User pane

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

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/AbstractInfoAction.java

    r2025 r2034  
    55
    66import java.awt.event.ActionEvent;
     7import java.net.URL;
    78import java.util.ArrayList;
    89import java.util.Iterator;
     
    3132     * @return the base URL, i.e. http://api.openstreetmap.org/browse
    3233     */
    33     protected String getBaseURL() {
     34    protected String getBaseBrowseUrl() {
    3435        String baseUrl = Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api");
    3536        Pattern pattern = Pattern.compile("/api/?$");
    3637        String ret =  pattern.matcher(baseUrl).replaceAll("/browse");
    3738        if (ret.equals(baseUrl)) {
    38             System.out.println(tr("WARNING: unexpected format of API base URL. Redirection to history page for OSM primitive will probably fail. API base URL is: ''{0}''",baseUrl));
     39            System.out.println(tr("WARNING: unexpected format of API base URL. Redirection to info or history page for OSM primitive will probably fail. API base URL is: ''{0}''",baseUrl));
    3940        }
    4041        if (ret.startsWith("http://api.openstreetmap.org/")) {
     
    4546    }
    4647
    47     protected void launchBrowser() {
     48    /**
     49     * replies the base URL for browsing information about a user
     50     *
     51     * @return the base URL, i.e. http://ww.openstreetmap.org/user
     52     */
     53    protected String getBaseUserUrl() {
     54        String baseUrl = Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api");
     55        Pattern pattern = Pattern.compile("/api/?$");
     56        String ret =  pattern.matcher(baseUrl).replaceAll("/user");
     57        if (ret.equals(baseUrl)) {
     58            System.out.println(tr("WARNING: unexpected format of API base URL. Redirection to user page for OSM user will probably fail. API base URL is: ''{0}''",baseUrl));
     59        }
     60        if (ret.startsWith("http://api.openstreetmap.org/")) {
     61            ret = ret.substring("http://api.openstreetmap.org/".length());
     62            ret = "http://www.openstreetmap.org/" + ret;
     63        }
     64        return ret;
     65    }
     66
     67    protected void launchBrowser(URL url) {
     68        OpenBrowser.displayUrl(
     69                url.toString()
     70        );
     71    }
     72
     73    protected void launchBrowser(String url) {
     74        OpenBrowser.displayUrl(
     75                url
     76        );
     77    }
     78
     79    protected void launchInfoBrowsersForSelectedPrimitives() {
    4880        ArrayList<OsmPrimitive> primitivesToShow = new ArrayList<OsmPrimitive>(getCurrentDataSet().getSelected());
    4981
     
    74106        }
    75107        for(int i = 0; i < max; i++) {
    76             OpenBrowser.displayUrl(
    77                     createInfoUrl(primitivesToShow.get(i))
    78             );
     108            launchBrowser(createInfoUrl(primitivesToShow.get(i)));
    79109        }
    80110    }
    81111
    82112    public void actionPerformed(ActionEvent e) {
    83         launchBrowser();
     113        launchInfoBrowsersForSelectedPrimitives();
    84114    }
    85115
    86     protected abstract String createInfoUrl(OsmPrimitive primitive);
     116    protected abstract String createInfoUrl(Object infoObject);
    87117
    88118    @Override
  • trunk/src/org/openstreetmap/josm/actions/HistoryInfoAction.java

    r2025 r2034  
    2020
    2121    @Override
    22     protected  String createInfoUrl(OsmPrimitive primitive) {
    23         return getBaseURL() + "/" + OsmPrimitiveType.from(primitive).getAPIName() + "/" + primitive.getId() + "/history";
     22    protected  String createInfoUrl(Object infoObject) {
     23        OsmPrimitive primitive = (OsmPrimitive)infoObject;
     24        return getBaseBrowseUrl() + "/" + OsmPrimitiveType.from(primitive).getAPIName() + "/" + primitive.getId() + "/history";
    2425    }
    2526}
  • trunk/src/org/openstreetmap/josm/actions/InfoAction.java

    r2025 r2034  
    2020
    2121    @Override
    22     protected  String createInfoUrl(OsmPrimitive primitive) {
    23         return getBaseURL() + "/" + OsmPrimitiveType.from(primitive).getAPIName() + "/" + primitive.getId();
     22    protected  String createInfoUrl(Object infoObject) {
     23        OsmPrimitive primitive = (OsmPrimitive)infoObject;
     24        return getBaseBrowseUrl() + "/" + OsmPrimitiveType.from(primitive).getAPIName() + "/" + primitive.getId();
    2425    }
    2526}
  • trunk/src/org/openstreetmap/josm/data/osm/User.java

    r1677 r2034  
    3939        return user;
    4040    }
     41
     42    @Override
     43    public int hashCode() {
     44        final int prime = 31;
     45        int result = 1;
     46        result = prime * result + ((name == null) ? 0 : name.hashCode());
     47        result = prime * result + ((uid == null) ? 0 : uid.hashCode());
     48        return result;
     49    }
     50
     51    @Override
     52    public boolean equals(Object obj) {
     53        if (this == obj)
     54            return true;
     55        if (obj == null)
     56            return false;
     57        if (getClass() != obj.getClass())
     58            return false;
     59        User other = (User) obj;
     60        if (name == null) {
     61            if (other.name != null)
     62                return false;
     63        } else if (!name.equals(other.name))
     64            return false;
     65        if (uid == null) {
     66            if (other.uid != null)
     67                return false;
     68        } else if (!uid.equals(other.uid))
     69            return false;
     70        return true;
     71    }
    4172}
  • trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java

    r2033 r2034  
    66
    77import java.awt.BorderLayout;
     8import java.awt.FlowLayout;
     9import java.awt.event.ActionEvent;
    810import java.awt.event.KeyEvent;
     11import java.awt.event.MouseAdapter;
    912import java.awt.event.MouseEvent;
    10 import java.awt.event.MouseListener;
    11 import java.util.Arrays;
     13import java.text.NumberFormat;
     14import java.util.ArrayList;
    1215import java.util.Collection;
    13 import java.util.Comparator;
     16import java.util.Collections;
    1417import java.util.HashMap;
     18import java.util.HashSet;
     19import java.util.Iterator;
    1520import java.util.LinkedList;
    16 
     21import java.util.List;
     22import java.util.Map;
     23import java.util.Set;
     24
     25import javax.swing.AbstractAction;
     26import javax.swing.JPanel;
    1727import javax.swing.JScrollPane;
    1828import javax.swing.JTable;
    1929import javax.swing.ListSelectionModel;
     30import javax.swing.event.ListSelectionEvent;
     31import javax.swing.event.ListSelectionListener;
    2032import javax.swing.table.DefaultTableModel;
    2133
    2234import org.openstreetmap.josm.Main;
     35import org.openstreetmap.josm.actions.AbstractInfoAction;
    2336import org.openstreetmap.josm.data.SelectionChangedListener;
    2437import org.openstreetmap.josm.data.osm.DataSet;
    2538import org.openstreetmap.josm.data.osm.OsmPrimitive;
    2639import org.openstreetmap.josm.data.osm.User;
     40import org.openstreetmap.josm.gui.SideButton;
    2741import org.openstreetmap.josm.gui.layer.Layer;
    2842import org.openstreetmap.josm.gui.layer.OsmDataLayer;
    2943import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
     44import org.openstreetmap.josm.tools.ImageProvider;
    3045import org.openstreetmap.josm.tools.Shortcut;
    3146
     
    3449 * selection area, along with the number of objects.
    3550 *
    36  * @author Frederik Ramm <frederik@remote.org>
    3751 */
    38 public class UserListDialog extends ToggleDialog implements SelectionChangedListener, MouseListener, LayerChangeListener {
     52public class UserListDialog extends ToggleDialog implements SelectionChangedListener, LayerChangeListener {
    3953
    4054    /**
    4155     * The display list.
    4256     */
    43     private final DefaultTableModel data = new DefaultTableModel() {
    44         @Override public boolean isCellEditable(int row, int column) {
    45             return false;
    46         }
    47         @Override public Class<?> getColumnClass(int columnIndex) {
    48             return columnIndex == 0 ? String.class : Integer.class;
    49         }
    50     };
    51 
    52     private JTable userTable = new JTable(data);
    53 
    54     private static User anonymousUser = User.get("(anonymous users)");
     57    private JTable userTable;
     58    private UserTableModel model;
     59    private SelectUsersPrimitivesAction selectionUsersPrimitivesAction;
     60    private ShowUserInfoAction showUserInfoAction;
    5561
    5662    public UserListDialog() {
     
    5864                Shortcut.registerShortcut("subwindow:authors", tr("Toggle: {0}", tr("Authors")), KeyEvent.VK_A, Shortcut.GROUP_LAYER, Shortcut.SHIFT_DEFAULT), 150);
    5965
    60         data.setColumnIdentifiers(new String[]{tr("Author"),tr("# Objects"),"%"});
    61         userTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    62         add(new JScrollPane(userTable), BorderLayout.CENTER);
    63         if (Main.main.getCurrentDataSet() != null) {
    64             selectionChanged(Main.main.getCurrentDataSet().getSelected());
    65         }
    66         userTable.addMouseListener(this);
     66        build();
    6767        DataSet.selListeners.add(this);
    6868        Layer.listeners.add(this);
    6969    }
    7070
    71     @Override public void setVisible(boolean b) {
    72         super.setVisible(b);
    73         if (b && Main.main.getCurrentDataSet() != null) {
    74             selectionChanged(Main.main.getCurrentDataSet().getSelected());
    75         }
     71    protected JPanel buildButtonRow() {
     72        JPanel pnl = new JPanel();
     73        pnl.setLayout(new FlowLayout(FlowLayout.LEFT));
     74
     75        // -- select users primitives action
     76        //
     77        selectionUsersPrimitivesAction = new SelectUsersPrimitivesAction();
     78        userTable.getSelectionModel().addListSelectionListener(selectionUsersPrimitivesAction);
     79        pnl.add(new SideButton(selectionUsersPrimitivesAction));
     80
     81        // -- info action
     82        //
     83        showUserInfoAction = new ShowUserInfoAction();
     84        userTable.getSelectionModel().addListSelectionListener(showUserInfoAction);
     85        pnl.add(new SideButton(showUserInfoAction));
     86        return pnl;
     87    }
     88
     89    protected void build() {
     90        JPanel pnl = new JPanel();
     91        pnl.setLayout(new BorderLayout());
     92        model = new UserTableModel();
     93        userTable = new JTable(model);
     94        userTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
     95        pnl.add(new JScrollPane(userTable), BorderLayout.CENTER);
     96
     97        // -- the button row
     98        pnl.add(buildButtonRow(), BorderLayout.SOUTH);
     99        userTable.addMouseListener(new DoubleClickAdapter());
     100        add(pnl, BorderLayout.CENTER);
    76101    }
    77102
     
    81106     */
    82107    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
    83         if (!isVisible())
    84             return;
    85 
    86         class UserCount {
    87             User user;
    88             int count;
    89             UserCount(User user, int count) { this.user=user; this.count=count; }
    90         }
    91 
    92         if (data == null)
    93             return; // selection changed may be received in base class constructor before init
    94 
    95         data.setRowCount(0);
    96 
    97         HashMap<User,UserCount> counters = new HashMap<User,UserCount>();
    98         int all = 0;
    99         for (OsmPrimitive p : newSelection) {
    100             User u = p.user;
    101             if (u == null) {
    102                 u = anonymousUser;
    103             }
    104             UserCount uc = counters.get(u);
    105             if (uc == null) {
    106                 counters.put(u, uc = new UserCount(u, 0));
    107             }
    108             uc.count++;
    109             all++;
    110         }
    111         UserCount[] ucArr = new UserCount[counters.size()];
    112         counters.values().toArray(ucArr);
    113         Arrays.sort(ucArr, new Comparator<UserCount>() {
    114             public int compare(UserCount a, UserCount b) {
    115                 return (a.count<b.count) ? 1 : (a.count>b.count) ? -1 : 0;
    116             }
    117         });
    118 
    119         for (UserCount uc : ucArr) {
    120             data.addRow(new Object[] { uc.user.name, uc.count, uc.count * 100 / all });
    121         }
    122 
    123         if(ucArr.length != 0) {
    124             setTitle(trn("{0} Author", "{0} Authors", ucArr.length, ucArr.length));
     108        refresh(newSelection);
     109    }
     110
     111    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
     112        if (newLayer instanceof OsmDataLayer) {
     113            refresh(((OsmDataLayer) newLayer).data.getSelected());
     114        } else {
     115            refresh(null);
     116        }
     117    }
     118
     119    public void layerAdded(Layer newLayer) {
     120        // do nothing
     121    }
     122
     123    public void layerRemoved(Layer oldLayer) {
     124        // do nothing
     125    }
     126
     127    public void refresh(Collection<? extends OsmPrimitive> fromPrimitives) {
     128        model.populate(fromPrimitives);
     129        if(model.getRowCount() != 0) {
     130            setTitle(trn("{0} Author", "{0} Authors", model.getRowCount() , model.getRowCount()));
    125131        } else {
    126132            setTitle(tr("Authors"));
     
    128134    }
    129135
    130     public void mouseClicked(MouseEvent e) {
    131         if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount()==2) {
    132             int index = userTable.getSelectedRow();
    133             String userName = (String) data.getValueAt(index, 0);
    134             if (userName==null)
    135                 return;
     136    class SelectUsersPrimitivesAction extends AbstractAction implements ListSelectionListener{
     137        public SelectUsersPrimitivesAction() {
     138            putValue(NAME, tr("Select"));
     139            putValue(SHORT_DESCRIPTION, tr("Select primitives submitted by this user"));
     140            putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
     141            updateEnabledState();
     142        }
     143
     144        public void select() {
     145            int indexes[] = userTable.getSelectedRows();
     146            if (indexes == null || indexes.length == 0) return;
     147            model.selectPrimitivesOwnedBy(userTable.getSelectedRows());
     148        }
     149
     150        public void actionPerformed(ActionEvent e) {
     151            select();
     152        }
     153
     154        protected void updateEnabledState() {
     155            setEnabled(userTable != null && userTable.getSelectedRowCount() > 0);
     156        }
     157
     158        public void valueChanged(ListSelectionEvent e) {
     159            updateEnabledState();
     160        }
     161    }
     162
     163    /**
     164     * Action for launching the info page of a user
     165     */
     166    class ShowUserInfoAction extends AbstractInfoAction implements ListSelectionListener {
     167
     168        public ShowUserInfoAction() {
     169            putValue(NAME, tr("Show info"));
     170            putValue(SHORT_DESCRIPTION, tr("Launches a browser with information about the user"));
     171            putValue(SMALL_ICON, ImageProvider.get("about"));
     172            updateEnabledState();
     173        }
     174
     175        @Override
     176        public void actionPerformed(ActionEvent e) {
     177            int rows[] = userTable.getSelectedRows();
     178            if (rows == null || rows.length == 0) return;
     179            List<User> users = model.getSelectedUsers(rows);
     180            if (users.isEmpty()) return;
     181            if (users.size() > 10) {
     182                System.out.println(tr("Warning: only launching info browsers for the first {0} of {1} selected users", 10, users.size()));
     183            }
     184            int num = Math.min(10, users.size());
     185            Iterator<User> it = users.iterator();
     186            while(it.hasNext() && num > 0) {
     187                launchBrowser(createInfoUrl(it.next()));
     188                num--;
     189            }
     190        }
     191
     192        @Override
     193        protected String createInfoUrl(Object infoObject) {
     194            User user = (User)infoObject;
     195            return getBaseUserUrl() + "/" + user.name;
     196        }
     197
     198        @Override
     199        protected void updateEnabledState() {
     200            setEnabled(userTable != null && userTable.getSelectedRowCount() > 0);
     201        }
     202
     203        public void valueChanged(ListSelectionEvent e) {
     204            updateEnabledState();
     205        }
     206    }
     207
     208    class DoubleClickAdapter extends MouseAdapter {
     209        @Override
     210        public void mouseClicked(MouseEvent e) {
     211            if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount()==2) {
     212                selectionUsersPrimitivesAction.select();
     213            }
     214        }
     215    }
     216
     217    /**
     218     * Action for selecting the primitives contributed by the currently selected
     219     * users.
     220     *
     221     */
     222    private static class UserInfo implements Comparable<UserInfo> {
     223        public User user;
     224        public int count;
     225        public double percent;
     226        UserInfo(User user, int count, double percent) {
     227            this.user=user;
     228            this.count=count;
     229            this.percent = percent;
     230        }
     231        public int compareTo(UserInfo o) {
     232            if (count < o.count) return 1;
     233            if (count > o.count) return -1;
     234            if (user== null || user.name == null) return 1;
     235            if (o.user == null || o.user.name == null) return -1;
     236            return user.name.compareTo(o.user.name);
     237        }
     238
     239        public String getName() {
     240            if (user == null) return null;
     241            return user.name;
     242        }
     243    }
     244
     245    /**
     246     * The table model for the users
     247     *
     248     */
     249    class UserTableModel extends DefaultTableModel {
     250        private ArrayList<UserInfo> data;
     251
     252        public UserTableModel() {
     253            setColumnIdentifiers(new String[]{tr("Author"),tr("# Objects"),"%"});
     254            data = new ArrayList<UserInfo>();
     255        }
     256
     257        protected Map<User, Integer> computeStatistics(Collection<? extends OsmPrimitive> primitives) {
     258            HashMap<User, Integer> ret = new HashMap<User, Integer>();
     259            if (primitives == null || primitives.isEmpty()) return ret;
     260            for (OsmPrimitive primitive: primitives) {
     261                if (primitive.user == null) {
     262                    continue;
     263                }
     264                if (ret.containsKey(primitive.user)) {
     265                    ret.put(primitive.user, ret.get(primitive.user) + 1);
     266                } else {
     267                    ret.put(primitive.user, 1);
     268                }
     269            }
     270            return ret;
     271        }
     272
     273        public void populate(Collection<? extends OsmPrimitive> primitives) {
     274            Map<User,Integer> statistics = computeStatistics(primitives);
     275            data.clear();
     276            if (primitives != null) {
     277                for (Map.Entry<User, Integer> entry: statistics.entrySet()) {
     278                    data.add(new UserInfo(entry.getKey(), entry.getValue(), (double)entry.getValue() /  (double)primitives.size()));
     279                }
     280            }
     281            Collections.sort(data);
     282            fireTableDataChanged();
     283        }
     284
     285        @Override
     286        public int getRowCount() {
     287            if (data == null) return 0;
     288            return data.size();
     289        }
     290
     291        @Override
     292        public Object getValueAt(int row, int column) {
     293            UserInfo info = data.get(row);
     294            switch(column) {
     295                case 0: /* author */ return info.getName() == null ? "" : info.getName();
     296                case 1: /* count */ return info.count;
     297                case 2: /* percent */ return NumberFormat.getPercentInstance().format(info.percent);
     298            }
     299            return null;
     300        }
     301
     302        @Override
     303        public boolean isCellEditable(int row, int column) {
     304            return false;
     305        }
     306
     307        public void selectPrimitivesOwnedBy(int [] rows) {
     308            Set<User> users= new HashSet<User>();
     309            for (int index: rows) {
     310                if (data.get(index).user == null) {
     311                    continue;
     312                }
     313                users.add(data.get(index).user);
     314            }
    136315            Collection<OsmPrimitive> selected = Main.main.getCurrentDataSet().getSelected();
    137316            Collection<OsmPrimitive> byUser = new LinkedList<OsmPrimitive>();
    138317            for (OsmPrimitive p : selected) {
    139                 if (p.user!= null && userName.equals(p.user.name)) {
     318                if (p.user == null) {
     319                    continue;
     320                }
     321                if (users.contains(p.user)) {
    140322                    byUser.add(p);
    141323                }
     
    143325            Main.main.getCurrentDataSet().setSelected(byUser);
    144326        }
    145     }
    146 
    147     public void mouseEntered(MouseEvent e) {
    148     }
    149 
    150     public void mouseExited(MouseEvent e) {
    151     }
    152 
    153     public void mousePressed(MouseEvent e) {
    154     }
    155 
    156     public void mouseReleased(MouseEvent e) {
    157     }
    158 
    159     public void activeLayerChange(Layer oldLayer, Layer newLayer) {
    160         if (newLayer instanceof OsmDataLayer) {
    161             OsmDataLayer dataLayer = (OsmDataLayer)newLayer;
    162             selectionChanged(dataLayer.data.getSelected());
    163 
    164         }
    165     }
    166 
    167     public void layerAdded(Layer newLayer) {
    168         // do nothing
    169     }
    170 
    171     public void layerRemoved(Layer oldLayer) {
    172         // do nothing
     327
     328        public List<User> getSelectedUsers(int rows[]) {
     329            LinkedList<User> ret = new LinkedList<User>();
     330            if (rows == null || rows.length == 0) return ret;
     331            for (int row: rows) {
     332                if (data.get(row).user == null) {
     333                    continue;
     334                }
     335                ret.add(data.get(row).user);
     336            }
     337            return ret;
     338        }
    173339    }
    174340}
Note: See TracChangeset for help on using the changeset viewer.