public void setValueAt(Object aValue, int row, int col) {
   AbstractPartitionData partition = options.dataPartitions.get(row);
   switch (col) {
     case 0:
       String name = ((String) aValue).trim();
       if (options.hasPartitionData(name)) {
         JOptionPane.showMessageDialog(
             frame,
             "Duplicate partition name.",
             "Illegal Argument Exception",
             JOptionPane.ERROR_MESSAGE);
         return;
       }
       if (name.length() > 0) {
         options.renamePartition(partition, name);
       }
       break;
     case 5:
       //                    partition.setPloidyType((PloidyType) aValue);
       //                    break;
       //                case 6:
       if (((PartitionSubstitutionModel) aValue).getDataType().equals(partition.getDataType())) {
         partition.setPartitionSubstitutionModel((PartitionSubstitutionModel) aValue);
       }
       break;
     case 6:
       partition.setPartitionClockModel((PartitionClockModel) aValue);
       break;
     case 7:
       partition.setPartitionTreeModel((PartitionTreeModel) aValue);
       break;
   }
   fireDataChanged();
 }
    public boolean isCellEditable(int row, int col) {
      boolean editable;

      AbstractPartitionData partition = options.dataPartitions.get(row);

      switch (col) {
        case 0: // name
          editable = true;
          break;
          //                case 5:// ploidy type selection menu
          //                    editable = true;
          //                    break;
        case 5: // substitution model selection menu
          editable = partition.getDataType().getType() != DataType.CONTINUOUS;
          break;
        case 6: // clock model selection menu
          editable = partition.getDataType().getType() != DataType.CONTINUOUS;
          break;
        case 7: // tree selection menu
          editable = true;
          break;
        default:
          editable = false;
      }

      return editable;
    }
  public void linkClocks() { // keep previous PartitionTreePrior for reuse
    int[] selRows = dataTable.getSelectedRows();

    List<AbstractPartitionData> selectedPartitionData = new ArrayList<AbstractPartitionData>();
    for (int row : selRows) {
      AbstractPartitionData partition = options.dataPartitions.get(row);

      if (!selectedPartitionData.contains(partition)) selectedPartitionData.add(partition);
    }
    Object[] modelArray = options.getPartitionClockModels(selectedPartitionData).toArray();

    if (selectClockDialog == null) {
      selectClockDialog = new SelectClockDialog(frame);
    }

    int result = selectClockDialog.showDialog(modelArray);
    if (result != JOptionPane.CANCEL_OPTION) {
      PartitionClockModel model = selectClockDialog.getModel();
      if (selectClockDialog.getMakeCopy()) {
        model.setName(selectClockDialog.getName());
      }

      for (AbstractPartitionData partition : selectedPartitionData) {
        partition.setPartitionClockModel(model);
      }
    }

    modelsChanged();

    fireDataChanged();
    repaint();
  }
  public void linkTrees() { // keep previous PartitionTreePrior for reuse
    int[] selRows = dataTable.getSelectedRows();

    List<AbstractPartitionData> selectedPartitionData = new ArrayList<AbstractPartitionData>();
    for (int row : selRows) {
      AbstractPartitionData partition = options.dataPartitions.get(row);

      if (!selectedPartitionData.contains(partition)) selectedPartitionData.add(partition);
    }

    if (selectedPartitionData.size() > 1) {
      if (!options.hasIdenticalTaxa(selectedPartitionData)) {
        String errMsg = "To share a tree, partitions need to have identical taxa.";
        if (selectedPartitionData.get(0).getDataType().getType() == DataType.MICRO_SAT)
          errMsg += "\nThe data must be all diploid or all haploid when you want to link the tree.";
        JOptionPane.showMessageDialog(
            this, errMsg, "Illegal Configuration", JOptionPane.ERROR_MESSAGE);
        return;
      }
    }

    Object[] treeArray = options.getPartitionTreeModels(selectedPartitionData).toArray();

    if (selectTreeDialog == null) {
      selectTreeDialog = new SelectTreeDialog(frame);
    }

    int result = selectTreeDialog.showDialog(treeArray);
    if (result != JOptionPane.CANCEL_OPTION) {
      PartitionTreeModel model = selectTreeDialog.getTree();
      if (selectTreeDialog.getMakeCopy()) {
        model.setName(selectTreeDialog.getName());
      }
      PartitionTreePrior prior = model.getPartitionTreePrior();
      options.linkTreePriors(prior);

      for (AbstractPartitionData partition : selectedPartitionData) {
        partition.setPartitionTreeModel(model);
      }

      for (Taxa taxa :
          options.taxonSets) { // Issue 454: all the taxon sets are deleted when link/unlink tree
        PartitionTreeModel prevModel = options.taxonSetsTreeModel.get(taxa);
        if (prevModel != model) options.taxonSetsTreeModel.put(taxa, model);
      }
    }

    modelsChanged();

    fireDataChanged();
    repaint();
  }
  public void linkModels() {
    int[] selRows = dataTable.getSelectedRows();
    List<AbstractPartitionData> selectedPartitionData = new ArrayList<AbstractPartitionData>();
    DataType dateType = null;
    for (int row : selRows) {
      AbstractPartitionData partition = options.dataPartitions.get(row);
      if (dateType == null) {
        dateType = partition.getDataType();
      } else {
        if (partition.getDataType() != dateType) {
          JOptionPane.showMessageDialog(
              this,
              "Can only link the models for data partitions \n"
                  + "of the same data type (e.g., nucleotides)",
              "Unable to link models",
              JOptionPane.ERROR_MESSAGE);
          return;
        }
      }

      if (!selectedPartitionData.contains(partition)) selectedPartitionData.add(partition);
    }

    Object[] modelArray = options.getPartitionSubstitutionModels(selectedPartitionData).toArray();

    if (selectModelDialog == null) {
      selectModelDialog = new SelectModelDialog(frame);
    }

    int result = selectModelDialog.showDialog(modelArray);
    if (result != JOptionPane.CANCEL_OPTION) {
      PartitionSubstitutionModel model = selectModelDialog.getModel();
      if (selectModelDialog.getMakeCopy()) {
        model.setName(selectModelDialog.getName());
      }

      for (AbstractPartitionData partition : selectedPartitionData) {
        partition.setPartitionSubstitutionModel(model);
      }
    }

    if (options.getPartitionSubstitutionModels(Microsatellite.INSTANCE).size() <= 1) {
      options.shareMicroSat = true;
    }

    modelsChanged();

    fireDataChanged();
    repaint();
  }
  public void unlinkClocks() { // reuse previous PartitionTreePrior
    int[] selRows = dataTable.getSelectedRows();
    for (int row : selRows) {
      AbstractPartitionData partition = options.dataPartitions.get(row);

      PartitionClockModel model = partition.getPartitionClockModel();
      if (!model.getName().equals(partition.getName())) {
        PartitionClockModel newModel = new PartitionClockModel(options, partition.getName(), model);
        partition.setPartitionClockModel(newModel);
        newModel.setClockModelGroup(model.getClockModelGroup()); // set clock model group
      }
    }

    modelsChanged();

    fireDataChanged();
    repaint();
  }
  public void unlinkModels() {
    int[] selRows = dataTable.getSelectedRows();
    for (int row : selRows) {
      AbstractPartitionData partition = options.dataPartitions.get(row);

      PartitionSubstitutionModel model = partition.getPartitionSubstitutionModel();
      if (!model.getName().equals(partition.getName())) {
        PartitionSubstitutionModel newModel =
            new PartitionSubstitutionModel(options, partition.getName(), model);
        partition.setPartitionSubstitutionModel(newModel);
      }
    }

    modelsChanged();

    fireDataChanged();
    repaint();
  }
  public void unlinkTrees() { // reuse previous PartitionTreePrior
    int[] selRows = dataTable.getSelectedRows();
    for (int row : selRows) {
      AbstractPartitionData partition = options.dataPartitions.get(row);

      PartitionTreeModel model = partition.getPartitionTreeModel();
      if (!model.getName().equals(partition.getName())
          && partition.getTraits() == null) { // not a trait
        PartitionTreeModel newTree = new PartitionTreeModel(options, partition.getName(), model);

        // this prevents partition not broken, and used for unsharing tree prior only,
        // because sharing uses shareSameTreePrior, unsharing uses getPartitionTreePrior
        //                newTree.setPartitionTreePrior(newPrior); // important

        partition.setPartitionTreeModel(newTree);
      }
    }

    options.linkTreePriors(frame.getCurrentPartitionTreePrior());

    modelsChanged();

    fireDataChanged();
    repaint();
  }
 public Object getValueAt(int row, int col) {
   //            PartitionData partition = options.getPartitionDataNoSpecies().get(row);
   AbstractPartitionData partition = options.dataPartitions.get(row);
   switch (col) {
     case 0:
       return partition.getName();
     case 1:
       return partition.getFileName();
     case 2:
       return "" + (partition.getTaxonCount() >= 0 ? partition.getTaxonCount() : "-");
     case 3:
       return "" + (partition.getSiteCount() >= 0 ? partition.getSiteCount() : "-");
     case 4:
       return partition.getDataDescription();
     case 5:
       //                    return partition.getPloidyType();
       //                case 6:
       return partition.getPartitionSubstitutionModel().getName();
     case 6:
       return ""
           + (partition.getPartitionClockModel() != null
               ? partition.getPartitionClockModel().getName()
               : "-");
     case 7:
       return partition.getPartitionTreeModel().getName();
     default:
       throw new IllegalArgumentException("unknown column, " + col);
   }
 }