/** Handles model changed events from the submodels. */
  protected void handleModelChangedEvent(Model model, Object object, int index) {

    fireModelChanged();

    if (model == treeModel) {
      if (object instanceof TreeModel.TreeChangedEvent) {

        if (((TreeModel.TreeChangedEvent) object).isNodeChanged()) {
          // If a node event occurs the node and its two child nodes
          // are flagged for updating (this will result in everything
          // above being updated as well. Node events occur when a node
          // is added to a branch, removed from a branch or its height or
          // rate changes.
          updateNodeAndChildren(((TreeModel.TreeChangedEvent) object).getNode());
          updateRestrictedNodePartials = true;

        } else if (((TreeModel.TreeChangedEvent) object).isTreeChanged()) {
          // Full tree events result in a complete updating of the tree likelihood
          // This event type is now used for EmpiricalTreeDistributions.
          //                    System.err.println("Full tree update event - these events currently
          // aren't used\n" +
          //                            "so either this is in error or a new feature is using them
          // so remove this message.");
          updateAllNodes();
          updateRestrictedNodePartials = true;
        } else {
          // Other event types are ignored (probably trait changes).
          // System.err.println("Another tree event has occured (possibly a trait change).");
        }
      }

    } else if (model == branchRateModel) {
      if (index == -1) {
        if (COUNT_TOTAL_OPERATIONS) totalRateUpdateAllCount++;
        updateAllNodes();
      } else {
        if (COUNT_TOTAL_OPERATIONS) totalRateUpdateSingleCount++;
        updateNode(treeModel.getNode(index));
      }

    } else if (model == branchModel) {
      //            if (index == -1) {
      //                updateSubstitutionModel = true;
      //                updateAllNodes();
      //            } else {
      //                updateNode(treeModel.getNode(index));
      //            }

      makeDirty();

    } else if (model == siteModel) {

      updateSiteModel = true;
      updateAllNodes();

    } else if (model == tipStatesModel) {
      if (object instanceof Taxon) {
        for (int i = 0; i < treeModel.getNodeCount(); i++)
          if (treeModel.getNodeTaxon(treeModel.getNode(i)) != null
              && treeModel
                  .getNodeTaxon(treeModel.getNode(i))
                  .getId()
                  .equalsIgnoreCase(((Taxon) object).getId())) updateNode(treeModel.getNode(i));
      } else updateAllNodes();
    } else {

      throw new RuntimeException("Unknown componentChangedEvent");
    }

    super.handleModelChangedEvent(model, object, index);
  }