1   /****************************************************************************
2    * This demo file is part of yFiles for Java 2.14.
3    * Copyright (c) 2000-2017 by yWorks GmbH, Vor dem Kreuzberg 28,
4    * 72070 Tuebingen, Germany. All rights reserved.
5    * 
6    * yFiles demo files exhibit yFiles for Java functionalities. Any redistribution
7    * of demo files in source code or binary form, with or without
8    * modification, is not permitted.
9    * 
10   * Owners of a valid software license for a yFiles for Java version that this
11   * demo is shipped with are allowed to use the demo source code as basis
12   * for their own yFiles for Java powered applications. Use of such programs is
13   * governed by the rights and conditions as set out in the yFiles for Java
14   * license agreement.
15   * 
16   * THIS SOFTWARE IS PROVIDED ''AS IS'' AND ANY EXPRESS OR IMPLIED
17   * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18   * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
19   * NO EVENT SHALL yWorks BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
21   * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23   * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24   * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   *
27   ***************************************************************************/
28  package demo.view.anim;
29  
30  import y.io.GraphMLIOHandler;
31  import y.io.IOHandler;
32  import y.option.CompoundEditor;
33  import y.option.ConstraintManager;
34  import y.option.DefaultEditorFactory;
35  import y.option.Editor;
36  import y.option.EnumOptionItem;
37  import y.option.GuiFactory;
38  import y.option.ItemEditor;
39  import y.option.OptionGroup;
40  import y.option.OptionHandler;
41  import y.option.OptionItem;
42  import y.util.D;
43  import y.view.Graph2D;
44  import y.view.Graph2DView;
45  import y.view.ViewAnimationFactory;
46  
47  import javax.swing.AbstractAction;
48  import javax.swing.Action;
49  import javax.swing.BorderFactory;
50  import javax.swing.DefaultListCellRenderer;
51  import javax.swing.Icon;
52  import javax.swing.JButton;
53  import javax.swing.JComponent;
54  import javax.swing.JList;
55  import javax.swing.JPanel;
56  import javax.swing.JTable;
57  import javax.swing.ListCellRenderer;
58  import javax.swing.table.DefaultTableCellRenderer;
59  import javax.swing.table.TableCellRenderer;
60  import java.awt.BorderLayout;
61  import java.awt.Color;
62  import java.awt.Component;
63  import java.awt.FlowLayout;
64  import java.awt.GridBagConstraints;
65  import java.awt.GridBagLayout;
66  import java.awt.event.ActionEvent;
67  import java.io.File;
68  import java.io.IOException;
69  import java.net.URL;
70  import java.net.URLDecoder;
71  import java.util.HashMap;
72  import java.util.Iterator;
73  import java.util.Map;
74  
75  /**
76   * Provides the GUI and option handling for <code>AnimationEffectsDemo</code>.
77   * Cannot be used for anything else.
78   *
79   * @see AnimationEffectsDemo
80   * @see <a href="http://docs.yworks.com/yfiles/doc/api/index.html#/dguide/animation" target="_blank">Section Animations for Graph Elements</a> in the yFiles for Java Developer's Guide
81   */
82  abstract class AnimationEffectsDemoBase {
83    static final byte NO_ANIM = (byte) 0;
84  
85    static final byte BLUR_IN = (byte) 11;
86    static final byte FADE_IN = (byte) 12;
87    static final byte IMPLODE = (byte) 13;
88    static final byte WHIRL_IN = (byte) 14;
89  
90    static final byte EXTRACT = (byte) 15;
91  
92    static final byte BLUR_OUT = (byte) 21;
93    static final byte FADE_OUT = (byte) 22;
94    static final byte EXPLODE = (byte) 23;
95    static final byte WHIRL_OUT = (byte) 24;
96  
97    static final byte RETRACT = (byte) 25;
98  
99    static final byte TRAVERSE_EDGE = (byte) 31;
100   static final byte ZOOM = (byte) 32;
101   static final byte MOVE_CAMERA = (byte) 33;
102   static final byte MORPH = (byte) 34;
103   static final byte RESIZE = (byte) 35;
104   static final byte BLINK = (byte) 36;
105   static final byte ANIMATED_LOAD = (byte) 37;
106   static final byte ANIMATED_CLEAR = (byte) 38;
107 
108 
109   static final String DEMO_NAME;
110 
111   static {
112     String name = AnimationEffectsDemo.class.getName();
113     name = name.substring(name.lastIndexOf('.') + 1);
114     DEMO_NAME = name;
115   }
116 
117 
118   final Graph2DView view;
119   final GuiFactory i18n;
120   final OptionHandler oh;
121   boolean compoundAction;
122 
123   private final boolean wantsRadioButtons;
124 
125   /**
126    * Creates a new AnimationEffectsDemoBase.
127    * @param i18n   localization data
128    */
129   protected AnimationEffectsDemoBase(
130           final GuiFactory i18n,
131           final boolean wantsRadioButtons
132   ) {
133     this.wantsRadioButtons = wantsRadioButtons;
134     this.view = new Graph2DView();
135     this.view.setFitContentOnResize(true);
136     this.i18n = i18n;
137     this.oh = createOptionHandler();
138     this.compoundAction = false;
139   }
140 
141   abstract void animate();
142 
143   void selectAllEdges() {
144     final Graph2D graph = view.getGraph2D();
145     graph.setSelected(graph.edges(), true);
146   }
147 
148   void openGraph(final String resource) {
149     final URL url = getResource(resource);
150     if (url != null) {
151       final Graph2D graph = view.getGraph2D();
152       graph.clear();
153 
154       try {
155         final String name = URLDecoder.decode(url.getFile(), "UTF-8");
156         getIoHandler(name).read(graph, name);
157       }
158       catch (IOException ioe) {
159         D.show(ioe);
160       }
161 
162       view.fitContent();
163     } else {
164       final File file = new File(resource);
165       if (file.exists()) {
166         final Graph2D graph = view.getGraph2D();
167         graph.clear();
168 
169         try {
170           final String name = file.getAbsolutePath();
171           getIoHandler(name).read(graph, name);
172         }
173         catch (IOException ioe) {
174           D.show(ioe);
175         }
176 
177         view.fitContent();
178       } else {
179         D.show(new Exception("Cannot locate file: " + resource));
180       }
181     }
182   }
183 
184   void localizeAction(final Action action, final String key) {
185     action.putValue(Action.NAME, i18n.getString(key));
186     action.putValue(Action.SHORT_DESCRIPTION,
187         i18n.getString(key + ".shortDescription"));
188 
189     final String iconKey = key + ".smallIcon";
190     final String iconName = i18n.getString(iconKey);
191     if (!iconKey.equals(iconName)) {
192       action.putValue(Action.SMALL_ICON, getIconResource(iconName));
193     }
194   }
195 
196   private URL getResource( final String name ) {
197     return demo.view.DemoBase.getResource(getClass(), name);
198   }
199 
200   private Icon getIconResource( final String name ) {
201     return demo.view.DemoBase.getIconResource(name);
202   }
203 
204   /**
205    * Creates an OptionHandler.
206    */
207   private OptionHandler createOptionHandler() {
208     final OptionHandler optionHandler = new OptionHandler(DEMO_NAME);
209 
210     final ConstraintManager cm = new ConstraintManager(optionHandler);
211 
212     OptionGroup group;
213     OptionGroup section;
214     OptionItem item;
215 
216 
217     final Byte noAnim = new Byte(NO_ANIM);
218 
219 
220     optionHandler.useSection("elements");
221     section = new OptionGroup();
222     section.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "elements");
223 
224     final Byte blurIn = new Byte(BLUR_IN);
225     final Byte fadeIn = new Byte(FADE_IN);
226     final Byte implode = new Byte(IMPLODE);
227     final Byte whirlIn = new Byte(WHIRL_IN);
228 
229     final Byte blurOut = new Byte(BLUR_OUT);
230     final Byte fadeOut = new Byte(FADE_OUT);
231     final Byte explode = new Byte(EXPLODE);
232     final Byte whirlOut = new Byte(WHIRL_OUT);
233 
234     final Byte extract = new Byte(EXTRACT);
235     final Byte retract = new Byte(RETRACT);
236 
237     final ElementsRenderer elementsRenderer = new ElementsRenderer();
238     item = optionHandler.addEnum("createNode", new Byte[]{noAnim, blurIn, fadeIn, implode, whirlIn}, 4);
239     item.setAttribute(EnumOptionItem.ATTRIBUTE_RENDERER, elementsRenderer);
240     section.addItem(item);
241     item = optionHandler.addEnum("deleteNode", new Byte[]{noAnim, blurOut, fadeOut, explode, whirlOut}, 1);
242     item.setAttribute(EnumOptionItem.ATTRIBUTE_RENDERER, elementsRenderer);
243     section.addItem(item);
244     item = optionHandler.addEnum("createEdge", new Byte[]{noAnim, blurIn, fadeIn, implode, extract}, 2);
245     item.setAttribute(EnumOptionItem.ATTRIBUTE_RENDERER, elementsRenderer);
246     section.addItem(item);
247     item = optionHandler.addEnum("deleteEdge", new Byte[]{noAnim, blurOut, fadeOut, explode, retract}, 4);
248     item.setAttribute(EnumOptionItem.ATTRIBUTE_RENDERER, elementsRenderer);
249     section.addItem(item);
250 
251     optionHandler.useSection("misc");
252     section = new OptionGroup();
253 
254     final Byte animatedClear = new Byte(ANIMATED_CLEAR);
255     final Byte animatedLoad = new Byte(ANIMATED_LOAD);
256     final Byte traverseEdge = new Byte(TRAVERSE_EDGE);
257     final Byte zoom = new Byte(ZOOM);
258     final Byte moveCamera = new Byte(MOVE_CAMERA);
259     final Byte morph = new Byte(MORPH);
260     final Byte resize = new Byte(RESIZE);
261     final Byte blink = new Byte(BLINK);
262 
263     item = optionHandler.addEnum("animation", new Byte[]{
264         animatedLoad, animatedClear,
265         traverseEdge, zoom, moveCamera,
266         morph, resize, blink
267     }, 2);
268     item.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
269         DEMO_NAME + "Base.animation");
270     item.setAttribute(EnumOptionItem.ATTRIBUTE_RENDERER,
271         new AnimationRenderer());
272     item.setAttribute(DefaultEditorFactory.ATTRIBUTE_ENUM_STYLE,
273         wantsRadioButtons
274             ? DefaultEditorFactory.STYLE_RADIO_BUTTONS
275             : DefaultEditorFactory.STYLE_COMBO_BOX);
276     section.addItem(item);
277 
278     final OrderRenderer orderRenderer = new OrderRenderer();
279     final Object[] order = {
280         ViewAnimationFactory.LEFT_TO_RIGHT,
281         ViewAnimationFactory.RIGHT_TO_LEFT,
282         ViewAnimationFactory.CLOCKWISE,
283         ViewAnimationFactory.COUNTER_CLOCKWISE
284     };
285 
286     group = new OptionGroup();
287     group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "misc_animation_properties");
288     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
289         DEMO_NAME + "Base.animation");
290     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, animatedLoad.toString());
291     item = optionHandler.addEnum("animateLoad_graph", new String[]{"big", "small"}, 0);
292     item.setAttribute(DefaultEditorFactory.ATTRIBUTE_ENUM_STYLE,
293         DefaultEditorFactory.STYLE_RADIO_BUTTONS);
294     item.setAttribute(DefaultEditorFactory.ATTRIBUTE_ENUM_ALIGNMENT,
295         DefaultEditorFactory.ALIGNMENT_HORIZONTAL);
296     group.addItem(item);
297     item = optionHandler.addEnum("animateLoad_nodeOrder", order, 0);
298     item.setAttribute(EnumOptionItem.ATTRIBUTE_RENDERER, orderRenderer);
299     group.addItem(item);
300     group.addItem(optionHandler.addBool("animateLoad_obeyEdgeDirection", false));
301     group.addItem(optionHandler.addDouble("animateLoad_ratio", 0.15, 0.1, 1.0));
302     cm.setEnabledOnValueEquals("animation", animatedLoad, group);
303 
304     group = new OptionGroup();
305     group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "misc_animation_properties");
306     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
307         DEMO_NAME + "Base.animation");
308     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, animatedClear.toString());
309     item = optionHandler.addEnum("animateClear_nodeOrder", order, 0);
310     item.setAttribute(EnumOptionItem.ATTRIBUTE_RENDERER, orderRenderer);
311     group.addItem(item);
312     group.addItem(optionHandler.addBool("animateClear_obeyEdgeDirection", false));
313     group.addItem(optionHandler.addDouble("animateClear_ratio", 0.15, 0.1, 1.0));
314     cm.setEnabledOnValueEquals("animation", animatedClear, group);
315 
316     group = new OptionGroup();
317     group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "misc_animation_properties");
318     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
319         DEMO_NAME + "Base.animation");
320     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, traverseEdge.toString());
321 
322     group.addItem(optionHandler.addColor("colorVisited", Color.RED, true, true, false, false));
323     group.addItem(optionHandler.addColor("colorUnvisited", Color.BLACK, true, true, false, false));
324     cm.setEnabledOnValueEquals("animation", traverseEdge, group);
325     addItems(group, section);
326 
327     group = new OptionGroup();
328     group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "misc_animation_properties");
329     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
330         DEMO_NAME + "Base.animation");
331     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, zoom.toString());
332 
333     group.addItem(optionHandler.addDouble("zoom_factor", 1.0, 0.1, 16.0));
334     cm.setEnabledOnValueEquals("animation", zoom, group);
335 
336     group = new OptionGroup();
337     group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "misc_animation_properties");
338     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
339         DEMO_NAME + "Base.animation");
340     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, morph.toString());
341 
342     group.addItem(optionHandler.addDouble("translateX", 50));
343     group.addItem(optionHandler.addDouble("translateY", 50));
344     group.addItem(optionHandler.addDouble("width", 100));
345     group.addItem(optionHandler.addDouble("height", 25));
346     group.addItem(optionHandler.addColor("fillColor", Color.RED, true, true, false, false));
347     group.addItem(optionHandler.addColor("fillColor2", Color.YELLOW, true, true, false, false));
348     group.addItem(optionHandler.addColor("lineColor", Color.BLACK, true, true, false, false));
349     cm.setEnabledOnValueEquals("animation", morph, group);
350     addItems(group, section);
351 
352     group = new OptionGroup();
353     group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "misc_animation_properties");
354     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
355         DEMO_NAME + "Base.animation");
356     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, resize.toString());
357 
358     group.addItem(optionHandler.addDouble("resize_width", 100));
359     group.addItem(optionHandler.addDouble("resize_height", 100));
360     cm.setEnabledOnValueEquals("animation", resize, group);
361     addItems(group, section);
362 
363     group = new OptionGroup();
364     group.setAttribute(OptionGroup.ATTRIBUTE_TITLE, "misc_animation_properties");
365     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CONTROLLER_ID,
366         DEMO_NAME + "Base.animation");
367     group.setAttribute(DefaultEditorFactory.ATTRIBUTE_CARD_ID, blink.toString());
368 
369     group.addItem(optionHandler.addInt("repetitions", 1, 1, 25));
370     cm.setEnabledOnValueEquals("animation", blink, group);
371     addItems(group, section);
372 
373     optionHandler.useSection("global");
374     optionHandler.addDouble("speed", 2.0, 0.25, 4.0, 2);
375 
376     return optionHandler;
377   }
378 
379   private JComponent createControlPane() {
380     final DefaultEditorFactory editorFactory = new DefaultEditorFactory();
381     editorFactory.setGuiFactory(i18n);
382 
383     final Map attributes = new HashMap();
384     final Editor editor = editorFactory.createEditor(oh, attributes);
385     setAutoAdopt(true, editor);
386     setAutoCommit(true, editor);
387 
388     final JPanel buttonPane = new JPanel(new FlowLayout(FlowLayout.LEADING));
389     buttonPane.add(new JButton(createAnimateAction()));
390 
391     JPanel spacer = new JPanel();
392     final JPanel pane = new JPanel(new GridBagLayout());
393 
394     int row = 0;
395 
396     final GridBagConstraints gbc = new GridBagConstraints();
397     gbc.fill = GridBagConstraints.HORIZONTAL;
398     gbc.anchor = GridBagConstraints.WEST;
399 
400     {
401       final CompoundEditor ce = (CompoundEditor) editor;
402       for (int i = 0, n = ce.editorCount() - 2; i < n; ++i) {
403         gbc.gridy = row++;
404         pane.add(ce.getEditor(i).getComponent(), gbc);
405       }
406       // special case for last two editors:
407       // misc section and animation speed setting
408       {
409         final GridBagConstraints compoundConstraints = new GridBagConstraints();
410         final JPanel compoundPane = new JPanel(new GridBagLayout());
411         compoundPane.setBorder(
412             BorderFactory.createTitledBorder(
413                 i18n.getString(DEMO_NAME + ".GROUP.misc")));
414 
415         compoundConstraints.fill = GridBagConstraints.HORIZONTAL;
416         compoundConstraints.anchor = GridBagConstraints.NORTHWEST;
417         compoundConstraints.gridy = 0;
418         compoundConstraints.gridwidth = 2;
419         compoundConstraints.weightx = 1.0;
420         compoundPane.add(ce.getEditor(ce.editorCount() - 2).getComponent(),
421             compoundConstraints);
422 
423         compoundConstraints.fill = GridBagConstraints.BOTH;
424         compoundConstraints.anchor = GridBagConstraints.WEST;
425         compoundConstraints.gridy = 1;
426         compoundConstraints.weighty = 1.0;
427         compoundPane.add(spacer, compoundConstraints);
428 
429         compoundConstraints.gridy = 2;
430         compoundConstraints.gridwidth = 1;
431         compoundConstraints.anchor = GridBagConstraints.SOUTHWEST;
432         compoundPane.add(buttonPane, compoundConstraints);
433 
434         compoundConstraints.gridx = 1;
435         compoundPane.add(ce.getEditor(ce.editorCount() - 1).getComponent(),
436             compoundConstraints);
437 
438         gbc.gridy = row++;
439         pane.add(compoundPane, gbc);
440       }
441     }
442 
443     spacer = new JPanel();
444     gbc.fill = GridBagConstraints.BOTH;
445     gbc.gridy = row;
446     gbc.weighty = 0.75;
447     pane.add(spacer, gbc);
448 
449     return pane;
450   }
451 
452   JComponent createContentPane() {
453     final JPanel pane = new JPanel(new BorderLayout());
454     pane.add(createControlPane(), BorderLayout.WEST);
455     pane.add(view, BorderLayout.CENTER);
456     return pane;
457   }
458 
459   private Action createAnimateAction() {
460     final Action action = new AbstractAction() {
461       public void actionPerformed(final ActionEvent e) {
462         animate();
463       }
464     };
465     localizeAction(action, DEMO_NAME + ".action.Animate");
466 
467     return action;
468   }
469 
470   private IOHandler getIoHandler(final String filename) {
471     return new GraphMLIOHandler();
472   }
473 
474 
475   private static void addItems(final OptionGroup src, final OptionGroup tgt) {
476     for (Iterator it = src.items(); it.hasNext();) {
477       tgt.addItem((OptionItem) it.next());
478     }
479   }
480 
481   /**
482    * Sets the <code>autoCommit</code> property to the specified value,
483    * if the specified editor support setting said property.
484    */
485   private static void setAutoCommit(final boolean autoCommit,
486                                     final Editor editor) {
487     if (editor instanceof CompoundEditor) {
488       for (Iterator it = ((CompoundEditor) editor).editors(); it.hasNext();) {
489         setAutoCommit(autoCommit, (Editor) it.next());
490       }
491     }
492     if (editor instanceof ItemEditor) {
493       ((ItemEditor) editor).setAutoCommit(autoCommit);
494     }
495   }
496 
497   /**
498    * Sets the <code>autoAdopt</code> property for all items of the specified
499    * option handler.
500    */
501   private static void setAutoAdopt(final boolean autoAdopt,
502                                    final Editor editor) {
503     if (editor instanceof CompoundEditor) {
504       for (Iterator it = ((CompoundEditor) editor).editors(); it.hasNext();) {
505         setAutoAdopt(autoAdopt, (Editor) it.next());
506       }
507     }
508     if (editor instanceof ItemEditor) {
509       ((ItemEditor) editor).setAutoAdopt(autoAdopt);
510     }
511   }
512 
513 
514   private abstract static class I18nRenderer
515       implements ListCellRenderer, TableCellRenderer {
516     private final DefaultListCellRenderer listDelegate;
517     private final DefaultTableCellRenderer tableDelegate;
518 
519     protected I18nRenderer() {
520       this.listDelegate = new DefaultListCellRenderer();
521       this.tableDelegate = new DefaultTableCellRenderer();
522     }
523 
524     public Component getListCellRendererComponent(final JList list,
525                                                   final Object value,
526                                                   final int index,
527                                                   final boolean isSelected,
528                                                   final boolean hasFocus) {
529       return listDelegate.getListCellRendererComponent(list, toString(value),
530           index,
531           isSelected, hasFocus);
532     }
533 
534     public Component getTableCellRendererComponent(final JTable table,
535                                                    final Object value,
536                                                    final boolean isSelected,
537                                                    final boolean hasFocus,
538                                                    final int row,
539                                                    final int column) {
540       return tableDelegate.getTableCellRendererComponent(table, toString(value),
541           isSelected, hasFocus,
542           row, column);
543     }
544 
545     abstract String toString(final Object value);
546   }
547 
548   private final class ElementsRenderer extends I18nRenderer {
549     String toString(final Object animation) {
550       switch (((Byte) animation).byteValue()) {
551         case NO_ANIM:
552           return i18n.getString(DEMO_NAME + ".elements.VALUE.noAnimation");
553         case BLUR_IN:
554           return i18n.getString(DEMO_NAME + ".elements.VALUE.blurIn");
555         case FADE_IN:
556           return i18n.getString(DEMO_NAME + ".elements.VALUE.fadeIn");
557         case IMPLODE:
558           return i18n.getString(DEMO_NAME + ".elements.VALUE.implode");
559         case WHIRL_IN:
560           return i18n.getString(DEMO_NAME + ".elements.VALUE.whirlIn");
561         case EXTRACT:
562           return i18n.getString(DEMO_NAME + ".elements.VALUE.extract");
563         case BLUR_OUT:
564           return i18n.getString(DEMO_NAME + ".elements.VALUE.blurOut");
565         case FADE_OUT:
566           return i18n.getString(DEMO_NAME + ".elements.VALUE.fadeOut");
567         case EXPLODE:
568           return i18n.getString(DEMO_NAME + ".elements.VALUE.explode");
569         case WHIRL_OUT:
570           return i18n.getString(DEMO_NAME + ".elements.VALUE.whirlOut");
571         case RETRACT:
572           return i18n.getString(DEMO_NAME + ".elements.VALUE.retract");
573         default:
574           // this should never happen
575           return "";
576       }
577     }
578   }
579 
580   private final class AnimationRenderer extends I18nRenderer {
581     String toString(final Object animation) {
582       switch (((Byte) animation).byteValue()) {
583         case NO_ANIM:
584           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.noAnimation");
585         case TRAVERSE_EDGE:
586           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.traverseEdge");
587         case ZOOM:
588           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.zoom");
589         case MOVE_CAMERA:
590           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.moveCamera");
591         case MORPH:
592           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.morph");
593         case RESIZE:
594           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.resize");
595         case BLINK:
596           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.blink");
597         case ANIMATED_LOAD:
598           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.animatedLoad");
599         case ANIMATED_CLEAR:
600           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.animatedClear");
601         default:
602           return i18n.getString(DEMO_NAME + ".misc.animation.VALUE.noAnimation");
603       }
604     }
605   }
606 
607   private final class OrderRenderer extends I18nRenderer {
608     String toString(final Object nodeOrder) {
609       if (nodeOrder == ViewAnimationFactory.LEFT_TO_RIGHT) {
610         return i18n.getString("ViewAnimationFactory.LEFT_TO_RIGHT");
611       }
612       if (nodeOrder == ViewAnimationFactory.RIGHT_TO_LEFT) {
613         return i18n.getString("ViewAnimationFactory.RIGHT_TO_LEFT");
614       }
615       if (nodeOrder == ViewAnimationFactory.CLOCKWISE) {
616         return i18n.getString("ViewAnimationFactory.CLOCKWISE");
617       }
618       if (nodeOrder == ViewAnimationFactory.COUNTER_CLOCKWISE) {
619         return i18n.getString("ViewAnimationFactory.COUNTER_CLOCKWISE");
620       }
621       // this should never happen
622       return null;
623     }
624   }
625 }
626