source: josm/trunk/src/org/openstreetmap/josm/gui/dialogs/InspectPrimitiveDialog.java@ 16950

Last change on this file since 16950 was 16950, checked in by simon04, 4 years ago

Revert "fix #19717 - DefaultNameFormatter: use FIRST-STRONG ISOLATE for bidirectional texts"

This reverts commit r16937

  • Property svn:eol-style set to native
File size: 9.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.dialogs;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trn;
6
7import java.awt.Dimension;
8import java.awt.GridBagLayout;
9import java.io.PrintWriter;
10import java.io.StringWriter;
11import java.text.Collator;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.List;
15import java.util.Locale;
16import java.util.Map;
17import java.util.Map.Entry;
18import java.util.Objects;
19import java.util.TreeMap;
20import java.util.stream.Collectors;
21
22import javax.swing.JPanel;
23import javax.swing.JScrollPane;
24import javax.swing.JTabbedPane;
25import javax.swing.SingleSelectionModel;
26
27import org.openstreetmap.josm.data.osm.DefaultNameFormatter;
28import org.openstreetmap.josm.data.osm.IPrimitive;
29import org.openstreetmap.josm.data.osm.OsmData;
30import org.openstreetmap.josm.data.osm.PrimitiveComparator;
31import org.openstreetmap.josm.data.osm.User;
32import org.openstreetmap.josm.gui.ExtendedDialog;
33import org.openstreetmap.josm.gui.MainApplication;
34import org.openstreetmap.josm.gui.NavigatableComponent;
35import org.openstreetmap.josm.gui.mappaint.Cascade;
36import org.openstreetmap.josm.gui.mappaint.ElemStyles;
37import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
38import org.openstreetmap.josm.gui.mappaint.MultiCascade;
39import org.openstreetmap.josm.gui.mappaint.StyleCache;
40import org.openstreetmap.josm.gui.mappaint.StyleElementList;
41import org.openstreetmap.josm.gui.mappaint.StyleSource;
42import org.openstreetmap.josm.gui.mappaint.mapcss.MapCSSStyleSource;
43import org.openstreetmap.josm.gui.mappaint.styleelement.StyleElement;
44import org.openstreetmap.josm.gui.util.GuiHelper;
45import org.openstreetmap.josm.gui.util.WindowGeometry;
46import org.openstreetmap.josm.gui.widgets.JosmTextArea;
47import org.openstreetmap.josm.tools.GBC;
48
49/**
50 * Panel to inspect one or more OsmPrimitives.
51 *
52 * Gives an unfiltered view of the object's internal state.
53 * Might be useful for power users to give more detailed bug reports and
54 * to better understand the JOSM data representation.
55 */
56public class InspectPrimitiveDialog extends ExtendedDialog {
57
58 protected transient List<IPrimitive> primitives;
59 private boolean mappaintTabLoaded;
60 private boolean editcountTabLoaded;
61
62 /**
63 * Constructs a new {@code InspectPrimitiveDialog}.
64 * @param primitives collection of primitives
65 * @param data data set
66 * @since 12672 (signature)
67 */
68 public InspectPrimitiveDialog(final Collection<? extends IPrimitive> primitives, OsmData<?, ?, ?, ?> data) {
69 super(MainApplication.getMainFrame(), tr("Advanced object info"), tr("Close"));
70 this.primitives = new ArrayList<>(primitives);
71 setRememberWindowGeometry(getClass().getName() + ".geometry",
72 WindowGeometry.centerInWindow(MainApplication.getMainFrame(), new Dimension(750, 550)));
73
74 setButtonIcons("ok");
75 final JTabbedPane tabs = new JTabbedPane();
76
77 tabs.addTab(tr("data"), genericMonospacePanel(new JPanel(), buildDataText(data, this.primitives)));
78
79 final JPanel pMapPaint = new JPanel();
80 tabs.addTab(tr("map style"), pMapPaint);
81 tabs.getModel().addChangeListener(e -> {
82 if (!mappaintTabLoaded && ((SingleSelectionModel) e.getSource()).getSelectedIndex() == 1) {
83 mappaintTabLoaded = true;
84 genericMonospacePanel(pMapPaint, buildMapPaintText());
85 }
86 });
87
88 final JPanel pEditCounts = new JPanel();
89 tabs.addTab(tr("edit counts"), pEditCounts);
90 tabs.getModel().addChangeListener(e -> {
91 if (!editcountTabLoaded && ((SingleSelectionModel) e.getSource()).getSelectedIndex() == 2) {
92 editcountTabLoaded = true;
93 genericMonospacePanel(pEditCounts, buildListOfEditorsText(primitives));
94 }
95 });
96
97 setContent(tabs, false);
98 configureContextsensitiveHelp("/Action/InfoAboutElements", true /* show help button */);
99 }
100
101 protected static JPanel genericMonospacePanel(JPanel p, String s) {
102 p.setLayout(new GridBagLayout());
103 JosmTextArea jte = new JosmTextArea();
104 jte.setFont(GuiHelper.getMonospacedFont(jte));
105 jte.setEditable(false);
106 jte.append(s);
107 jte.setCaretPosition(0);
108 p.add(new JScrollPane(jte), GBC.std().fill());
109 return p;
110 }
111
112 protected static String buildDataText(OsmData<?, ?, ?, ?> data, List<IPrimitive> primitives) {
113 InspectPrimitiveDataText dt = new InspectPrimitiveDataText(data);
114 primitives.stream()
115 .sorted(PrimitiveComparator.orderingWaysRelationsNodes().thenComparing(PrimitiveComparator.comparingNames()))
116 .forEachOrdered(dt::addPrimitive);
117 return dt.toString();
118 }
119
120 protected static String buildMapPaintText() {
121 final Collection<? extends IPrimitive> sel = MainApplication.getLayerManager().getActiveData().getAllSelected();
122 ElemStyles elemstyles = MapPaintStyles.getStyles();
123 NavigatableComponent nc = MainApplication.getMap().mapView;
124 double scale = nc.getDist100Pixel();
125
126 final StringWriter stringWriter = new StringWriter();
127 final PrintWriter txtMappaint = new PrintWriter(stringWriter);
128 MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().lock();
129 try {
130 for (IPrimitive osm : sel) {
131 String heading = tr("Styles for \"{0}\":", osm.getDisplayName(DefaultNameFormatter.getInstance()));
132 txtMappaint.println(heading);
133 txtMappaint.println(repeatString("=", heading.length()));
134
135 MultiCascade mc = new MultiCascade();
136
137 for (StyleSource s : elemstyles.getStyleSources()) {
138 if (s.active) {
139 heading = tr("{0} style \"{1}\"", getSort(s), s.getDisplayString());
140 txtMappaint.println(heading);
141 txtMappaint.println(repeatString("-", heading.length()));
142 s.apply(mc, osm, scale, false);
143 txtMappaint.println(tr("Display range: {0}", mc.range));
144 for (Entry<String, Cascade> e : mc.getLayers()) {
145 txtMappaint.println(tr("Layer {0}", e.getKey()));
146 txtMappaint.print(" * ");
147 txtMappaint.println(e.getValue());
148 }
149 }
150 }
151 txtMappaint.println();
152 heading = tr("List of generated Styles:");
153 txtMappaint.println(heading);
154 txtMappaint.println(repeatString("-", heading.length()));
155 StyleElementList sl = elemstyles.get(osm, scale, nc);
156 for (StyleElement s : sl) {
157 txtMappaint.print(" * ");
158 txtMappaint.println(s);
159 }
160 txtMappaint.println();
161 txtMappaint.println();
162 }
163 } finally {
164 MapCSSStyleSource.STYLE_SOURCE_LOCK.readLock().unlock();
165 }
166 if (sel.size() == 2) {
167 List<IPrimitive> selList = new ArrayList<>(sel);
168 StyleCache sc1 = selList.get(0).getCachedStyle();
169 StyleCache sc2 = selList.get(1).getCachedStyle();
170 if (sc1 == sc2) {
171 txtMappaint.println(tr("The 2 selected objects have identical style caches."));
172 }
173 if (!sc1.equals(sc2)) {
174 txtMappaint.println(tr("The 2 selected objects have different style caches."));
175 }
176 if (sc1 != sc2 && sc1.equals(sc2)) {
177 txtMappaint.println(tr("Warning: The 2 selected objects have equal, but not identical style caches."));
178 }
179 }
180 return stringWriter.toString();
181 }
182
183 private static String repeatString(String string, int count) {
184 // Java 11: use String.repeat
185 return new String(new char[count]).replace("\0", string);
186 }
187
188 /* Future Ideas:
189 Calculate the most recent edit date from o.getTimestamp().
190 Sort by the count for presentation, so the most active editors are on top.
191 Count only tagged nodes (so empty way nodes don't inflate counts).
192 */
193 protected static String buildListOfEditorsText(Collection<? extends IPrimitive> primitives) {
194 final Map<String, Long> editCountByUser = primitives.stream()
195 .map(IPrimitive::getUser)
196 .filter(Objects::nonNull)
197 .collect(Collectors.groupingBy(
198 User::getName,
199 () -> new TreeMap<>(Collator.getInstance(Locale.getDefault())),
200 Collectors.counting()));
201
202 // Print the count in sorted order
203 final StringBuilder s = new StringBuilder(48)
204 .append(trn("{0} user last edited the selection:", "{0} users last edited the selection:",
205 editCountByUser.size(), editCountByUser.size()))
206 .append("\n\n");
207 editCountByUser.forEach((username, editCount) ->
208 s.append(String.format("%6d %s", editCount, username)).append('\n'));
209 return s.toString();
210 }
211
212 private static String getSort(StyleSource s) {
213 if (s instanceof MapCSSStyleSource) {
214 return "MapCSS";
215 } else {
216 return tr("UNKNOWN");
217 }
218 }
219}
Note: See TracBrowser for help on using the repository browser.