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

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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.