Package org.beryl.gui.builder

Source Code of org.beryl.gui.builder.WidgetTree$DebuggingModelChangeListener

/*
* Beryl - A web platform based on XML, XSLT and Java
* This file is part of the Beryl XML GUI
*
* Copyright (C) 2004 Wenzel Jakob <wazlaf@tigris.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.

* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-3107  USA
*/

package org.beryl.gui.builder;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;

import javax.swing.JComponent;

import org.beryl.gui.AnchorFactory;
import org.beryl.gui.Controller;
import org.beryl.gui.GUIEvent;
import org.beryl.gui.GUIEventListener;
import org.beryl.gui.GUIException;
import org.beryl.gui.InternationalizationManager;
import org.beryl.gui.LayoutFactory;
import org.beryl.gui.MessageDialog;
import org.beryl.gui.PropertyFactory;
import org.beryl.gui.Widget;
import org.beryl.gui.WidgetFactory;
import org.beryl.gui.WidgetInfo;
import org.beryl.gui.XMLUtils;
import org.beryl.gui.model.MapChangeEvent;
import org.beryl.gui.model.MapDataModel;
import org.beryl.gui.model.ModelChangeEvent;
import org.beryl.gui.model.ModelChangeListener;
import org.beryl.gui.model.TableDataModel;
import org.beryl.gui.model.TableRow;
import org.beryl.gui.widgets.Dialog;
import org.beryl.gui.widgets.Frame;
import org.beryl.gui.widgets.Panel;
import org.beryl.gui.widgets.PopupMenu;
import org.beryl.gui.widgets.Table;
import org.beryl.gui.widgets.Tree;
import org.beryl.gui.widgets.TreeItem;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class WidgetTree extends Controller implements ModelChangeListener {
  private static PropertyFactory pf = PropertyFactory.getInstance();
  private static LayoutFactory lf = LayoutFactory.getInstance();
  private static AnchorFactory af = AnchorFactory.getInstance();

  /**
   * The widget tree frame
   */
  private Frame frame = null;

  /**
   * The data model
   */
  private MapDataModel dataModel = null;

  /**
   * The tree component
   */
  private Tree widgetTree = null;

  /**
   * Root node
   */
  private TreeItem rootNode = null;

  /**
   * Tree popup menu
   */
  private PopupMenu treePopupMenu = null;

  /**
   * Property popup menu
   */
  private PopupMenu propertyPopupMenu = null;

  /**
   * Property table
   */
  private Table table = null;

  /**
   * Empty table data model
   */
  private TableDataModel emptyModel = null;

  /* DEBUGGING */
  private GUIEventListener debuggingGUIEventListener = null;
  private MapDataModel debuggingMapDataModel = null;

  private class DebuggingModelChangeListener implements ModelChangeListener {
    public void modelChanged(ModelChangeEvent e) {
      if (e instanceof MapChangeEvent) {
        MapChangeEvent event = (MapChangeEvent) e;
        log.debug("Data model change: '" + event.getKey() + "' => '" + event.getNewValue() + "'");
      } else {
        log.debug("Data model change: " + e.toString());
      }
    }
  };

  public WidgetTree(Builder builder) throws GUIException {
    dataModel = new MapDataModel();

    frame = constructFrame("WidgetTree", dataModel);
    treePopupMenu = (PopupMenu) constructWidget("WidgetPopup");
    propertyPopupMenu = (PopupMenu) constructWidget("PropertyPopup");
    emptyModel = new TableDataModel();

    widgetTree = (Tree) frame.getWidget("Tree");
    table = (Table) frame.getWidget("Table");
    rootNode = (TreeItem) frame.getWidget("RootNode");
    table.setTableDataModel(emptyModel);
    debuggingMapDataModel = new MapDataModel();
    debuggingMapDataModel.addModelChangeListener(new DebuggingModelChangeListener());
    dataModel.addModelChangeListener(this);
  }

  public void refresh(Document document) throws GUIException {
    for (int i = 0; i < rootNode.getChildCount(); i++) {
      TreeItem item = (TreeItem) rootNode.getChild(i);
      WidgetUserObject object = (WidgetUserObject) item.getUserObject();

      if (object.widget instanceof Frame) {
        ((Frame) object.widget).dispose();
      } else if (object.widget instanceof Dialog) {
        ((Dialog) object.widget).dispose();
      }
    }

    rootNode.removeAllChildren();
    NodeList children = document.getDocumentElement().getChildNodes();
    for (int i = 0; i < children.getLength(); i++) {
      Node node = (Node) children.item(i);

      if (node.getNodeType() == Node.ELEMENT_NODE && node.getNodeName().equals("widget")) {
        traverseDocument((Element) node, rootNode);
      }
    }
    rootNode.setUserObject(new WidgetUserObject(document.getDocumentElement(), null, rootNode));
    widgetTree.structureChanged(rootNode);
    System.out.println(frame.dumpStructure());
  }

  /**
   * Traverses the XML tree, creates the preview
   * and builds the widget tree
   */
  private Widget traverseDocument(Element xmlNode, TreeItem parentNode) throws GUIException {
    TreeItem newNode = new TreeItem(parentNode, null);
    WidgetUserObject parent = (WidgetUserObject) parentNode.getUserObject();

    String classAttribute = xmlNode.getAttribute("class");
    String nameAttribute = xmlNode.getAttribute("name");
    String presetAttribute = xmlNode.getAttribute("preset");

    if (presetAttribute.equals(""))
      presetAttribute = null;
    if (nameAttribute.equals(""))
      nameAttribute = null;
    Widget widget = constructWidget(parent.widget, classAttribute, nameAttribute, presetAttribute);
    WidgetUserObject object = new WidgetUserObject(xmlNode, widget, newNode);
    newNode.setUserObject(object);
    newNode.setText(describeWidget(xmlNode));

    NodeList childNodes = xmlNode.getChildNodes();

    object.tableModel.addRow(new NameTableRow(object));
    Element anchorNode = XMLUtils.getChild(xmlNode, "anchor");

    if (anchorNode != null) {
      object.tableModel.addRow(new PropertyTableRow(object, null, anchorNode));
    }

    for (int o = 0; o < childNodes.getLength(); o++) {
      if (childNodes.item(o).getNodeName().equals("property")) {
        Element propertyNode = (Element) childNodes.item(o);
        String propertyName = propertyNode.getAttribute("name");
        Object propertyValue = pf.constructProperty(propertyNode);
        object.tableModel.addRow(new PropertyTableRow(object, propertyValue, propertyNode));
        widget.setProperty(propertyName, propertyValue);
      } else if (childNodes.item(o).getNodeName().equals("layout")) {
        Element layoutNode = (Element) childNodes.item(o);
        Object propertyValue = lf.constructLayout(widget, layoutNode);
        object.tableModel.addRow(new PropertyTableRow(object, propertyValue, layoutNode));
        widget.setProperty("layout", propertyValue);
      } else if (childNodes.item(o).getNodeName().equals("emit")) {
        Element emitNode = (Element) childNodes.item(o);
        String name = emitNode.getAttribute("name");
        TableRow row = new TableRow();
        row.setValue("event", emitNode.getAttribute("event"));
        row.setValue("name", name);
        row.setValue(
          "description",
          widget.getWidgetInfo().getEventEntry(emitNode.getAttribute("event")).getDescription());
        row.setValue("node", emitNode);

        object.eventModel.addRow(row);
      }
    }

    for (int i = 0; i < childNodes.getLength(); i++) {
      if (childNodes.item(i).getNodeName().equals("widget")) {
        Element childNode = (Element) childNodes.item(i);

        /* Get the child's anchor subnode */
        anchorNode = XMLUtils.getChild(childNode, "anchor");
        Widget childWidget = traverseDocument(childNode, newNode);

        widget.addChild(childWidget, createAnchor(childWidget, anchorNode));

      }
    }

    parentNode.addChild(newNode, null);
    widget.finalizeConstruction();

    if (widget instanceof Dialog) {
      /* Dialogs get treated a little bit differently */
      Dialog dialog = (Dialog) widget;
      dialog.initDialog(null);
      dialog.show();
    }

    return widget;
  }

  public static Object createAnchor(Widget widget, Element anchorNode) throws GUIException {
    Object anchor = null;

    if (anchorNode != null) {
      anchor = af.constructAnchor(anchorNode);
      if (anchor instanceof AnchorFactory.BoxAnchor) {
        JComponent component = (JComponent) widget.getWidget();

        AnchorFactory.BoxAnchor ba = (AnchorFactory.BoxAnchor) anchor;
        component.setAlignmentX(ba.getAlignmentX());
        component.setAlignmentY(ba.getAlignmentY());
        anchor = null;
      }
    } else {
      Object comp = widget.getWidget();

      if (comp != null && comp instanceof JComponent) {
        JComponent component = (JComponent) comp;

        component.setAlignmentX(0.0f);
        component.setAlignmentY(0.0f);
      }
    }

    return anchor;
  }

  /**
   * Return a string description of a widget element
   */
  public static String describeWidget(Element element) {
    StringBuffer buf = new StringBuffer();

    String classAttribute = element.getAttribute("class");
    String nameAttribute = element.getAttribute("name");
    String presetAttribute = element.getAttribute("preset");

    buf.append(classAttribute);
    if (!nameAttribute.equals("")) {
      buf.append(" (").append(nameAttribute).append(")");
    }
    if (!presetAttribute.equals("")) {
      buf.append(" [").append(presetAttribute).append("]");
    }

    return buf.toString();
  }

  public void doInsert(String className) throws GUIException {
    TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");
    if (items.length == 1) {
      WidgetInfo info = constructWidget(null, className, null, null).getWidgetInfo();
      Element anchorElement =
        ((WidgetUserObject) rootNode.getUserObject()).element.getOwnerDocument().createElement("anchor");
      new InsertDialog(this, className, info, anchorElement);
    }
  }

  public void doInsert(String className, String preset, Element anchorNode) throws GUIException {
    TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");
    TreeItem item = items[0];
    WidgetUserObject parentObject = (WidgetUserObject) item.getUserObject();
    Document document = parentObject.element.getOwnerDocument();

    Element childWidget = document.createElement("widget");
    childWidget.setAttribute("class", className);
    if (preset != null)
      childWidget.setAttribute("preset", preset);

    TreeItem newNode = new TreeItem(item, null);
    Widget parentWidget = ((WidgetUserObject) item.getUserObject()).widget;
    Widget widget = constructWidget(parentWidget, className, null, preset);

    Object anchor = null;

    if (parentWidget != null) {
      anchor = createAnchor(widget, anchorNode);
      parentWidget.addChild(widget, anchor);
    }

    widget.finalizeConstruction();

    parentObject.element.appendChild(childWidget);

    if (widget instanceof Dialog) {
      Dialog dialog = (Dialog) widget;
      dialog.initDialog(null);
      dialog.show();
    }

    if (parentWidget != null)
      revalidate(parentWidget);

    WidgetUserObject userObject = new WidgetUserObject(childWidget, widget, newNode);
    userObject.tableModel.addRow(new NameTableRow(userObject));

    if (anchorNode != null) {
      childWidget.appendChild(anchorNode);
      PropertyTableRow row = new PropertyTableRow(userObject, anchor, anchorNode);
      userObject.tableModel.addRow(row);
    }

    newNode.setUserObject(userObject);
    newNode.setText(className);
    item.addChild(newNode, null);
    widgetTree.structureChanged(item);
    dataModel.setValue("tree.selected", new TreeItem[] { newNode });
    Builder.markModified();
  }

  private Widget constructWidget(Widget parentWidget, String className, String widgetName, String preset)
    throws GUIException {
    try {
      if (className.indexOf('.') == -1)
        className = WidgetFactory.DEFAULT_PREFIX + className;
      Class wClass = Class.forName(className);
      Constructor widgetConstructor = null;
      Widget widget = null;
      if (preset != null)
        widgetConstructor = wClass.getConstructor(new Class[] { Widget.class, String.class, String.class });
      else
        widgetConstructor = wClass.getConstructor(new Class[] { Widget.class, String.class });
      if (preset != null)
        widget = (Widget) widgetConstructor.newInstance(new Object[] { parentWidget, widgetName, preset });
      else
        widget = (Widget) widgetConstructor.newInstance(new Object[] { parentWidget, widgetName });

      widget.setDataModel(debuggingMapDataModel);

      return widget;
    } catch (ClassNotFoundException e) {
      throw new GUIException("Unknown widget class [" + className + "]");
    } catch (NoSuchMethodException e) {
      throw new GUIException("Widget constructor not found", e);
    } catch (IllegalAccessException e) {
      throw new GUIException("Widget constructor could not be called", e);
    } catch (InstantiationException e) {
      throw new GUIException("Widget is abstract", e);
    } catch (InvocationTargetException e) {
      throw new GUIException("Widget constructor threw an exception", e);
    }
  }

  private void doDelete(TreeItem item) throws GUIException {
    TreeItem parent = (TreeItem) item.getParent();
    WidgetUserObject object = (WidgetUserObject) item.getUserObject();
    object.element.getParentNode().removeChild(object.element);
    Widget parentWidget = object.widget.getParentWidget();

    if (object.widget.getParentWidget() != null) {
      object.widget.getParentWidget().removeChildWidget(object.widget);
      revalidate(parentWidget);
    } else {
      if (object.widget instanceof Frame) {
        ((Frame) object.widget).dispose();
      } else if (object.widget instanceof Dialog) {
        ((Dialog) object.widget).dispose();
      }
    }

    parent.remove(item);
    widgetTree.structureChanged(parent);
    Builder.markModified();
  }

  public static void revalidate(Widget widget) throws GUIException {
    if (widget instanceof Panel)
      ((Panel) widget).recreateLayout();
    else
      widget.revalidate();
  }

  /**
   * Removes and then re-inserts all children of the given widget's parent
   */
  public static void doReInsert(WidgetUserObject object) throws GUIException {
    ArrayList temp = new ArrayList(), tempAnchors = new ArrayList();
    Widget parentWidget = object.widget.getParentWidget();
    TreeItem parentNode = (TreeItem) object.treeNode.getParentWidget();

    for (int i=0, count=parentNode.getChildCount(); i<count; i++) {
      TreeItem node = (TreeItem) parentNode.getChild(i);
      WidgetUserObject nodeObj = (WidgetUserObject) node.getUserObject();
      temp.add(nodeObj.widget);
      tempAnchors.add(XMLUtils.getChild(nodeObj.element, "anchor"));
      parentWidget.removeChildWidget(nodeObj.widget);
    }
    for (int i=0; i<temp.size(); i++) {
      Object anchor = createAnchor((Widget) temp.get(i), (Element) tempAnchors.get(i));
      parentWidget.addChild((Widget) temp.get(i), anchor);
    }
    revalidate(parentWidget);
  }

  public static void doDeleteProperty(PropertyTableRow row) throws GUIException {
    WidgetUserObject object = row.getUserObject();
    String name = (String) row.getValue("name");

    if (name.equals("anchor")) {
      row.getPropertyNode().getParentNode().removeChild(row.getPropertyNode());
      doReInsert(object);
    } else {
      WidgetInfo.PropertyEntry entry = object.widget.getWidgetInfo().getPropertyEntry(name);

      MapChangeEvent evt = new MapChangeEvent(null, null, "value", null, entry.defaultValue);
      row.modelChanged(evt);

      row.getPropertyNode().getParentNode().removeChild(row.getPropertyNode());
    }

    object.tableModel.removeRow(row);
  }

  /**
   * For simplicity's sake, the XML GUI does not have insertAt style methods
   * Therefore we now must remove everything and then add it in a different order
   */
  private void doMove(TreeItem moveItem, boolean up) throws GUIException {
    WidgetUserObject object = (WidgetUserObject) moveItem.getUserObject();
    ArrayList temp = new ArrayList();

    /* Update tree */
    TreeItem parentTreeItem = (TreeItem) moveItem.getParentWidget();
    int treeIndex = parentTreeItem.getChildIndex(moveItem);
    if (treeIndex == -1)
      throw new GUIException("Tree node not found");
    for (int i=0, count=parentTreeItem.getChildCount(); i<count; i++) {
      TreeItem item = (TreeItem) parentTreeItem.getChild(0);
      if (item != moveItem)
        temp.add(item);
      parentTreeItem.removeChildWidget(item);
    }
    temp.add(treeIndex + (up ? -1 : 1), moveItem);
    for (int i=0; i<temp.size(); i++)
      parentTreeItem.addChild((Widget) temp.get(i), null);
    temp.clear();


    /* Update widget */   
    Widget parentWidget = object.widget.getParentWidget();
    int widgetIndex = parentWidget.getChildIndex(object.widget);
    if (widgetIndex == -1)
      throw new GUIException("Widget not found");
    for (int i=0, count=parentWidget.getChildCount(); i<count; i++) {
      Widget widget = (Widget) parentWidget.getChild(0);
      if (widget != object.widget)
        temp.add(widget);
      parentWidget.removeChildWidget(widget);
    }
    temp.add(widgetIndex + (up ? -1 : 1), object.widget);
    for (int i=0; i<temp.size(); i++) {
      Element anchorNode = XMLUtils.getChild(object.element, "anchor");
      Object anchor = null;
      if (anchorNode != null)
        anchor = AnchorFactory.getInstance().constructAnchor(anchorNode);
      parentWidget.addChild((Widget) temp.get(i), anchor);
    }

    /* Update XML - This is horrible */
    Element parentElement = (Element) object.element.getParentNode();
    NodeList nodes = parentElement.getChildNodes();
 
    Element lastWidget = null, beforeWidget = null;
 
    int distance = -1;
    for (int i=0; i<nodes.getLength(); i++) {
      Node node = nodes.item(i);
      if (node == object.element) {
        if (up) {
          beforeWidget = lastWidget;
          break;
        } else {
          distance = 1;
        }
      } else if (node instanceof Element) {
        Element element = (Element) node;
        if (element.getNodeName().equals("widget")) {
          lastWidget = element;
         
          if (distance == 0) {
            beforeWidget = lastWidget;
            break;
          }
        }
        if (distance != -1)
          distance--;
      }
    }

    parentElement.removeChild(object.element);
    parentElement.insertBefore(object.element, beforeWidget);

    revalidate(parentWidget);
    widgetTree.structureChanged(parentTreeItem);
    Builder.markModified();
  }

  public Frame getFrame() {
    return frame;
  }

  public void eventOccured(GUIEvent event) {
    String command = event.getName();

    try {
      if (command.equals("tree.popup")) {
        TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");
        if (items.length > 0) {
          boolean notRoot = items.length > 1 || (items.length == 1 && items[0] != rootNode);
          boolean moveUp =
            items.length == 1
              && items[0] != rootNode
              && (items[0].getParentWidget().getChildIndex(items[0]) > 0);
          boolean moveDown =
            items.length == 1
              && items[0] != rootNode
              && (items[0].getParentWidget().getChildIndex(items[0])
                < items[0].getParentWidget().getChildCount() - 1);
          treePopupMenu.getWidget("Delete").setEnabled(notRoot);
          treePopupMenu.getWidget("MoveUp").setEnabled(moveUp);
          treePopupMenu.getWidget("MoveDown").setEnabled(moveDown);
          treePopupMenu.popup(event);
        }
      } else if (command.equals("property.popup")) {
        propertyPopupMenu.popup(event);
      } else if (command.equals("delete")) {
        TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");
        for (int i = 0; i < items.length; i++) {
          if (items[i] != rootNode)
            doDelete(items[i]);
        }
      } else if (command.equals("add_property")) {
        TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");
        if (items.length == 1 && items[0] != rootNode) {
          new AddPropertyDialog(frame, (WidgetUserObject) items[0].getUserObject());
        }
      } else if (command.equals("delete_property")) {
        TableRow rows[] = (TableRow[]) dataModel.getValue("property.value");
        for (int i = 0; i < rows.length; i++) {
          if (rows[i] instanceof PropertyTableRow) {
            doDeleteProperty((PropertyTableRow) rows[i]);
            Builder.markModified();
          }
        }
      } else if (command.equals("events")) {
        TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");

        if (items.length == 1 && items[0] != rootNode) {
          new EventDialog(this, frame, (WidgetUserObject) items[0].getUserObject());
        }
      } else if (command.equals("move_up")) {
        TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");

        if (items.length == 1 && items[0] != rootNode) {
          doMove(items[0], true);
        }
      } else if (command.equals("move_down")) {
        TreeItem items[] = (TreeItem[]) dataModel.getValue("tree.selected");

        if (items.length == 1 && items[0] != rootNode) {
          doMove(items[0], false);
        }
      }
    } catch (Exception e) {
      new MessageDialog(e);
    }
  }

  public void modelChanged(ModelChangeEvent e) throws GUIException {
    if (e instanceof MapChangeEvent) {
      MapChangeEvent event = (MapChangeEvent) e;
      if (event.getKey().equals("tree.selected")) {
        TreeItem items[] = (TreeItem[]) event.getNewValue();
        dataModel.setValue("property.value", new TableRow[] {
        });
        if (items.length == 1 && items[0] != rootNode) {
          WidgetUserObject object = (WidgetUserObject) items[0].getUserObject();
          table.setTableDataModel(object.tableModel);
        } else {
          table.setTableDataModel(emptyModel);
        }
      }
    }
  }

  public void refreshInternationalProperties() throws GUIException {
    refreshInternationalProperties(rootNode);
  }

  private void refreshInternationalProperties(TreeItem treeItem) throws GUIException {
    WidgetUserObject object = (WidgetUserObject) treeItem.getUserObject();

    if (object.element != null) {
      NodeList nodes = object.element.getChildNodes();
      for (int i = 0; i < nodes.getLength(); i++) {
        Node node = nodes.item(i);
        if (node instanceof Element && node.getNodeName().equals("property")) {
          Element propertyNode = (Element) node;
          String type = propertyNode.getAttribute("type");
          String name = propertyNode.getAttribute("name");
          if (type.equals("") || type.equals("istring")) {
            String text = XMLUtils.extractTextChildren(propertyNode);
            try {
              object.widget.setProperty(name, InternationalizationManager.getString(text));
            } catch (Exception e) {
              log.warn(
                "error while refreshing property ["
                  + name
                  + "] with internationalization ["
                  + text
                  + "]",
                e);
            }
          }
        }
      }
    }

    for (int i = 0; i < treeItem.getChildCount(); i++)
      refreshInternationalProperties((TreeItem) treeItem.getChild(i));
  }

}
TOP

Related Classes of org.beryl.gui.builder.WidgetTree$DebuggingModelChangeListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.