source: josm/trunk/src/org/openstreetmap/josm/gui/layer/NoteLayer.java@ 7882

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

fix #10606 - add ID of notes (patch by ToeBee)

  • Property svn:eol-style set to native
File size: 8.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Dimension;
7import java.awt.Graphics2D;
8import java.awt.Point;
9import java.awt.event.MouseEvent;
10import java.awt.event.MouseListener;
11import java.io.File;
12import java.text.SimpleDateFormat;
13import java.util.ArrayList;
14import java.util.List;
15
16import javax.swing.Action;
17import javax.swing.Icon;
18import javax.swing.ImageIcon;
19import javax.swing.JToolTip;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.actions.SaveActionBase;
23import org.openstreetmap.josm.data.Bounds;
24import org.openstreetmap.josm.data.notes.Note;
25import org.openstreetmap.josm.data.notes.Note.State;
26import org.openstreetmap.josm.data.notes.NoteComment;
27import org.openstreetmap.josm.data.osm.NoteData;
28import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
29import org.openstreetmap.josm.gui.MapView;
30import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
31import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
32import org.openstreetmap.josm.gui.dialogs.NotesDialog;
33import org.openstreetmap.josm.io.NoteExporter;
34import org.openstreetmap.josm.io.XmlWriter;
35import org.openstreetmap.josm.tools.ColorHelper;
36
37/**
38 * A layer to hold Note objects
39 */
40public class NoteLayer extends AbstractModifiableLayer implements MouseListener {
41
42 private final NoteData noteData;
43
44 /**
45 * Create a new note layer with a set of notes
46 * @param notes A list of notes to show in this layer
47 * @param name The name of the layer. Typically "Notes"
48 */
49 public NoteLayer(List<Note> notes, String name) {
50 super(name);
51 noteData = new NoteData(notes);
52 }
53
54 /** Convenience constructor that creates a layer with an empty note list */
55 public NoteLayer() {
56 super(tr("Notes"));
57 noteData = new NoteData();
58 }
59
60 @Override
61 public void hookUpMapView() {
62 Main.map.mapView.addMouseListener(this);
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
73 @Override
74 public boolean isModified() {
75 return noteData.isModified();
76 }
77
78 @Override
79 public boolean requiresUploadToServer() {
80 return isModified();
81 }
82
83 @Override
84 public boolean isSavable() {
85 return true;
86 }
87
88 @Override
89 public boolean requiresSaveToFile() {
90 Main.debug("associated notes file: " + getAssociatedFile());
91 return getAssociatedFile() != null && isModified();
92 }
93
94 @Override
95 public void paint(Graphics2D g, MapView mv, Bounds box) {
96 for (Note note : noteData.getNotes()) {
97 Point p = mv.getPoint(note.getLatLon());
98
99 ImageIcon icon = null;
100 if (note.getId() < 0) {
101 icon = NotesDialog.ICON_NEW_SMALL;
102 } else if (note.getState() == State.closed) {
103 icon = NotesDialog.ICON_CLOSED_SMALL;
104 } else {
105 icon = NotesDialog.ICON_OPEN_SMALL;
106 }
107 int width = icon.getIconWidth();
108 int height = icon.getIconHeight();
109 g.drawImage(icon.getImage(), p.x - (width / 2), p.y - height, Main.map.mapView);
110 }
111 if (noteData.getSelectedNote() != null) {
112 StringBuilder sb = new StringBuilder("<html>");
113 sb.append(tr("Note"));
114 sb.append(" " + noteData.getSelectedNote().getId());
115 List<NoteComment> comments = noteData.getSelectedNote().getComments();
116 SimpleDateFormat dayFormat = new SimpleDateFormat("MMM d, yyyy");
117 for (NoteComment comment : comments) {
118 String commentText = comment.getText();
119 //closing a note creates an empty comment that we don't want to show
120 if (commentText != null && commentText.trim().length() > 0) {
121 sb.append("<hr/>");
122 String userName = XmlWriter.encode(comment.getUser().getName());
123 if (userName == null || userName.trim().length() == 0) {
124 userName = "&lt;Anonymous&gt;";
125 }
126 sb.append(userName);
127 sb.append(" on ");
128 sb.append(dayFormat.format(comment.getCommentTimestamp()));
129 sb.append(":<br/>");
130 String htmlText = XmlWriter.encode(comment.getText(), true);
131 htmlText = htmlText.replace("&#xA;", "<br/>"); //encode method leaves us with entity instead of \n
132 sb.append(htmlText);
133 }
134 }
135 sb.append("</html>");
136 JToolTip toolTip = new JToolTip();
137 toolTip.setTipText(sb.toString());
138 Point p = mv.getPoint(noteData.getSelectedNote().getLatLon());
139
140 g.setColor(ColorHelper.html2color(Main.pref.get("color.selected")));
141 g.drawRect(p.x - (NotesDialog.ICON_SMALL_SIZE / 2), p.y - NotesDialog.ICON_SMALL_SIZE, NotesDialog.ICON_SMALL_SIZE - 1, NotesDialog.ICON_SMALL_SIZE - 1);
142
143 int tx = p.x + (NotesDialog.ICON_SMALL_SIZE / 2) + 5;
144 int ty = p.y - NotesDialog.ICON_SMALL_SIZE - 1;
145 g.translate(tx, ty);
146
147 //Carried over from the OSB plugin. Not entirely sure why it is needed
148 //but without it, the tooltip doesn't get sized correctly
149 for (int x = 0; x < 2; x++) {
150 Dimension d = toolTip.getUI().getPreferredSize(toolTip);
151 d.width = Math.min(d.width, (mv.getWidth() * 1 / 2));
152 toolTip.setSize(d);
153 toolTip.paint(g);
154 }
155 g.translate(-tx, -ty);
156 }
157 }
158
159 @Override
160 public Icon getIcon() {
161 return NotesDialog.ICON_OPEN_SMALL;
162 }
163
164 @Override
165 public String getToolTipText() {
166 return noteData.getNotes().size() + " " + tr("Notes");
167 }
168
169 @Override
170 public void mergeFrom(Layer from) {
171 throw new UnsupportedOperationException("Notes layer does not support merging yet");
172 }
173
174 @Override
175 public boolean isMergable(Layer other) {
176 return false;
177 }
178
179 @Override
180 public void visitBoundingBox(BoundingXYVisitor v) {
181 }
182
183 @Override
184 public Object getInfoComponent() {
185 StringBuilder sb = new StringBuilder();
186 sb.append(tr("Notes layer"));
187 sb.append("\n");
188 sb.append(tr("Total notes:"));
189 sb.append(" ");
190 sb.append(noteData.getNotes().size());
191 sb.append("\n");
192 sb.append(tr("Changes need uploading?"));
193 sb.append(" ");
194 sb.append(isModified());
195 return sb.toString();
196 }
197
198 @Override
199 public Action[] getMenuEntries() {
200 List<Action> actions = new ArrayList<>();
201 actions.add(LayerListDialog.getInstance().createShowHideLayerAction());
202 actions.add(LayerListDialog.getInstance().createDeleteLayerAction());
203 actions.add(new LayerListPopup.InfoAction(this));
204 actions.add(new LayerSaveAction(this));
205 actions.add(new LayerSaveAsAction(this));
206 return actions.toArray(new Action[actions.size()]);
207 }
208
209 @Override
210 public void mouseClicked(MouseEvent e) {
211 if (e.getButton() != MouseEvent.BUTTON1) {
212 return;
213 }
214 Point clickPoint = e.getPoint();
215 double snapDistance = 10;
216 double minDistance = Double.MAX_VALUE;
217 Note closestNote = null;
218 for (Note note : noteData.getNotes()) {
219 Point notePoint = Main.map.mapView.getPoint(note.getLatLon());
220 //move the note point to the center of the icon where users are most likely to click when selecting
221 notePoint.setLocation(notePoint.getX(), notePoint.getY() - NotesDialog.ICON_SMALL_SIZE / 2);
222 double dist = clickPoint.distanceSq(notePoint);
223 if (minDistance > dist && clickPoint.distance(notePoint) < snapDistance ) {
224 minDistance = dist;
225 closestNote = note;
226 }
227 }
228 noteData.setSelectedNote(closestNote);
229 }
230
231 @Override
232 public File createAndOpenSaveFileChooser() {
233 return SaveActionBase.createAndOpenSaveFileChooser(tr("Save GPX file"), NoteExporter.FILE_FILTER);
234 }
235
236 @Override
237 public void mousePressed(MouseEvent e) { }
238
239 @Override
240 public void mouseReleased(MouseEvent e) { }
241
242 @Override
243 public void mouseEntered(MouseEvent e) { }
244
245 @Override
246 public void mouseExited(MouseEvent e) { }
247}
Note: See TracBrowser for help on using the repository browser.