/** Notify this instance that it may now render a GUI */
  public synchronized void okToUseGui() {
    if (!okToUseGui) {
      okToUseGui = true;

      // lets also tell the Children that can that they may use their GUI's
      synchronized (children) {
        for (Iterator i = children.keySet().iterator(); i.hasNext(); ) {
          Visibility v = getChildVisibility(i.next());

          if (v != null) v.okToUseGui();
        }
      }
    }
  }
  /**
   * Adds/nests a child within this <tt>BeanContext</tt>.
   *
   * <p>Invoked as a side effect of java.beans.Beans.instantiate(). If the child object is not valid
   * for adding then this method throws an IllegalStateException.
   *
   * @param targetChild The child objects to nest within this <tt>BeanContext</tt>
   * @return true if the child was added successfully.
   * @see #validatePendingAdd
   */
  public boolean add(Object targetChild) {

    if (targetChild == null) throw new IllegalArgumentException();

    // The specification requires that we do nothing if the child
    // is already nested herein.

    if (children.containsKey(targetChild)) return false; // test before locking

    synchronized (BeanContext.globalHierarchyLock) {
      if (children.containsKey(targetChild)) return false; // check again

      if (!validatePendingAdd(targetChild)) {
        throw new IllegalStateException();
      }

      // The specification requires that we invoke setBeanContext() on the
      // newly added child if it implements the java.beans.beancontext.BeanContextChild interface

      BeanContextChild cbcc = getChildBeanContextChild(targetChild);
      BeanContextChild bccp = null;

      synchronized (targetChild) {
        if (targetChild instanceof BeanContextProxy) {
          bccp = ((BeanContextProxy) targetChild).getBeanContextProxy();

          if (bccp == null) throw new NullPointerException("BeanContextPeer.getBeanContextProxy()");
        }

        BCSChild bcsc = createBCSChild(targetChild, bccp);
        BCSChild pbcsc = null;

        synchronized (children) {
          children.put(targetChild, bcsc);

          if (bccp != null) children.put(bccp, pbcsc = createBCSChild(bccp, targetChild));
        }

        if (cbcc != null)
          synchronized (cbcc) {
            try {
              cbcc.setBeanContext(getBeanContextPeer());
            } catch (PropertyVetoException pve) {

              synchronized (children) {
                children.remove(targetChild);

                if (bccp != null) children.remove(bccp);
              }

              throw new IllegalStateException();
            }

            cbcc.addPropertyChangeListener("beanContext", childPCL);
            cbcc.addVetoableChangeListener("beanContext", childVCL);
          }

        Visibility v = getChildVisibility(targetChild);

        if (v != null) {
          if (okToUseGui) v.okToUseGui();
          else v.dontUseGui();
        }

        if (getChildSerializable(targetChild) != null) serializable++;

        childJustAddedHook(targetChild, bcsc);

        if (bccp != null) {
          v = getChildVisibility(bccp);

          if (v != null) {
            if (okToUseGui) v.okToUseGui();
            else v.dontUseGui();
          }

          if (getChildSerializable(bccp) != null) serializable++;

          childJustAddedHook(bccp, pbcsc);
        }
      }

      // The specification requires that we fire a notification of the change

      fireChildrenAdded(
          new BeanContextMembershipEvent(
              getBeanContextPeer(),
              bccp == null ? new Object[] {targetChild} : new Object[] {targetChild, bccp}));
    }

    return true;
  }