source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/properties/PropertiesCellRenderer.java@ 14509

Last change on this file since 14509 was 14185, checked in by Don-vip, 6 years ago

fix #16687 - Display tag languages in italic

  • Property svn:eol-style set to native
File size: 7.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs.properties;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6import static org.openstreetmap.josm.tools.I18n.trn;
7
8import java.awt.Color;
9import java.awt.Component;
10import java.awt.Font;
11import java.util.Collection;
12import java.util.Locale;
13import java.util.Map;
14import java.util.Objects;
15import java.util.Optional;
16import java.util.concurrent.CopyOnWriteArrayList;
17import java.util.regex.Matcher;
18import java.util.regex.Pattern;
19
20import javax.swing.JLabel;
21import javax.swing.JTable;
22import javax.swing.UIManager;
23import javax.swing.table.DefaultTableCellRenderer;
24import javax.swing.table.TableCellRenderer;
25
26import org.openstreetmap.josm.data.osm.AbstractPrimitive;
27import org.openstreetmap.josm.data.preferences.BooleanProperty;
28import org.openstreetmap.josm.data.preferences.CachingProperty;
29import org.openstreetmap.josm.data.preferences.NamedColorProperty;
30
31/**
32 * Cell renderer of tags table.
33 * @since 6314
34 */
35public class PropertiesCellRenderer extends DefaultTableCellRenderer {
36
37 private static final CachingProperty<Color> SELECTED_FG
38 = new NamedColorProperty(marktr("Discardable key: selection Foreground"), Color.GRAY).cached();
39 private static final CachingProperty<Color> SELECTED_BG;
40 private static final CachingProperty<Color> NORMAL_FG
41 = new NamedColorProperty(marktr("Discardable key: foreground"), Color.GRAY).cached();
42 private static final CachingProperty<Color> NORMAL_BG;
43 private static final CachingProperty<Boolean> DISCARDABLE
44 = new BooleanProperty("display.discardable-keys", false).cached();
45
46 // Matches ISO-639 two and three letters language codes
47 private static final Pattern LANGUAGE_NAMES = Pattern.compile("name:(\\p{Lower}{2,3})");
48
49 static {
50 SELECTED_BG = new NamedColorProperty(marktr("Discardable key: selection Background"),
51 Optional.ofNullable(UIManager.getColor("Table.selectionBackground")).orElse(Color.BLUE)).cached();
52 NORMAL_BG = new NamedColorProperty(marktr("Discardable key: background"),
53 Optional.ofNullable(UIManager.getColor("Table.background")).orElse(Color.WHITE)).cached();
54 }
55
56 private final Collection<TableCellRenderer> customRenderer = new CopyOnWriteArrayList<>();
57
58 private static void setColors(Component c, String key, boolean isSelected) {
59
60 if (AbstractPrimitive.getDiscardableKeys().contains(key)) {
61 c.setForeground((isSelected ? SELECTED_FG : NORMAL_FG).get());
62 c.setBackground((isSelected ? SELECTED_BG : NORMAL_BG).get());
63 } else {
64 c.setForeground(UIManager.getColor("Table."+(isSelected ? "selectionF" : "f")+"oreground"));
65 c.setBackground(UIManager.getColor("Table."+(isSelected ? "selectionB" : "b")+"ackground"));
66 }
67 }
68
69 @Override
70 public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
71 for (TableCellRenderer renderer : customRenderer) {
72 final Component component = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
73 if (component != null) {
74 return component;
75 }
76 }
77 if (value == null)
78 return this;
79 Component c = super.getTableCellRendererComponent(table, value, isSelected, false, row, column);
80 if (c instanceof JLabel) {
81 String str = null;
82 if (value instanceof String) {
83 str = (String) value;
84 } else if (value instanceof Map<?, ?>) {
85 Map<?, ?> v = (Map<?, ?>) value;
86 if (v.size() != 1) { // Multiple values: give user a short summary of the values
87 Integer blankCount;
88 Integer otherCount;
89 if (v.get("") == null) {
90 blankCount = 0;
91 otherCount = v.size();
92 } else {
93 blankCount = (Integer) v.get("");
94 otherCount = v.size()-1;
95 }
96 StringBuilder sb = new StringBuilder("<");
97 if (otherCount == 1) {
98 // Find the non-blank value in the map
99 v.entrySet().stream().filter(entry -> !Objects.equals(entry.getKey(), ""))
100 /* I18n: properties display partial string joined with comma, first is count, second is value */
101 .findAny().ifPresent(entry -> sb.append(tr("{0} ''{1}''", entry.getValue().toString(), entry.getKey())));
102 } else {
103 /* I18n: properties display partial string joined with comma */
104 sb.append(trn("{0} different", "{0} different", otherCount, otherCount));
105 }
106 if (blankCount > 0) {
107 /* I18n: properties display partial string joined with comma */
108 sb.append(trn(", {0} unset", ", {0} unset", blankCount, blankCount));
109 }
110 sb.append('>');
111 str = sb.toString();
112 c.setFont(c.getFont().deriveFont(Font.ITALIC));
113
114 } else { // One value: display the value
115 str = (String) v.entrySet().iterator().next().getKey();
116 }
117 }
118 boolean knownNameKey = false;
119 if (column == 0 && str != null) {
120 Matcher m = LANGUAGE_NAMES.matcher(str);
121 if (m.matches()) {
122 String code = m.group(1);
123 String label = new Locale(code).getDisplayLanguage();
124 knownNameKey = !code.equals(label);
125 if (knownNameKey) {
126 str = new StringBuilder("<html><body>").append(str)
127 .append(" <i>&lt;").append(label).append("&gt;</i></body></html>").toString();
128 }
129 }
130 }
131 ((JLabel) c).putClientProperty("html.disable", knownNameKey ? null : Boolean.TRUE); // Fix #8730
132 ((JLabel) c).setText(str);
133 if (DISCARDABLE.get()) {
134 String key = null;
135 if (column == 0) {
136 key = str;
137 } else if (column == 1) {
138 Object value0 = table.getModel().getValueAt(row, 0);
139 if (value0 instanceof String) {
140 key = (String) value0;
141 }
142 }
143 setColors(c, key, isSelected);
144 }
145 }
146 return c;
147 }
148
149 /**
150 * Adds a custom table cell renderer to render cells of the tags table.
151 *
152 * If the renderer is not capable performing a {@link TableCellRenderer#getTableCellRendererComponent},
153 * it should return {@code null} to fall back to the
154 * {@link PropertiesCellRenderer#getTableCellRendererComponent default implementation}.
155 * @param renderer the renderer to add
156 * @since 9149
157 */
158 public void addCustomRenderer(TableCellRenderer renderer) {
159 customRenderer.add(renderer);
160 }
161
162 /**
163 * Removes a custom table cell renderer.
164 * @param renderer the renderer to remove
165 * @since 9149
166 */
167 public void removeCustomRenderer(TableCellRenderer renderer) {
168 customRenderer.remove(renderer);
169 }
170}
Note: See TracBrowser for help on using the repository browser.