X

Geertjan's Blog

  • August 25, 2009

How to Serialize Visual Library Scenes

Geertjan Wielenga
Product Manager
The many Visual Library samples in "contrib" include one called "serialization". I used that sample today to serialize one of my own scenes.

Before showing the code, some screenshots. First, I drag and drop one or two items from the palette onto my scene:

Next, after resizing them (code for which you can find via the NetBeans Platform Tutorials page, bearing in mind this issue), I save them, using the Save menu item:

Then, simply as a result of using the above menu item, this XML file is created, containing the state of my objects, which I can then load into the scene via the Load menu item above:

Here's how to do it (but, again, have a look at the sample pointed out above, in the first sentence of this blog entry). Before looking at the code below, you need to be aware that I have a business object called "AWidget", which has a name, an icon, a width, a height, and a location. I also have a scene called "AWidgetGraphScene", which extends "GraphScene", using my business object for the node of the scene. The scene has no edges.

  1. In my scene constructor:
    final JPopupMenu menu = new JPopupMenu();
    JMenuItem load = new JMenuItem("Load scene...");
    load.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    load ();
    }
    });
    menu.add(load);
    JMenuItem save = new JMenuItem("Save scene...");
    save.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
    save();
    }
    });
    menu.add(save);
    getActions().addAction(ActionFactory.createPopupMenuAction(new PopupMenuProvider() {
    @Override
    public JPopupMenu getPopupMenu(Widget widget, Point localLocation) {
    return menu;
    }
    }));

  2. Here are the definitions of "load()" and "save()":
    private void load () {
    JFileChooser chooser = new JFileChooser ();
    chooser.setDialogTitle ("Load Scene ...");
    chooser.setMultiSelectionEnabled (false);
    chooser.setFileSelectionMode (JFileChooser.FILES_ONLY);
    if (chooser.showOpenDialog (getView ()) == JFileChooser.APPROVE_OPTION) {
    for (String edge : new ArrayList (getEdges ()))
    removeEdge (edge);
    for (AWidget node : new ArrayList (getNodes ()))
    removeNode (node);
    SceneSerializer.deserialize (this, chooser.getSelectedFile ());
    validate ();
    }
    }
    private void save() {
    JFileChooser chooser = new JFileChooser();
    chooser.setDialogTitle("Save Scene ...");
    chooser.setMultiSelectionEnabled(false);
    chooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
    if (chooser.showSaveDialog(getView()) == JFileChooser.APPROVE_OPTION) {
    SceneSerializer.serialize(this, chooser.getSelectedFile());
    }
    }

  3. And here, almost identical to the original referred to above, is the "SceneSerializer" class:
    import org.netbeans.api.visual.widget.Widget;
    import org.openide.util.Exceptions;
    import org.openide.xml.XMLUtil;
    import org.w3c.dom.\*;
    import org.xml.sax.ErrorHandler;
    import org.xml.sax.InputSource;
    import org.xml.sax.SAXException;
    import org.xml.sax.SAXParseException;
    import java.awt.\*;
    import java.io.\*;
    public class SceneSerializer {
    private static final String SCENE_ELEMENT = "Scene"; // NOI18N
    private static final String VERSION_ATTR = "version"; // NOI18N
    private static final String SCENE_NODE_COUNTER_ATTR = "nodeIDcounter"; // NOI18N
    private static final String NODE_ELEMENT = "Node"; // NOI18N
    private static final String NODE_ID_ATTR = "id"; // NOI18N
    private static final String NODE_X_ATTR = "x"; // NOI18N
    private static final String NODE_Y_ATTR = "y"; // NOI18N
    private static final String NODE_WIDTH = "w"; // NOI18N
    private static final String NODE_HEIGHT = "h"; // NOI18N
    private static final String NODE_ICON = "icon"; // NOI18N
    private static final String VERSION_VALUE_1 = "1"; // NOI18N
    // call in AWT to serialize scene
    public static void serialize (AWidgetGraphScene scene, File file) {
    Document document = XMLUtil.createDocument (SCENE_ELEMENT, null, null, null);
    Node sceneElement = document.getFirstChild ();
    setAttribute (document, sceneElement, VERSION_ATTR, VERSION_VALUE_1);
    setAttribute (document, sceneElement, SCENE_NODE_COUNTER_ATTR, Long.toString (scene.nodeIDcounter));
    for (AWidget node : scene.getNodes ()) {
    Element nodeElement = document.createElement (NODE_ELEMENT);
    setAttribute (document, nodeElement, NODE_ID_ATTR, node.getType());
    Widget widget = scene.findWidget (node);
    Point location = widget.getPreferredLocation ();
    setAttribute (document, nodeElement, NODE_WIDTH, Integer.toString (widget.getClientArea().width));
    setAttribute (document, nodeElement, NODE_HEIGHT, Integer.toString (widget.getClientArea().height));
    setAttribute (document, nodeElement, NODE_X_ATTR, Integer.toString (location.x));
    setAttribute (document, nodeElement, NODE_Y_ATTR, Integer.toString (location.y));
    setAttribute (document, nodeElement, NODE_ICON, node.getIcon());
    sceneElement.appendChild (nodeElement);
    }
    FileOutputStream fos = null;
    try {
    fos = new FileOutputStream (file);
    XMLUtil.write (document, fos, "UTF-8"); // NOI18N
    } catch (Exception e) {
    Exceptions.printStackTrace (e);
    } finally {
    try {
    if (fos != null) {
    fos.close ();
    }
    } catch (Exception e) {
    Exceptions.printStackTrace (e);
    }
    }
    }
    // call in AWT to deserialize scene
    public static void deserialize (AWidgetGraphScene scene, File file) {
    Node sceneElement = getRootNode (file);
    if (! VERSION_VALUE_1.equals (getAttributeValue (sceneElement, VERSION_ATTR)))
    return;
    scene.nodeIDcounter = Long.parseLong (getAttributeValue (sceneElement, SCENE_NODE_COUNTER_ATTR));
    for (Node element : getChildNode (sceneElement)) {
    if (NODE_ELEMENT.equals (element.getNodeName ())) {
    String type = getAttributeValue (element, NODE_ID_ATTR);
    int x = Integer.parseInt (getAttributeValue (element, NODE_X_ATTR));
    int y = Integer.parseInt (getAttributeValue (element, NODE_Y_ATTR));
    int width = Integer.parseInt (getAttributeValue (element, NODE_WIDTH));
    int height = Integer.parseInt (getAttributeValue (element, NODE_HEIGHT));
    String icon = getAttributeValue (element, NODE_ICON);
    AWidget aWidget = new AWidget();
    aWidget.setType(type);
    aWidget.setIcon(icon);
    Widget nodeWidget = scene.addNode(aWidget);
    nodeWidget.setPreferredLocation (new Point (x, y));
    nodeWidget.setPreferredSize (new Dimension (width, height));
    }
    }
    }
    private static void setAttribute (Document xml, Node node, String name, String value) {
    NamedNodeMap map = node.getAttributes ();
    Attr attribute = xml.createAttribute (name);
    attribute.setValue (value);
    map.setNamedItem (attribute);
    }
    private static Node getRootNode (File file) {
    FileInputStream is = null;
    try {
    is = new FileInputStream (file);
    Document doc = XMLUtil.parse (new InputSource (is), false, false, new ErrorHandler() {
    public void error (SAXParseException e) throws SAXException {
    throw new SAXException (e);
    }
    public void fatalError (SAXParseException e) throws SAXException {
    throw new SAXException (e);
    }
    public void warning (SAXParseException e) {
    Exceptions.printStackTrace (e);
    }
    }, null);
    return doc.getFirstChild ();
    } catch (Exception e) {
    Exceptions.printStackTrace (e);
    } finally {
    try {
    if (is != null)
    is.close ();
    } catch (IOException e) {
    Exceptions.printStackTrace (e);
    }
    }
    return null;
    }
    private static String getAttributeValue (Node node, String attr) {
    try {
    if (node != null) {
    NamedNodeMap map = node.getAttributes ();
    if (map != null) {
    node = map.getNamedItem (attr);
    if (node != null)
    return node.getNodeValue ();
    }
    }
    } catch (DOMException e) {
    Exceptions.printStackTrace (e);
    }
    return null;
    }
    private static Node[] getChildNode (Node node) {
    NodeList childNodes = node.getChildNodes ();
    Node[] nodes = new Node[childNodes != null ? childNodes.getLength () : 0];
    for (int i = 0; i < nodes.length; i++)
    nodes[i] = childNodes.item (i);
    return nodes;
    }
    }

That's it. Put the generated XML page into a MultiViewElement and then you have the makings of a GUI editor.

Join the discussion

Comments ( 3 )
  • Trey Spiva Tuesday, August 25, 2009

    You may want to check out how the UML component serializes the diagram information. It was designed to be extensible since the serialization mechanism needed to support multiple types of nodes. Including container nodes.


  • Daniel Wednesday, August 26, 2009

    Hi, i nedd to display a object images (objet compose with varios basic shape, circle, arc,etc), and the other funcionaliti its cahnge the color depend of arbritari value. its possible?

    thanks


  • Donald Wednesday, September 9, 2009

    using this method how can you serialize/deserialize edges and pins for the widgets?


Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.