source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/UserListDialog.java@ 9059

Last change on this file since 9059 was 9059, checked in by Don-vip, 8 years ago

checkstyle

  • Property svn:eol-style set to native
File size: 12.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.text.NumberFormat;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.Collections;
16import java.util.HashMap;
17import java.util.HashSet;
18import java.util.Iterator;
19import java.util.LinkedList;
20import java.util.List;
21import java.util.Map;
22import java.util.Set;
23
24import javax.swing.AbstractAction;
25import javax.swing.JTable;
26import javax.swing.ListSelectionModel;
27import javax.swing.event.ListSelectionEvent;
28import javax.swing.event.ListSelectionListener;
29import javax.swing.table.DefaultTableModel;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.actions.AbstractInfoAction;
33import org.openstreetmap.josm.data.SelectionChangedListener;
34import org.openstreetmap.josm.data.osm.DataSet;
35import org.openstreetmap.josm.data.osm.OsmPrimitive;
36import org.openstreetmap.josm.data.osm.User;
37import org.openstreetmap.josm.gui.MapView;
38import org.openstreetmap.josm.gui.SideButton;
39import org.openstreetmap.josm.gui.layer.Layer;
40import org.openstreetmap.josm.gui.layer.OsmDataLayer;
41import org.openstreetmap.josm.gui.util.GuiHelper;
42import org.openstreetmap.josm.tools.ImageProvider;
43import org.openstreetmap.josm.tools.OpenBrowser;
44import org.openstreetmap.josm.tools.Shortcut;
45import org.openstreetmap.josm.tools.Utils;
46
47/**
48 * Displays a dialog with all users who have last edited something in the
49 * selection area, along with the number of objects.
50 *
51 */
52public class UserListDialog extends ToggleDialog implements SelectionChangedListener, MapView.LayerChangeListener {
53
54 /**
55 * The display list.
56 */
57 private JTable userTable;
58 private UserTableModel model;
59 private SelectUsersPrimitivesAction selectionUsersPrimitivesAction;
60 private ShowUserInfoAction showUserInfoAction;
61
62 /**
63 * Constructs a new {@code UserListDialog}.
64 */
65 public UserListDialog() {
66 super(tr("Authors"), "userlist", tr("Open a list of people working on the selected objects."),
67 Shortcut.registerShortcut("subwindow:authors", tr("Toggle: {0}", tr("Authors")), KeyEvent.VK_A, Shortcut.ALT_SHIFT), 150);
68 build();
69 }
70
71 @Override
72 public void showNotify() {
73 DataSet.addSelectionListener(this);
74 MapView.addLayerChangeListener(this);
75 }
76
77 @Override
78 public void hideNotify() {
79 MapView.removeLayerChangeListener(this);
80 DataSet.removeSelectionListener(this);
81 }
82
83 protected void build() {
84 model = new UserTableModel();
85 userTable = new JTable(model);
86 userTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
87 userTable.addMouseListener(new DoubleClickAdapter());
88
89 // -- select users primitives action
90 //
91 selectionUsersPrimitivesAction = new SelectUsersPrimitivesAction();
92 userTable.getSelectionModel().addListSelectionListener(selectionUsersPrimitivesAction);
93
94 // -- info action
95 //
96 showUserInfoAction = new ShowUserInfoAction();
97 userTable.getSelectionModel().addListSelectionListener(showUserInfoAction);
98
99 createLayout(userTable, true, Arrays.asList(new SideButton[] {
100 new SideButton(selectionUsersPrimitivesAction),
101 new SideButton(showUserInfoAction)
102 }));
103 }
104
105 /**
106 * Called when the selection in the dataset changed.
107 * @param newSelection The new selection array.
108 */
109 @Override
110 public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
111 refresh(newSelection);
112 }
113
114 @Override
115 public void activeLayerChange(Layer oldLayer, Layer newLayer) {
116 if (newLayer instanceof OsmDataLayer) {
117 refresh(((OsmDataLayer) newLayer).data.getAllSelected());
118 } else {
119 refresh(null);
120 }
121 }
122
123 @Override
124 public void layerAdded(Layer newLayer) {
125 // do nothing
126 }
127
128 @Override
129 public void layerRemoved(Layer oldLayer) {
130 // do nothing
131 }
132
133 public void refresh(Collection<? extends OsmPrimitive> fromPrimitives) {
134 model.populate(fromPrimitives);
135 GuiHelper.runInEDT(new Runnable() {
136 @Override
137 public void run() {
138 if (model.getRowCount() != 0) {
139 setTitle(trn("{0} Author", "{0} Authors", model.getRowCount(), model.getRowCount()));
140 } else {
141 setTitle(tr("Authors"));
142 }
143 }
144 });
145 }
146
147 @Override
148 public void showDialog() {
149 super.showDialog();
150 Layer layer = Main.main.getActiveLayer();
151 if (layer instanceof OsmDataLayer) {
152 refresh(((OsmDataLayer) layer).data.getAllSelected());
153 }
154
155 }
156
157 class SelectUsersPrimitivesAction extends AbstractAction implements ListSelectionListener {
158
159 /**
160 * Constructs a new {@code SelectUsersPrimitivesAction}.
161 */
162 SelectUsersPrimitivesAction() {
163 putValue(NAME, tr("Select"));
164 putValue(SHORT_DESCRIPTION, tr("Select objects submitted by this user"));
165 putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
166 updateEnabledState();
167 }
168
169 public void select() {
170 int[] indexes = userTable.getSelectedRows();
171 if (indexes == null || indexes.length == 0) return;
172 model.selectPrimitivesOwnedBy(userTable.getSelectedRows());
173 }
174
175 @Override
176 public void actionPerformed(ActionEvent e) {
177 select();
178 }
179
180 protected void updateEnabledState() {
181 setEnabled(userTable != null && userTable.getSelectedRowCount() > 0);
182 }
183
184 @Override
185 public void valueChanged(ListSelectionEvent e) {
186 updateEnabledState();
187 }
188 }
189
190 /*
191 * Action for launching the info page of a user
192 */
193 class ShowUserInfoAction extends AbstractInfoAction implements ListSelectionListener {
194
195 ShowUserInfoAction() {
196 super(false);
197 putValue(NAME, tr("Show info"));
198 putValue(SHORT_DESCRIPTION, tr("Launches a browser with information about the user"));
199 putValue(SMALL_ICON, ImageProvider.get("help/internet"));
200 updateEnabledState();
201 }
202
203 @Override
204 public void actionPerformed(ActionEvent e) {
205 int[] rows = userTable.getSelectedRows();
206 if (rows == null || rows.length == 0) return;
207 List<User> users = model.getSelectedUsers(rows);
208 if (users.isEmpty()) return;
209 if (users.size() > 10) {
210 Main.warn(tr("Only launching info browsers for the first {0} of {1} selected users", 10, users.size()));
211 }
212 int num = Math.min(10, users.size());
213 Iterator<User> it = users.iterator();
214 while (it.hasNext() && num > 0) {
215 String url = createInfoUrl(it.next());
216 if (url == null) {
217 break;
218 }
219 OpenBrowser.displayUrl(url);
220 num--;
221 }
222 }
223
224 @Override
225 protected String createInfoUrl(Object infoObject) {
226 if (infoObject instanceof User) {
227 User user = (User) infoObject;
228 return Main.getBaseUserUrl() + '/' + Utils.encodeUrl(user.getName()).replaceAll("\\+", "%20");
229 } else {
230 return null;
231 }
232 }
233
234 @Override
235 protected void updateEnabledState() {
236 setEnabled(userTable != null && userTable.getSelectedRowCount() > 0);
237 }
238
239 @Override
240 public void valueChanged(ListSelectionEvent e) {
241 updateEnabledState();
242 }
243 }
244
245 class DoubleClickAdapter extends MouseAdapter {
246 @Override
247 public void mouseClicked(MouseEvent e) {
248 if (e.getButton() == MouseEvent.BUTTON1 && e.getClickCount() == 2) {
249 selectionUsersPrimitivesAction.select();
250 }
251 }
252 }
253
254 /**
255 * Action for selecting the primitives contributed by the currently selected users.
256 *
257 */
258 private static class UserInfo implements Comparable<UserInfo> {
259 public User user;
260 public int count;
261 public double percent;
262
263 UserInfo(User user, int count, double percent) {
264 this.user = user;
265 this.count = count;
266 this.percent = percent;
267 }
268
269 @Override
270 public int compareTo(UserInfo o) {
271 if (count < o.count) return 1;
272 if (count > o.count) return -1;
273 if (user == null || user.getName() == null) return 1;
274 if (o.user == null || o.user.getName() == null) return -1;
275 return user.getName().compareTo(o.user.getName());
276 }
277
278 public String getName() {
279 if (user == null)
280 return tr("<new object>");
281 return user.getName();
282 }
283 }
284
285 /**
286 * The table model for the users
287 *
288 */
289 static class UserTableModel extends DefaultTableModel {
290 private transient List<UserInfo> data;
291
292 UserTableModel() {
293 setColumnIdentifiers(new String[]{tr("Author"), tr("# Objects"), "%"});
294 data = new ArrayList<>();
295 }
296
297 protected Map<User, Integer> computeStatistics(Collection<? extends OsmPrimitive> primitives) {
298 Map<User, Integer> ret = new HashMap<>();
299 if (primitives == null || primitives.isEmpty()) return ret;
300 for (OsmPrimitive primitive: primitives) {
301 if (ret.containsKey(primitive.getUser())) {
302 ret.put(primitive.getUser(), ret.get(primitive.getUser()) + 1);
303 } else {
304 ret.put(primitive.getUser(), 1);
305 }
306 }
307 return ret;
308 }
309
310 public void populate(Collection<? extends OsmPrimitive> primitives) {
311 Map<User, Integer> statistics = computeStatistics(primitives);
312 data.clear();
313 if (primitives != null) {
314 for (Map.Entry<User, Integer> entry: statistics.entrySet()) {
315 data.add(new UserInfo(entry.getKey(), entry.getValue(), (double) entry.getValue() / (double) primitives.size()));
316 }
317 }
318 Collections.sort(data);
319 GuiHelper.runInEDTAndWait(new Runnable() {
320 @Override
321 public void run() {
322 fireTableDataChanged();
323 }
324 });
325 }
326
327 @Override
328 public int getRowCount() {
329 if (data == null) return 0;
330 return data.size();
331 }
332
333 @Override
334 public Object getValueAt(int row, int column) {
335 UserInfo info = data.get(row);
336 switch(column) {
337 case 0: /* author */ return info.getName() == null ? "" : info.getName();
338 case 1: /* count */ return info.count;
339 case 2: /* percent */ return NumberFormat.getPercentInstance().format(info.percent);
340 }
341 return null;
342 }
343
344 @Override
345 public boolean isCellEditable(int row, int column) {
346 return false;
347 }
348
349 public void selectPrimitivesOwnedBy(int[] rows) {
350 Set<User> users = new HashSet<>();
351 for (int index: rows) {
352 users.add(data.get(index).user);
353 }
354 Collection<OsmPrimitive> selected = Main.main.getCurrentDataSet().getAllSelected();
355 Collection<OsmPrimitive> byUser = new LinkedList<>();
356 for (OsmPrimitive p : selected) {
357 if (users.contains(p.getUser())) {
358 byUser.add(p);
359 }
360 }
361 Main.main.getCurrentDataSet().setSelected(byUser);
362 }
363
364 public List<User> getSelectedUsers(int[] rows) {
365 List<User> ret = new LinkedList<>();
366 if (rows == null || rows.length == 0) return ret;
367 for (int row: rows) {
368 if (data.get(row).user == null) {
369 continue;
370 }
371 ret.add(data.get(row).user);
372 }
373 return ret;
374 }
375 }
376}
Note: See TracBrowser for help on using the repository browser.