/**
  * Retrieves indent options for PSI file from an associated document or (if not defined in the
  * document) from file indent options providers.
  *
  * @param file The PSI file to retrieve options for.
  * @param formatRange The text range within the file for formatting purposes or null if there is
  *     either no specific range or multiple ranges. If the range covers the entire file (full
  *     reformat), options stored in the document are ignored and indent options are taken from
  *     file indent options providers.
  * @param ignoreDocOptions Ignore options stored in the document and use file indent options
  *     providers even if there is no text range or the text range doesn't cover the entire file.
  * @param providerProcessor A callback object containing a reference to indent option provider
  *     which has returned indent options.
  * @return Indent options from the associated document or file indent options providers.
  * @see com.intellij.psi.codeStyle.FileIndentOptionsProvider
  */
 @NotNull
 public IndentOptions getIndentOptionsByFile(
     @Nullable PsiFile file,
     @Nullable TextRange formatRange,
     boolean ignoreDocOptions,
     @Nullable Processor<FileIndentOptionsProvider> providerProcessor) {
   if (file != null && file.isValid() && file.isWritable()) {
     boolean isFullReformat = isFileFullyCoveredByRange(file, formatRange);
     if (!ignoreDocOptions && !isFullReformat) {
       IndentOptions docOptions = IndentOptions.retrieveFromAssociatedDocument(file);
       if (docOptions != null) return docOptions;
     }
     FileIndentOptionsProvider[] providers =
         Extensions.getExtensions(FileIndentOptionsProvider.EP_NAME);
     for (FileIndentOptionsProvider provider : providers) {
       if (!isFullReformat || provider.useOnFullReformat()) {
         IndentOptions indentOptions = provider.getIndentOptions(this, file);
         if (indentOptions != null) {
           if (providerProcessor != null) {
             providerProcessor.process(provider);
           }
           logIndentOptions(file, provider, indentOptions);
           return indentOptions;
         }
       }
     }
     return getIndentOptions(file.getFileType());
   } else return OTHER_INDENT_OPTIONS;
 }
  @NotNull
  private List<AnnotationData> doCollect(
      @NotNull PsiModifierListOwner listOwner, boolean onlyWritable) {
    final List<PsiFile> files = findExternalAnnotationsFiles(listOwner);
    if (files == null) {
      return NO_DATA;
    }
    SmartList<AnnotationData> result = new SmartList<AnnotationData>();
    String externalName = getExternalName(listOwner, false);
    if (externalName == null) return NO_DATA;

    for (PsiFile file : files) {
      if (!file.isValid()) continue;
      if (onlyWritable && !file.isWritable()) continue;

      MostlySingularMultiMap<String, AnnotationData> fileData = getDataFromFile(file);

      ContainerUtil.addAll(result, fileData.get(externalName));
    }
    if (result.isEmpty()) {
      return NO_DATA;
    }
    result.trimToSize();
    return result;
  }
 private boolean checkFileWritable(final PsiFile file) {
   if (!file.isWritable()) {
     MessagesEx.fileIsReadOnly(myProject, file.getVirtualFile())
         .setTitle(CodeInsightBundle.message("error.dialog.readonly.file.title"))
         .showLater();
     return false;
   } else {
     return true;
   }
 }
    @Override
    public boolean iteration() {
      if (myStopFormatting) {
        return true;
      }

      if (!myFilesCountingFinished) {
        updateIndicatorText(ApplicationBundle.message("bulk.reformat.prepare.progress.text"), "");
        countingIteration();
        return true;
      }

      updateIndicatorFraction(myFilesProcessed);

      if (myFileTreeIterator.hasNext()) {
        final PsiFile file = myFileTreeIterator.next();
        myFilesProcessed++;
        if (file.isWritable() && canBeFormatted(file) && acceptedByFilters(file)) {
          updateIndicatorText(
              ApplicationBundle.message("bulk.reformat.process.progress.text"),
              getPresentablePath(file));
          ApplicationManager.getApplication()
              .runWriteAction(
                  new Runnable() {
                    @Override
                    public void run() {
                      DumbService.getInstance(myProject)
                          .withAlternativeResolveEnabled(
                              new Runnable() {
                                @Override
                                public void run() {
                                  performFileProcessing(file);
                                }
                              });
                    }
                  });
        }
      }

      return true;
    }
  private void replaceWithPrompt(final ReplaceContext replaceContext) {
    final List<Usage> _usages = replaceContext.getUsageView().getSortedUsages();

    if (hasReadOnlyUsages(_usages)) {
      WindowManager.getInstance()
          .getStatusBar(myProject)
          .setInfo(FindBundle.message("find.replace.occurrences.found.in.read.only.files.status"));
      return;
    }

    final Usage[] usages = _usages.toArray(new Usage[_usages.size()]);

    // usageView.expandAll();
    for (int i = 0; i < usages.length; ++i) {
      final Usage usage = usages[i];
      final UsageInfo usageInfo = ((UsageInfo2UsageAdapter) usage).getUsageInfo();

      final PsiElement elt = usageInfo.getElement();
      if (elt == null) continue;
      final PsiFile psiFile = elt.getContainingFile();
      if (!psiFile.isWritable()) continue;

      Runnable selectOnEditorRunnable =
          new Runnable() {
            @Override
            public void run() {
              final VirtualFile virtualFile = psiFile.getVirtualFile();

              if (virtualFile != null
                  && ApplicationManager.getApplication()
                      .runReadAction(
                          new Computable<Boolean>() {
                            @Override
                            public Boolean compute() {
                              return virtualFile.isValid() ? Boolean.TRUE : Boolean.FALSE;
                            }
                          })
                      .booleanValue()) {

                if (usage.isValid()) {
                  usage.highlightInEditor();
                  replaceContext.getUsageView().selectUsages(new Usage[] {usage});
                }
              }
            }
          };

      CommandProcessor.getInstance()
          .executeCommand(
              myProject,
              selectOnEditorRunnable,
              FindBundle.message("find.replace.select.on.editor.command"),
              null);
      String title = FindBundle.message("find.replace.found.usage.title", i + 1, usages.length);

      int result;
      try {
        replaceUsage(
            usage, replaceContext.getFindModel(), replaceContext.getExcludedSetCached(), true);
        result =
            FindManager.getInstance(myProject)
                .showPromptDialog(replaceContext.getFindModel(), title);
      } catch (FindManager.MalformedReplacementStringException e) {
        markAsMalformedReplacement(replaceContext, usage);
        result =
            FindManager.getInstance(myProject)
                .showMalformedReplacementPrompt(replaceContext.getFindModel(), title, e);
      }

      if (result == FindManager.PromptResult.CANCEL) {
        return;
      }
      if (result == FindManager.PromptResult.SKIP) {
        continue;
      }

      final int currentNumber = i;
      if (result == FindManager.PromptResult.OK) {
        final Ref<Boolean> success = Ref.create();
        Runnable runnable =
            new Runnable() {
              @Override
              public void run() {
                success.set(replaceUsageAndRemoveFromView(usage, replaceContext));
              }
            };
        CommandProcessor.getInstance()
            .executeCommand(myProject, runnable, FindBundle.message("find.replace.command"), null);
        if (closeUsageViewIfEmpty(replaceContext.getUsageView(), success.get())) {
          return;
        }
      }

      if (result == FindManager.PromptResult.ALL_IN_THIS_FILE) {
        final int[] nextNumber = new int[1];

        Runnable runnable =
            new Runnable() {
              @Override
              public void run() {
                int j = currentNumber;
                boolean success = true;
                for (; j < usages.length; j++) {
                  final Usage usage = usages[j];
                  final UsageInfo usageInfo = ((UsageInfo2UsageAdapter) usage).getUsageInfo();

                  final PsiElement elt = usageInfo.getElement();
                  if (elt == null) continue;
                  PsiFile otherPsiFile = elt.getContainingFile();
                  if (!otherPsiFile.equals(psiFile)) {
                    break;
                  }
                  if (!replaceUsageAndRemoveFromView(usage, replaceContext)) {
                    success = false;
                  }
                }
                closeUsageViewIfEmpty(replaceContext.getUsageView(), success);
                nextNumber[0] = j;
              }
            };

        CommandProcessor.getInstance()
            .executeCommand(myProject, runnable, FindBundle.message("find.replace.command"), null);

        //noinspection AssignmentToForLoopParameter
        i = nextNumber[0] - 1;
      }

      if (result == FindManager.PromptResult.ALL_FILES) {
        CommandProcessor.getInstance()
            .executeCommand(
                myProject,
                new Runnable() {
                  @Override
                  public void run() {
                    final boolean success = replaceUsages(replaceContext, _usages);
                    closeUsageViewIfEmpty(replaceContext.getUsageView(), success);
                  }
                },
                FindBundle.message("find.replace.command"),
                null);
        break;
      }
    }
  }