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

Last change on this file since 7909 was 7305, checked in by Don-vip, 10 years ago

fix #10239 - proper display of bidirectional texts (osm primitives with RTL names)

  • Property svn:eol-style set to native
File size: 24.6 KB
RevLine 
[2512]1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
[3389]5import static org.openstreetmap.josm.tools.I18n.trc;
[4144]6import static org.openstreetmap.josm.tools.I18n.trc_lazy;
[2512]7import static org.openstreetmap.josm.tools.I18n.trn;
8
[7305]9import java.awt.ComponentOrientation;
[2512]10import java.util.ArrayList;
11import java.util.Arrays;
[5059]12import java.util.Collection;
[2563]13import java.util.Collections;
[4070]14import java.util.Comparator;
[2512]15import java.util.HashSet;
[4209]16import java.util.LinkedList;
[2512]17import java.util.List;
[7305]18import java.util.Locale;
[7018]19import java.util.Map;
[2512]20import java.util.Set;
21
22import org.openstreetmap.josm.Main;
23import org.openstreetmap.josm.data.coor.CoordinateFormat;
[5346]24import org.openstreetmap.josm.data.coor.LatLon;
[2512]25import org.openstreetmap.josm.data.osm.Changeset;
[4100]26import org.openstreetmap.josm.data.osm.IPrimitive;
27import org.openstreetmap.josm.data.osm.IRelation;
[2512]28import org.openstreetmap.josm.data.osm.NameFormatter;
29import org.openstreetmap.josm.data.osm.Node;
[5059]30import org.openstreetmap.josm.data.osm.OsmPrimitive;
[3268]31import org.openstreetmap.josm.data.osm.OsmUtils;
[2512]32import org.openstreetmap.josm.data.osm.Relation;
33import org.openstreetmap.josm.data.osm.Way;
[2689]34import org.openstreetmap.josm.data.osm.history.HistoryNameFormatter;
35import org.openstreetmap.josm.data.osm.history.HistoryNode;
36import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
37import org.openstreetmap.josm.data.osm.history.HistoryRelation;
38import org.openstreetmap.josm.data.osm.history.HistoryWay;
[4431]39import org.openstreetmap.josm.gui.tagging.TaggingPreset;
[7119]40import org.openstreetmap.josm.gui.tagging.TaggingPresetNameTemplateList;
[5083]41import org.openstreetmap.josm.tools.AlphanumComparator;
[4477]42import org.openstreetmap.josm.tools.I18n;
[5132]43import org.openstreetmap.josm.tools.Utils;
44import org.openstreetmap.josm.tools.Utils.Function;
[2512]45
46/**
[5266]47 * This is the default implementation of a {@link NameFormatter} for names of {@link OsmPrimitive}s.
[2512]48 *
49 */
[2689]50public class DefaultNameFormatter implements NameFormatter, HistoryNameFormatter {
[2512]51
[6889]52 private static DefaultNameFormatter instance;
[2512]53
[7005]54 private static final List<NameFormatterHook> formatHooks = new LinkedList<>();
[4209]55
[2512]56 /**
57 * Replies the unique instance of this formatter
58 *
59 * @return the unique instance of this formatter
60 */
[6889]61 public static DefaultNameFormatter getInstance() {
[2512]62 if (instance == null) {
63 instance = new DefaultNameFormatter();
64 }
65 return instance;
66 }
[4431]67
[4209]68 /**
69 * Registers a format hook. Adds the hook at the first position of the format hooks.
70 * (for plugins)
71 *
72 * @param hook the format hook. Ignored if null.
73 */
74 public static void registerFormatHook(NameFormatterHook hook) {
75 if (hook == null) return;
76 if (!formatHooks.contains(hook)) {
77 formatHooks.add(0,hook);
78 }
79 }
[2512]80
[4209]81 /**
82 * Unregisters a format hook. Removes the hook from the list of format hooks.
83 *
84 * @param hook the format hook. Ignored if null.
85 */
86 public static void unregisterFormatHook(NameFormatterHook hook) {
87 if (hook == null) return;
88 if (formatHooks.contains(hook)) {
89 formatHooks.remove(hook);
90 }
91 }
92
[4882]93 /** The default list of tags which are used as naming tags in relations.
94 * A ? prefix indicates a boolean value, for which the key (instead of the value) is used.
95 */
[6889]96 public static final String[] DEFAULT_NAMING_TAGS_FOR_RELATIONS = {"name", "ref", "restriction", "landuse", "natural",
[4882]97 "public_transport", ":LocationCode", "note", "?building"};
[2512]98
99 /** the current list of tags used as naming tags in relations */
[6889]100 private static List<String> namingTagsForRelations = null;
[2512]101
102 /**
103 * Replies the list of naming tags used in relations. The list is given (in this order) by:
104 * <ul>
105 * <li>by the tag names in the preference <tt>relation.nameOrder</tt></li>
[5266]106 * <li>by the default tags in {@link #DEFAULT_NAMING_TAGS_FOR_RELATIONS}
[2512]107 * </ul>
108 *
109 * @return the list of naming tags used in relations
110 */
[6889]111 public static List<String> getNamingtagsForRelations() {
[2512]112 if (namingTagsForRelations == null) {
[7005]113 namingTagsForRelations = new ArrayList<>(
[2512]114 Main.pref.getCollection("relation.nameOrder", Arrays.asList(DEFAULT_NAMING_TAGS_FOR_RELATIONS))
[4431]115 );
[2512]116 }
117 return namingTagsForRelations;
118 }
119
120 /**
121 * Decorates the name of primitive with its id, if the preference
[2973]122 * <tt>osm-primitives.showid</tt> is set. Shows unique id if osm-primitives.showid.new-primitives is set
[2512]123 *
124 * @param name the name without the id
125 * @param primitive the primitive
126 */
[4431]127 protected void decorateNameWithId(StringBuilder name, IPrimitive primitive) {
128 if (Main.pref.getBoolean("osm-primitives.showid")) {
129 if (Main.pref.getBoolean("osm-primitives.showid.new-primitives")) {
130 name.append(tr(" [id: {0}]", primitive.getUniqueId()));
131 } else {
132 name.append(tr(" [id: {0}]", primitive.getId()));
133 }
134 }
[2512]135 }
136
137 /**
138 * Formats a name for a node
139 *
140 * @param node the node
141 * @return the name
142 */
[6084]143 @Override
[4431]144 public String format(Node node) {
145 StringBuilder name = new StringBuilder();
[2578]146 if (node.isIncomplete()) {
[4431]147 name.append(tr("incomplete"));
[2512]148 } else {
[4431]149 TaggingPreset preset = TaggingPresetNameTemplateList.getInstance().findPresetTemplate(node);
150 if (preset == null) {
151 String n;
152 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
153 n = node.getLocalName();
154 } else {
155 n = node.getName();
[3887]156 }
[4431]157 if(n == null)
158 {
159 String s;
160 if((s = node.get("addr:housename")) != null) {
161 /* I18n: name of house as parameter */
162 n = tr("House {0}", s);
163 }
164 if(n == null && (s = node.get("addr:housenumber")) != null) {
165 String t = node.get("addr:street");
166 if(t != null) {
167 /* I18n: house number, street as parameter, number should remain
[3887]168 before street for better visibility */
[4431]169 n = tr("House number {0} at {1}", s, t);
170 }
171 else {
172 /* I18n: house number as parameter */
173 n = tr("House number {0}", s);
174 }
[3887]175 }
176 }
177
[4431]178 if (n == null) {
[6986]179 n = node.isNew() ? tr("node") : Long.toString(node.getId());
[4431]180 }
181 name.append(n);
182 } else {
183 preset.nameTemplate.appendText(name, node);
[2512]184 }
[5328]185 if (node.getCoor() != null) {
186 name.append(" \u200E(").append(node.getCoor().latToString(CoordinateFormat.getDefaultFormat())).append(", ").append(node.getCoor().lonToString(CoordinateFormat.getDefaultFormat())).append(")");
187 }
[2512]188 }
[4431]189 decorateNameWithId(name, node);
[4209]190
[4431]191
192 String result = name.toString();
[4209]193 for (NameFormatterHook hook: formatHooks) {
[4431]194 String hookResult = hook.checkFormat(node, result);
195 if (hookResult != null)
[4209]196 return hookResult;
197 }
198
[4431]199 return result;
[2512]200 }
201
[4070]202 private final Comparator<Node> nodeComparator = new Comparator<Node>() {
203 @Override
204 public int compare(Node n1, Node n2) {
205 return format(n1).compareTo(format(n2));
206 }
207 };
208
[6084]209 @Override
[4070]210 public Comparator<Node> getNodeComparator() {
211 return nodeComparator;
212 }
213
214
[2512]215 /**
216 * Formats a name for a way
217 *
218 * @param way the way
219 * @return the name
220 */
[6084]221 @Override
[4431]222 public String format(Way way) {
223 StringBuilder name = new StringBuilder();
[7305]224
225 char mark = 0;
226 // If current language is left-to-right (almost all languages)
227 if (ComponentOrientation.getOrientation(Locale.getDefault()).isLeftToRight()) {
228 // will insert Left-To-Right Mark to ensure proper display of text in the case when object name is right-to-left
229 mark = '\u200E';
230 } else {
231 // otherwise will insert Right-To-Left Mark to ensure proper display in the opposite case
232 mark = '\u200F';
233 }
234 // Initialize base direction of the string
235 name.append(mark);
236
[2578]237 if (way.isIncomplete()) {
[4431]238 name.append(tr("incomplete"));
[2512]239 } else {
[4431]240 TaggingPreset preset = TaggingPresetNameTemplateList.getInstance().findPresetTemplate(way);
241 if (preset == null) {
242 String n;
243 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
244 n = way.getLocalName();
245 } else {
246 n = way.getName();
[3887]247 }
[4431]248 if (n == null) {
249 n = way.get("ref");
250 }
251 if (n == null) {
[7305]252 n = (way.get("highway") != null) ? tr("highway") :
[4431]253 (way.get("railway") != null) ? tr("railway") :
254 (way.get("waterway") != null) ? tr("waterway") :
[4744]255 (way.get("landuse") != null) ? tr("landuse") : null;
[4431]256 }
[7305]257 if (n == null) {
[4431]258 String s;
259 if((s = way.get("addr:housename")) != null) {
260 /* I18n: name of house as parameter */
261 n = tr("House {0}", s);
262 }
263 if(n == null && (s = way.get("addr:housenumber")) != null) {
264 String t = way.get("addr:street");
265 if(t != null) {
266 /* I18n: house number, street as parameter, number should remain
[3887]267 before street for better visibility */
[4431]268 n = tr("House number {0} at {1}", s, t);
269 }
270 else {
271 /* I18n: house number as parameter */
272 n = tr("House number {0}", s);
273 }
[3887]274 }
275 }
[4807]276 if(n == null && way.get("building") != null) n = tr("building");
[4431]277 if(n == null || n.length() == 0) {
278 n = String.valueOf(way.getId());
279 }
280
281 name.append(n);
282 } else {
283 preset.nameTemplate.appendText(name, way);
[3887]284 }
[2512]285
[5847]286 int nodesNo = way.getRealNodesCount();
[3286]287 /* note: length == 0 should no longer happen, but leave the bracket code
288 nevertheless, who knows what future brings */
[3887]289 /* I18n: count of nodes as parameter */
[2512]290 String nodes = trn("{0} node", "{0} nodes", nodesNo, nodesNo);
[7305]291 name.append(mark).append(" (").append(nodes).append(")");
[2512]292 }
[4431]293 decorateNameWithId(name, way);
294
295 String result = name.toString();
[4209]296 for (NameFormatterHook hook: formatHooks) {
[4431]297 String hookResult = hook.checkFormat(way, result);
298 if (hookResult != null)
[4209]299 return hookResult;
300 }
301
[4431]302 return result;
[2512]303 }
304
[4070]305 private final Comparator<Way> wayComparator = new Comparator<Way>() {
306 @Override
307 public int compare(Way w1, Way w2) {
308 return format(w1).compareTo(format(w2));
309 }
310 };
311
[6084]312 @Override
[4070]313 public Comparator<Way> getWayComparator() {
314 return wayComparator;
315 }
316
317
[2512]318 /**
319 * Formats a name for a relation
320 *
321 * @param relation the relation
322 * @return the name
323 */
[6084]324 @Override
[4431]325 public String format(Relation relation) {
326 StringBuilder name = new StringBuilder();
[2578]327 if (relation.isIncomplete()) {
[4431]328 name.append(tr("incomplete"));
[2512]329 } else {
[4431]330 TaggingPreset preset = TaggingPresetNameTemplateList.getInstance().findPresetTemplate(relation);
[2512]331
[4431]332 formatRelationNameAndType(relation, name, preset);
333
[2512]334 int mbno = relation.getMembersCount();
[4431]335 name.append(trn("{0} member", "{0} members", mbno, mbno));
[2885]336
[4431]337 if (relation.hasIncompleteMembers()) {
338 name.append(", ").append(tr("incomplete"));
[2885]339 }
340
[4431]341 name.append(")");
[2512]342 }
[4431]343 decorateNameWithId(name, relation);
[4209]344
[4431]345 String result = name.toString();
[4209]346 for (NameFormatterHook hook: formatHooks) {
[4431]347 String hookResult = hook.checkFormat(relation, result);
348 if (hookResult != null)
[4209]349 return hookResult;
350 }
351
[4431]352 return result;
[2512]353 }
354
[4431]355 private void formatRelationNameAndType(Relation relation, StringBuilder result, TaggingPreset preset) {
356 if (preset == null) {
357 result.append(getRelationTypeName(relation));
358 String relationName = getRelationName(relation);
359 if (relationName == null) {
360 relationName = Long.toString(relation.getId());
361 } else {
362 relationName = "\"" + relationName + "\"";
363 }
364 result.append(" (").append(relationName).append(", ");
365 } else {
366 preset.nameTemplate.appendText(result, relation);
367 result.append("(");
368 }
369 }
370
[4070]371 private final Comparator<Relation> relationComparator = new Comparator<Relation>() {
372 @Override
373 public int compare(Relation r1, Relation r2) {
[4431]374 //TODO This doesn't work correctly with formatHooks
[4070]375
[4431]376 TaggingPreset preset1 = TaggingPresetNameTemplateList.getInstance().findPresetTemplate(r1);
377 TaggingPreset preset2 = TaggingPresetNameTemplateList.getInstance().findPresetTemplate(r2);
[4070]378
[4431]379 if (preset1 != null || preset2 != null) {
380 StringBuilder name1 = new StringBuilder();
381 formatRelationNameAndType(r1, name1, preset1);
382 StringBuilder name2 = new StringBuilder();
383 formatRelationNameAndType(r2, name2, preset2);
[4070]384
[7098]385 int comp = AlphanumComparator.getInstance().compare(name1.toString(), name2.toString());
[4070]386 if (comp != 0)
387 return comp;
[4431]388 } else {
[4070]389
[4431]390 String type1 = getRelationTypeName(r1);
391 String type2 = getRelationTypeName(r2);
392
[6804]393 int comp = AlphanumComparator.getInstance().compare(type1, type2);
[4070]394 if (comp != 0)
395 return comp;
396
[4431]397 String name1 = getRelationName(r1);
398 String name2 = getRelationName(r2);
399
[6804]400 comp = AlphanumComparator.getInstance().compare(name1, name2);
[5710]401 if (comp != 0)
402 return comp;
[4070]403 }
404
405 if (r1.getMembersCount() != r2.getMembersCount())
406 return (r1.getMembersCount() > r2.getMembersCount())?1:-1;
407
[4431]408 int comp = Boolean.valueOf(r1.hasIncompleteMembers()).compareTo(Boolean.valueOf(r2.hasIncompleteMembers()));
[4070]409 if (comp != 0)
410 return comp;
411
[6070]412 if (r1.getUniqueId() > r2.getUniqueId())
[5750]413 return 1;
414 else if (r1.getUniqueId() < r2.getUniqueId())
415 return -1;
416 else
417 return 0;
[4070]418 }
419 };
420
[6084]421 @Override
[4070]422 public Comparator<Relation> getRelationComparator() {
423 return relationComparator;
424 }
425
[4100]426 private String getRelationTypeName(IRelation relation) {
[4070]427 String name = trc("Relation type", relation.get("type"));
428 if (name == null) {
429 name = (relation.get("public_transport") != null) ? tr("public transport") : null;
430 }
431 if (name == null) {
432 String building = relation.get("building");
[4744]433 if (OsmUtils.isTrue(building)) {
[4070]434 name = tr("building");
435 } else if(building != null)
436 {
437 name = tr(building); // translate tag!
438 }
439 }
440 if (name == null) {
441 name = trc("Place type", relation.get("place"));
442 }
443 if (name == null) {
444 name = tr("relation");
445 }
446 String admin_level = relation.get("admin_level");
447 if (admin_level != null) {
448 name += "["+admin_level+"]";
449 }
[4431]450
[4209]451 for (NameFormatterHook hook: formatHooks) {
452 String hookResult = hook.checkRelationTypeName(relation, name);
[4431]453 if (hookResult != null)
[4209]454 return hookResult;
455 }
[4070]456
457 return name;
458 }
459
[4100]460 private String getNameTagValue(IRelation relation, String nameTag) {
[6990]461 if ("name".equals(nameTag)) {
[4070]462 if (Main.pref.getBoolean("osm-primitives.localize-name", true))
463 return relation.getLocalName();
464 else
465 return relation.getName();
[6990]466 } else if (":LocationCode".equals(nameTag)) {
[4070]467 for (String m : relation.keySet()) {
468 if (m.endsWith(nameTag))
469 return relation.get(m);
470 }
471 return null;
[4882]472 } else if (nameTag.startsWith("?") && OsmUtils.isTrue(relation.get(nameTag.substring(1)))) {
473 return tr(nameTag.substring(1));
474 } else if (nameTag.startsWith("?") && OsmUtils.isFalse(relation.get(nameTag.substring(1)))) {
[4744]475 return null;
[7112]476 } else if (nameTag.startsWith("?")) {
477 return trc_lazy(nameTag, I18n.escape(relation.get(nameTag.substring(1))));
[4744]478 } else {
[4477]479 return trc_lazy(nameTag, I18n.escape(relation.get(nameTag)));
[4744]480 }
[4070]481 }
482
[4100]483 private String getRelationName(IRelation relation) {
[4070]484 String nameTag = null;
485 for (String n : getNamingtagsForRelations()) {
486 nameTag = getNameTagValue(relation, n);
487 if (nameTag != null)
488 return nameTag;
489 }
490 return null;
491 }
492
[2512]493 /**
494 * Formats a name for a changeset
495 *
496 * @param changeset the changeset
497 * @return the name
498 */
[6084]499 @Override
[2512]500 public String format(Changeset changeset) {
501 return tr("Changeset {0}",changeset.getId());
502 }
[2563]503
504 /**
505 * Builds a default tooltip text for the primitive <code>primitive</code>.
[2711]506 *
[2563]507 * @param primitive the primitmive
508 * @return the tooltip text
509 */
[4100]510 public String buildDefaultToolTip(IPrimitive primitive) {
[7018]511 return buildDefaultToolTip(primitive.getId(), primitive.getKeys());
512 }
[7098]513
[7018]514 private String buildDefaultToolTip(long id, Map<String, String> tags) {
[2563]515 StringBuilder sb = new StringBuilder();
516 sb.append("<html>");
517 sb.append("<strong>id</strong>=")
[7018]518 .append(id)
[2563]519 .append("<br>");
[7018]520 List<String> keyList = new ArrayList<>(tags.keySet());
[2563]521 Collections.sort(keyList);
522 for (int i = 0; i < keyList.size(); i++) {
523 if (i > 0) {
524 sb.append("<br>");
525 }
526 String key = keyList.get(i);
527 sb.append("<strong>")
528 .append(key)
529 .append("</strong>")
530 .append("=");
[7018]531 String value = tags.get(key);
[2563]532 while(value.length() != 0) {
533 sb.append(value.substring(0,Math.min(50, value.length())));
534 if (value.length() > 50) {
535 sb.append("<br>");
536 value = value.substring(50);
537 } else {
538 value = "";
539 }
540 }
541 }
542 sb.append("</html>");
543 return sb.toString();
544 }
[2689]545
546 /**
547 * Decorates the name of primitive with its id, if the preference
548 * <tt>osm-primitives.showid</tt> is set.
[2711]549 *
[7187]550 * The id is append to the {@link StringBuilder} passed in <code>name</code>.
[2689]551 *
552 * @param name the name without the id
553 * @param primitive the primitive
554 */
555 protected void decorateNameWithId(StringBuilder name, HistoryOsmPrimitive primitive) {
556 if (Main.pref.getBoolean("osm-primitives.showid")) {
557 name.append(tr(" [id: {0}]", primitive.getId()));
558 }
559 }
560
561 /**
562 * Formats a name for a history node
563 *
564 * @param node the node
565 * @return the name
566 */
[6084]567 @Override
[2689]568 public String format(HistoryNode node) {
569 StringBuilder sb = new StringBuilder();
570 String name;
571 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
572 name = node.getLocalName();
573 } else {
574 name = node.getName();
575 }
576 if (name == null) {
577 sb.append(node.getId());
578 } else {
579 sb.append(name);
580 }
[5346]581 LatLon coord = node.getCoords();
582 if (coord != null) {
583 sb.append(" (")
584 .append(coord.latToString(CoordinateFormat.getDefaultFormat()))
585 .append(", ")
586 .append(coord.lonToString(CoordinateFormat.getDefaultFormat()))
587 .append(")");
588 }
[2689]589 decorateNameWithId(sb, node);
590 return sb.toString();
591 }
592
593 /**
594 * Formats a name for a way
595 *
596 * @param way the way
597 * @return the name
598 */
[6084]599 @Override
[2689]600 public String format(HistoryWay way) {
601 StringBuilder sb = new StringBuilder();
602 String name;
603 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
604 name = way.getLocalName();
605 } else {
606 name = way.getName();
607 }
608 if (name != null) {
609 sb.append(name);
610 }
611 if (sb.length() == 0 && way.get("ref") != null) {
612 sb.append(way.get("ref"));
613 }
614 if (sb.length() == 0) {
615 sb.append(
616 (way.get("highway") != null) ? tr("highway") :
617 (way.get("railway") != null) ? tr("railway") :
618 (way.get("waterway") != null) ? tr("waterway") :
619 (way.get("landuse") != null) ? tr("landuse") : ""
[4431]620 );
[2689]621 }
622
623 int nodesNo = way.isClosed() ? way.getNumNodes() -1 : way.getNumNodes();
624 String nodes = trn("{0} node", "{0} nodes", nodesNo, nodesNo);
[4070]625 if(sb.length() == 0 ) {
[3286]626 sb.append(way.getId());
[4070]627 }
[3286]628 /* note: length == 0 should no longer happen, but leave the bracket code
629 nevertheless, who knows what future brings */
[2689]630 sb.append((sb.length() > 0) ? " ("+nodes+")" : nodes);
631 decorateNameWithId(sb, way);
632 return sb.toString();
633 }
634
635 /**
[5266]636 * Formats a name for a {@link HistoryRelation})
[2689]637 *
638 * @param relation the relation
639 * @return the name
640 */
[6084]641 @Override
[2689]642 public String format(HistoryRelation relation) {
643 StringBuilder sb = new StringBuilder();
644 if (relation.get("type") != null) {
645 sb.append(relation.get("type"));
646 } else {
647 sb.append(tr("relation"));
648 }
649 sb.append(" (");
650 String nameTag = null;
[7005]651 Set<String> namingTags = new HashSet<>(getNamingtagsForRelations());
[2689]652 for (String n : relation.getTags().keySet()) {
653 // #3328: "note " and " note" are name tags too
654 if (namingTags.contains(n.trim())) {
655 if (Main.pref.getBoolean("osm-primitives.localize-name", true)) {
656 nameTag = relation.getLocalName();
657 } else {
658 nameTag = relation.getName();
659 }
660 if (nameTag == null) {
661 nameTag = relation.get(n);
662 }
663 }
664 if (nameTag != null) {
665 break;
666 }
667 }
668 if (nameTag == null) {
669 sb.append(Long.toString(relation.getId())).append(", ");
670 } else {
671 sb.append("\"").append(nameTag).append("\", ");
672 }
673
674 int mbno = relation.getNumMembers();
675 sb.append(trn("{0} member", "{0} members", mbno, mbno)).append(")");
676
677 decorateNameWithId(sb, relation);
678 return sb.toString();
679 }
680
681 /**
682 * Builds a default tooltip text for an HistoryOsmPrimitive <code>primitive</code>.
[2711]683 *
[2689]684 * @param primitive the primitmive
685 * @return the tooltip text
686 */
687 public String buildDefaultToolTip(HistoryOsmPrimitive primitive) {
[7018]688 return buildDefaultToolTip(primitive.getId(), primitive.getTags());
[2689]689 }
[5059]690
691 public String formatAsHtmlUnorderedList(Collection<? extends OsmPrimitive> primitives) {
[5132]692 return Utils.joinAsHtmlUnorderedList(Utils.transform(primitives, new Function<OsmPrimitive, String>() {
693
694 @Override
695 public String apply(OsmPrimitive x) {
696 return x.getDisplayName(DefaultNameFormatter.this);
697 }
698 }));
[5059]699 }
700
701 public String formatAsHtmlUnorderedList(OsmPrimitive... primitives) {
702 return formatAsHtmlUnorderedList(Arrays.asList(primitives));
703 }
[2512]704}
Note: See TracBrowser for help on using the repository browser.