source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/NoteDialog.java@ 7782

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

fix #10826 - Add note sorting options (patch by ToeBee)

File size: 13.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.Image;
9import java.awt.event.ActionEvent;
10import java.text.SimpleDateFormat;
11import java.util.ArrayList;
12import java.util.Arrays;
13import java.util.List;
14
15import javax.swing.AbstractAction;
16import javax.swing.AbstractListModel;
17import javax.swing.DefaultListCellRenderer;
18import javax.swing.ImageIcon;
19import javax.swing.JLabel;
20import javax.swing.JList;
21import javax.swing.JOptionPane;
22import javax.swing.JPanel;
23import javax.swing.JScrollPane;
24import javax.swing.ListCellRenderer;
25import javax.swing.ListSelectionModel;
26import javax.swing.event.ListSelectionEvent;
27import javax.swing.event.ListSelectionListener;
28
29import org.openstreetmap.josm.Main;
30import org.openstreetmap.josm.actions.UploadNotesAction;
31import org.openstreetmap.josm.actions.mapmode.AddNoteAction;
32import org.openstreetmap.josm.data.notes.Note;
33import org.openstreetmap.josm.data.notes.Note.State;
34import org.openstreetmap.josm.data.osm.NoteData;
35import org.openstreetmap.josm.gui.MapView;
36import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
37import org.openstreetmap.josm.gui.NoteInputDialog;
38import org.openstreetmap.josm.gui.NoteSortDialog;
39import org.openstreetmap.josm.gui.SideButton;
40import org.openstreetmap.josm.gui.layer.Layer;
41import org.openstreetmap.josm.gui.layer.NoteLayer;
42import org.openstreetmap.josm.tools.ImageProvider;
43
44/**
45 * Dialog to display and manipulate notes
46 */
47public class NoteDialog extends ToggleDialog implements LayerChangeListener {
48
49
50 /** Small icon size for use in graphics calculations */
51 public static final int ICON_SMALL_SIZE = 16;
52 /** Large icon size for use in graphics calculations */
53 public static final int ICON_LARGE_SIZE = 24;
54 /** 24x24 icon for unresolved notes */
55 public static final ImageIcon ICON_OPEN = ImageProvider.get("dialogs/notes", "note_open.png");
56 /** 16x16 icon for unresolved notes */
57 public static final ImageIcon ICON_OPEN_SMALL =
58 new ImageIcon(ICON_OPEN.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH));
59 /** 24x24 icon for resolved notes */
60 public static final ImageIcon ICON_CLOSED = ImageProvider.get("dialogs/notes", "note_closed.png");
61 /** 16x16 icon for resolved notes */
62 public static final ImageIcon ICON_CLOSED_SMALL =
63 new ImageIcon(ICON_CLOSED.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH));
64 /** 24x24 icon for new notes */
65 public static final ImageIcon ICON_NEW = ImageProvider.get("dialogs/notes", "note_new.png");
66 /** 16x16 icon for new notes */
67 public static final ImageIcon ICON_NEW_SMALL =
68 new ImageIcon(ICON_NEW.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH));
69 /** Icon for note comments */
70 public static final ImageIcon ICON_COMMENT = ImageProvider.get("dialogs/notes", "note_comment.png");
71
72 private NoteTableModel model;
73 private JList<Note> displayList;
74 private final AddCommentAction addCommentAction;
75 private final CloseAction closeAction;
76 private final NewAction newAction;
77 private final ReopenAction reopenAction;
78 private final SortAction sortAction;
79 private final UploadNotesAction uploadAction;
80
81 private NoteData noteData;
82
83 /** Creates a new toggle dialog for notes */
84 public NoteDialog() {
85 super("Notes", "notes/note_open.png", "List of notes", null, 150);
86 if (Main.isDebugEnabled()) {
87 Main.debug("constructed note dialog");
88 }
89
90 addCommentAction = new AddCommentAction();
91 closeAction = new CloseAction();
92 newAction = new NewAction();
93 reopenAction = new ReopenAction();
94 sortAction = new SortAction();
95 uploadAction = new UploadNotesAction();
96 buildDialog();
97 }
98
99 @Override
100 public void showDialog() {
101 super.showDialog();
102 }
103
104 private void buildDialog() {
105 model = new NoteTableModel();
106 displayList = new JList<Note>(model);
107 displayList.setCellRenderer(new NoteRenderer());
108 displayList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
109 displayList.addListSelectionListener(new ListSelectionListener() {
110 @Override
111 public void valueChanged(ListSelectionEvent e) {
112 if (noteData != null) { //happens when layer is deleted while note selected
113 noteData.setSelectedNote(displayList.getSelectedValue());
114 }
115 updateButtonStates();
116 }});
117
118 JPanel pane = new JPanel(new BorderLayout());
119 pane.add(new JScrollPane(displayList), BorderLayout.CENTER);
120
121 createLayout(pane, false, Arrays.asList(new SideButton[]{
122 new SideButton(newAction, false),
123 new SideButton(addCommentAction, false),
124 new SideButton(closeAction, false),
125 new SideButton(reopenAction, false),
126 new SideButton(sortAction, false),
127 new SideButton(uploadAction, false)}));
128 updateButtonStates();
129 }
130
131 private void updateButtonStates() {
132 if (noteData == null || noteData.getSelectedNote() == null) {
133 closeAction.setEnabled(false);
134 addCommentAction.setEnabled(false);
135 reopenAction.setEnabled(false);
136 } else if (noteData.getSelectedNote().getState() == State.open){
137 closeAction.setEnabled(true);
138 addCommentAction.setEnabled(true);
139 reopenAction.setEnabled(false);
140 } else { //note is closed
141 closeAction.setEnabled(false);
142 addCommentAction.setEnabled(false);
143 reopenAction.setEnabled(true);
144 }
145 if(noteData == null || !noteData.isModified()) {
146 uploadAction.setEnabled(false);
147 } else {
148 uploadAction.setEnabled(true);
149 }
150 //enable sort button if any notes are loaded
151 if (noteData == null || noteData.getNotes().isEmpty()) {
152 sortAction.setEnabled(false);
153 } else {
154 sortAction.setEnabled(true);
155 }
156 }
157
158 @Override
159 public void showNotify() {
160 MapView.addLayerChangeListener(this);
161 }
162
163 @Override
164 public void hideNotify() {
165 MapView.removeLayerChangeListener(this);
166 }
167
168 @Override
169 public void activeLayerChange(Layer oldLayer, Layer newLayer) { }
170
171 @Override
172 public void layerAdded(Layer newLayer) {
173 if (newLayer instanceof NoteLayer) {
174 noteData = ((NoteLayer)newLayer).getNoteData();
175 model.setData(noteData.getNotes());
176 setNoteList(noteData.getNotes());
177 }
178 }
179
180 @Override
181 public void layerRemoved(Layer oldLayer) {
182 if (oldLayer instanceof NoteLayer) {
183 if (Main.isDebugEnabled()) {
184 Main.debug("note layer removed. Clearing everything");
185 }
186 noteData = null;
187 model.clearData();
188 if (Main.map.mapMode instanceof AddNoteAction) {
189 Main.map.selectMapMode(Main.map.mapModeSelect);
190 }
191 }
192 }
193
194 /**
195 * Sets the list of notes to be displayed in the dialog.
196 * The dialog should match the notes displayed in the note layer.
197 * @param noteList List of notes to display
198 */
199 public void setNoteList(List<Note> noteList) {
200 model.setData(noteList);
201 updateButtonStates();
202 this.repaint();
203 }
204
205 /**
206 * Notify the dialog that the note selection has changed.
207 * Causes it to update or clear its selection in the UI.
208 */
209 public void selectionChanged() {
210 if (noteData == null || noteData.getSelectedNote() == null) {
211 displayList.clearSelection();
212 } else {
213 displayList.setSelectedValue(noteData.getSelectedNote(), true);
214 }
215 updateButtonStates();
216 }
217
218 private class NoteRenderer implements ListCellRenderer<Note> {
219
220 private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer();
221 private final SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy kk:mm");
222
223 @Override
224 public Component getListCellRendererComponent(JList<? extends Note> list, Note note, int index,
225 boolean isSelected, boolean cellHasFocus) {
226 Component comp = defaultListCellRenderer.getListCellRendererComponent(list, note, index, isSelected, cellHasFocus);
227 if (note != null && comp instanceof JLabel) {
228 String text = note.getFirstComment().getText();
229 String userName = note.getFirstComment().getUser().getName();
230 if (userName == null || userName.isEmpty()) {
231 userName = "<Anonymous>";
232 }
233 String toolTipText = userName + " @ " + sdf.format(note.getCreatedAt());
234 JLabel jlabel = (JLabel)comp;
235 jlabel.setText(text);
236 ImageIcon icon;
237 if (note.getId() < 0) {
238 icon = ICON_NEW_SMALL;
239 } else if (note.getState() == State.closed) {
240 icon = ICON_CLOSED_SMALL;
241 } else {
242 icon = ICON_OPEN_SMALL;
243 }
244 jlabel.setIcon(icon);
245 jlabel.setToolTipText(toolTipText);
246 }
247 return comp;
248 }
249 }
250
251 class NoteTableModel extends AbstractListModel<Note> {
252 private List<Note> data;
253
254 public NoteTableModel() {
255 data = new ArrayList<Note>();
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(List<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 public AddCommentAction() {
287 putValue(SHORT_DESCRIPTION,tr("Add comment"));
288 putValue(NAME, tr("Comment"));
289 putValue(SMALL_ICON, ICON_COMMENT);
290 }
291
292 @Override
293 public void actionPerformed(ActionEvent e) {
294 Note note = displayList.getSelectedValue();
295 if (note == null) {
296 JOptionPane.showMessageDialog(Main.map,
297 "You must select a note first",
298 "No note selected",
299 JOptionPane.ERROR_MESSAGE);
300 return;
301 }
302 NoteInputDialog dialog = new NoteInputDialog(Main.parent, tr("Comment on note"), tr("Add comment"));
303 dialog.showNoteDialog(tr("Add comment to note:"), NoteDialog.ICON_COMMENT);
304 if (dialog.getValue() != 1) {
305 Main.debug("User aborted note reopening");
306 return;
307 }
308 noteData.addCommentToNote(note, dialog.getInputText());
309 }
310 }
311
312 class CloseAction extends AbstractAction {
313
314 public CloseAction() {
315 putValue(SHORT_DESCRIPTION,tr("Close note"));
316 putValue(NAME, tr("Close"));
317 putValue(SMALL_ICON, ICON_CLOSED);
318 }
319
320 @Override
321 public void actionPerformed(ActionEvent e) {
322 NoteInputDialog dialog = new NoteInputDialog(Main.parent, tr("Close note"), tr("Close note"));
323 dialog.showNoteDialog(tr("Close note with message:"), NoteDialog.ICON_CLOSED);
324 if (dialog.getValue() != 1) {
325 Main.debug("User aborted note closing");
326 return;
327 }
328 Note note = displayList.getSelectedValue();
329 noteData.closeNote(note, dialog.getInputText());
330 }
331 }
332
333 class NewAction extends AbstractAction {
334
335 public NewAction() {
336 putValue(SHORT_DESCRIPTION,tr("Create a new note"));
337 putValue(NAME, tr("Create"));
338 putValue(SMALL_ICON, ICON_NEW);
339 }
340
341 @Override
342 public void actionPerformed(ActionEvent e) {
343 if (noteData == null) { //there is no notes layer. Create one first
344 Main.map.mapView.addLayer(new NoteLayer());
345 }
346 Main.map.selectMapMode(new AddNoteAction(Main.map, noteData));
347 }
348 }
349
350 class ReopenAction extends AbstractAction {
351
352 public ReopenAction() {
353 putValue(SHORT_DESCRIPTION,tr("Reopen note"));
354 putValue(NAME, tr("Reopen"));
355 putValue(SMALL_ICON, ICON_OPEN);
356 }
357
358 @Override
359 public void actionPerformed(ActionEvent e) {
360 NoteInputDialog dialog = new NoteInputDialog(Main.parent, tr("Reopen note"), tr("Reopen note"));
361 dialog.showNoteDialog(tr("Reopen note with message:"), NoteDialog.ICON_OPEN);
362 if (dialog.getValue() != 1) {
363 Main.debug("User aborted note reopening");
364 return;
365 }
366
367 Note note = displayList.getSelectedValue();
368 noteData.reOpenNote(note, dialog.getInputText());
369 }
370 }
371
372 class SortAction extends AbstractAction {
373
374 public SortAction() {
375 putValue(SHORT_DESCRIPTION, tr("Sort notes"));
376 putValue(NAME, tr("Sort"));
377 putValue(SMALL_ICON, ImageProvider.get("dialogs", "sort"));
378 }
379
380 @Override
381 public void actionPerformed(ActionEvent e) {
382 NoteSortDialog sortDialog = new NoteSortDialog(Main.parent, tr("Sort notes"), tr("Apply"));
383 sortDialog.showSortDialog(noteData.getCurrentSortMethod());
384 if (sortDialog.getValue() == 1) {
385 noteData.setSortMethod(sortDialog.getSelectedComparator());
386 }
387 }
388 }
389}
Note: See TracBrowser for help on using the repository browser.