| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.psi.codeStyle.arrangement; |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.text.StringUtil; |
| import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingRule; |
| import com.intellij.psi.codeStyle.arrangement.match.*; |
| import com.intellij.psi.codeStyle.arrangement.std.*; |
| import com.intellij.util.containers.ContainerUtil; |
| import org.jdom.Attribute; |
| import org.jdom.Element; |
| import org.jetbrains.annotations.NonNls; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| /** |
| * {@link ArrangementSettingsSerializer} which knows how to handle {@link StdArrangementSettings built-in arrangement tokens} |
| * and {@link Mixin can be used as a base for custom serializer implementation}. |
| * |
| * @author Denis Zhdanov |
| * @since 7/18/12 10:37 AM |
| */ |
| public class DefaultArrangementSettingsSerializer implements ArrangementSettingsSerializer { |
| private static final Logger LOG = Logger.getInstance("#" + DefaultArrangementSettingsSerializer.class.getName()); |
| |
| @NotNull @NonNls private static final String GROUPS_ELEMENT_NAME = "groups"; |
| @NotNull @NonNls private static final String GROUP_ELEMENT_NAME = "group"; |
| @NotNull @NonNls private static final String RULES_ELEMENT_NAME = "rules"; |
| @NotNull @NonNls private static final String SECTION_ELEMENT_NAME = "section"; |
| @NotNull @NonNls private static final String SECTION_START_ATTRIBUTE = "start_comment"; |
| @NotNull @NonNls private static final String SECTION_END_ATTRIBUTE = "end_comment"; |
| @NotNull @NonNls private static final String RULE_ELEMENT_NAME = "rule"; |
| @NotNull @NonNls private static final String TYPE_ELEMENT_NAME = "type"; |
| @NotNull @NonNls private static final String MATCHER_ELEMENT_NAME = "match"; |
| @NotNull @NonNls private static final String ORDER_TYPE_ELEMENT_NAME = "order"; |
| |
| @NotNull private final DefaultArrangementEntryMatcherSerializer myMatcherSerializer; |
| @NotNull private final Mixin myMixin; |
| @NotNull private final ArrangementSettings myDefaultSettings; |
| |
| public DefaultArrangementSettingsSerializer(@NotNull StdArrangementSettings defaultSettings) { |
| this(Mixin.NULL, defaultSettings); |
| } |
| |
| public DefaultArrangementSettingsSerializer(@NotNull Mixin mixin, @NotNull StdArrangementSettings defaultSettings) { |
| myMixin = mixin; |
| myMatcherSerializer = new DefaultArrangementEntryMatcherSerializer(mixin); |
| myDefaultSettings = defaultSettings; |
| } |
| |
| @Override |
| public void serialize(@NotNull ArrangementSettings s, @NotNull Element holder) { |
| if (!(s instanceof StdArrangementSettings)) { |
| return; |
| } |
| |
| StdArrangementSettings settings = (StdArrangementSettings)s; |
| List<ArrangementGroupingRule> groupings = settings.getGroupings(); |
| final boolean isDefaultGroupings = groupings.equals(myDefaultSettings.getGroupings()); |
| if (!isDefaultGroupings) { |
| Element groupingsElement = new Element(GROUPS_ELEMENT_NAME); |
| holder.addContent(groupingsElement); |
| for (ArrangementGroupingRule group : groupings) { |
| Element groupElement = new Element(GROUP_ELEMENT_NAME); |
| groupingsElement.addContent(groupElement); |
| groupElement.addContent(new Element(TYPE_ELEMENT_NAME).setText(group.getGroupingType().getId())); |
| groupElement.addContent(new Element(ORDER_TYPE_ELEMENT_NAME).setText(group.getOrderType().getId())); |
| } |
| } |
| |
| final List<ArrangementSectionRule> sections = settings.getSections(); |
| final boolean isDefaultRules = sections.equals((myDefaultSettings).getSections()); |
| if (!isDefaultRules) { |
| Element rulesElement = new Element(RULES_ELEMENT_NAME); |
| holder.addContent(rulesElement); |
| for (ArrangementSectionRule section : sections) { |
| rulesElement.addContent(serialize(section)); |
| } |
| } |
| } |
| |
| @Nullable |
| @Override |
| public ArrangementSettings deserialize(@NotNull Element element) { |
| final List<ArrangementGroupingRule> groupingRules = deserializeGropings(element, myDefaultSettings); |
| final Element rulesElement = element.getChild(RULES_ELEMENT_NAME); |
| final List<ArrangementSectionRule> sectionRules = ContainerUtil.newArrayList(); |
| if(rulesElement == null) { |
| sectionRules.addAll(myDefaultSettings.getSections()); |
| } |
| else { |
| sectionRules.addAll(deserializeSectionRules(rulesElement)); |
| if (sectionRules.isEmpty()) { |
| // for backward compatibility |
| final List<StdArrangementMatchRule> rules = deserializeRules(rulesElement); |
| return StdArrangementSettings.createByMatchRules(groupingRules, rules); |
| } |
| } |
| return new StdArrangementSettings(groupingRules, sectionRules); |
| } |
| |
| @NotNull |
| private List<ArrangementGroupingRule> deserializeGropings(@NotNull Element element, @Nullable ArrangementSettings defaultSettings) { |
| Element groups = element.getChild(GROUPS_ELEMENT_NAME); |
| if (groups == null) { |
| return defaultSettings == null ? ContainerUtil.<ArrangementGroupingRule>newSmartList() : defaultSettings.getGroupings(); |
| } |
| |
| final List<ArrangementGroupingRule> groupings = new ArrayList<ArrangementGroupingRule>(); |
| for (Object group : groups.getChildren(GROUP_ELEMENT_NAME)) { |
| Element groupElement = (Element)group; |
| |
| // Grouping type. |
| String groupingTypeId = groupElement.getChildText(TYPE_ELEMENT_NAME); |
| ArrangementSettingsToken groupingType = StdArrangementTokens.byId(groupingTypeId); |
| if (groupingType == null) { |
| groupingType = myMixin.deserializeToken(groupingTypeId); |
| } |
| if (groupingType == null) { |
| LOG.warn(String.format("Can't deserialize grouping type token by id '%s'", groupingTypeId)); |
| continue; |
| } |
| |
| // Order type. |
| String orderTypeId = groupElement.getChildText(ORDER_TYPE_ELEMENT_NAME); |
| ArrangementSettingsToken orderType = StdArrangementTokens.byId(orderTypeId); |
| if (orderType == null) { |
| orderType = myMixin.deserializeToken(orderTypeId); |
| } |
| if (orderType == null) { |
| LOG.warn(String.format("Can't deserialize grouping order type token by id '%s'", orderTypeId)); |
| continue; |
| } |
| groupings.add(new ArrangementGroupingRule(groupingType, orderType)); |
| } |
| return groupings; |
| } |
| |
| @NotNull |
| private List<ArrangementSectionRule> deserializeSectionRules(@NotNull Element rulesElement) { |
| final List<ArrangementSectionRule> sectionRules = new ArrayList<ArrangementSectionRule>(); |
| for (Object o : rulesElement.getChildren(SECTION_ELEMENT_NAME)) { |
| final Element sectionElement = (Element)o; |
| final List<StdArrangementMatchRule> rules = deserializeRules(sectionElement); |
| final Attribute start = sectionElement.getAttribute(SECTION_START_ATTRIBUTE); |
| final String startComment = start != null ? start.getValue().trim() : null; |
| final Attribute end = sectionElement.getAttribute(SECTION_END_ATTRIBUTE); |
| final String endComment = end != null ? end.getValue().trim() : null; |
| sectionRules.add(ArrangementSectionRule.create(startComment, endComment, rules)); |
| } |
| return sectionRules; |
| } |
| |
| @NotNull |
| private List<StdArrangementMatchRule> deserializeRules(@NotNull Element element) { |
| final List<StdArrangementMatchRule> rules = new ArrayList<StdArrangementMatchRule>(); |
| for (Object o : element.getChildren(RULE_ELEMENT_NAME)) { |
| Element ruleElement = (Element)o; |
| Element matcherElement = ruleElement.getChild(MATCHER_ELEMENT_NAME); |
| if (matcherElement == null) { |
| continue; |
| } |
| |
| StdArrangementEntryMatcher matcher = null; |
| for (Object c : matcherElement.getChildren()) { |
| matcher = myMatcherSerializer.deserialize((Element)c); |
| if (matcher != null) { |
| break; |
| } |
| } |
| |
| if (matcher == null) { |
| return ContainerUtil.newSmartList(); |
| } |
| |
| Element orderTypeElement = ruleElement.getChild(ORDER_TYPE_ELEMENT_NAME); |
| ArrangementSettingsToken orderType = null; |
| if (orderTypeElement != null) { |
| String orderTypeId = orderTypeElement.getText(); |
| orderType = StdArrangementTokens.byId(orderTypeId); |
| if (orderType == null) { |
| orderType = myMixin.deserializeToken(orderTypeId); |
| } |
| if (orderType == null) { |
| LOG.warn(String.format("Can't deserialize matching rule order type for id '%s'. Falling back to default (%s)", |
| orderTypeId, ArrangementMatchRule.DEFAULT_ORDER_TYPE.getId())); |
| } |
| } |
| if (orderType == null) { |
| orderType = ArrangementMatchRule.DEFAULT_ORDER_TYPE; |
| } |
| rules.add(new StdArrangementMatchRule(matcher, orderType)); |
| } |
| return rules; |
| } |
| |
| @Nullable |
| public Element serialize(@NotNull ArrangementMatchRule rule) { |
| Element matcherElement = myMatcherSerializer.serialize(rule.getMatcher()); |
| if (matcherElement == null) { |
| return null; |
| } |
| |
| Element result = new Element(RULE_ELEMENT_NAME); |
| result.addContent(new Element(MATCHER_ELEMENT_NAME).addContent(matcherElement)); |
| if (rule.getOrderType() != ArrangementMatchRule.DEFAULT_ORDER_TYPE) { |
| result.addContent(new Element(ORDER_TYPE_ELEMENT_NAME).setText(rule.getOrderType().getId())); |
| } |
| return result; |
| } |
| |
| @Nullable |
| public Element serialize(@NotNull ArrangementSectionRule section) { |
| final Element sectionElement = new Element(SECTION_ELEMENT_NAME); |
| if (StringUtil.isNotEmpty(section.getStartComment())) { |
| // or only != null ? |
| sectionElement.setAttribute(SECTION_START_ATTRIBUTE, section.getStartComment()); |
| } |
| if (StringUtil.isNotEmpty(section.getEndComment())) { |
| sectionElement.setAttribute(SECTION_END_ATTRIBUTE, section.getEndComment()); |
| } |
| |
| //TODO: serialize start & end comment as rule? |
| final List<StdArrangementMatchRule> rules = section.getMatchRules(); |
| for (int i = 0; i < rules.size(); i++) { |
| StdArrangementMatchRule rule = rules.get(i); |
| if ((i != 0 || StringUtil.isEmpty(section.getStartComment())) && |
| (i != rules.size() - 1 || StringUtil.isEmpty(section.getEndComment()))) { |
| sectionElement.addContent(serialize(rule)); |
| } |
| } |
| return sectionElement; |
| } |
| |
| public interface Mixin { |
| |
| Mixin NULL = new Mixin() { |
| @Nullable |
| @Override |
| public ArrangementSettingsToken deserializeToken(@NotNull String id) { return null; } |
| }; |
| |
| @Nullable |
| ArrangementSettingsToken deserializeToken(@NotNull String id); |
| } |
| } |