source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/NotesDialog.java@ 12279

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

sonar - squid:S3878 - Arrays should not be created for varargs parameters

  • Property svn:eol-style set to native
File size: 15.9 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;
5
6import java.awt.BorderLayout;
7import java.awt.Component;
8import java.awt.event.ActionEvent;
9import java.awt.event.MouseAdapter;
10import java.awt.event.MouseEvent;
11import java.text.DateFormat;
12import java.util.ArrayList;
13import java.util.Arrays;
14import java.util.Collection;
15import java.util.List;
16
17import javax.swing.AbstractAction;
18import javax.swing.AbstractListModel;
19import javax.swing.DefaultListCellRenderer;
20import javax.swing.ImageIcon;
21import javax.swing.JLabel;
22import javax.swing.JList;
23import javax.swing.JOptionPane;
24import javax.swing.JPanel;
25import javax.swing.JScrollPane;
26import javax.swing.ListCellRenderer;
27import javax.swing.ListSelectionModel;
28import javax.swing.SwingUtilities;
29
30import org.openstreetmap.josm.Main;
31import org.openstreetmap.josm.actions.DownloadNotesInViewAction;
32import org.openstreetmap.josm.actions.UploadNotesAction;
33import org.openstreetmap.josm.actions.mapmode.AddNoteAction;
34import org.openstreetmap.josm.data.notes.Note;
35import org.openstreetmap.josm.data.notes.Note.State;
36import org.openstreetmap.josm.data.notes.NoteComment;
37import org.openstreetmap.josm.data.osm.NoteData;
38import org.openstreetmap.josm.gui.NoteInputDialog;
39import org.openstreetmap.josm.gui.NoteSortDialog;
40import org.openstreetmap.josm.gui.SideButton;
41import org.openstreetmap.josm.gui.layer.LayerManager.LayerAddEvent;
42import org.openstreetmap.josm.gui.layer.LayerManager.LayerChangeListener;
43import org.openstreetmap.josm.gui.layer.LayerManager.LayerOrderChangeEvent;
44import org.openstreetmap.josm.gui.layer.LayerManager.LayerRemoveEvent;
45import org.openstreetmap.josm.gui.layer.NoteLayer;
46import org.openstreetmap.josm.tools.ImageProvider;
47import org.openstreetmap.josm.tools.OpenBrowser;
48import org.openstreetmap.josm.tools.date.DateUtils;
49
50/**
51 * Dialog to display and manipulate notes.
52 * @since 7852 (renaming)
53 * @since 7608 (creation)
54 */
55public class NotesDialog extends ToggleDialog implements LayerChangeListener {
56
57 private NoteTableModel model;
58 private JList<Note> displayList;
59 private final AddCommentAction addCommentAction;
60 private final CloseAction closeAction;
61 private final DownloadNotesInViewAction downloadNotesInViewAction;
62 private final NewAction newAction;
63 private final ReopenAction reopenAction;
64 private final SortAction sortAction;
65 private final OpenInBrowserAction openInBrowserAction;
66 private final UploadNotesAction uploadAction;
67
68 private transient NoteData noteData;
69
70 /** Creates a new toggle dialog for notes */
71 public NotesDialog() {
72 super(tr("Notes"), "notes/note_open", tr("List of notes"), null, 150);
73 addCommentAction = new AddCommentAction();
74 closeAction = new CloseAction();
75 downloadNotesInViewAction = DownloadNotesInViewAction.newActionWithDownloadIcon();
76 newAction = new NewAction();
77 reopenAction = new ReopenAction();
78 sortAction = new SortAction();
79 openInBrowserAction = new OpenInBrowserAction();
80 uploadAction = new UploadNotesAction();
81 buildDialog();
82 Main.getLayerManager().addLayerChangeListener(this);
83 }
84
85 private void buildDialog() {
86 model = new NoteTableModel();
87 displayList = new JList<>(model);
88 displayList.setCellRenderer(new NoteRenderer());
89 displayList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
90 displayList.addListSelectionListener(e -> {
91 if (noteData != null) { //happens when layer is deleted while note selected
92 noteData.setSelectedNote(displayList.getSelectedValue());
93 }
94 updateButtonStates();
95 });
96 displayList.addMouseListener(new MouseAdapter() {
97 //center view on selected note on double click
98 @Override
99 public void mouseClicked(MouseEvent e) {
100 if (SwingUtilities.isLeftMouseButton(e) && e.getClickCount() == 2 && noteData != null && noteData.getSelectedNote() != null) {
101 Main.map.mapView.zoomTo(noteData.getSelectedNote().getLatLon());
102 }
103 }
104 });
105
106 JPanel pane = new JPanel(new BorderLayout());
107 pane.add(new JScrollPane(displayList), BorderLayout.CENTER);
108
109 createLayout(pane, false, Arrays.asList(
110 new SideButton(downloadNotesInViewAction, false),
111 new SideButton(newAction, false),
112 new SideButton(addCommentAction, false),
113 new SideButton(closeAction, false),
114 new SideButton(reopenAction, false),
115 new SideButton(sortAction, false),
116 new SideButton(openInBrowserAction, false),
117 new SideButton(uploadAction, false)));
118 updateButtonStates();
119 }
120
121 private void updateButtonStates() {
122 if (noteData == null || noteData.getSelectedNote() == null) {
123 closeAction.setEnabled(false);
124 addCommentAction.setEnabled(false);
125 reopenAction.setEnabled(false);
126 } else if (noteData.getSelectedNote().getState() == State.OPEN) {
127 closeAction.setEnabled(true);
128 addCommentAction.setEnabled(true);
129 reopenAction.setEnabled(false);
130 } else { //note is closed
131 closeAction.setEnabled(false);
132 addCommentAction.setEnabled(false);
133 reopenAction.setEnabled(true);
134 }
135 openInBrowserAction.setEnabled(noteData != null && noteData.getSelectedNote() != null && noteData.getSelectedNote().getId() > 0);
136 if (noteData == null || !noteData.isModified()) {
137 uploadAction.setEnabled(false);
138 } else {
139 uploadAction.setEnabled(true);
140 }
141 //enable sort button if any notes are loaded
142 if (noteData == null || noteData.getNotes().isEmpty()) {
143 sortAction.setEnabled(false);
144 } else {
145 sortAction.setEnabled(true);
146 }
147 }
148
149 @Override
150 public void layerAdded(LayerAddEvent e) {
151 if (e.getAddedLayer() instanceof NoteLayer) {
152 noteData = ((NoteLayer) e.getAddedLayer()).getNoteData();
153 model.setData(noteData.getNotes());
154 setNotes(noteData.getSortedNotes());
155 }
156 }
157
158 @Override
159 public void layerRemoving(LayerRemoveEvent e) {
160 if (e.getRemovedLayer() instanceof NoteLayer) {
161 noteData = null;
162 model.clearData();
163 if (Main.map.mapMode instanceof AddNoteAction) {
164 Main.map.selectMapMode(Main.map.mapModeSelect);
165 }
166 }
167 }
168
169 @Override
170 public void layerOrderChanged(LayerOrderChangeEvent e) {
171 // ignored
172 }
173
174 /**
175 * Sets the list of notes to be displayed in the dialog.
176 * The dialog should match the notes displayed in the note layer.
177 * @param noteList List of notes to display
178 */
179 public void setNotes(Collection<Note> noteList) {
180 model.setData(noteList);
181 updateButtonStates();
182 this.repaint();
183 }
184
185 /**
186 * Notify the dialog that the note selection has changed.
187 * Causes it to update or clear its selection in the UI.
188 */
189 public void selectionChanged() {
190 if (noteData == null || noteData.getSelectedNote() == null) {
191 displayList.clearSelection();
192 } else {
193 displayList.setSelectedValue(noteData.getSelectedNote(), true);
194 }
195 updateButtonStates();
196 // TODO make a proper listener mechanism to handle change of note selection
197 Main.main.menu.infoweb.noteSelectionChanged();
198 }
199
200 /**
201 * Returns the currently selected note, if any.
202 * @return currently selected note, or null
203 * @since 8475
204 */
205 public Note getSelectedNote() {
206 return noteData != null ? noteData.getSelectedNote() : null;
207 }
208
209 private static class NoteRenderer implements ListCellRenderer<Note> {
210
211 private final DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
212 private final DateFormat dateFormat = DateUtils.getDateTimeFormat(DateFormat.MEDIUM, DateFormat.SHORT);
213
214 @Override
215 public Component getListCellRendererComponent(JList<? extends Note> list, Note note, int index,
216 boolean isSelected, boolean cellHasFocus) {
217 Component comp = defaultListCellRenderer.getListCellRendererComponent(list, note, index, isSelected, cellHasFocus);
218 if (note != null && comp instanceof JLabel) {
219 NoteComment fstComment = note.getFirstComment();
220 JLabel jlabel = (JLabel) comp;
221 if (fstComment != null) {
222 String text = note.getFirstComment().getText();
223 String userName = note.getFirstComment().getUser().getName();
224 if (userName == null || userName.isEmpty()) {
225 userName = "<Anonymous>";
226 }
227 String toolTipText = userName + " @ " + dateFormat.format(note.getCreatedAt());
228 jlabel.setToolTipText(toolTipText);
229 jlabel.setText(note.getId() + ": " +text);
230 } else {
231 jlabel.setToolTipText(null);
232 jlabel.setText(Long.toString(note.getId()));
233 }
234 ImageIcon icon;
235 if (note.getId() < 0) {
236 icon = ImageProvider.get("dialogs/notes", "note_new", ImageProvider.ImageSizes.SMALLICON);
237 } else if (note.getState() == State.CLOSED) {
238 icon = ImageProvider.get("dialogs/notes", "note_closed", ImageProvider.ImageSizes.SMALLICON);
239 } else {
240 icon = ImageProvider.get("dialogs/notes", "note_open", ImageProvider.ImageSizes.SMALLICON);
241 }
242 jlabel.setIcon(icon);
243 }
244 return comp;
245 }
246 }
247
248 class NoteTableModel extends AbstractListModel<Note> {
249 private final transient List<Note> data;
250
251 /**
252 * Constructs a new {@code NoteTableModel}.
253 */
254 NoteTableModel() {
255 data = new ArrayList<>();
256 }
257
258 @Override
259 public int getSize() {
260 if (data == null) {
261 return 0;
262 }
263 return data.size();
264 }
265
266 @Override
267 public Note getElementAt(int index) {
268 return data.get(index);
269 }
270
271 public void setData(Collection<Note> noteList) {
272 data.clear();
273 data.addAll(noteList);
274 fireContentsChanged(this, 0, noteList.size());
275 }
276
277 public void clearData() {
278 displayList.clearSelection();
279 data.clear();
280 fireIntervalRemoved(this, 0, getSize());
281 }
282 }
283
284 class AddCommentAction extends AbstractAction {
285
286 /**
287 * Constructs a new {@code AddCommentAction}.
288 */
289 AddCommentAction() {
290 putValue(SHORT_DESCRIPTION, tr("Add comment"));
291 putValue(NAME, tr("Comment"));
292 new ImageProvider("dialogs/notes", "note_comment").getResource().attachImageIcon(this, true);
293 }
294
295 @Override
296 public void actionPerformed(ActionEvent e) {
297 Note note = displayList.getSelectedValue();
298 if (note == null) {
299 JOptionPane.showMessageDialog(Main.map,
300 "You must select a note first",
301 "No note selected",
302 JOptionPane.ERROR_MESSAGE);
303 return;
304 }
305 NoteInputDialog dialog = new NoteInputDialog(Main.parent, tr("Comment on note"), tr("Add comment"));
306 dialog.showNoteDialog(tr("Add comment to note:"), ImageProvider.get("dialogs/notes", "note_comment"));
307 if (dialog.getValue() != 1) {
308 return;
309 }
310 int selectedIndex = displayList.getSelectedIndex();
311 noteData.addCommentToNote(note, dialog.getInputText());
312 noteData.setSelectedNote(model.getElementAt(selectedIndex));
313 }
314 }
315
316 class CloseAction extends AbstractAction {
317
318 /**
319 * Constructs a new {@code CloseAction}.
320 */
321 CloseAction() {
322 putValue(SHORT_DESCRIPTION, tr("Close note"));
323 putValue(NAME, tr("Close"));
324 new ImageProvider("dialogs/notes", "note_closed").getResource().attachImageIcon(this, true);
325 }
326
327 @Override
328 public void actionPerformed(ActionEvent e) {
329 NoteInputDialog dialog = new NoteInputDialog(Main.parent, tr("Close note"), tr("Close note"));
330 dialog.showNoteDialog(tr("Close note with message:"), ImageProvider.get("dialogs/notes", "note_closed"));
331 if (dialog.getValue() != 1) {
332 return;
333 }
334 Note note = displayList.getSelectedValue();
335 int selectedIndex = displayList.getSelectedIndex();
336 noteData.closeNote(note, dialog.getInputText());
337 noteData.setSelectedNote(model.getElementAt(selectedIndex));
338 }
339 }
340
341 class NewAction extends AbstractAction {
342
343 /**
344 * Constructs a new {@code NewAction}.
345 */
346 NewAction() {
347 putValue(SHORT_DESCRIPTION, tr("Create a new note"));
348 putValue(NAME, tr("Create"));
349 new ImageProvider("dialogs/notes", "note_new").getResource().attachImageIcon(this, true);
350 }
351
352 @Override
353 public void actionPerformed(ActionEvent e) {
354 if (noteData == null) { //there is no notes layer. Create one first
355 Main.getLayerManager().addLayer(new NoteLayer());
356 }
357 Main.map.selectMapMode(new AddNoteAction(noteData));
358 }
359 }
360
361 class ReopenAction extends AbstractAction {
362
363 /**
364 * Constructs a new {@code ReopenAction}.
365 */
366 ReopenAction() {
367 putValue(SHORT_DESCRIPTION, tr("Reopen note"));
368 putValue(NAME, tr("Reopen"));
369 new ImageProvider("dialogs/notes", "note_open").getResource().attachImageIcon(this, true);
370 }
371
372 @Override
373 public void actionPerformed(ActionEvent e) {
374 NoteInputDialog dialog = new NoteInputDialog(Main.parent, tr("Reopen note"), tr("Reopen note"));
375 dialog.showNoteDialog(tr("Reopen note with message:"), ImageProvider.get("dialogs/notes", "note_open"));
376 if (dialog.getValue() != 1) {
377 return;
378 }
379
380 Note note = displayList.getSelectedValue();
381 int selectedIndex = displayList.getSelectedIndex();
382 noteData.reOpenNote(note, dialog.getInputText());
383 noteData.setSelectedNote(model.getElementAt(selectedIndex));
384 }
385 }
386
387 class SortAction extends AbstractAction {
388
389 /**
390 * Constructs a new {@code SortAction}.
391 */
392 SortAction() {
393 putValue(SHORT_DESCRIPTION, tr("Sort notes"));
394 putValue(NAME, tr("Sort"));
395 new ImageProvider("dialogs", "sort").getResource().attachImageIcon(this, true);
396 }
397
398 @Override
399 public void actionPerformed(ActionEvent e) {
400 NoteSortDialog sortDialog = new NoteSortDialog(Main.parent, tr("Sort notes"), tr("Apply"));
401 sortDialog.showSortDialog(noteData.getCurrentSortMethod());
402 if (sortDialog.getValue() == 1) {
403 noteData.setSortMethod(sortDialog.getSelectedComparator());
404 }
405 }
406 }
407
408 class OpenInBrowserAction extends AbstractAction {
409 OpenInBrowserAction() {
410 putValue(SHORT_DESCRIPTION, tr("Open the note in an external browser"));
411 new ImageProvider("help", "internet").getResource().attachImageIcon(this, true);
412 }
413
414 @Override
415 public void actionPerformed(ActionEvent e) {
416 final Note note = displayList.getSelectedValue();
417 if (note.getId() > 0) {
418 final String url = Main.getBaseBrowseUrl() + "/note/" + note.getId();
419 OpenBrowser.displayUrl(url);
420 }
421 }
422 }
423}
Note: See TracBrowser for help on using the repository browser.