source: josm/trunk/src/org/openstreetmap/josm/gui/DefaultNameFormatter.java@ 4100

Last change on this file since 4100 was 4100, checked in by bastiK, 14 years ago

use IPrimitive to make upload code work for both OsmPrimitive and PrimitiveData

  • Property svn:eol-style set to native
File size: 20.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trc;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.util.ArrayList;
9import java.util.Arrays;
10import java.util.Collections;
11import java.util.Comparator;
12import java.util.HashSet;
13import java.util.List;
14import java.util.Set;
15
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.data.coor.CoordinateFormat;
18import org.openstreetmap.josm.data.osm.Changeset;
19import org.openstreetmap.josm.data.osm.INode;
20import org.openstreetmap.josm.data.osm.IPrimitive;
21import org.openstreetmap.josm.data.osm.IRelation;
22import org.openstreetmap.josm.data.osm.IWay;
23import org.openstreetmap.josm.data.osm.NameFormatter;
24import org.openstreetmap.josm.data.osm.Node;
25import org.openstreetmap.josm.data.osm.OsmPrimitive;
26import org.openstreetmap.josm.data.osm.OsmUtils;
27import org.openstreetmap.josm.data.osm.Relation;
28import org.openstreetmap.josm.data.osm.RelationMember;
29import org.openstreetmap.josm.data.osm.Way;
30import org.openstreetmap.josm.data.osm.history.HistoryNameFormatter;
31import org.openstreetmap.josm.data.osm.history.HistoryNode;
32import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
33import org.openstreetmap.josm.data.osm.history.HistoryRelation;
34import org.openstreetmap.josm.data.osm.history.HistoryWay;
35
36/**
37 * This is the default implementation of a {@see NameFormatter} for names of {@see OsmPrimitive}s.
38 *
39 */
40public class DefaultNameFormatter implements NameFormatter, HistoryNameFormatter {
41
42 static private DefaultNameFormatter instance;
43
44 /**
45 * Replies the unique instance of this formatter
46 *
47 * @return the unique instance of this formatter
48 */
49 static public DefaultNameFormatter getInstance() {
50 if (instance == null) {
51 instance = new DefaultNameFormatter();
52 }
53 return instance;
54 }
55
56 /** the default list of tags which are used as naming tags in relations */
57 static public final String[] DEFAULT_NAMING_TAGS_FOR_RELATIONS = {"name", "ref", "restriction", "landuse", "natural",
58 "public_transport", ":LocationCode", "note"};
59
60 /** the current list of tags used as naming tags in relations */
61 static private List<String> namingTagsForRelations = null;
62
63 /**
64 * Replies the list of naming tags used in relations. The list is given (in this order) by:
65 * <ul>
66 * <li>by the tag names in the preference <tt>relation.nameOrder</tt></li>
67 * <li>by the default tags in {@see #DEFAULT_NAMING_TAGS_FOR_RELATIONS}
68 * </ul>
69 *
70 * @return the list of naming tags used in relations
71 */
72 static public List<String> getNamingtagsForRelations() {
73 if (namingTagsForRelations == null) {
74 namingTagsForRelations = new ArrayList<String>(
75 Main.pref.getCollection("relation.nameOrder", Arrays.asList(DEFAULT_NAMING_TAGS_FOR_RELATIONS))
76 );
77 }
78 return namingTagsForRelations;
79 }
80
81 /**
82 * Decorates the name of primitive with its id, if the preference
83 * <tt>osm-primitives.showid</tt> is set. Shows unique id if osm-primitives.showid.new-primitives is set
84 *
85 * @param name the name without the id
86 * @param primitive the primitive
87 * @return the decorated name
88 */
89 protected String decorateNameWithId(String name, IPrimitive primitive) {
90 if (Main.pref.getBoolean("osm-primitives.showid"))
91 if (Main.pref.getBoolean("osm-primitives.showid.new-primitives"))
92 return name + tr(" [id: {0}]", primitive.getUniqueId());
93 else
94 return name + tr(" [id: {0}]", primitive.getId());
95 else
96 return name;
97 }
98
99 /**
100 * Formats a name for a node
101 *
102 * @param node the node
103 * @return the name
104 */
105 public String format(INode node) {
106 String name = "";
107 if (node.isIncomplete()) {
108 name = tr("incomplete");
109 } else {
110 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
111 name = node.getLocalName();
112 } else {
113 name = node.getName();
114 }
115 if(name == null)
116 {
117 String s;
118 if((s = node.get("addr:housename")) != null) {
119 /* I18n: name of house as parameter */
120 name = tr("House {0}", s);
121 }
122 if(name == null && (s = node.get("addr:housenumber")) != null) {
123 String t = node.get("addr:street");
124 if(t != null) {
125 /* I18n: house number, street as parameter, number should remain
126 before street for better visibility */
127 name = tr("House number {0} at {1}", s, t);
128 }
129 else {
130 /* I18n: house number as parameter */
131 name = tr("House number {0}", s);
132 }
133 }
134 }
135
136 if (name == null) {
137 name = node.isNew() ? tr("node") : ""+ node.getId();
138 }
139 name += " (" + node.getCoor().latToString(CoordinateFormat.getDefaultFormat()) + ", " + node.getCoor().lonToString(CoordinateFormat.getDefaultFormat()) + ")";
140 }
141 name = decorateNameWithId(name, node);
142 return name;
143 }
144
145 private final Comparator<Node> nodeComparator = new Comparator<Node>() {
146 @Override
147 public int compare(Node n1, Node n2) {
148 return format(n1).compareTo(format(n2));
149 }
150 };
151
152 public Comparator<Node> getNodeComparator() {
153 return nodeComparator;
154 }
155
156
157 /**
158 * Formats a name for a way
159 *
160 * @param way the way
161 * @return the name
162 */
163 public String format(IWay way) {
164 String name = "";
165 if (way.isIncomplete()) {
166 name = tr("incomplete");
167 } else {
168 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
169 name = way.getLocalName();
170 } else {
171 name = way.getName();
172 }
173 if (name == null) {
174 name = way.get("ref");
175 }
176 if (name == null) {
177 name =
178 (way.get("highway") != null) ? tr("highway") :
179 (way.get("railway") != null) ? tr("railway") :
180 (way.get("waterway") != null) ? tr("waterway") :
181 (way.get("landuse") != null) ? tr("landuse") : null;
182 }
183 if(name == null)
184 {
185 String s;
186 if((s = way.get("addr:housename")) != null) {
187 /* I18n: name of house as parameter */
188 name = tr("House {0}", s);
189 }
190 if(name == null && (s = way.get("addr:housenumber")) != null) {
191 String t = way.get("addr:street");
192 if(t != null) {
193 /* I18n: house number, street as parameter, number should remain
194 before street for better visibility */
195 name = tr("House number {0} at {1}", s, t);
196 }
197 else {
198 /* I18n: house number as parameter */
199 name = tr("House number {0}", s);
200 }
201 }
202 }
203
204 int nodesNo = way.getNodesCount();
205 if (nodesNo > 1 && way.isClosed()) {
206 nodesNo--;
207 }
208 if(name == null || name.length() == 0) {
209 name = String.valueOf(way.getId());
210 }
211 /* note: length == 0 should no longer happen, but leave the bracket code
212 nevertheless, who knows what future brings */
213 /* I18n: count of nodes as parameter */
214 String nodes = trn("{0} node", "{0} nodes", nodesNo, nodesNo);
215 name += (name.length() > 0) ? " ("+nodes+")" : nodes;
216 }
217 name = decorateNameWithId(name, way);
218 return name;
219 }
220
221 private final Comparator<Way> wayComparator = new Comparator<Way>() {
222 @Override
223 public int compare(Way w1, Way w2) {
224 return format(w1).compareTo(format(w2));
225 }
226 };
227
228 public Comparator<Way> getWayComparator() {
229 return wayComparator;
230 }
231
232
233 /**
234 * Formats a name for a relation
235 *
236 * @param relation the relation
237 * @return the name
238 */
239 public String format(IRelation relation) {
240 String name;
241 if (relation.isIncomplete()) {
242 name = tr("incomplete");
243 } else {
244 name = getRelationTypeName(relation);
245 String relationName = getRelationName(relation);
246 if (relationName == null) {
247 relationName = Long.toString(relation.getId());
248 } else {
249 relationName = "\"" + relationName + "\"";
250 }
251 name += " (" + relationName + ", ";
252
253 int mbno = relation.getMembersCount();
254 name += trn("{0} member", "{0} members", mbno, mbno);
255
256 if (relation instanceof Relation) {
257 if (relationHasIncompleteMember((Relation) relation)) {
258 name += ", "+tr("incomplete");
259 }
260 }
261
262 name += ")";
263 }
264 name = decorateNameWithId(name, relation);
265 return name;
266 }
267
268 private final Comparator<Relation> relationComparator = new Comparator<Relation>() {
269 @Override
270 public int compare(Relation r1, Relation r2) {
271 String type1 = getRelationTypeName(r1);
272 String type2 = getRelationTypeName(r2);
273
274 int comp = type1.compareTo(type2);
275 if (comp != 0)
276 return comp;
277
278 String name1 = getRelationName(r1);
279 String name2 = getRelationName(r2);
280
281 if (name1 == null && name2 == null)
282 return (r1.getUniqueId() > r2.getUniqueId())?1:-1;
283 else if (name1 == null)
284 return -1;
285 else if (name2 == null)
286 return 1;
287 else if (!name1.isEmpty() && !name2.isEmpty() && Character.isDigit(name1.charAt(0)) && Character.isDigit(name2.charAt(0))) {
288 //Compare numerically
289 String ln1 = getLeadingNumber(name1);
290 String ln2 = getLeadingNumber(name2);
291
292 comp = Long.valueOf(ln1).compareTo(Long.valueOf(ln2));
293 if (comp != 0)
294 return comp;
295
296 // put 1 before 0001
297 comp = ln1.compareTo(ln2);
298 if (comp != 0)
299 return comp;
300
301 comp = name1.substring(ln1.length()).compareTo(name2.substring(ln2.length()));
302 if (comp != 0)
303 return comp;
304 } else {
305 comp = name1.compareToIgnoreCase(name2);
306 if (comp != 0)
307 return comp;
308 }
309
310 if (r1.getMembersCount() != r2.getMembersCount())
311 return (r1.getMembersCount() > r2.getMembersCount())?1:-1;
312
313 comp = Boolean.valueOf(relationHasIncompleteMember(r1)).compareTo(Boolean.valueOf(relationHasIncompleteMember(r2)));
314 if (comp != 0)
315 return comp;
316
317 return r1.getUniqueId() > r2.getUniqueId()?1:-1;
318 }
319 };
320
321 public Comparator<Relation> getRelationComparator() {
322 return relationComparator;
323 }
324
325 private String getLeadingNumber(String s) {
326 int i = 0;
327 while (i < s.length() && Character.isDigit(s.charAt(i))) {
328 i++;
329 }
330 return s.substring(0, i);
331 }
332
333 private String getRelationTypeName(IRelation relation) {
334 String name = trc("Relation type", relation.get("type"));
335 if (name == null) {
336 name = (relation.get("public_transport") != null) ? tr("public transport") : null;
337 }
338 if (name == null) {
339 String building = relation.get("building");
340 if(OsmUtils.isTrue(building)) {
341 name = tr("building");
342 } else if(building != null)
343 {
344 name = tr(building); // translate tag!
345 }
346 }
347 if (name == null) {
348 name = trc("Place type", relation.get("place"));
349 }
350 if (name == null) {
351 name = tr("relation");
352 }
353 String admin_level = relation.get("admin_level");
354 if (admin_level != null) {
355 name += "["+admin_level+"]";
356 }
357
358 return name;
359 }
360
361 private String getNameTagValue(IRelation relation, String nameTag) {
362 if (nameTag.equals("name")) {
363 if (Main.pref.getBoolean("osm-primitives.localize-name", true))
364 return relation.getLocalName();
365 else
366 return relation.getName();
367 } else if (nameTag.equals(":LocationCode")) {
368 for (String m : relation.keySet()) {
369 if (m.endsWith(nameTag))
370 return relation.get(m);
371 }
372 return null;
373 } else
374 return relation.get(nameTag);
375 }
376
377 private String getRelationName(IRelation relation) {
378 String nameTag = null;
379 for (String n : getNamingtagsForRelations()) {
380 nameTag = getNameTagValue(relation, n);
381 if (nameTag != null)
382 return nameTag;
383 }
384 return null;
385 }
386
387 private boolean relationHasIncompleteMember(Relation relation) {
388 for (RelationMember m : relation.getMembers()) {
389 if (m.getMember().isIncomplete())
390 return true;
391 }
392 return false;
393 }
394
395 /**
396 * Formats a name for a changeset
397 *
398 * @param changeset the changeset
399 * @return the name
400 */
401 public String format(Changeset changeset) {
402 return tr("Changeset {0}",changeset.getId());
403 }
404
405 /**
406 * Builds a default tooltip text for the primitive <code>primitive</code>.
407 *
408 * @param primitive the primitmive
409 * @return the tooltip text
410 */
411 public String buildDefaultToolTip(IPrimitive primitive) {
412 StringBuilder sb = new StringBuilder();
413 sb.append("<html>");
414 sb.append("<strong>id</strong>=")
415 .append(primitive.getId())
416 .append("<br>");
417 ArrayList<String> keyList = new ArrayList<String>(primitive.keySet());
418 Collections.sort(keyList);
419 for (int i = 0; i < keyList.size(); i++) {
420 if (i > 0) {
421 sb.append("<br>");
422 }
423 String key = keyList.get(i);
424 sb.append("<strong>")
425 .append(key)
426 .append("</strong>")
427 .append("=");
428 String value = primitive.get(key);
429 while(value.length() != 0) {
430 sb.append(value.substring(0,Math.min(50, value.length())));
431 if (value.length() > 50) {
432 sb.append("<br>");
433 value = value.substring(50);
434 } else {
435 value = "";
436 }
437 }
438 }
439 sb.append("</html>");
440 return sb.toString();
441 }
442
443 /**
444 * Decorates the name of primitive with its id, if the preference
445 * <tt>osm-primitives.showid</tt> is set.
446 *
447 * The id is append to the {@see StringBuilder} passed in in <code>name</code>.
448 *
449 * @param name the name without the id
450 * @param primitive the primitive
451 */
452 protected void decorateNameWithId(StringBuilder name, HistoryOsmPrimitive primitive) {
453 if (Main.pref.getBoolean("osm-primitives.showid")) {
454 name.append(tr(" [id: {0}]", primitive.getId()));
455 }
456 }
457
458 /**
459 * Formats a name for a history node
460 *
461 * @param node the node
462 * @return the name
463 */
464 public String format(HistoryNode node) {
465 StringBuilder sb = new StringBuilder();
466 String name;
467 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
468 name = node.getLocalName();
469 } else {
470 name = node.getName();
471 }
472 if (name == null) {
473 sb.append(node.getId());
474 } else {
475 sb.append(name);
476 }
477 sb.append(" (")
478 .append(node.getCoords().latToString(CoordinateFormat.getDefaultFormat()))
479 .append(", ")
480 .append(node.getCoords().lonToString(CoordinateFormat.getDefaultFormat()))
481 .append(")");
482 decorateNameWithId(sb, node);
483 return sb.toString();
484 }
485
486 /**
487 * Formats a name for a way
488 *
489 * @param way the way
490 * @return the name
491 */
492 public String format(HistoryWay way) {
493 StringBuilder sb = new StringBuilder();
494 String name;
495 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
496 name = way.getLocalName();
497 } else {
498 name = way.getName();
499 }
500 if (name != null) {
501 sb.append(name);
502 }
503 if (sb.length() == 0 && way.get("ref") != null) {
504 sb.append(way.get("ref"));
505 }
506 if (sb.length() == 0) {
507 sb.append(
508 (way.get("highway") != null) ? tr("highway") :
509 (way.get("railway") != null) ? tr("railway") :
510 (way.get("waterway") != null) ? tr("waterway") :
511 (way.get("landuse") != null) ? tr("landuse") : ""
512 );
513 }
514
515 int nodesNo = way.isClosed() ? way.getNumNodes() -1 : way.getNumNodes();
516 String nodes = trn("{0} node", "{0} nodes", nodesNo, nodesNo);
517 if(sb.length() == 0 ) {
518 sb.append(way.getId());
519 }
520 /* note: length == 0 should no longer happen, but leave the bracket code
521 nevertheless, who knows what future brings */
522 sb.append((sb.length() > 0) ? " ("+nodes+")" : nodes);
523 decorateNameWithId(sb, way);
524 return sb.toString();
525 }
526
527 /**
528 * Formats a name for a {@see HistoryRelation})
529 *
530 * @param relation the relation
531 * @return the name
532 */
533 public String format(HistoryRelation relation) {
534 StringBuilder sb = new StringBuilder();
535 if (relation.get("type") != null) {
536 sb.append(relation.get("type"));
537 } else {
538 sb.append(tr("relation"));
539 }
540 sb.append(" (");
541 String nameTag = null;
542 Set<String> namingTags = new HashSet<String>(getNamingtagsForRelations());
543 for (String n : relation.getTags().keySet()) {
544 // #3328: "note " and " note" are name tags too
545 if (namingTags.contains(n.trim())) {
546 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
547 nameTag = relation.getLocalName();
548 } else {
549 nameTag = relation.getName();
550 }
551 if (nameTag == null) {
552 nameTag = relation.get(n);
553 }
554 }
555 if (nameTag != null) {
556 break;
557 }
558 }
559 if (nameTag == null) {
560 sb.append(Long.toString(relation.getId())).append(", ");
561 } else {
562 sb.append("\"").append(nameTag).append("\", ");
563 }
564
565 int mbno = relation.getNumMembers();
566 sb.append(trn("{0} member", "{0} members", mbno, mbno)).append(")");
567
568 decorateNameWithId(sb, relation);
569 return sb.toString();
570 }
571
572 /**
573 * Builds a default tooltip text for an HistoryOsmPrimitive <code>primitive</code>.
574 *
575 * @param primitive the primitmive
576 * @return the tooltip text
577 */
578 public String buildDefaultToolTip(HistoryOsmPrimitive primitive) {
579 StringBuilder sb = new StringBuilder();
580 sb.append("<html>");
581 sb.append("<strong>id</strong>=")
582 .append(primitive.getId())
583 .append("<br>");
584 ArrayList<String> keyList = new ArrayList<String>(primitive.getTags().keySet());
585 Collections.sort(keyList);
586 for (int i = 0; i < keyList.size(); i++) {
587 if (i > 0) {
588 sb.append("<br>");
589 }
590 String key = keyList.get(i);
591 sb.append("<strong>")
592 .append(key)
593 .append("</strong>")
594 .append("=");
595 String value = primitive.get(key);
596 while(value.length() != 0) {
597 sb.append(value.substring(0,Math.min(50, value.length())));
598 if (value.length() > 50) {
599 sb.append("<br>");
600 value = value.substring(50);
601 } else {
602 value = "";
603 }
604 }
605 }
606 sb.append("</html>");
607 return sb.toString();
608 }
609}
Note: See TracBrowser for help on using the repository browser.