private void copyCustomSettingsFrom(@NotNull CodeStyleSettings from) {
    synchronized (myCustomSettings) {
      myCustomSettings.clear();

      for (final CustomCodeStyleSettings settings : from.getCustomSettingsValues()) {
        addCustomSettings((CustomCodeStyleSettings) settings.clone());
      }

      FIELD_TYPE_TO_NAME.copyFrom(from.FIELD_TYPE_TO_NAME);
      STATIC_FIELD_TYPE_TO_NAME.copyFrom(from.STATIC_FIELD_TYPE_TO_NAME);
      PARAMETER_TYPE_TO_NAME.copyFrom(from.PARAMETER_TYPE_TO_NAME);
      LOCAL_VARIABLE_TYPE_TO_NAME.copyFrom(from.LOCAL_VARIABLE_TYPE_TO_NAME);

      PACKAGES_TO_USE_IMPORT_ON_DEMAND.copyFrom(from.PACKAGES_TO_USE_IMPORT_ON_DEMAND);
      IMPORT_LAYOUT_TABLE.copyFrom(from.IMPORT_LAYOUT_TABLE);

      OTHER_INDENT_OPTIONS.copyFrom(from.OTHER_INDENT_OPTIONS);

      myAdditionalIndentOptions.clear();
      for (Map.Entry<FileType, IndentOptions> optionEntry :
          from.myAdditionalIndentOptions.entrySet()) {
        IndentOptions options = optionEntry.getValue();
        myAdditionalIndentOptions.put(optionEntry.getKey(), (IndentOptions) options.clone());
      }

      myCommonSettingsManager = from.myCommonSettingsManager.clone(this);
    }
  }
  @Override
  public void writeExternal(Element element) throws WriteExternalException {
    final CodeStyleSettings parentSettings = new CodeStyleSettings();
    DefaultJDOMExternalizer.writeExternal(
        this, element, new DifferenceFilter<CodeStyleSettings>(this, parentSettings));
    List<CustomCodeStyleSettings> customSettings =
        new ArrayList<CustomCodeStyleSettings>(getCustomSettingsValues());

    Collections.sort(
        customSettings,
        new Comparator<CustomCodeStyleSettings>() {
          @Override
          public int compare(final CustomCodeStyleSettings o1, final CustomCodeStyleSettings o2) {
            return o1.getTagName().compareTo(o2.getTagName());
          }
        });

    for (final CustomCodeStyleSettings settings : customSettings) {
      final CustomCodeStyleSettings parentCustomSettings =
          parentSettings.getCustomSettings(settings.getClass());
      if (parentCustomSettings == null) {
        throw new WriteExternalException("Custom settings are null for " + settings.getClass());
      }
      settings.writeExternal(element, parentCustomSettings);
    }

    final FileType[] fileTypes =
        myAdditionalIndentOptions
            .keySet()
            .toArray(new FileType[myAdditionalIndentOptions.keySet().size()]);
    Arrays.sort(
        fileTypes,
        new Comparator<FileType>() {
          @Override
          public int compare(final FileType o1, final FileType o2) {
            return o1.getDefaultExtension().compareTo(o2.getDefaultExtension());
          }
        });

    for (FileType fileType : fileTypes) {
      final IndentOptions indentOptions = myAdditionalIndentOptions.get(fileType);
      Element additionalIndentOptions = new Element(ADDITIONAL_INDENT_OPTIONS);
      indentOptions.serialize(additionalIndentOptions, getDefaultIndentOptions(fileType));
      additionalIndentOptions.setAttribute(FILETYPE, fileType.getDefaultExtension());
      if (!additionalIndentOptions.getChildren().isEmpty()) {
        element.addContent(additionalIndentOptions);
      }
    }

    myCommonSettingsManager.writeExternal(element);
  }
 /**
  * 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;
 }
 private boolean importOldIndentOptions(@NonNls Element element) {
   final List options = element.getChildren("option");
   boolean optionsImported = false;
   for (Object option1 : options) {
     @NonNls Element option = (Element) option1;
     @NonNls final String name = option.getAttributeValue("name");
     if ("TAB_SIZE".equals(name)) {
       final int value = Integer.parseInt(option.getAttributeValue("value"));
       JAVA_INDENT_OPTIONS.TAB_SIZE = value;
       JSP_INDENT_OPTIONS.TAB_SIZE = value;
       XML_INDENT_OPTIONS.TAB_SIZE = value;
       OTHER_INDENT_OPTIONS.TAB_SIZE = value;
       optionsImported = true;
     } else if ("INDENT_SIZE".equals(name)) {
       final int value = Integer.parseInt(option.getAttributeValue("value"));
       JAVA_INDENT_OPTIONS.INDENT_SIZE = value;
       JSP_INDENT_OPTIONS.INDENT_SIZE = value;
       XML_INDENT_OPTIONS.INDENT_SIZE = value;
       OTHER_INDENT_OPTIONS.INDENT_SIZE = value;
       optionsImported = true;
     } else if ("CONTINUATION_INDENT_SIZE".equals(name)) {
       final int value = Integer.parseInt(option.getAttributeValue("value"));
       JAVA_INDENT_OPTIONS.CONTINUATION_INDENT_SIZE = value;
       JSP_INDENT_OPTIONS.CONTINUATION_INDENT_SIZE = value;
       XML_INDENT_OPTIONS.CONTINUATION_INDENT_SIZE = value;
       OTHER_INDENT_OPTIONS.CONTINUATION_INDENT_SIZE = value;
       optionsImported = true;
     } else if ("USE_TAB_CHARACTER".equals(name)) {
       final boolean value = Boolean.parseBoolean(option.getAttributeValue("value"));
       JAVA_INDENT_OPTIONS.USE_TAB_CHARACTER = value;
       JSP_INDENT_OPTIONS.USE_TAB_CHARACTER = value;
       XML_INDENT_OPTIONS.USE_TAB_CHARACTER = value;
       OTHER_INDENT_OPTIONS.USE_TAB_CHARACTER = value;
       optionsImported = true;
     } else if ("SMART_TABS".equals(name)) {
       final boolean value = Boolean.parseBoolean(option.getAttributeValue("value"));
       JAVA_INDENT_OPTIONS.SMART_TABS = value;
       JSP_INDENT_OPTIONS.SMART_TABS = value;
       XML_INDENT_OPTIONS.SMART_TABS = value;
       OTHER_INDENT_OPTIONS.SMART_TABS = value;
       optionsImported = true;
     } else if ("SPACE_AFTER_UNARY_OPERATOR".equals(name)) {
       SPACE_AROUND_UNARY_OPERATOR = Boolean.parseBoolean(option.getAttributeValue("value"));
       optionsImported = true;
     }
   }
   return optionsImported;
 }
  @Override
  public void readExternal(Element element) throws InvalidDataException {
    DefaultJDOMExternalizer.readExternal(this, element);
    if (LAYOUT_STATIC_IMPORTS_SEPARATELY) {
      // add <all other static imports> entry if there is none
      boolean found = false;
      for (PackageEntry entry : IMPORT_LAYOUT_TABLE.getEntries()) {
        if (entry == PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY) {
          found = true;
          break;
        }
      }
      if (!found) {
        PackageEntry last =
            IMPORT_LAYOUT_TABLE.getEntryCount() == 0
                ? null
                : IMPORT_LAYOUT_TABLE.getEntryAt(IMPORT_LAYOUT_TABLE.getEntryCount() - 1);
        if (last != PackageEntry.BLANK_LINE_ENTRY) {
          IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.BLANK_LINE_ENTRY);
        }
        IMPORT_LAYOUT_TABLE.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY);
      }
    }
    boolean oldOptionsImported = importOldIndentOptions(element);
    for (final CustomCodeStyleSettings settings : getCustomSettingsValues()) {
      settings.readExternal(element);
      settings.importLegacySettings();
    }

    final List list = element.getChildren(ADDITIONAL_INDENT_OPTIONS);
    if (list != null) {
      for (Object o : list) {
        if (o instanceof Element) {
          final Element additionalIndentElement = (Element) o;
          final String fileTypeId = additionalIndentElement.getAttributeValue(FILETYPE);

          if (fileTypeId != null && !fileTypeId.isEmpty()) {
            FileType target = FileTypeManager.getInstance().getFileTypeByExtension(fileTypeId);
            if (FileTypes.UNKNOWN == target
                || FileTypes.PLAIN_TEXT == target
                || target.getDefaultExtension().isEmpty()) {
              target = new TempFileType(fileTypeId);
            }

            final IndentOptions options = getDefaultIndentOptions(target);
            options.readExternal(additionalIndentElement);
            registerAdditionalIndentOptions(target, options);
          }
        }
      }
    }

    myCommonSettingsManager.readExternal(element);

    if (oldOptionsImported) {
      copyOldIndentOptions("java", JAVA_INDENT_OPTIONS);
      copyOldIndentOptions("jsp", JSP_INDENT_OPTIONS);
      copyOldIndentOptions("xml", XML_INDENT_OPTIONS);
    }

    if (USE_SAME_INDENTS) IGNORE_SAME_INDENTS_FOR_LANGUAGES = true;
  }