1
14
15 package demo.yext.svg;
16
17 import y.option.DefaultEditorFactory;
18 import y.option.Editor;
19 import y.option.EditorFactory;
20 import y.option.ItemEditor;
21 import y.option.OptionGroup;
22 import y.option.OptionHandler;
23 import y.option.OptionItem;
24 import y.option.ComponentOptionItem;
25 import y.io.YGFIOHandler;
26 import y.util.D;
27 import y.view.Graph2D;
28 import y.view.NodeRealizer;
29 import y.view.EditMode;
30 import y.base.Node;
31 import y.base.NodeCursor;
32 import yext.svg.view.SVGModel;
33 import yext.svg.view.SVGNodeRealizer;
34
35 import java.awt.BorderLayout;
36 import java.awt.Color;
37 import java.awt.Dimension;
38 import java.awt.GridBagConstraints;
39 import java.awt.GridBagLayout;
40 import java.awt.event.ComponentAdapter;
41 import java.awt.event.ComponentEvent;
42 import java.beans.PropertyChangeEvent;
43 import java.beans.PropertyChangeListener;
44 import java.util.HashSet;
45 import java.util.Iterator;
46 import java.util.LinkedHashMap;
47 import java.util.Map;
48 import java.util.Set;
49 import java.net.URL;
50 import java.io.IOException;
51 import javax.swing.JFrame;
52 import javax.swing.JLabel;
53 import javax.swing.JMenu;
54 import javax.swing.JMenuBar;
55 import javax.swing.JPanel;
56 import javax.swing.JScrollPane;
57 import javax.swing.JSplitPane;
58 import javax.swing.JTextArea;
59
60
83 public class RenderingPerformanceDemo extends SVGExportDemo {
84 private static final String GRAPH =
85 "Graph";
86 private static final String IMAGE_CACHE_ENABLED =
87 "Image Cache Enabled";
88 private static final String IMAGE_CACHE_SIZE =
89 "Image Cache Size";
90 private static final String MAXIMUM_IMAGE_SIZE =
91 "Maximum Image Size (in bytes)";
92 private static final String MINIMUM_RELATIVE_IMAGE_SIZE =
93 "Minimum Relative Image Size";
94
95 private Map nameToUrl;
96
97 public RenderingPerformanceDemo() {
98 createNameToUrlMap();
99
100 if (nameToUrl != null && !nameToUrl.isEmpty()) {
101 readGraph((URL)nameToUrl.values().iterator().next());
102 }
103
104 createContent();
105 createListeners();
106 updateView();
107 }
108
109 private void createNameToUrlMap() {
110 nameToUrl = new LinkedHashMap();
111
112 final String[] names = {
113 "100Earths",
114 "mimeTypes",
115 "mixedSizes"
116 };
117 URL url;
118 for (int i = 0; i < names.length; ++i) {
119 final String resource = "resource/" + names[i] + ".ygf";
120 url = RenderingPerformanceDemo.class.getResource(resource);
121 if (url != null) {
122 nameToUrl.put(names[i], url);
123 } else {
124 System.err.println("Could not resolve " + resource + "!");
125 }
126 }
127 }
128
129 private void createListeners() {
130 final Dimension oldSize = view.getPreferredSize();
131 view.addComponentListener(new ComponentAdapter() {
132 public void componentResized( final ComponentEvent e ) {
133 final Dimension newSize = e.getComponent().getSize();
134 if (oldSize.width < newSize.width || oldSize.height < newSize.height) {
135 updateView();
136 view.removeComponentListener(this);
137 }
138 }
139 });
140 }
141
142
145 private void createContent() {
146 final String[] names;
147 if (nameToUrl != null && !nameToUrl.isEmpty()) {
148 names = new String[nameToUrl.size()];
149 int i = 0;
150 for (Iterator it = nameToUrl.keySet().iterator(); it.hasNext(); ++i) {
151 names[i] = (String)it.next();
152 }
153 } else {
154 names = new String[0];
155 }
156
157 OptionGroup group;
158
159 final OptionHandler oh = new OptionHandler("CacheOptions");
160 OptionItem item;
161
162 if (names.length > 0) {
163 group = new OptionGroup();
164 group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "Sample SVG Graph");
165 item = oh.addEnum(GRAPH, names, 0);
166 item.setAttribute(ItemEditor.ATTRIBUTE_AUTO_COMMIT, Boolean.TRUE);
167 group.addItem(item);
168 } else {
169 group = new OptionGroup();
170 group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "Sample SVG Graph");
171
172 final JLabel label = new JLabel("No graphs available.");
173 label.setForeground(Color.RED.darker());
174 item = new ComponentOptionItem("_COMPONENT", label) {
175 public boolean wantsVisibleName() {
176 return false;
177 }
178 };
179 oh.addItem(item);
180 group.addItem(item);
181 }
182
183 group = new OptionGroup();
184 group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "SVG Image Cache Options");
185
186 item = oh.addBool(IMAGE_CACHE_ENABLED, SVGModel.isImageCacheEnabled());
187 item.setTipText(
188 "<html><body><table width=\"240\"><tr><td>" +
189 "Enables or disables image caching. " +
190 "Image caching is a performance optimization that tries to " +
191 "minimize expensive vector graphics rendering to a cached " +
192 "intermediate image that will be displayed instead. To achieve " +
193 "nice rendering quality images are created and cached for " +
194 "multiple zoom levels." +
195 "</td></tr></table></body></html>"
196 );
197 item.setAttribute(ItemEditor.ATTRIBUTE_AUTO_COMMIT, Boolean.TRUE);
198 group.addItem(item);
199 item = oh.addInt(IMAGE_CACHE_SIZE, SVGModel.getImageCacheSize());
200 item.setTipText(
201 "<html><body><table width=\"240\"><tr><td>" +
202 "The maximum number of images that will be cached." +
203 "</td></tr></table></body></html>"
204 );
205 item.setAttribute(ItemEditor.ATTRIBUTE_AUTO_COMMIT, Boolean.TRUE);
206 group.addItem(item);
207 item = oh.addInt(MAXIMUM_IMAGE_SIZE, SVGModel.getMaximumImageSize());
208 item.setTipText(
209 "<html><body><table width=\"240\"><tr><td>" +
210 "The maximum size of images that will be cached. " +
211 "Image size is measured in bytes necessary to store it. " +
212 "For an image with size <code>W x H</code> the image size " +
213 "is <code>W * H * 4</code>. " +
214 "The width and height of an image is calulated by " +
215 "multiplying the width and height of the SVG by the scale " +
216 "factor of the graphics context it is rendered on." +
217 "</td></tr></table></body></html>"
218 );
219 item.setAttribute(ItemEditor.ATTRIBUTE_AUTO_COMMIT, Boolean.TRUE);
220 group.addItem(item);
221 item = oh.addDouble(MINIMUM_RELATIVE_IMAGE_SIZE, SVGModel.getMinimumRelativeImageSize());
222 item.setTipText(
223 "<html><body><table width=\"240\"><tr><td>" +
224 "The minimum relative image size for which precached image " +
225 "duplicates are reused. I.e. if the image cache is queried for " +
226 "an intermediate image for a given SVG definition and image " +
227 "size, a cache miss is avoided if there is a cached image for " +
228 "the given SVG definition and <code>query width/cached width " +
229 ">= minimumRelativeImageSize</code> as well as " +
230 "<code>query height/cached height >= minimumRelativeImageSize</code> " +
231 "hold." +
232 "</td></tr></table></body></html>"
233 );
234 item.setAttribute(ItemEditor.ATTRIBUTE_AUTO_COMMIT, Boolean.TRUE);
235 group.addItem(item);
236
237
238 final JTextArea jta = new JTextArea();
239 jta.setText(info());
240 jta.setEditable(false);
241 jta.setLineWrap(true);
242 jta.setWrapStyleWord(true);
243 final JScrollPane jsp = new JScrollPane(jta);
244 jsp.setPreferredSize(new Dimension(200, 100));
245 item = new ComponentOptionItem("Comment", jsp) {
246 public boolean wantsVisibleName() {
247 return false;
248 }
249 };
250 oh.addItem(item);
251
252 oh.addChildPropertyChangeListener(new PropertyChangeListener() {
253 public void propertyChange( PropertyChangeEvent evt ) {
254 final OptionItem src = (OptionItem)evt.getSource();
255 final String name = src.getName();
256 if (GRAPH.equals(name)) {
257 SVGModel.clearImageCache();
258 readGraph((URL)nameToUrl.get(evt.getNewValue()));
259 jta.setText(info());
260 } else if (IMAGE_CACHE_ENABLED.equals(name)) {
261 SVGModel.setImageCacheEnabled(((Boolean)evt.getNewValue()).booleanValue());
262 } else if (IMAGE_CACHE_SIZE.equals(name)) {
263 SVGModel.setImageCacheSize(((Number)evt.getNewValue()).intValue());
264 } else if (MAXIMUM_IMAGE_SIZE.equals(name)) {
265 SVGModel.setMaximumImageSize(((Number)evt.getNewValue()).intValue());
266 } else if (MINIMUM_RELATIVE_IMAGE_SIZE.equals(name)) {
267 SVGModel.setMinimumRelativeImageSize(((Number)evt.getNewValue()).doubleValue());
268 view.repaint();
269 }
270 }
271 });
272
273
274 final EditorFactory ef = new DefaultEditorFactory(); final Editor editor = ef.createEditor(oh);
276
277 final GridBagConstraints gbc = new GridBagConstraints();
278 final JPanel editorPane = new JPanel(new GridBagLayout());
279 gbc.fill = GridBagConstraints.HORIZONTAL;
280 gbc.gridx = 0;
281 gbc.gridy = 0;
282 gbc.weightx = 1.0;
283 gbc.weighty = 0.0;
284 editorPane.add(editor.getComponent(), gbc);
285 gbc.fill = GridBagConstraints.BOTH;
286 ++gbc.gridy;
287 gbc.weighty = 1.0;
288 editorPane.add(new JPanel(), gbc);
289
290 remove(view);
291 add(new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true,
292 editorPane, view),
293 BorderLayout.CENTER);
294 }
295
296
297 protected JMenuBar createMenuBar() {
298 JMenuBar jmb = new JMenuBar();
299 JMenu menu = new JMenu("File");
300 menu.add(new ExitAction());
301 jmb.add(menu);
302 return jmb;
303 }
304
305 protected EditMode createEditMode() {
306 final EditMode em = new EditMode() {
307 protected String getNodeTip( final Node v ) {
308 final NodeRealizer nr = getGraph2D().getRealizer(v);
309 final double zoom = view.getZoom();
310 final int bytes = (int)Math.ceil(nr.getWidth() *zoom) *
311 (int)Math.ceil(nr.getHeight()*zoom) * 4;
312 return "Corresponding image size: " + bytes + " bytes";
313 }
314 };
315 em.showNodeTips(true);
316 em.allowBendCreation(false);
317 em.allowEdgeCreation(false);
318 em.allowNodeCreation(false);
319 return em;
320 }
321
322 public void start(final String title) {
323 JFrame frame = new JFrame(title);
324 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
325 addContentTo(frame.getRootPane());
326 frame.pack();
327 frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
328 frame.setLocationRelativeTo(null);
329 frame.setVisible(true);
330 }
331
332 private void readGraph( final URL url ) {
333 if (url == null) {
334 return;
335 }
336
337 final Graph2D graph = view.getGraph2D();
338
339 final YGFIOHandler ioh = new YGFIOHandler();
340 try {
341 graph.clear();
342 ioh.read(view.getGraph2D(), url);
343 } catch (IOException ioe) {
344 D.show(ioe);
345 }
346
347 graph.setSelected(graph.nodes(), true);
348 graph.setBendsSelected(graph.edges(), true);
349
350 updateView();
351 }
352
353 private void updateView() {
354 view.fitContent();
355 view.setPaintDetailThreshold(0);
356 view.updateView();
357 }
358
359 private String info() {
360 final Graph2D graph = view.getGraph2D();
361
362 final StringBuffer sb = new StringBuffer();
363 sb.append(graph.N()).append(" node(s),\n");
364 sb.append(graph.E()).append(" edge(s),\n");
365
366 final Set urls = new HashSet();
367 for (NodeCursor nc = graph.nodes(); nc.ok(); nc.next()) {
368 final NodeRealizer nr = graph.getRealizer(nc.node());
369 if (nr instanceof SVGNodeRealizer) {
370 urls.add(((SVGNodeRealizer)nr).getSVGURL());
371 }
372 }
373 sb.append(urls.size()).append(" SVG image(s)");
374 return sb.toString();
375 }
376
377
378 public static void main( String[] args ) {
379 initLnF();
380
381 (new RenderingPerformanceDemo()).start();
382 }
383 }
384