/**
   * Create a variation (copy) of a given resource file (of a given type).
   *
   * @param xmlFile the XML resource file to fork
   * @param myNewFolder the resource folder to create, or null to ask the user
   * @param open if true, open the file after creating it
   */
  public static void forkResourceFile(
      @NotNull final XmlFile xmlFile, @Nullable String myNewFolder, boolean open) {
    VirtualFile file = xmlFile.getVirtualFile();
    if (file == null) {
      return;
    }
    Module module = AndroidPsiUtils.getModuleSafely(xmlFile);
    if (module == null) {
      return;
    }
    ResourceFolderType folderType = ResourceHelper.getFolderType(xmlFile);
    if (folderType == null || folderType == ResourceFolderType.VALUES) {
      return;
    }
    Configuration configuration = null;
    if (folderType == ResourceFolderType.LAYOUT) {
      AndroidFacet facet = AndroidFacet.getInstance(module);
      if (facet != null) {
        configuration = facet.getConfigurationManager().getConfiguration(file);
      }
    }

    // Suppress: IntelliJ claims folderType can be null here, but it can't (and inserting assert
    // folderType != null is correctly
    // identified as redundant)
    //noinspection ConstantConditions
    forkResourceFile(module, folderType, file, xmlFile, myNewFolder, configuration, open);
  }
  @NotNull
  private static XmlFileHeader calcXmlFileHeader(final XmlFile file) {

    if (file instanceof PsiFileEx
        && ((PsiFileEx) file).isContentsLoaded()
        && file.getNode().isParsed()) {
      return computeHeaderByPsi(file);
    }

    if (!XmlUtil.isStubBuilding() && file.getFileType() == XmlFileType.INSTANCE) {
      VirtualFile virtualFile = file.getVirtualFile();
      if (virtualFile instanceof VirtualFileWithId) {
        ObjectStubTree tree =
            StubTreeLoader.getInstance().readFromVFile(file.getProject(), virtualFile);
        if (tree != null) {
          Stub root = tree.getRoot();
          if (root instanceof FileStub) {
            return ((FileStub) root).getHeader();
          }
        }
      }
    }

    if (!file.isValid()) return XmlFileHeader.EMPTY;

    return NanoXmlUtil.parseHeader(file);
  }
  public static DomFileEditor createDomFileEditor(
      final String name,
      @Nullable final Icon icon,
      final DomElement element,
      final Factory<? extends CommittablePanel> committablePanel) {

    final XmlFile file = DomUtil.getFile(element);
    final Factory<BasicDomElementComponent> factory =
        new Factory<BasicDomElementComponent>() {
          @Override
          public BasicDomElementComponent create() {

            CaptionComponent captionComponent = new CaptionComponent(name, icon);
            captionComponent.initErrorPanel(element);
            BasicDomElementComponent component =
                createComponentWithCaption(committablePanel.create(), captionComponent, element);
            Disposer.register(component, captionComponent);
            return component;
          }
        };
    return new DomFileEditor<BasicDomElementComponent>(
        file.getProject(), file.getVirtualFile(), name, factory) {
      @Override
      public JComponent getPreferredFocusedComponent() {
        return null;
      }
    };
  }
 public AntHectorConfigurable(XmlFile file) {
   myFile = file;
   myProject = file.getProject();
   final VirtualFile selfVFile = myFile.getVirtualFile();
   myLocalPath = PathUtil.getLocalPath(selfVFile);
   myFileFilter = GlobalSearchScope.projectScope(myProject);
 }
 @Nullable
 public final <T extends DomElement> DomFileElementImpl<T> getFileElement(XmlFile file) {
   if (file == null) return null;
   if (!(file.getFileType() instanceof DomSupportEnabled)) return null;
   final VirtualFile virtualFile = file.getVirtualFile();
   if (virtualFile != null && virtualFile.isDirectory()) return null;
   return this.<T>getOrCreateCachedValueProvider(file).getFileElement();
 }
 @Override
 public boolean deannotate(
     @NotNull final PsiModifierListOwner listOwner, @NotNull final String annotationFQN) {
   try {
     final List<XmlFile> files = findExternalAnnotationsXmlFiles(listOwner);
     if (files == null) {
       return false;
     }
     for (XmlFile file : files) {
       if (!file.isValid()) {
         continue;
       }
       final XmlDocument document = file.getDocument();
       if (document == null) {
         continue;
       }
       final XmlTag rootTag = document.getRootTag();
       if (rootTag == null) {
         continue;
       }
       final String externalName = getExternalName(listOwner, false);
       final String oldExternalName = getNormalizedExternalName(listOwner);
       for (final XmlTag tag : rootTag.getSubTags()) {
         final String className = tag.getAttributeValue("name");
         if (!Comparing.strEqual(className, externalName)
             && !Comparing.strEqual(className, oldExternalName)) {
           continue;
         }
         for (XmlTag annotationTag : tag.getSubTags()) {
           if (!Comparing.strEqual(annotationTag.getAttributeValue("name"), annotationFQN)) {
             continue;
           }
           if (ReadonlyStatusHandler.getInstance(myPsiManager.getProject())
               .ensureFilesWritable(file.getVirtualFile())
               .hasReadonlyFiles()) {
             return false;
           }
           try {
             annotationTag.delete();
             if (tag.getSubTags().length == 0) {
               tag.delete();
             }
           } catch (IncorrectOperationException e) {
             LOG.error(e);
           }
           return true;
         }
         return false;
       }
     }
     return false;
   } finally {
     dropCache();
   }
 }
  private void annotateExternally(
      @NotNull final VirtualFile file,
      @NotNull final PsiModifierListOwner listOwner,
      @NotNull Project project,
      @NotNull final String packageName,
      final VirtualFile virtualFile,
      @NotNull final String annotationFQName,
      @NotNull final PsiFile fromFile,
      final PsiNameValuePair[] value) {
    final XmlFile[] annotationsXml = new XmlFile[1];
    List<XmlFile> xmlFiles = findExternalAnnotationsXmlFiles(listOwner);
    if (xmlFiles != null) {
      for (XmlFile xmlFile : xmlFiles) {
        final VirtualFile vXmlFile = xmlFile.getVirtualFile();
        assert vXmlFile != null;
        if (VfsUtilCore.isAncestor(file, vXmlFile, false)) {
          annotationsXml[0] = xmlFile;
          if (!CodeInsightUtilBase.preparePsiElementForWrite(xmlFile)) return;
        }
      }
    } else {
      xmlFiles = new ArrayList<XmlFile>();
    }

    final List<PsiFile> annotationFiles = new ArrayList<PsiFile>(xmlFiles);
    new WriteCommandAction(project) {
      @Override
      protected void run(final Result result) throws Throwable {
        if (annotationsXml[0] == null) {
          annotationsXml[0] = createAnnotationsXml(file, packageName);
        }
        if (annotationsXml[0] != null) {
          annotationFiles.add(annotationsXml[0]);
          myExternalAnnotations.put(getFQN(packageName, virtualFile), annotationFiles);
          annotateExternally(listOwner, annotationFQName, annotationsXml[0], fromFile, value);
        }
      }
    }.execute();

    UndoManager.getInstance(project)
        .undoableActionPerformed(
            new BasicUndoableAction() {
              @Override
              public void undo() throws UnexpectedUndoException {
                dropCache();
              }

              @Override
              public void redo() throws UnexpectedUndoException {
                dropCache();
              }
            });
  }
 @Nullable
 private static XmlFile findXmlFileInRoot(
     @Nullable List<XmlFile> xmlFiles, @NotNull VirtualFile root) {
   if (xmlFiles != null) {
     for (XmlFile xmlFile : xmlFiles) {
       VirtualFile vf = xmlFile.getVirtualFile();
       if (vf != null) {
         if (VfsUtilCore.isAncestor(root, vf, false)) {
           return xmlFile;
         }
       }
     }
   }
   return null;
 }
 @NotNull
 private static XmlFile parseXmlFileInTemplate(
     String templateString, CustomTemplateCallback callback, boolean createPhysicalFile) {
   XmlFile xmlFile =
       (XmlFile)
           PsiFileFactory.getInstance(callback.getProject())
               .createFileFromText(
                   "dummy.xml",
                   StdFileTypes.XML,
                   templateString,
                   LocalTimeCounter.currentTime(),
                   createPhysicalFile);
   VirtualFile vFile = xmlFile.getVirtualFile();
   if (vFile != null) {
     vFile.putUserData(UndoConstants.DONT_RECORD_UNDO, Boolean.TRUE);
   }
   return xmlFile;
 }
 private boolean processExistingExternalAnnotations(
     @NotNull final PsiModifierListOwner listOwner,
     @NotNull final String annotationFQN,
     @NotNull final Processor<XmlTag> annotationTagProcessor) {
   try {
     final List<XmlFile> files = findExternalAnnotationsXmlFiles(listOwner);
     if (files == null) {
       notifyAfterAnnotationChanging(listOwner, annotationFQN, false);
       return false;
     }
     boolean processedAnything = false;
     for (final XmlFile file : files) {
       if (!file.isValid()) {
         continue;
       }
       if (ReadonlyStatusHandler.getInstance(myPsiManager.getProject())
           .ensureFilesWritable(file.getVirtualFile())
           .hasReadonlyFiles()) {
         continue;
       }
       final XmlDocument document = file.getDocument();
       if (document == null) {
         continue;
       }
       final XmlTag rootTag = document.getRootTag();
       if (rootTag == null) {
         continue;
       }
       final String externalName = getExternalName(listOwner, false);
       final String oldExternalName = getNormalizedExternalName(listOwner);
       for (final XmlTag tag : rootTag.getSubTags()) {
         final String className = StringUtil.unescapeXml(tag.getAttributeValue("name"));
         if (!Comparing.strEqual(className, externalName)
             && !Comparing.strEqual(className, oldExternalName)) {
           continue;
         }
         for (final XmlTag annotationTag : tag.getSubTags()) {
           if (!Comparing.strEqual(annotationTag.getAttributeValue("name"), annotationFQN)) {
             continue;
           }
           CommandProcessor.getInstance()
               .executeCommand(
                   myPsiManager.getProject(),
                   new Runnable() {
                     @Override
                     public void run() {
                       try {
                         annotationTagProcessor.process(annotationTag);
                         commitChanges(file);
                       } catch (IncorrectOperationException e) {
                         LOG.error(e);
                       }
                     }
                   },
                   ExternalAnnotationsManagerImpl.class.getName(),
                   null);
           processedAnything = true;
         }
       }
     }
     notifyAfterAnnotationChanging(listOwner, annotationFQN, processedAnything);
     return processedAnything;
   } finally {
     dropCache();
   }
 }
 /**
  * @param xmlFile
  * @return True if the file is contained within 'OSGI-INF/blueprint'
  */
 private boolean isInsideOsgiInfBlueprint(XmlFile xmlFile) {
   String localPath = PathUtil.getLocalPath(xmlFile.getVirtualFile());
   if (localPath == null) return false;
   String parentPath = PathUtil.getParentPath(localPath);
   return parentPath.endsWith("OSGI-INF\\blueprint") || parentPath.endsWith("OSGI-INF/blueprint");
 }
  public void annotate(
      @NotNull final PsiElement psiElement, @NotNull final AnnotationHolder holder) {
    if (!(psiElement instanceof XmlFile)) {
      return;
    }

    if (psiElement instanceof JspFile) {
      return;
    }

    final Module module = ModuleUtil.findModuleForPsiElement(psiElement);
    if (module == null) {
      return;
    }

    // do not run when facet not enabled
    if (StrutsFacet.getInstance(module) == null) {
      return;
    }

    final XmlFile xmlFile = (XmlFile) psiElement;
    final Project project = psiElement.getProject();

    final StrutsManager strutsManager = StrutsManager.getInstance(project);
    if (!strutsManager.isStruts2ConfigFile(xmlFile)) {
      return;
    }

    final VirtualFile currentVirtualFile = xmlFile.getVirtualFile();
    assert currentVirtualFile != null;

    final Set<StrutsFileSet> allConfigFileSets = strutsManager.getAllConfigFileSets(module);
    for (final StrutsFileSet configFileSet : allConfigFileSets) {
      if (configFileSet.hasFile(currentVirtualFile)) {
        return;
      }
    }

    final boolean fileSetAvailable = allConfigFileSets.size() != 0;
    final Annotation annotation =
        holder.createWarningAnnotation(
            xmlFile,
            fileSetAvailable
                ? StrutsBundle.message("annotators.fileset.file.not.registered")
                : StrutsBundle.message("annotators.fileset.no.file.sets"));
    annotation.setFileLevelAnnotation(true);

    if (fileSetAvailable) {
      final AddToFileSetFix addToFileSetFix = new AddToFileSetFix(xmlFile.getName());
      annotation.registerFix(addToFileSetFix);
    } else {
      annotation.registerFix(
          new IntentionAction() {
            @NotNull
            public String getText() {
              return StrutsBundle.message("annotators.fileset.edit.facet.settings");
            }

            @NotNull
            public String getFamilyName() {
              return StrutsBundle.message("intentions.family.name");
            }

            public boolean isAvailable(
                @NotNull final Project project, final Editor editor, final PsiFile psiFile) {
              return true;
            }

            public void invoke(
                @NotNull final Project project, final Editor editor, final PsiFile psiFile)
                throws IncorrectOperationException {
              final StrutsFacet strutsFacet = StrutsFacet.getInstance(module);
              assert strutsFacet != null;
              ModulesConfigurator.showFacetSettingsDialog(strutsFacet, null);
            }

            public boolean startInWriteAction() {
              return false;
            }
          });
    }
  }
  public JComponent createComponent() {
    final JPanel panel = new JPanel(new GridBagLayout());
    panel.setBorder(IdeBorderFactory.createTitledBorder("File Context", false));
    myCombo = new ComboBox();
    myCombo.putClientProperty(CONTEXTS_COMBO_KEY, Boolean.TRUE);
    panel.add(
        new JLabel("Included into:"),
        new GridBagConstraints(
            0,
            0,
            1,
            1,
            0.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.NONE,
            new Insets(5, 0, 5, 0),
            0,
            0));
    panel.add(
        myCombo,
        new GridBagConstraints(
            1,
            0,
            1,
            1,
            1.0,
            0.0,
            GridBagConstraints.WEST,
            GridBagConstraints.HORIZONTAL,
            new Insets(5, 5, 5, 0),
            0,
            0));

    final PsiManager psiManager = PsiManager.getInstance(myProject);
    final FileBasedIndex fbi = FileBasedIndex.getInstance();
    final Collection<VirtualFile> antFiles =
        fbi.getContainingFiles(
            AntImportsIndex.INDEX_NAME, AntImportsIndex.ANT_FILES_WITH_IMPORTS_KEY, myFileFilter);

    for (VirtualFile file : antFiles) {
      final PsiFile psiFile = psiManager.findFile(file);
      if (!(psiFile instanceof XmlFile)) {
        continue;
      }
      final XmlFile xmlFile = (XmlFile) psiFile;
      if (!xmlFile.equals(myFile) && AntDomFileDescription.isAntFile(xmlFile)) {
        final String path = PathUtil.getLocalPath(file);
        final XmlFile previous = myPathToFileMap.put(path, xmlFile);
        assert previous == null;
      }
    }

    final List<String> paths = new ArrayList<String>(myPathToFileMap.keySet());
    Collections.sort(
        paths,
        new Comparator<String>() {
          public int compare(final String o1, final String o2) {
            return o1.compareTo(o2);
          }
        });

    myCombo.addItem(NONE);
    for (String path : paths) {
      myCombo.addItem(path);
    }

    final AntConfigurationBase antConfig = AntConfigurationBase.getInstance(myProject);
    final XmlFile currentContext = antConfig.getContextFile(myFile);
    if (currentContext != null) {
      final VirtualFile vFile = currentContext.getVirtualFile();

      assert vFile != null;

      final String path = PathUtil.getLocalPath(vFile);
      if (!FileUtil.pathsEqual(path, myLocalPath)) {
        myOriginalContext = path;
      }
    }
    myCombo.setSelectedItem(myOriginalContext);

    return panel;
  }
  @Override
  public boolean execute(
      @NotNull final PsiElement queryParameters, @NotNull final Processor<PsiElement> consumer) {
    if (queryParameters instanceof XmlTagImpl) {
      final XmlTagImpl xml = (XmlTagImpl) queryParameters;
      if (isTypeElement(xml)) {
        final Collection<SchemaTypeInfo> infos =
            ApplicationManager.getApplication()
                .runReadAction(
                    new Computable<Collection<SchemaTypeInfo>>() {

                      @Override
                      public Collection<SchemaTypeInfo> compute() {
                        return gatherInheritors(xml);
                      }
                    });

        if (infos != null && !infos.isEmpty()) {
          final Project project = XmlUtil.getContainingFile(xml).getProject();
          final Module module = ModuleUtil.findModuleForPsiElement(queryParameters);
          // if (module == null) return false;

          final XmlFile file = XmlUtil.getContainingFile(xml);
          final VirtualFile vf = file.getVirtualFile();
          String thisNs = XmlNamespaceIndex.getNamespace(vf, project);
          thisNs = thisNs == null ? getDefaultNs(file) : thisNs;
          // so thisNs can be null
          if (thisNs == null) return false;
          final ArrayList<SchemaTypeInfo> infosLst = new ArrayList<SchemaTypeInfo>(infos);
          Collections.sort(infosLst);
          final Map<String, Set<XmlFile>> nsMap = new HashMap<String, Set<XmlFile>>();
          for (final SchemaTypeInfo info : infosLst) {
            Set<XmlFile> targetFiles = nsMap.get(info.getNamespaceUri());
            if (targetFiles == null) {
              targetFiles = new HashSet<XmlFile>();
              if (Comparing.equal(info.getNamespaceUri(), thisNs)) {
                targetFiles.add(file);
              }
              final Collection<XmlFile> files =
                  ApplicationManager.getApplication()
                      .runReadAction(
                          new Computable<Collection<XmlFile>>() {
                            @Override
                            public Collection<XmlFile> compute() {
                              return XmlUtil.findNSFilesByURI(
                                  info.getNamespaceUri(), project, module);
                            }
                          });
              if (files != null) {
                targetFiles.addAll(files);
              }
              nsMap.put(info.getNamespaceUri(), targetFiles);
            }
            if (!targetFiles.isEmpty()) {
              for (final XmlFile targetFile : targetFiles) {
                ApplicationManager.getApplication()
                    .runReadAction(
                        new Runnable() {
                          @Override
                          public void run() {
                            final String prefixByURI =
                                XmlUtil.findNamespacePrefixByURI(
                                    targetFile, info.getNamespaceUri());
                            if (prefixByURI == null) return;
                            final PsiElementProcessor processor =
                                new PsiElementProcessor() {
                                  @Override
                                  public boolean execute(@NotNull PsiElement element) {
                                    if (element instanceof XmlTagImpl) {
                                      if (isCertainTypeElement(
                                              (XmlTagImpl) element, info.getTagName(), prefixByURI)
                                          || isElementWithEmbeddedType(
                                              (XmlTagImpl) element,
                                              info.getTagName(),
                                              prefixByURI)) {
                                        consumer.process(element);
                                        return false;
                                      }
                                    }
                                    return true;
                                  }
                                };
                            XmlUtil.processXmlElements(targetFile, processor, true);
                          }
                        });
              }
            }
          }
        }
      }
    }
    return true;
  }