/**
   * Set node content as replacement for the pickingGeometry field. This checks only for basic
   * geometry handling. If a concrete node needs a specific set of nodes, it should override this
   * method to check.
   *
   * @param app The new appearance. null will act like delete
   * @throws InvalidFieldValueException The node does not match the required type.
   */
  public void setPickingGeometry(VRMLNodeType child) throws InvalidFieldValueException {

    VRMLGeometryNodeType node;
    VRMLNodeType old_node;

    if (pPickingGeometry != null) old_node = pPickingGeometry;
    else old_node = vfPickingGeometry;

    if (child instanceof VRMLProtoInstance) {
      VRMLNodeType impl = ((VRMLProtoInstance) child).getImplementationNode();

      pPickingGeometry = (VRMLProtoInstance) child;

      while ((impl != null) && (impl instanceof VRMLProtoInstance))
        impl = ((VRMLProtoInstance) impl).getImplementationNode();

      if ((impl != null) && !(impl instanceof VRMLGeometryNodeType))
        throw new InvalidFieldValueException(GEOMETRY_PROTO_MSG);

      String name = impl.getVRMLNodeName();
      if (!validGeometryNodeNames.contains(name))
        throw new InvalidFieldValueException(PICK_GEOM_TYPE_MSG);

      node = (VRMLGeometryNodeType) impl;
    } else if (child instanceof VRMLGeometryNodeType) {
      String name = child.getVRMLNodeName();
      if (!validGeometryNodeNames.contains(name))
        throw new InvalidFieldValueException(PICK_GEOM_TYPE_MSG);

      pPickingGeometry = null;
      node = (VRMLGeometryNodeType) child;
    } else {
      throw new InvalidFieldValueException(GEOMETRY_NODE_MSG);
    }

    vfPickingGeometry = (VRMLGeometryNodeType) node;

    if (child != null) updateRefs(child, true);

    if (old_node != null) updateRefs(old_node, false);

    if (!inSetup) {
      if (old_node != null) stateManager.registerRemovedNode(old_node);

      if (child != null) stateManager.registerAddedNode(child);

      hasChanged[FIELD_PICKING_GEOMETRY] = true;
      fireFieldChanged(FIELD_PICKING_GEOMETRY);
    }
  }
  /**
   * Check to make sure the picking target node being added is of the correct type. If not, issue an
   * error.
   *
   * @param target The node to check that it follows the requirements
   * @throws InvalidFieldValueException The node is not a grouping or shape node
   */
  protected void checkPickTargetType(VRMLNodeType target) throws InvalidFieldValueException {

    if ((target instanceof VRMLGroupingNodeType) || (target instanceof VRMLShapeNodeType)) return;

    if (!(target instanceof VRMLProtoInstance))
      throw new InvalidFieldValueException(
          "pickTarget node not a group or shape node type: " + target.getVRMLNodeName());

    VRMLProtoInstance proto = (VRMLProtoInstance) target;
    VRMLNodeType node = proto.getImplementationNode();

    while ((node != null) && (node instanceof VRMLProtoInstance))
      node = ((VRMLProtoInstance) node).getImplementationNode();

    if ((node != null)
        && (!(node instanceof VRMLGroupingNodeType) && !(node instanceof VRMLShapeNodeType)))
      throw new InvalidFieldValueException(
          "pickTarget proto instance not a group or shape node type: " + target.getVRMLNodeName());
  }
  /**
   * Add a single child node to the list of available children. Override to
   * provide.renderer-specific behaviour, but remember to also call this implementation too.
   *
   * @param node The node to add
   */
  protected void addChildNode(VRMLNodeType node) {

    if (node instanceof VRMLProtoInstance) {
      VRMLNodeType impl = ((VRMLProtoInstance) node).getImplementationNode();

      // Walk down the proto impl looking for the real node to check it
      // is the right type.
      while ((impl != null) && (impl instanceof VRMLProtoInstance))
        impl = ((VRMLProtoInstance) impl).getImplementationNode();

      if ((impl != null) && !(impl instanceof VRMLWorldRootChildNodeType))
        throw new InvalidFieldValueException(NON_CHILD_PROTO_MSG + node.getVRMLNodeName());

    } else if (node != null && !(node instanceof VRMLWorldRootChildNodeType)) {
      throw new InvalidFieldValueException(NON_CHILD_NODE_MSG + node.getVRMLNodeName());
    }

    if (node != null) updateRefs(node, true);

    vfChildren.add(node);
    childCount++;

    if (!inSetup) stateManager.registerAddedNode(node);
  }