@Override
  public void change(GenericTagEditor ed) {
    for (String key : editors.keySet()) {
      GenericTagEditor dependentEditor = editors.get(key);
      Component dependentLabel = labels.get(key);
      Component dependentTypeLabel = types.get(key);
      List<Field> path = fieldPaths.get(key);
      List<Integer> indices = fieldIndices.get(key);
      String p = "";
      boolean conditionMet = true;
      for (int i = 0; i < path.size(); i++) {
        Field f = path.get(i);
        int index = indices.get(i);
        String par = p;
        if (!p.isEmpty()) {
          p += ".";
        }
        p += f.getName();
        if (ReflectionTools.needsIndex(f)) {
          p += "[" + index + "]";
        }
        Conditional cond = f.getAnnotation(Conditional.class);
        if (cond != null) {
          ConditionEvaluator ev = new ConditionEvaluator(cond);

          try {
            Set<String> fieldNames = ev.getFields();
            Map<String, Boolean> fields = new HashMap<>();
            for (String fld : fieldNames) {
              String ckey = "";
              if (!par.isEmpty()) {
                ckey = par + ".";
              }
              ckey += fld;
              if (editors.containsKey(ckey)) {
                GenericTagEditor editor = editors.get(ckey);
                Object val = editor.getChangedValue();
                fields.put(fld, true);
                if (val instanceof Boolean) {
                  fields.put(fld, (Boolean) val);
                }
              }
            }
            boolean ok = ev.eval(fields);
            if (conditionMet) {
              conditionMet = ok;
            }
            ((Component) dependentEditor).setVisible(conditionMet);
            dependentLabel.setVisible(conditionMet);
            dependentTypeLabel.setVisible(conditionMet);
          } catch (AnnotationParseException ex) {
            logger.log(Level.SEVERE, "Invalid condition", ex);
          }
        }
        if (!conditionMet) {
          break;
        }
      }
    }
    genericTagPropertiesEditPanel.removeAll();
    genericTagPropertiesEditPanel.setSize(0, 0);
    int propCount = 0;
    for (String key : keys) {

      Component dependentEditor;
      if (addKeys.contains(key)) {
        dependentEditor = addButtons.get(key);
      } else if (removeButtons.containsKey(key)) { // It's array/list, add remove button
        JPanel editRemPanel = new JPanel(new BorderLayout());
        editRemPanel.add((Component) editors.get(key), BorderLayout.CENTER);
        editRemPanel.add(removeButtons.get(key), BorderLayout.EAST);
        dependentEditor = editRemPanel;
      } else {
        dependentEditor = (Component) editors.get(key);
      }
      Component dependentLabel = labels.get(key);
      Component dependentTypeLabel = types.get(key);
      if (dependentEditor.isVisible()) {
        genericTagPropertiesEditPanel.add(dependentLabel);
        genericTagPropertiesEditPanel.add(((Component) dependentEditor));
        genericTagPropertiesEditPanel.add(dependentTypeLabel);
        propCount++;
      }
    }
    /*genericTagPropertiesEditPanel.add(new JPanel());
    genericTagPropertiesEditPanel.add(new JPanel());
    genericTagPropertiesEditPanel.add(new JPanel());*/
    relayout(propCount /*+ 1*/);
  }
  private int generateEditControlsRecursive(
      final Object obj,
      String parent,
      List<Field> parentFields,
      List<Integer> parentIndices,
      boolean readonly) {
    if (obj == null) {
      return 0;
    }
    Field[] fields = obj.getClass().getDeclaredFields();
    int propCount = 0;
    for (final Field field : fields) {
      try {
        if (Modifier.isStatic(field.getModifiers())) {
          continue;
        }
        field.setAccessible(true);
        String name = parent + field.getName();
        final Object value = field.get(obj);
        if (List.class.isAssignableFrom(field.getType())) {
          if (value != null) {
            int i = 0;
            for (Object obj1 : (Iterable) value) {
              final String subname = name + "[" + i + "]";
              propCount +=
                  addEditor(
                      subname,
                      obj,
                      field,
                      i,
                      obj1.getClass(),
                      obj1,
                      parentFields,
                      parentIndices,
                      readonly);
              final int fi = i;
              i++;
              JButton removeButton = new JButton(View.getIcon("close16"));
              removeButton.addActionListener(
                  new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                      removeItem(obj, field, fi);
                    }
                  });
              removeButtons.put(subname, removeButton);
            }
          }
        } else if (field.getType().isArray()) {
          if (value != null) {
            for (int i = 0; i < Array.getLength(value); i++) {
              Object item = Array.get(value, i);
              String subname = name + "[" + i + "]";
              propCount +=
                  addEditor(
                      subname,
                      obj,
                      field,
                      i,
                      item.getClass(),
                      item,
                      parentFields,
                      parentIndices,
                      readonly);
              final int fi = i;
              JButton removeButton = new JButton(View.getIcon("close16"));
              removeButton.addActionListener(
                  new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                      removeItem(obj, field, fi);
                    }
                  });
              removeButtons.put(subname, removeButton);
            }
          }
        } else {
          propCount +=
              addEditor(
                  name,
                  obj,
                  field,
                  0,
                  field.getType(),
                  value,
                  parentFields,
                  parentIndices,
                  readonly);
        }
        if (ReflectionTools.needsIndex(field)
            && !readonly
            && !field.getName().equals("clipActionRecords")) { // No clip actions, sorry
          JButton addButton = new JButton(View.getIcon("add16"));
          addButton.addActionListener(
              new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                  addItem(obj, field);
                }
              });
          name += "[]";

          List<Field> parList = new ArrayList<>(parentFields);
          parList.add(field);
          fieldPaths.put(name, parList);

          List<Integer> parIndices = new ArrayList<>(parentIndices);
          parIndices.add(0);
          fieldIndices.put(name, parIndices);

          addRow(name, addButton, field);
          addKeys.add(name);
          addButtons.put(name, addButton);
        }
      } catch (IllegalArgumentException | IllegalAccessException ex) {
        logger.log(Level.SEVERE, null, ex);
      }
    }
    return propCount;
  }