Ticket #10554: note_dialog.patch
| File note_dialog.patch, 33.8 KB (added by , 12 years ago) |
|---|
-
src/org/openstreetmap/josm/actions/downloadtasks/DownloadNotesTask.java
96 96 NoteLayer layer; 97 97 if (noteLayers != null && noteLayers.size() > 0) { 98 98 layer = noteLayers.get(0); 99 layer. addNotes(notesData);99 layer.getNoteData().addNotes(notesData); 100 100 } else { 101 101 layer = new NoteLayer(notesData, "Notes"); 102 102 Main.main.addLayer(layer); -
src/org/openstreetmap/josm/actions/mapmode/AddNoteAction.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.actions.mapmode; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.awt.event.MouseEvent; 7 8 import javax.swing.JLabel; 9 import javax.swing.JOptionPane; 10 import javax.swing.JScrollPane; 11 import javax.swing.JTextArea; 12 13 import org.openstreetmap.josm.Main; 14 import org.openstreetmap.josm.data.coor.LatLon; 15 import org.openstreetmap.josm.data.osm.NoteData; 16 import org.openstreetmap.josm.gui.MapFrame; 17 import org.openstreetmap.josm.gui.Notification; 18 import org.openstreetmap.josm.gui.dialogs.NoteDialog; 19 import org.openstreetmap.josm.tools.ImageProvider; 20 21 /** 22 * Map mode to add a new note. Listens for a mouse click and then 23 * prompts the user for text and adds a note to the note layer 24 */ 25 public class AddNoteAction extends MapMode { 26 27 private NoteData noteData; 28 29 /** 30 * Construct a new map mode. 31 * @param mapFrame Map frame to pass to the superconstructor 32 * @param data Note data container. Must not be null 33 */ 34 public AddNoteAction(MapFrame mapFrame, NoteData data) { 35 super(tr("Add a new Note"), "addnote.png", 36 tr("Add note mode"), 37 mapFrame, ImageProvider.getCursor("crosshair", "create_note")); 38 if (data == null) { 39 throw new IllegalArgumentException("Note data must not be null"); 40 } 41 noteData = data; 42 } 43 44 @Override 45 public String getModeHelpText() { 46 return tr("Click the location where you wish to create a new note"); 47 } 48 49 @Override 50 public void enterMode() { 51 super.enterMode(); 52 Main.map.mapView.addMouseListener(this); 53 } 54 55 @Override 56 public void exitMode() { 57 super.exitMode(); 58 Main.map.mapView.removeMouseListener(this); 59 } 60 61 @Override 62 public void mouseClicked(MouseEvent e) { 63 Main.map.selectMapMode(Main.map.mapModeSelect); 64 LatLon latlon = Main.map.mapView.getLatLon(e.getPoint().x, e.getPoint().y); 65 JLabel label = new JLabel(tr("Enter a comment for a new note")); 66 JTextArea textArea = new JTextArea(); 67 textArea.setRows(6); 68 textArea.setColumns(30); 69 textArea.setLineWrap(true); 70 JScrollPane scrollPane = new JScrollPane(textArea); 71 72 Object[] components = new Object[]{label, scrollPane}; 73 int option = JOptionPane.showConfirmDialog(Main.map, 74 components, 75 tr("Create new note"), 76 JOptionPane.OK_CANCEL_OPTION, 77 JOptionPane.PLAIN_MESSAGE, 78 NoteDialog.ICON_NEW); 79 if (option == JOptionPane.OK_OPTION) { 80 String input = textArea.getText(); 81 if (input != null && !input.isEmpty()) { 82 noteData.createNote(latlon, input); 83 } else { 84 Notification notification = new Notification("You must enter a comment to create a new note"); 85 notification.setIcon(JOptionPane.WARNING_MESSAGE); 86 notification.show(); 87 } 88 } 89 } 90 } -
src/org/openstreetmap/josm/data/osm/NoteData.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.data.osm; 3 4 import java.util.ArrayList; 5 import java.util.Date; 6 import java.util.List; 7 8 import org.openstreetmap.josm.Main; 9 import org.openstreetmap.josm.data.coor.LatLon; 10 import org.openstreetmap.josm.data.notes.Note; 11 import org.openstreetmap.josm.data.notes.Note.State; 12 import org.openstreetmap.josm.data.notes.NoteComment; 13 import org.openstreetmap.josm.gui.JosmUserIdentityManager; 14 15 /** 16 * Class to hold and perform operations on a set of notes 17 */ 18 public class NoteData { 19 20 private long newNoteId = -1; 21 22 private final List<Note> noteList; 23 private Note selectedNote = null; 24 25 /** 26 * Construct a new note container with an empty note list 27 */ 28 public NoteData() { 29 noteList = new ArrayList<>(); 30 } 31 32 /** 33 * Construct a new note container with a given list of notes 34 * @param notes The list of notes to populate the container with 35 */ 36 public NoteData(List<Note> notes) { 37 noteList = notes; 38 } 39 40 /** 41 * Returns the notes stored in this layer 42 * @return List of Note objects 43 */ 44 public List<Note> getNotes() { 45 return noteList; 46 } 47 48 /** Returns the currently selected note */ 49 public Note getSelectedNote() { 50 return selectedNote; 51 } 52 53 /** Set a selected note. Causes the dialog to select the note and 54 * the note layer to draw the selected note's comments. 55 * @param note Selected note. Null indicates no selection 56 */ 57 public void setSelectedNote(Note note) { 58 selectedNote = note; 59 Main.map.noteDialog.selectionChanged(); 60 Main.map.mapView.repaint(); 61 } 62 63 /** 64 * Add notes to the data set. It only adds a note if the ID is not already present 65 * @param newNotes A list of notes to add 66 */ 67 public void addNotes(List<Note> newNotes) { 68 for (Note newNote : newNotes) { 69 if (!noteList.contains(newNote)) { 70 noteList.add(newNote); 71 } 72 if (newNote.getId() <= newNoteId) { 73 newNoteId = newNote.getId() - 1; 74 } 75 } 76 dataUpdated(); 77 Main.debug("notes in current set: " + noteList.size()); 78 } 79 80 /** 81 * Create a new note 82 * @param location Location of note 83 * @param text Required comment with which to open the note 84 */ 85 public void createNote(LatLon location, String text) { 86 if(text == null || text.isEmpty()) { 87 throw new IllegalArgumentException("Comment can not be blank when creating a note"); 88 } 89 Note note = new Note(location); 90 note.setCreatedAt(new Date()); 91 note.setState(State.open); 92 note.setId(newNoteId--); 93 NoteComment comment = new NoteComment(new Date(), getCurrentUser(), text, NoteComment.Action.opened, true); 94 note.addComment(comment); 95 Main.debug("Created note {0} with comment: {1}", note.getId(), text); 96 noteList.add(note); 97 dataUpdated(); 98 } 99 100 /** 101 * Add a new comment to an existing note 102 * @param note Note to add comment to. Must already exist in the layer 103 * @param text Comment to add 104 */ 105 public void addCommentToNote(Note note, String text) { 106 if (!noteList.contains(note)) { 107 throw new IllegalArgumentException("Note to modify must be in layer"); 108 } 109 if (note.getState() == State.closed) { 110 throw new IllegalStateException("Cannot add a comment to a closed note"); 111 } 112 Main.debug("Adding comment to note {0}: {1}", note.getId(), text); 113 NoteComment comment = new NoteComment(new Date(), getCurrentUser(), text, NoteComment.Action.commented, true); 114 note.addComment(comment); 115 dataUpdated(); 116 } 117 118 /** 119 * Close note with comment 120 * @param note Note to close. Must already exist in the layer 121 * @param text Comment to attach to close action, if desired 122 */ 123 public void closeNote(Note note, String text) { 124 if (!noteList.contains(note)) { 125 throw new IllegalArgumentException("Note to close must be in layer"); 126 } 127 if (note.getState() != State.open) { 128 throw new IllegalStateException("Cannot close a note that isn't open"); 129 } 130 Main.debug("closing note {0} with comment: {1}", note.getId(), text); 131 NoteComment comment = new NoteComment(new Date(), getCurrentUser(), text, NoteComment.Action.closed, true); 132 note.addComment(comment); 133 note.setState(State.closed); 134 note.setClosedAt(new Date()); 135 dataUpdated(); 136 } 137 138 /** 139 * Reopen a closed note. 140 * @param note Note to reopen. Must already exist in the layer 141 * @param text Comment to attach to the reopen action, if desired 142 */ 143 public void reOpenNote(Note note, String text) { 144 if (!noteList.contains(note)) { 145 throw new IllegalArgumentException("Note to reopen must be in layer"); 146 } 147 if (note.getState() != State.closed) { 148 throw new IllegalStateException("Cannot reopen a note that isn't closed"); 149 } 150 Main.debug("reopening note {0} with comment: {1}", note.getId(), text); 151 NoteComment comment = new NoteComment(new Date(), getCurrentUser(), text, NoteComment.Action.reopened, true); 152 note.addComment(comment); 153 note.setState(State.open); 154 dataUpdated(); 155 } 156 157 private void dataUpdated() { 158 Main.map.noteDialog.setNoteList(noteList); 159 Main.map.mapView.repaint(); 160 } 161 162 private User getCurrentUser() { 163 JosmUserIdentityManager userMgr = JosmUserIdentityManager.getInstance(); 164 return User.createOsmUser(userMgr.getUserId(), userMgr.getUserName()); 165 } 166 } -
src/org/openstreetmap/josm/gui/MapFrame.java
66 66 import org.openstreetmap.josm.gui.dialogs.HistoryDialog; 67 67 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 68 68 import org.openstreetmap.josm.gui.dialogs.MapPaintDialog; 69 import org.openstreetmap.josm.gui.dialogs.NoteDialog; 69 70 import org.openstreetmap.josm.gui.dialogs.RelationListDialog; 70 71 import org.openstreetmap.josm.gui.dialogs.SelectionListDialog; 71 72 import org.openstreetmap.josm.gui.dialogs.ToggleDialog; … … 132 133 public ValidatorDialog validatorDialog; 133 134 public SelectionListDialog selectionListDialog; 134 135 public PropertiesDialog propertiesDialog; 136 public NoteDialog noteDialog; 135 137 136 138 // Map modes 137 139 public final SelectAction mapModeSelect; … … 242 244 addToggleDialog(filterDialog = new FilterDialog()); 243 245 addToggleDialog(new ChangesetDialog(), true); 244 246 addToggleDialog(new MapPaintDialog()); 247 //TODO: remove this if statement once note suppot is complete 248 if(Main.pref.getBoolean("osm.notes.enableDownload", false)) { 249 addToggleDialog(noteDialog = new NoteDialog()); 250 } 245 251 toolBarToggle.setFloatable(false); 246 252 247 253 // status line below the map -
src/org/openstreetmap/josm/gui/dialogs/NoteDialog.java
1 // License: GPL. For details, see LICENSE file. 2 package org.openstreetmap.josm.gui.dialogs; 3 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 6 import java.awt.BorderLayout; 7 import java.awt.Component; 8 import java.awt.Image; 9 import java.awt.event.ActionEvent; 10 import java.text.SimpleDateFormat; 11 import java.util.ArrayList; 12 import java.util.Arrays; 13 import java.util.List; 14 15 import javax.swing.AbstractAction; 16 import javax.swing.AbstractListModel; 17 import javax.swing.DefaultListCellRenderer; 18 import javax.swing.ImageIcon; 19 import javax.swing.JLabel; 20 import javax.swing.JList; 21 import javax.swing.JOptionPane; 22 import javax.swing.JPanel; 23 import javax.swing.JScrollPane; 24 import javax.swing.ListCellRenderer; 25 import javax.swing.ListSelectionModel; 26 import javax.swing.event.ListSelectionEvent; 27 import javax.swing.event.ListSelectionListener; 28 29 import org.openstreetmap.josm.Main; 30 import org.openstreetmap.josm.actions.mapmode.AddNoteAction; 31 import org.openstreetmap.josm.data.notes.Note; 32 import org.openstreetmap.josm.data.notes.Note.State; 33 import org.openstreetmap.josm.data.osm.NoteData; 34 import org.openstreetmap.josm.gui.MapView; 35 import org.openstreetmap.josm.gui.MapView.LayerChangeListener; 36 import org.openstreetmap.josm.gui.SideButton; 37 import org.openstreetmap.josm.gui.layer.Layer; 38 import org.openstreetmap.josm.gui.layer.NoteLayer; 39 import org.openstreetmap.josm.tools.ImageProvider; 40 41 /** 42 * Dialog to display and manipulate notes 43 */ 44 public class NoteDialog extends ToggleDialog implements LayerChangeListener { 45 46 47 /** Small icon size for use in graphics calculations */ 48 public static final int ICON_SMALL_SIZE = 16; 49 /** Large icon size for use in graphics calculations */ 50 public static final int ICON_LARGE_SIZE = 24; 51 /** 24x24 icon for unresolved notes */ 52 public static final ImageIcon ICON_OPEN = ImageProvider.get("dialogs/notes", "note_open.png"); 53 /** 16x16 icon for unresolved notes */ 54 public static final ImageIcon ICON_OPEN_SMALL = 55 new ImageIcon(ICON_OPEN.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH)); 56 /** 24x24 icon for resolved notes */ 57 public static final ImageIcon ICON_CLOSED = ImageProvider.get("dialogs/notes", "note_closed.png"); 58 /** 16x16 icon for resolved notes */ 59 public static final ImageIcon ICON_CLOSED_SMALL = 60 new ImageIcon(ICON_CLOSED.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH)); 61 /** 24x24 icon for new notes */ 62 public static final ImageIcon ICON_NEW = ImageProvider.get("dialogs/notes", "note_new.png"); 63 /** 16x16 icon for new notes */ 64 public static final ImageIcon ICON_NEW_SMALL = 65 new ImageIcon(ICON_NEW.getImage().getScaledInstance(ICON_SMALL_SIZE, ICON_SMALL_SIZE, Image.SCALE_SMOOTH)); 66 /** Icon for note comments */ 67 public static final ImageIcon ICON_COMMENT = ImageProvider.get("dialogs/notes", "note_comment.png"); 68 69 private NoteTableModel model; 70 private JList<Note> displayList; 71 private final AddCommentAction addCommentAction; 72 private final CloseAction closeAction; 73 private final NewAction newAction; 74 private final ReopenAction reopenAction; 75 76 private NoteData noteData; 77 78 /** Creates a new toggle dialog for notes */ 79 public NoteDialog() { 80 super("Notes", "notes/note_open.png", "List of notes", null, 150); 81 Main.debug("constructed note dialog"); 82 83 addCommentAction = new AddCommentAction(); 84 closeAction = new CloseAction(); 85 newAction = new NewAction(); 86 reopenAction = new ReopenAction(); 87 buildDialog(); 88 } 89 90 @Override 91 public void showDialog() { 92 super.showDialog(); 93 } 94 95 private void buildDialog() { 96 model = new NoteTableModel(); 97 displayList = new JList<Note>(model); 98 displayList.setCellRenderer(new NoteRenderer()); 99 displayList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); 100 displayList.addListSelectionListener(new ListSelectionListener() { 101 @Override 102 public void valueChanged(ListSelectionEvent e) { 103 if (noteData != null) { //happens when layer is deleted while note selected 104 noteData.setSelectedNote(displayList.getSelectedValue()); 105 } 106 updateButtonStates(); 107 }}); 108 109 JPanel pane = new JPanel(new BorderLayout()); 110 pane.add(new JScrollPane(displayList), BorderLayout.CENTER); 111 112 createLayout(pane, false, Arrays.asList(new SideButton[]{ 113 new SideButton(newAction, false), 114 new SideButton(addCommentAction, false), 115 new SideButton(closeAction, false), 116 new SideButton(reopenAction, false)})); 117 updateButtonStates(); 118 } 119 120 private void updateButtonStates() { 121 if (noteData == null || noteData.getSelectedNote() == null) { 122 closeAction.setEnabled(false); 123 addCommentAction.setEnabled(false); 124 reopenAction.setEnabled(false); 125 } else if (noteData.getSelectedNote().getState() == State.open){ 126 closeAction.setEnabled(true); 127 addCommentAction.setEnabled(true); 128 reopenAction.setEnabled(false); 129 } else { //note is closed 130 closeAction.setEnabled(false); 131 addCommentAction.setEnabled(false); 132 reopenAction.setEnabled(true); 133 } 134 } 135 136 @Override 137 public void showNotify() { 138 MapView.addLayerChangeListener(this); 139 } 140 141 @Override 142 public void hideNotify() { 143 MapView.removeLayerChangeListener(this); 144 } 145 146 @Override 147 public void activeLayerChange(Layer oldLayer, Layer newLayer) { } 148 149 @Override 150 public void layerAdded(Layer newLayer) { 151 Main.debug("layer added: " + newLayer); 152 if (newLayer instanceof NoteLayer) { 153 Main.debug("note layer added"); 154 noteData = ((NoteLayer)newLayer).getNoteData(); 155 model.setData(noteData.getNotes()); 156 } 157 } 158 159 @Override 160 public void layerRemoved(Layer oldLayer) { 161 if (oldLayer instanceof NoteLayer) { 162 Main.debug("note layer removed. Clearing everything"); 163 noteData = null; 164 model.clearData(); 165 if (Main.map.mapMode instanceof AddNoteAction) { 166 Main.map.selectMapMode(Main.map.mapModeSelect); 167 } 168 } 169 } 170 171 /** 172 * Sets the list of notes to be displayed in the dialog. 173 * The dialog should match the notes displayed in the note layer. 174 * @param noteList List of notes to display 175 */ 176 public void setNoteList(List<Note> noteList) { 177 model.setData(noteList); 178 updateButtonStates(); 179 this.repaint(); 180 } 181 182 /** 183 * Notify the dialog that the note selection has changed. 184 * Causes it to update or clear its selection in the UI. 185 */ 186 public void selectionChanged() { 187 if (noteData == null || noteData.getSelectedNote() == null) { 188 displayList.clearSelection(); 189 } else { 190 displayList.setSelectedValue(noteData.getSelectedNote(), true); 191 } 192 updateButtonStates(); 193 } 194 195 private class NoteRenderer implements ListCellRenderer<Note> { 196 197 private DefaultListCellRenderer defaultListCellRenderer = new DefaultListCellRenderer(); 198 private final SimpleDateFormat sdf = new SimpleDateFormat("dd MMM yyyy kk:mm"); 199 200 @Override 201 public Component getListCellRendererComponent(JList<? extends Note> list, Note note, int index, 202 boolean isSelected, boolean cellHasFocus) { 203 Component comp = defaultListCellRenderer.getListCellRendererComponent(list, note, index, isSelected, cellHasFocus); 204 if (note != null && comp instanceof JLabel) { 205 String text = note.getFirstComment().getText(); 206 String userName = note.getFirstComment().getUser().getName(); 207 if (userName == null || userName.isEmpty()) { 208 userName = "<Anonymous>"; 209 } 210 String toolTipText = userName + " @ " + sdf.format(note.getCreatedAt()); 211 JLabel jlabel = (JLabel)comp; 212 jlabel.setText(text); 213 ImageIcon icon; 214 if (note.getId() < 0) { 215 icon = ICON_NEW_SMALL; 216 } else if (note.getState() == State.closed) { 217 icon = ICON_CLOSED_SMALL; 218 } else { 219 icon = ICON_OPEN_SMALL; 220 } 221 jlabel.setIcon(icon); 222 jlabel.setToolTipText(toolTipText); 223 } 224 return comp; 225 } 226 } 227 228 class NoteTableModel extends AbstractListModel<Note> { 229 private List<Note> data; 230 231 public NoteTableModel() { 232 data = new ArrayList<Note>(); 233 } 234 235 @Override 236 public int getSize() { 237 if (data == null) { 238 return 0; 239 } 240 return data.size(); 241 } 242 243 @Override 244 public Note getElementAt(int index) { 245 return data.get(index); 246 } 247 248 public void setData(List<Note> noteList) { 249 data.clear(); 250 data.addAll(noteList); 251 fireContentsChanged(this, 0, noteList.size()); 252 } 253 254 public void clearData() { 255 displayList.clearSelection(); 256 data.clear(); 257 fireIntervalRemoved(this, 0, getSize()); 258 } 259 } 260 261 class AddCommentAction extends AbstractAction { 262 263 public AddCommentAction() { 264 putValue(SHORT_DESCRIPTION,tr("Add comment")); 265 putValue(NAME, tr("Comment")); 266 putValue(SMALL_ICON, ICON_COMMENT); 267 } 268 269 @Override 270 public void actionPerformed(ActionEvent e) { 271 Note note = displayList.getSelectedValue(); 272 if (note == null) { 273 JOptionPane.showMessageDialog(Main.map, 274 "You must select a note first", 275 "No note selected", 276 JOptionPane.ERROR_MESSAGE); 277 return; 278 } 279 Object userInput = JOptionPane.showInputDialog(Main.map, 280 tr("Add comment to note:"), 281 tr("Add comment"), 282 JOptionPane.QUESTION_MESSAGE, 283 ICON_COMMENT, 284 null,null); 285 if (userInput == null) { //user pressed cancel 286 return; 287 } 288 noteData.addCommentToNote(note, userInput.toString()); 289 } 290 } 291 292 class CloseAction extends AbstractAction { 293 294 public CloseAction() { 295 putValue(SHORT_DESCRIPTION,tr("Close note")); 296 putValue(NAME, tr("Close")); 297 putValue(SMALL_ICON, ICON_CLOSED); 298 } 299 300 @Override 301 public void actionPerformed(ActionEvent e) { 302 Object userInput = JOptionPane.showInputDialog(Main.map, 303 tr("Close note with message:"), 304 tr("Close Note"), 305 JOptionPane.QUESTION_MESSAGE, 306 ICON_CLOSED, 307 null,null); 308 if (userInput == null) { //user pressed cancel 309 return; 310 } 311 Note note = displayList.getSelectedValue(); 312 noteData.closeNote(note, userInput.toString()); 313 } 314 } 315 316 class NewAction extends AbstractAction { 317 318 public NewAction() { 319 putValue(SHORT_DESCRIPTION,tr("Create a new note")); 320 putValue(NAME, tr("Create")); 321 putValue(SMALL_ICON, ICON_NEW); 322 } 323 324 @Override 325 public void actionPerformed(ActionEvent e) { 326 if (noteData == null) { //there is no notes layer. Create one first 327 Main.map.mapView.addLayer(new NoteLayer()); 328 } 329 Main.map.selectMapMode(new AddNoteAction(Main.map, noteData)); 330 } 331 } 332 333 class ReopenAction extends AbstractAction { 334 335 public ReopenAction() { 336 putValue(SHORT_DESCRIPTION,tr("Reopen note")); 337 putValue(NAME, tr("Reopen")); 338 putValue(SMALL_ICON, ICON_OPEN); 339 } 340 341 @Override 342 public void actionPerformed(ActionEvent e) { 343 Object userInput = JOptionPane.showInputDialog(Main.map, 344 tr("Reopen note with message:"), 345 tr("Reopen note"), 346 JOptionPane.QUESTION_MESSAGE, 347 ICON_OPEN, 348 null,null); 349 if (userInput == null) { //user pressed cancel 350 return; 351 } 352 Note note = displayList.getSelectedValue(); 353 noteData.reOpenNote(note, userInput.toString()); 354 } 355 } 356 } -
src/org/openstreetmap/josm/gui/layer/NoteLayer.java
3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.awt.Dimension; 6 7 import java.awt.Graphics2D; 7 8 import java.awt.Point; 9 import java.awt.event.MouseEvent; 10 import java.awt.event.MouseListener; 11 import java.text.SimpleDateFormat; 8 12 import java.util.ArrayList; 9 13 import java.util.List; 10 14 11 15 import javax.swing.Action; 12 16 import javax.swing.Icon; 13 17 import javax.swing.ImageIcon; 18 import javax.swing.JToolTip; 14 19 15 20 import org.openstreetmap.josm.Main; 16 21 import org.openstreetmap.josm.data.Bounds; 17 22 import org.openstreetmap.josm.data.notes.Note; 18 23 import org.openstreetmap.josm.data.notes.Note.State; 19 24 import org.openstreetmap.josm.data.notes.NoteComment; 25 import org.openstreetmap.josm.data.osm.NoteData; 20 26 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor; 21 27 import org.openstreetmap.josm.gui.MapView; 22 28 import org.openstreetmap.josm.gui.dialogs.LayerListDialog; 23 29 import org.openstreetmap.josm.gui.dialogs.LayerListPopup; 24 import org.openstreetmap.josm.tools.ImageProvider; 30 import org.openstreetmap.josm.gui.dialogs.NoteDialog; 31 import org.openstreetmap.josm.io.XmlWriter; 32 import org.openstreetmap.josm.tools.ColorHelper; 25 33 26 34 /** 27 35 * A layer to hold Note objects 28 36 */ 29 public class NoteLayer extends AbstractModifiableLayer {37 public class NoteLayer extends AbstractModifiableLayer implements MouseListener { 30 38 31 private final List<Note> notes;39 private final NoteData noteData; 32 40 33 41 /** 34 42 * Create a new note layer with a set of notes … … 37 45 */ 38 46 public NoteLayer(List<Note> notes, String name) { 39 47 super(name); 40 this.notes = notes; 48 noteData = new NoteData(notes); 49 init(); 41 50 } 42 51 52 /** Convenience constructor that creates a layer with an empty note list */ 53 public NoteLayer() { 54 super(tr("Notes")); 55 noteData = new NoteData(); 56 init(); 57 } 58 59 private void init() { 60 if (Main.map != null && Main.map.mapView != null) { 61 Main.map.mapView.addMouseListener(this); 62 } 63 } 64 65 /** 66 * Returns the note data store being used by this layer 67 * @return noteData containing layer notes 68 */ 69 public NoteData getNoteData() { 70 return noteData; 71 } 72 43 73 @Override 44 74 public boolean isModified() { 45 for (Note note : note s) {75 for (Note note : noteData.getNotes()) { 46 76 if (note.getId() < 0) { //notes with negative IDs are new 47 77 return true; 48 78 } … … 62 92 63 93 @Override 64 94 public void paint(Graphics2D g, MapView mv, Bounds box) { 65 for (Note note : note s) {95 for (Note note : noteData.getNotes()) { 66 96 Point p = mv.getPoint(note.getLatLon()); 67 97 68 98 ImageIcon icon = null; 69 99 if (note.getId() < 0) { 70 icon = ImageProvider.get("notes", "note_new_16x16.png");100 icon = NoteDialog.ICON_NEW_SMALL; 71 101 } else if (note.getState() == State.closed) { 72 icon = ImageProvider.get("notes", "note_closed_16x16.png");102 icon = NoteDialog.ICON_CLOSED_SMALL; 73 103 } else { 74 icon = ImageProvider.get("notes", "note_open_16x16.png");104 icon = NoteDialog.ICON_OPEN_SMALL; 75 105 } 76 106 int width = icon.getIconWidth(); 77 107 int height = icon.getIconHeight(); 78 108 g.drawImage(icon.getImage(), p.x - (width / 2), p.y - height, Main.map.mapView); 79 109 } 110 if (noteData.getSelectedNote() != null) { 111 StringBuilder sb = new StringBuilder("<html>"); 112 List<NoteComment> comments = noteData.getSelectedNote().getComments(); 113 String sep = ""; 114 SimpleDateFormat dayFormat = new SimpleDateFormat("MMM d, yyyy"); 115 for (NoteComment comment : comments) { 116 String commentText = comment.getText(); 117 //closing a note creates an empty comment that we don't want to show 118 if (commentText != null && commentText.trim().length() > 0) { 119 sb.append(sep); 120 String userName = comment.getUser().getName(); 121 if (userName == null || userName.trim().length() == 0) { 122 userName = "<Anonymous>"; 123 } 124 sb.append(userName); 125 sb.append(" on "); 126 sb.append(dayFormat.format(comment.getCommentTimestamp())); 127 sb.append(":<br/>"); 128 String htmlText = XmlWriter.encode(comment.getText(), true); 129 htmlText = htmlText.replace("
", "<br/>"); //encode method leaves us with entity instead of \n 130 sb.append(htmlText); 131 } 132 sep = "<hr/>"; 133 } 134 sb.append("</html>"); 135 JToolTip toolTip = new JToolTip(); 136 toolTip.setTipText(sb.toString()); 137 Point p = mv.getPoint(noteData.getSelectedNote().getLatLon()); 138 139 g.setColor(ColorHelper.html2color(Main.pref.get("color.selected"))); 140 g.drawRect(p.x - (NoteDialog.ICON_SMALL_SIZE / 2), p.y - NoteDialog.ICON_SMALL_SIZE, NoteDialog.ICON_SMALL_SIZE - 1, NoteDialog.ICON_SMALL_SIZE - 1); 141 142 int tx = p.x + (NoteDialog.ICON_SMALL_SIZE / 2) + 5; 143 int ty = p.y - NoteDialog.ICON_SMALL_SIZE - 1; 144 g.translate(tx, ty); 145 146 //Carried over from the OSB plugin. Not entirely sure why it is needed 147 //but without it, the tooltip doesn't get sized correctly 148 for (int x = 0; x < 2; x++) { 149 Dimension d = toolTip.getUI().getPreferredSize(toolTip); 150 d.width = Math.min(d.width, (mv.getWidth() * 1 / 2)); 151 toolTip.setSize(d); 152 toolTip.paint(g); 153 } 154 g.translate(-tx, -ty); 155 } 80 156 } 81 157 82 158 @Override 83 159 public Icon getIcon() { 84 return ImageProvider.get("notes", "note_open_16x16.png");160 return NoteDialog.ICON_OPEN_SMALL; 85 161 } 86 162 87 163 @Override 88 164 public String getToolTipText() { 89 return note s.size() + " " + tr("Notes");165 return noteData.getNotes().size() + " " + tr("Notes"); 90 166 } 91 167 92 168 @Override … … 110 186 sb.append("\n"); 111 187 sb.append(tr("Total notes:")); 112 188 sb.append(" "); 113 sb.append(note s.size());189 sb.append(noteData.getNotes().size()); 114 190 sb.append("\n"); 115 191 sb.append(tr("Changes need uploading?")); 116 192 sb.append(" "); … … 127 203 return actions.toArray(new Action[actions.size()]); 128 204 } 129 205 130 /** 131 * Returns the notes stored in this layer 132 * @return List of Note objects 133 */ 134 public List<Note> getNotes() { 135 return notes; 136 } 137 138 /** 139 * Add notes to the layer. It only adds a note if the ID is not already present 140 * @param newNotes A list of notes to add 141 */ 142 public void addNotes(List<Note> newNotes) { 143 for (Note newNote : newNotes) { 144 if (!notes.contains(newNote)) { 145 notes.add(newNote); 206 @Override 207 public void mouseClicked(MouseEvent e) { 208 if (e.getButton() != MouseEvent.BUTTON1) { 209 return; 210 } 211 Point clickPoint = e.getPoint(); 212 double snapDistance = 10; 213 double minDistance = Double.MAX_VALUE; 214 Note closestNote = null; 215 for (Note note : noteData.getNotes()) { 216 Point notePoint = Main.map.mapView.getPoint(note.getLatLon()); 217 //move the note point to the center of the icon where users are most likely to click when selecting 218 notePoint.setLocation(notePoint.getX(), notePoint.getY() - NoteDialog.ICON_SMALL_SIZE / 2); 219 double dist = clickPoint.distanceSq(notePoint); 220 if (minDistance > dist && clickPoint.distance(notePoint) < snapDistance ) { 221 minDistance = dist; 222 closestNote = note; 146 223 } 147 224 } 148 Main.map.mapView.repaint(); 149 Main.debug("notes in layer: " + notes.size()); 225 noteData.setSelectedNote(closestNote); 150 226 } 227 228 @Override 229 public void mousePressed(MouseEvent e) { } 230 231 @Override 232 public void mouseReleased(MouseEvent e) { } 233 234 @Override 235 public void mouseEntered(MouseEvent e) { } 236 237 @Override 238 public void mouseExited(MouseEvent e) { } 151 239 } -
src/org/openstreetmap/josm/io/NoteImporter.java
51 51 } 52 52 if (noteLayers != null && noteLayers.size() > 0) { 53 53 NoteLayer layer = noteLayers.get(0); 54 layer. addNotes(fileNotes);54 layer.getNoteData().addNotes(fileNotes); 55 55 } else { 56 56 GuiHelper.runInEDT(new Runnable() { 57 57 @Override
