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

Last change on this file since 8214 was 8214, checked in by simon04, 9 years ago

Notes layer: make "Zoom to data/layer" work

  • 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.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.awt.Color;
8import java.awt.Graphics2D;
9import java.awt.Point;
10import java.awt.event.MouseEvent;
11import java.awt.event.MouseListener;
12import java.io.File;
13import java.text.DateFormat;
14import java.util.ArrayList;
15import java.util.List;
16
17import javax.swing.Action;
18import javax.swing.BorderFactory;
19import javax.swing.Icon;
20import javax.swing.ImageIcon;
21import javax.swing.JTextArea;
22
23import org.openstreetmap.josm.Main;
24import org.openstreetmap.josm.actions.SaveActionBase;
25import org.openstreetmap.josm.data.Bounds;
26import org.openstreetmap.josm.data.notes.Note;
27import org.openstreetmap.josm.data.notes.Note.State;
28import org.openstreetmap.josm.data.notes.NoteComment;
29import org.openstreetmap.josm.data.osm.NoteData;
30import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
31import org.openstreetmap.josm.data.preferences.ColorProperty;
32import org.openstreetmap.josm.gui.MapView;
33import org.openstreetmap.josm.gui.dialogs.LayerListDialog;
34import org.openstreetmap.josm.gui.dialogs.LayerListPopup;
35import org.openstreetmap.josm.gui.dialogs.NotesDialog;
36import org.openstreetmap.josm.io.NoteExporter;
37import org.openstreetmap.josm.tools.ColorHelper;
38import org.openstreetmap.josm.tools.date.DateUtils;
39
40/**
41 * A layer to hold Note objects
42 */
43public class NoteLayer extends AbstractModifiableLayer implements MouseListener {
44
45 private final NoteData noteData;
46
47 /**
48 * Property for note comment background
49 */
50 public static final ColorProperty PROP_BACKGROUND_COLOR = new ColorProperty(
51 marktr("Note comment background"), Color.decode("#b8cfe5"));
52
53 /**
54 * Create a new note layer with a set of notes
55 * @param notes A list of notes to show in this layer
56 * @param name The name of the layer. Typically "Notes"
57 */
58 public NoteLayer(List<Note> notes, String name) {
59 super(name);
60 noteData = new NoteData(notes);
61 }
62
63 /** Convenience constructor that creates a layer with an empty note list */
64 public NoteLayer() {
65 super(tr("Notes"));
66 noteData = new NoteData();
67 }
68
69 @Override
70 public void hookUpMapView() {
71 Main.map.mapView.addMouseListener(this);
72 }
73
74 /**
75 * Returns the note data store being used by this layer
76 * @return noteData containing layer notes
77 */
78 public NoteData getNoteData() {
79 return noteData;
80 }
81
82 @Override
83 public boolean isModified() {
84 return noteData.isModified();
85 }
86
87 @Override
88 public boolean requiresUploadToServer() {
89 return isModified();
90 }
91
92 @Override
93 public boolean isSavable() {
94 return true;
95 }
96
97 @Override
98 public boolean requiresSaveToFile() {
99 Main.debug("associated notes file: " + getAssociatedFile());
100 return getAssociatedFile() != null && isModified();
101 }
102
103 @Override
104 public void paint(Graphics2D g, MapView mv, Bounds box) {
105 for (Note note : noteData.getNotes()) {
106 Point p = mv.getPoint(note.getLatLon());
107
108 ImageIcon icon = null;
109 if (note.getId() < 0) {
110 icon = NotesDialog.ICON_NEW_SMALL;
111 } else if (note.getState() == State.closed) {
112 icon = NotesDialog.ICON_CLOSED_SMALL;
113 } else {
114 icon = NotesDialog.ICON_OPEN_SMALL;
115 }
116 int width = icon.getIconWidth();
117 int height = icon.getIconHeight();
118 g.drawImage(icon.getImage(), p.x - (width / 2), p.y - height, Main.map.mapView);
119 }
120 if (noteData.getSelectedNote() != null) {
121 StringBuilder sb = new StringBuilder();
122 sb.append(tr("Note"));
123 sb.append(" ").append(noteData.getSelectedNote().getId());
124 for (NoteComment comment : noteData.getSelectedNote().getComments()) {
125 String commentText = comment.getText();
126 //closing a note creates an empty comment that we don't want to show
127 if (commentText != null && commentText.trim().length() > 0) {
128 sb.append("\n\n");
129 String userName = comment.getUser().getName().trim();
130 sb.append(userName.isEmpty() ? "<Anonymous>" : userName);
131 sb.append(" on ");
132 sb.append(DateUtils.getDateFormat(DateFormat.MEDIUM).format(comment.getCommentTimestamp()));
133 sb.append(":\n");
134 sb.append(comment.getText().trim());
135 }
136 }
137 JTextArea toolTip = new JTextArea();
138 toolTip.setText(sb.toString());
139 toolTip.setLineWrap(true);
140 toolTip.setWrapStyleWord(true);
141 toolTip.setBackground(PROP_BACKGROUND_COLOR.get());
142 toolTip.setSize(Math.min(480, mv.getWidth() / 2), 1);
143 toolTip.setSize(toolTip.getPreferredSize().width + 6, toolTip.getPreferredSize().height + 6); // +6 for border
144 toolTip.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
145
146 Point p = mv.getPoint(noteData.getSelectedNote().getLatLon());
147
148 g.setColor(ColorHelper.html2color(Main.pref.get("color.selected")));
149 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);
150
151 int tx = p.x + (NotesDialog.ICON_SMALL_SIZE / 2) + 5;
152 int ty = p.y - NotesDialog.ICON_SMALL_SIZE - 1;
153 g.translate(tx, ty);
154 toolTip.paint(g);
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 for (Note note : noteData.getNotes()) {
182 v.visit(note.getLatLon());
183 }
184 }
185
186 @Override
187 public Object getInfoComponent() {
188 StringBuilder sb = new StringBuilder();
189 sb.append(tr("Notes layer"));
190 sb.append("\n");
191 sb.append(tr("Total notes:"));
192 sb.append(" ");
193 sb.append(noteData.getNotes().size());
194 sb.append("\n");
195 sb.append(tr("Changes need uploading?"));
196 sb.append(" ");
197 sb.append(isModified());
198 return sb.toString();
199 }
200
201 @Override
202 public Action[] getMenuEntries() {
203 List<Action> actions = new ArrayList<>();
204 actions.add(LayerListDialog.getInstance().createShowHideLayerAction());
205 actions.add(LayerListDialog.getInstance().createDeleteLayerAction());
206 actions.add(new LayerListPopup.InfoAction(this));
207 actions.add(new LayerSaveAction(this));
208 actions.add(new LayerSaveAsAction(this));
209 return actions.toArray(new Action[actions.size()]);
210 }
211
212 @Override
213 public void mouseClicked(MouseEvent e) {
214 if (e.getButton() != MouseEvent.BUTTON1) {
215 return;
216 }
217 Point clickPoint = e.getPoint();
218 double snapDistance = 10;
219 double minDistance = Double.MAX_VALUE;
220 Note closestNote = null;
221 for (Note note : noteData.getNotes()) {
222 Point notePoint = Main.map.mapView.getPoint(note.getLatLon());
223 //move the note point to the center of the icon where users are most likely to click when selecting
224 notePoint.setLocation(notePoint.getX(), notePoint.getY() - NotesDialog.ICON_SMALL_SIZE / 2);
225 double dist = clickPoint.distanceSq(notePoint);
226 if (minDistance > dist && clickPoint.distance(notePoint) < snapDistance ) {
227 minDistance = dist;
228 closestNote = note;
229 }
230 }
231 noteData.setSelectedNote(closestNote);
232 }
233
234 @Override
235 public File createAndOpenSaveFileChooser() {
236 return SaveActionBase.createAndOpenSaveFileChooser(tr("Save GPX file"), NoteExporter.FILE_FILTER);
237 }
238
239 @Override
240 public void mousePressed(MouseEvent e) { }
241
242 @Override
243 public void mouseReleased(MouseEvent e) { }
244
245 @Override
246 public void mouseEntered(MouseEvent e) { }
247
248 @Override
249 public void mouseExited(MouseEvent e) { }
250}
Note: See TracBrowser for help on using the repository browser.