public static List<DomElement> getDefinedChildren(
      @NotNull final DomElement parent, final boolean tags, final boolean attributes) {
    if (parent instanceof MergedObject) {
      final SmartList<DomElement> result = new SmartList<>();
      parent.acceptChildren(
          new DomElementVisitor() {
            @Override
            public void visitDomElement(final DomElement element) {
              if (hasXml(element)) {
                result.add(element);
              }
            }
          });
      return result;
    }

    ProgressManager.checkCanceled();

    if (parent instanceof GenericAttributeValue) return Collections.emptyList();

    if (parent instanceof DomFileElement) {
      final DomFileElement element = (DomFileElement) parent;
      return tags ? Arrays.asList(element.getRootElement()) : Collections.<DomElement>emptyList();
    }

    final XmlElement xmlElement = parent.getXmlElement();
    if (xmlElement instanceof XmlTag) {
      XmlTag tag = (XmlTag) xmlElement;
      final DomManager domManager = parent.getManager();
      final SmartList<DomElement> result = new SmartList<>();
      if (attributes) {
        for (final XmlAttribute attribute : tag.getAttributes()) {
          if (!attribute.isValid()) {
            LOG.error("Invalid attr: parent.valid=" + tag.isValid());
            continue;
          }
          GenericAttributeValue element = domManager.getDomElement(attribute);
          if (checkHasXml(attribute, element)) {
            ContainerUtil.addIfNotNull(result, element);
          }
        }
      }
      if (tags) {
        for (final XmlTag subTag : tag.getSubTags()) {
          if (!subTag.isValid()) {
            LOG.error("Invalid subtag: parent.valid=" + tag.isValid());
            continue;
          }
          DomElement element = domManager.getDomElement(subTag);
          if (checkHasXml(subTag, element)) {
            ContainerUtil.addIfNotNull(result, element);
          }
        }
      }
      return result;
    }
    return Collections.emptyList();
  }
  @Override
  public void invoke(
      @NotNull final Project project, @NotNull final Editor editor, @NotNull final PsiFile file) {
    if (!CodeInsightUtilBase.prepareEditorForWrite(editor)) return;
    try {
      final XmlTag contextTag = getContextTag(editor, file);
      if (contextTag == null) {
        throw new CommonRefactoringUtil.RefactoringErrorHintException(
            "Caret should be positioned inside a tag");
      }
      XmlElementDescriptor currentTagDescriptor = contextTag.getDescriptor();
      assert currentTagDescriptor != null;
      final XmlElementDescriptor[] descriptors =
          currentTagDescriptor.getElementsDescriptors(contextTag);
      Arrays.sort(
          descriptors,
          new Comparator<XmlElementDescriptor>() {
            @Override
            public int compare(XmlElementDescriptor o1, XmlElementDescriptor o2) {
              return o1.getName().compareTo(o2.getName());
            }
          });
      final JBList list = new JBList(descriptors);
      list.setCellRenderer(new MyListCellRenderer());
      Runnable runnable =
          new Runnable() {
            @Override
            public void run() {
              final XmlElementDescriptor selected = (XmlElementDescriptor) list.getSelectedValue();
              new WriteCommandAction.Simple(project, "Generate XML Tag", file) {
                @Override
                protected void run() {
                  if (selected == null) return;
                  XmlTag newTag = createTag(contextTag, selected);

                  PsiElement anchor = getAnchor(contextTag, editor, selected);
                  if (anchor == null) { // insert it in the cursor position
                    int offset = editor.getCaretModel().getOffset();
                    Document document = editor.getDocument();
                    document.insertString(offset, newTag.getText());
                    PsiDocumentManager.getInstance(project).commitDocument(document);
                    newTag =
                        PsiTreeUtil.getParentOfType(
                            file.findElementAt(offset + 1), XmlTag.class, false);
                  } else {
                    newTag = (XmlTag) contextTag.addAfter(newTag, anchor);
                  }
                  if (newTag != null) {
                    generateTag(newTag, editor);
                  }
                }
              }.execute();
            }
          };
      if (ApplicationManager.getApplication().isUnitTestMode()) {
        XmlElementDescriptor descriptor =
            ContainerUtil.find(
                descriptors,
                new Condition<XmlElementDescriptor>() {
                  @Override
                  public boolean value(XmlElementDescriptor xmlElementDescriptor) {
                    return xmlElementDescriptor.getName().equals(TEST_THREAD_LOCAL.get());
                  }
                });
        list.setSelectedValue(descriptor, false);
        runnable.run();
      } else {
        JBPopupFactory.getInstance()
            .createListPopupBuilder(list)
            .setTitle("Choose Tag Name")
            .setItemChoosenCallback(runnable)
            .setFilteringEnabled(
                new Function<Object, String>() {
                  @Override
                  public String fun(Object o) {
                    return ((XmlElementDescriptor) o).getName();
                  }
                })
            .createPopup()
            .showInBestPositionFor(editor);
      }
    } catch (CommonRefactoringUtil.RefactoringErrorHintException e) {
      HintManager.getInstance().showErrorHint(editor, e.getMessage());
    }
  }