diff --git a/platform/lang-api/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConstants.java b/platform/lang-api/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConstants.java index a755327dbf99..0682385f2775 100644 --- a/platform/lang-api/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConstants.java +++ b/platform/lang-api/src/com/intellij/application/options/codeStyle/arrangement/ArrangementConstants.java @@ -30,6 +30,10 @@ public class ArrangementConstants { @NonNls public static final String ACTION_GROUP_MATCHING_RULES_CONTROL_TOOLBAR = "Arrangement.Rule.Match.Control.ToolBar"; @NonNls public static final String MATCHING_RULES_CONTROL_TOOLBAR_PLACE = "Arrangement.Rule.Match.Control.ToolBar.Place"; @NonNls public static final String MATCHING_RULES_CONTROL_PLACE = "Arrangement.Rule.Match.Control.Place"; + @NonNls public static final String ALIAS_RULE_CONTEXT_MENU = "Arrangement.Alias.Rule.Context.Menu"; + @NonNls public static final String ALIAS_RULE_CONTROL_TOOLBAR = "Arrangement.Alias.Rule.ToolBar"; + @NonNls public static final String ALIAS_RULE_CONTROL_TOOLBAR_PLACE = "Arrangement.Alias.Rule.ToolBar.Place"; + @NonNls public static final String ALIAS_RULE_CONTROL_PLACE = "Arrangement.Alias.Rule.Control.Place"; @NonNls public static final String MATCHING_RULE_ADD = "Arrangement.Rule.Add"; @NonNls public static final String MATCHING_RULE_REMOVE = "Arrangement.Rule.Remove"; @@ -39,6 +43,12 @@ public class ArrangementConstants { @NonNls public static final String GROUPING_RULE_MOVE_UP = "Arrangement.Rule.Group.Condition.Move.Up"; @NonNls public static final String GROUPING_RULE_MOVE_DOWN = "Arrangement.Rule.Group.Condition.Move.Down"; + @NonNls public static final String MATCHING_ALIAS_RULE_ADD = "Arrangement.Alias.Rule.Add"; + @NonNls public static final String MATCHING_ALIAS_RULE_REMOVE = "Arrangement.Alias.Rule.Remove"; + @NonNls public static final String MATCHING_ALIAS_RULE_EDIT = "Arrangement.Alias.Rule.Edit"; + @NonNls public static final String MATCHING_ALIAS_RULE_MOVE_UP = "Arrangement.Alias.Rule.Match.Condition.Move.Up"; + @NonNls public static final String MATCHING_ALIAS_RULE_MOVE_DOWN = "Arrangement.Alias.Rule.Match.Condition.Move.Down"; + public static final int HORIZONTAL_PADDING = 8; public static final int VERTICAL_PADDING = 4; public static final int HORIZONTAL_GAP = 5; @@ -51,6 +61,7 @@ public class ArrangementConstants { public static final int TEXT_UPDATE_DELAY_MILLIS = 1000; public static final boolean LOG_RULE_MODIFICATION = Boolean.parseBoolean(System.getProperty("log.arrangement.rule.modification")); + public static final boolean LOG_ALIAS_RULE_MODIFICATION = Boolean.parseBoolean(System.getProperty("log.arrangement.rule.sequence.modification")); private ArrangementConstants() { } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementExtendableSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementExtendableSettings.java new file mode 100644 index 000000000000..7ebc1cc77a05 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementExtendableSettings.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2014 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.psi.codeStyle.arrangement.match.ArrangementSectionRule; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementRuleAlias; + +import java.util.List; +import java.util.Set; + +/** + * Arrangement settings that can be extended by aliasing sequence of rules to one token, + * e.g. alias: 'visibility' -> {'public', 'protected', 'private'} + * + * @author Svetlana.Zemlyanskaya + */ +public interface ArrangementExtendableSettings extends ArrangementSettings { + + Set getRuleAliases(); + + /** + * Use this method to get all rules with replaced custom aliases + */ + List getExtendedSectionRules(); +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java index 174db45b2f11..16a1ae821db0 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/ArrangementUtil.java @@ -314,4 +314,20 @@ public class ArrangementUtil { return matchRules; } //endregion + + //region Arrangement Custom Tokens + public static List getExtendedSectionRules(@NotNull ArrangementSettings settings) { + return settings instanceof ArrangementExtendableSettings ? + ((ArrangementExtendableSettings)settings).getExtendedSectionRules() : settings.getSections(); + } + + @NotNull + public static ArrangementSettingsToken createRuleAliasToken(@NotNull String id, @NotNull String name) { + return StdArrangementSettingsToken.token(id, name, StdArrangementTokenType.ALIAS); + } + + public static boolean isAliasedCondition(@NotNull ArrangementAtomMatchCondition condition) { + return StdArrangementTokenType.ALIAS.is(condition.getType()); + } + //endregion } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementSettingsSerializer.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementSettingsSerializer.java index 0d193ed1aaa6..1cbd110ecda8 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementSettingsSerializer.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/DefaultArrangementSettingsSerializer.java @@ -21,6 +21,7 @@ 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 gnu.trove.THashSet; import org.jdom.Attribute; import org.jdom.Element; import org.jetbrains.annotations.NonNls; @@ -29,6 +30,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.Set; /** * {@link ArrangementSettingsSerializer} which knows how to handle {@link StdArrangementSettings built-in arrangement tokens} @@ -43,6 +45,10 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings @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 TOKENS_ELEMENT_NAME = "tokens"; + @NotNull @NonNls private static final String TOKEN_ELEMENT_NAME = "token"; + @NotNull @NonNls private static final String TOKEN_ID = "id"; + @NotNull @NonNls private static final String TOKEN_NAME = "name"; @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"; @@ -60,8 +66,8 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings } public DefaultArrangementSettingsSerializer(@NotNull Mixin mixin, @NotNull StdArrangementSettings defaultSettings) { - myMixin = mixin; - myMatcherSerializer = new DefaultArrangementEntryMatcherSerializer(mixin); + myMixin = new MutableMixin(mixin); + myMatcherSerializer = new DefaultArrangementEntryMatcherSerializer(myMixin); myDefaultSettings = defaultSettings; } @@ -72,6 +78,32 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings } StdArrangementSettings settings = (StdArrangementSettings)s; + if (settings instanceof ArrangementExtendableSettings && myDefaultSettings instanceof ArrangementExtendableSettings) { + final Set tokensDefinition = + ((ArrangementExtendableSettings)settings).getRuleAliases(); + final boolean isDefault = tokensDefinition.equals(((ArrangementExtendableSettings)myDefaultSettings).getRuleAliases()); + if (!isDefault) { + final Element tokensElement = new Element(TOKENS_ELEMENT_NAME); + if (tokensDefinition.isEmpty()) { + tokensElement.addContent(new Element("no_tokens")); + } + for (ArrangementRuleAlias definition : tokensDefinition) { + final Element tokenElement = new Element(TOKEN_ELEMENT_NAME); + final ArrangementSettingsToken token = definition.getAliasToken(); + tokenElement.setAttribute(TOKEN_ID, token.getId()); + tokenElement.setAttribute(TOKEN_NAME, token.getRepresentationValue()); + + final Element rulesElement = new Element(RULES_ELEMENT_NAME); + for (StdArrangementMatchRule rule : definition.getDefinitionRules()) { + rulesElement.addContent(serialize(rule)); + } + tokenElement.addContent(rulesElement); + tokensElement.addContent(tokenElement); + } + holder.addContent(tokensElement); + } + } + List groupings = settings.getGroupings(); final boolean isDefaultGroupings = groupings.equals(myDefaultSettings.getGroupings()); if (!isDefaultGroupings) { @@ -99,6 +131,7 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings @Nullable @Override public ArrangementSettings deserialize(@NotNull Element element) { + final Set tokensDefinition = deserializeTokensDefinition(element, myDefaultSettings); final List groupingRules = deserializeGropings(element, myDefaultSettings); final Element rulesElement = element.getChild(RULES_ELEMENT_NAME); final List sectionRules = ContainerUtil.newArrayList(); @@ -106,14 +139,45 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings sectionRules.addAll(myDefaultSettings.getSections()); } else { - sectionRules.addAll(deserializeSectionRules(rulesElement)); + sectionRules.addAll(deserializeSectionRules(rulesElement, tokensDefinition)); if (sectionRules.isEmpty()) { // for backward compatibility - final List rules = deserializeRules(rulesElement); + final List rules = deserializeRules(rulesElement, tokensDefinition); return StdArrangementSettings.createByMatchRules(groupingRules, rules); } } - return new StdArrangementSettings(groupingRules, sectionRules); + + if (tokensDefinition == null) { + return new StdArrangementSettings(groupingRules, sectionRules); + } + return new StdArrangementExtendableSettings(groupingRules, sectionRules, tokensDefinition); + } + + @Nullable + private Set deserializeTokensDefinition(@NotNull Element element, @NotNull ArrangementSettings defaultSettings) { + if (!(defaultSettings instanceof ArrangementExtendableSettings)) { + return null; + } + + final Element tokensRoot = element.getChild(TOKENS_ELEMENT_NAME); + if (tokensRoot == null || tokensRoot.getChildren().size() == 0) { + // no tag for tokens exists -> get from default + return ((ArrangementExtendableSettings)myDefaultSettings).getRuleAliases(); + } + + final Set tokenDefinitions = + new THashSet(); + final List tokens = tokensRoot.getChildren(TOKEN_ELEMENT_NAME); + for (Element token : tokens) { + final Attribute id = token.getAttribute(TOKEN_ID); + final Attribute name = token.getAttribute(TOKEN_NAME); + assert id != null && name != null : "Can not find id for token: " + token; + final Element rules = token.getChild(RULES_ELEMENT_NAME); + final ArrangementSettingsToken addToken = ArrangementUtil.createRuleAliasToken(id.getValue(), name.getValue()); + final List tokenRules = deserializeRules(rules, null); + tokenDefinitions.add(new ArrangementRuleAlias(addToken, tokenRules)); + } + return tokenDefinitions; } @NotNull @@ -154,11 +218,12 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings } @NotNull - private List deserializeSectionRules(@NotNull Element rulesElement) { + private List deserializeSectionRules(@NotNull Element rulesElement, + @Nullable Set tokens) { final List sectionRules = new ArrayList(); for (Object o : rulesElement.getChildren(SECTION_ELEMENT_NAME)) { final Element sectionElement = (Element)o; - final List rules = deserializeRules(sectionElement); + final List rules = deserializeRules(sectionElement, tokens); 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); @@ -169,7 +234,10 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings } @NotNull - private List deserializeRules(@NotNull Element element) { + private List deserializeRules(@NotNull Element element, @Nullable final Set aliases) { + if (aliases != null && myMixin instanceof MutableMixin) { + ((MutableMixin)myMixin).setMyRuleAliases(aliases); + } final List rules = new ArrayList(); for (Object o : element.getChildren(RULE_ELEMENT_NAME)) { Element ruleElement = (Element)o; @@ -247,6 +315,35 @@ public class DefaultArrangementSettingsSerializer implements ArrangementSettings } } return sectionElement; + } + + public static class MutableMixin implements Mixin { + private Mixin myDelegate; + private Set myRuleAliases; + + public MutableMixin(Mixin delegate) { + myDelegate = delegate; + } + + public void setMyRuleAliases(Set aliases) { + myRuleAliases = aliases; + } + + @Nullable + @Override + public ArrangementSettingsToken deserializeToken(@NotNull String id) { + final ArrangementSettingsToken token = myDelegate.deserializeToken(id); + if (token != null || myRuleAliases == null) { + return token; + } + + for (ArrangementRuleAlias alias : myRuleAliases) { + if (StringUtil.equals(alias.getAliasToken().getId(), id)) { + return alias.getAliasToken(); + } + } + return null; + } } public interface Mixin { diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementExtendableSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementExtendableSettingsManager.java new file mode 100644 index 000000000000..e2cabc1cd02d --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementExtendableSettingsManager.java @@ -0,0 +1,89 @@ +/* + * Copyright 2000-2014 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.std; + +import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * Extension for {@link ArrangementStandardSettingsManager} for managing matching rules with custom aliases + * + * @author Svetlana.Zemlyanskaya + */ +public class ArrangementExtendableSettingsManager extends ArrangementStandardSettingsManager { + @NotNull private Collection myRuleAliases; + + @NotNull private CompositeArrangementSettingsToken myRuleAliasToken; + @NotNull private Set myRuleAliasMutex; + + + public ArrangementExtendableSettingsManager(@NotNull ArrangementStandardSettingsAware delegate, + @NotNull ArrangementColorsProvider colorsProvider, + @NotNull Collection aliases) { + super(delegate, colorsProvider); + final Set tokensSet = ContainerUtil.newHashSet(); + for (ArrangementRuleAlias token : aliases) { + tokensSet.add(token.getAliasToken()); + } + + myRuleAliases = aliases; + myRuleAliasToken = createAliasTokenRepresentation(tokensSet); + myRuleAliasMutex = tokensSet; + } + + @NotNull + private static CompositeArrangementSettingsToken createAliasTokenRepresentation(@NotNull Collection tokens) { + return new CompositeArrangementSettingsToken(StdArrangementTokens.General.ALIAS, tokens); + } + + @NotNull + public Collection getRuleAliases() { + return myRuleAliases; + } + + @Nullable + public List getSupportedMatchingTokens() { + final List tokens = super.getSupportedMatchingTokens(); + if (tokens == null) { + return null; + } + + final List allTokens = ContainerUtil.newArrayList(tokens); + allTokens.add(myRuleAliasToken); + return allTokens; + } + + public boolean isEnabled(@NotNull ArrangementSettingsToken token, @Nullable ArrangementMatchCondition current) { + if (myRuleAliasMutex.contains(token)) { + return true; + } + return super.isEnabled(token, current); + } + + @NotNull + public Collection> getMutexes() { + final List> allMutexes = ContainerUtil.newArrayList(super.getMutexes()); + allMutexes.add(myRuleAliasMutex); + return allMutexes; + } +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementRuleAlias.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementRuleAlias.java new file mode 100644 index 000000000000..dae4b2086821 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementRuleAlias.java @@ -0,0 +1,91 @@ +/* + * Copyright 2000-2014 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.std; + +import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class ArrangementRuleAlias implements Cloneable { + /** + * Token to be used in matching rules ui + */ + private ArrangementSettingsToken myAliasToken; + + /** + * All usages of alias token will be replaced by this sequence of rules + */ + private List myDefinitionRules; + + public ArrangementRuleAlias() { + } + + public ArrangementRuleAlias(@NotNull ArrangementSettingsToken aliasToken, + @NotNull List definitionRules) { + myAliasToken = aliasToken; + myDefinitionRules = definitionRules; + } + + public ArrangementSettingsToken getAliasToken() { + return myAliasToken; + } + + public void setAliasToken(@NotNull ArrangementSettingsToken aliasToken) { + myAliasToken = aliasToken; + } + + public List getDefinitionRules() { + return myDefinitionRules; + } + + public void setDefinitionRules(List definitionRules) { + myDefinitionRules = definitionRules; + } + + @Override + protected ArrangementRuleAlias clone() { + final List newValue = new ArrayList(myDefinitionRules.size()); + for (StdArrangementMatchRule rule : myDefinitionRules) { + newValue.add(rule.clone()); + } + return new ArrangementRuleAlias(myAliasToken, newValue); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + ArrangementRuleAlias token = (ArrangementRuleAlias)o; + + if (myAliasToken != null ? !myAliasToken.equals(token.myAliasToken) : token.myAliasToken != null) return false; + if (myDefinitionRules != null ? !myDefinitionRules.equals(token.myDefinitionRules) : token.myDefinitionRules != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = myAliasToken != null ? myAliasToken.hashCode() : 0; + result = 31 * result + (myDefinitionRules != null ? myDefinitionRules.hashCode() : 0); + return result; + } +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java index 5b3ccac7d3c8..75ba777956a1 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/ArrangementStandardSettingsManager.java @@ -89,6 +89,11 @@ public class ArrangementStandardSettingsManager { } } + @NotNull + public ArrangementStandardSettingsAware getDelegate() { + return myDelegate; + } + private void parseWidths(@NotNull Collection compositeTokens, @NotNull SimpleColoredComponent renderer) { diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementExtendableSettings.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementExtendableSettings.java new file mode 100644 index 000000000000..7a5aba5f7cf1 --- /dev/null +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementExtendableSettings.java @@ -0,0 +1,190 @@ +/* + * Copyright 2000-2014 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.std; + +import com.intellij.psi.codeStyle.arrangement.ArrangementExtendableSettings; +import com.intellij.psi.codeStyle.arrangement.ArrangementUtil; +import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingRule; +import com.intellij.psi.codeStyle.arrangement.match.ArrangementMatchRule; +import com.intellij.psi.codeStyle.arrangement.match.ArrangementSectionRule; +import com.intellij.psi.codeStyle.arrangement.match.StdArrangementEntryMatcher; +import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchConditionVisitor; +import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashMap; +import gnu.trove.THashSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class StdArrangementExtendableSettings extends StdArrangementSettings implements ArrangementExtendableSettings { + @NotNull private final Set myRulesAliases = new THashSet(); + + // cached values + @NotNull private final List myExtendedSectionRules = new ArrayList(); + + public StdArrangementExtendableSettings() { + super(); + } + + public StdArrangementExtendableSettings(@NotNull List groupingRules, + @NotNull List sectionRules, + @NotNull Collection rulesAliases) { + super(groupingRules, sectionRules); + myRulesAliases.addAll(rulesAliases); + } + + @Override + public Set getRuleAliases() { + return myRulesAliases; + } + + private Set cloneTokenDefinitions() { + final Set definitions = new THashSet(); + for (ArrangementRuleAlias definition : myRulesAliases) { + definitions.add(definition.clone()); + } + return definitions; + } + + @Override + public List getExtendedSectionRules() { + if (myExtendedSectionRules.isEmpty()) { + final Map tokenIdToDefinition = new THashMap(myRulesAliases.size()); + for (ArrangementRuleAlias alias : myRulesAliases) { + final String id = alias.getAliasToken().getId(); + tokenIdToDefinition.put(id, alias); + } + + final List sections = getSections(); + for (ArrangementSectionRule section : sections) { + final List extendedRules = new ArrayList(); + for (StdArrangementMatchRule rule : section.getMatchRules()) { + appendExpandedRules(rule, extendedRules, tokenIdToDefinition); + } + myExtendedSectionRules.add(ArrangementSectionRule.create(section.getStartComment(), section.getEndComment(), extendedRules)); + } + } + return myExtendedSectionRules; + } + + public void appendExpandedRules(@NotNull final StdArrangementMatchRule rule, + @NotNull final List rules, + @NotNull final Map tokenIdToDefinition) { + final List sequence = getRuleSequence(rule, tokenIdToDefinition); + if (sequence == null || sequence.isEmpty()) { + rules.add(rule); + return; + } + + final ArrangementCompositeMatchCondition ruleTemplate = removeAliasRuleToken(rule.getMatcher().getCondition()); + for (StdArrangementMatchRule matchRule : sequence) { + final ArrangementCompositeMatchCondition extendedRule = ruleTemplate.clone(); + extendedRule.addOperand(matchRule.getMatcher().getCondition()); + rules.add(new StdArrangementMatchRule(new StdArrangementEntryMatcher(extendedRule))); + } + } + + @Nullable + private List getRuleSequence(@NotNull final StdArrangementMatchRule rule, + @NotNull final Map tokenIdToDefinition) { + final List seqRule = ContainerUtil.newSmartList(); + rule.getMatcher().getCondition().invite(new ArrangementMatchConditionVisitor() { + @Override + public void visit(@NotNull ArrangementAtomMatchCondition condition) { + final ArrangementRuleAlias token = tokenIdToDefinition.get(condition.getType().getId()); + if (token != null && !token.getDefinitionRules().isEmpty()) { + seqRule.addAll(token.getDefinitionRules()); + } + } + + @Override + public void visit(@NotNull ArrangementCompositeMatchCondition condition) { + for (ArrangementMatchCondition operand : condition.getOperands()) { + if (!seqRule.isEmpty()) { + return; + } + operand.invite(this); + } + } + }); + return seqRule; + } + + @NotNull + private static ArrangementCompositeMatchCondition removeAliasRuleToken(final ArrangementMatchCondition original) { + final ArrangementCompositeMatchCondition composite = new ArrangementCompositeMatchCondition(); + original.invite(new ArrangementMatchConditionVisitor() { + @Override + public void visit(@NotNull ArrangementAtomMatchCondition condition) { + if (!ArrangementUtil.isAliasedCondition(condition)) { + composite.addOperand(condition); + } + } + + @Override + public void visit(@NotNull ArrangementCompositeMatchCondition condition) { + for (ArrangementMatchCondition c : condition.getOperands()) { + c.invite(this); + } + } + }); + return composite; + } + + @Override + public void addRule(@NotNull StdArrangementMatchRule rule) { + super.addRule(rule); + myExtendedSectionRules.clear(); + } + + @NotNull + @Override + public List getRulesSortedByPriority() { + if (myRulesByPriority.isEmpty()) { + for (ArrangementSectionRule rule : getExtendedSectionRules()) { + myRulesByPriority.addAll(rule.getMatchRules()); + } + ContainerUtil.sort(myRulesByPriority); + } + return myRulesByPriority; + } + + @NotNull + @Override + public StdArrangementExtendableSettings clone() { + return new StdArrangementExtendableSettings(cloneGroupings(), cloneSectionRules(), cloneTokenDefinitions()); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StdArrangementExtendableSettings settings = (StdArrangementExtendableSettings)o; + + if (!super.equals(settings)) return false; + if (!myRulesAliases.equals(settings.myRulesAliases)) return false; + + return true; + } +} diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokenType.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokenType.java index 1d6886f7d7c3..96786adcc51d 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokenType.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokenType.java @@ -63,6 +63,7 @@ public class StdArrangementTokenType { public static final String REG_EXP_ID = "REG_EXP"; public static final String ENTRY_TYPE_ID = "ENTRY_TYPE"; public static final String ORDER_ID = "ORDER"; + public static final String ALIAS_ID = "ALIAS"; public static final StdArrangementTokenType GENERAL = new StdArrangementTokenType(StdArrangementTokenUiRole.LABEL, GENERAL_ID); public static final StdArrangementTokenType GROUPING = new StdArrangementTokenType(StdArrangementTokenUiRole.CHECKBOX, GROUPING_ID); @@ -70,4 +71,5 @@ public class StdArrangementTokenType { public static final StdArrangementTokenType REG_EXP = new StdArrangementTokenType(StdArrangementTokenUiRole.TEXT_FIELD, REG_EXP_ID); public static final StdArrangementTokenType ENTRY_TYPE = new StdArrangementTokenType(StdArrangementTokenUiRole.BULB, ENTRY_TYPE_ID); public static final StdArrangementTokenType ORDER = new StdArrangementTokenType(StdArrangementTokenUiRole.COMBO_BOX, ORDER_ID); + public static final StdArrangementTokenType ALIAS = new StdArrangementTokenType(StdArrangementTokenUiRole.BULB, ALIAS_ID); } diff --git a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java index 15770aded615..c204cdf83c65 100644 --- a/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java +++ b/platform/lang-api/src/com/intellij/psi/codeStyle/arrangement/std/StdArrangementTokens.java @@ -110,6 +110,7 @@ public class StdArrangementTokens { @NotNull public static final ArrangementSettingsToken TYPE = token("TYPE", "arrangement.settings.text.general.type", StdArrangementTokenType.GENERAL); @NotNull public static final ArrangementSettingsToken MODIFIER = token("MODIFIER", "arrangement.settings.text.general.modifier", StdArrangementTokenType.GENERAL); @NotNull public static final ArrangementSettingsToken ORDER = token("ORDER", "arrangement.settings.text.general.order", StdArrangementTokenType.GENERAL); + @NotNull public static final ArrangementSettingsToken ALIAS = token("ALIAS", "arrangement.settings.text.general.sequence", StdArrangementTokenType.GENERAL); private General() { } diff --git a/platform/lang-api/testSources/com/intellij/psi/codeStyle/arrangement/ArrangementSettingsSerializationTest.java b/platform/lang-api/testSources/com/intellij/psi/codeStyle/arrangement/ArrangementSettingsSerializationTest.java index 1ae055b80c3e..405753078b40 100644 --- a/platform/lang-api/testSources/com/intellij/psi/codeStyle/arrangement/ArrangementSettingsSerializationTest.java +++ b/platform/lang-api/testSources/com/intellij/psi/codeStyle/arrangement/ArrangementSettingsSerializationTest.java @@ -15,13 +15,16 @@ */ package com.intellij.psi.codeStyle.arrangement; +import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.arrangement.group.ArrangementGroupingRule; import com.intellij.psi.codeStyle.arrangement.match.ArrangementSectionRule; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementEntryMatcher; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementRuleAlias; import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; +import com.intellij.psi.codeStyle.arrangement.std.StdArrangementExtendableSettings; import com.intellij.psi.codeStyle.arrangement.std.StdArrangementSettings; import com.intellij.util.containers.ContainerUtil; import org.jdom.Element; @@ -30,13 +33,14 @@ import org.jetbrains.annotations.Nullable; import org.junit.Test; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.Set; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.FIELD; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.EntryType.METHOD; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Grouping.OVERRIDDEN_METHODS; -import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.PRIVATE; -import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.PUBLIC; +import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Modifier.*; import static com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens.Order.BY_NAME; import static org.junit.Assert.*; @@ -76,15 +80,44 @@ public class ArrangementSettingsSerializationTest { return section(null, null, rule(byName, tokens)); } - private static StdArrangementSettings sectionSettings(@NotNull List groupings, - @NotNull List sections) { + private static StdArrangementSettings settings(@NotNull List groupings, + @NotNull List sections) { return new StdArrangementSettings(groupings, sections); } + private static StdArrangementExtendableSettings extendableSettings(@NotNull List groupings, + @NotNull List sections, + @NotNull Collection tokens) { + return new StdArrangementExtendableSettings(groupings, sections, tokens); + } + private static StdArrangementSettings emptySettings() { return new StdArrangementSettings(ContainerUtil.emptyList(), ContainerUtil.emptyList()); } + private static ArrangementSettingsToken customToken(@NotNull String name) { + return ArrangementUtil.createRuleAliasToken(name, name); + } + + private static ArrangementRuleAlias visibilityToken() { + final ArrayList rules = new ArrayList(); + rules.add(rule(false, PUBLIC)); + rules.add(rule(false, PROTECTED)); + rules.add(rule(false, PRIVATE)); + return new ArrangementRuleAlias(customToken("visibility"), rules); + } + + private static ArrangementRuleAlias modifiersToken() { + final ArrayList rules = new ArrayList(); + rules.add(rule(false, PUBLIC, STATIC)); + rules.add(rule(false, PROTECTED, STATIC)); + rules.add(rule(false, PRIVATE, STATIC)); + rules.add(rule(false, PUBLIC)); + rules.add(rule(false, PROTECTED)); + rules.add(rule(false, PRIVATE)); + return new ArrangementRuleAlias(customToken("modifiers"), rules); + } + @Test public void all() { final StdArrangementSettings settings = new StdArrangementSettings(); @@ -177,7 +210,7 @@ public class ArrangementSettingsSerializationTest { @Test public void testSimpleSectionSerialize() { final StdArrangementSettings settings = - sectionSettings(ContainerUtil.newArrayList(group(OVERRIDDEN_METHODS)), ContainerUtil.newArrayList(section(true, FIELD))); + settings(ContainerUtil.newArrayList(group(OVERRIDDEN_METHODS)), ContainerUtil.newArrayList(section(true, FIELD))); final Element holder = doSerializationTest(settings, emptySettings()); assertTrue(holder.getChildren().size() == 2); assertNotNull(holder.getChild("groups")); @@ -196,7 +229,7 @@ public class ArrangementSettingsSerializationTest { ContainerUtil.newArrayList(section("start section", "end section", rule(true, METHOD, PRIVATE), rule(false, METHOD, PUBLIC)), section("start section", "end section", rule(true, FIELD))); final StdArrangementSettings settings = - sectionSettings(ContainerUtil.newArrayList(group(OVERRIDDEN_METHODS)), sections); + settings(ContainerUtil.newArrayList(group(OVERRIDDEN_METHODS)), sections); final Element holder = doSerializationTest(settings, emptySettings()); assertTrue(holder.getChildren().size() == 2); @@ -209,6 +242,104 @@ public class ArrangementSettingsSerializationTest { assertEquals(section.getAttribute("end_comment").getValue(), "end section"); } + @Test + public void testDefaultCustomTokenSerialize() { + final Set tokens = ContainerUtil.newHashSet(visibilityToken()); + final ArrayList groupings = + ContainerUtil.newArrayList(new ArrangementGroupingRule(OVERRIDDEN_METHODS, BY_NAME)); + final ArrayList rules = ContainerUtil.newArrayList(section(true, FIELD)); + final StdArrangementExtendableSettings settings = extendableSettings(groupings, rules, tokens); + + final Element holder = doSerializationTest(settings, settings.clone()); + assertTrue(holder.getChildren().isEmpty()); + } + + @Test + public void testCustomTokenSerializeLessThanDefault() { + final Set tokens = ContainerUtil.newHashSet(visibilityToken()); + final ArrayList groupings = ContainerUtil.newArrayList( + new ArrangementGroupingRule(OVERRIDDEN_METHODS, BY_NAME)); + final ArrayList rules = ContainerUtil.newArrayList(section(true, FIELD)); + final StdArrangementExtendableSettings settings = extendableSettings(groupings, rules, tokens); + + final Set defaultTokens = ContainerUtil.newHashSet(visibilityToken(), modifiersToken()); + final StdArrangementExtendableSettings defaultSettings = extendableSettings(groupings, rules, defaultTokens); + + final Element holder = doSerializationTest(settings, defaultSettings); + assertTrue(holder.getChildren().size() == 1); + final Element tokenElement = holder.getChildren().get(0); + assertEquals(tokenElement.getName(), "tokens"); + assertTrue(tokenElement.getChildren().size() == 1); + final List tokenElements = tokenElement.getChildren(); + final Element element = tokenElements.get(0); + assertEquals(element.getName(), "token"); + assertTrue(StringUtil.equals(element.getAttributeValue("id"), "visibility")); + } + + @Test + public void testCustomTokenSerializeMoreThanDefault() { + final Set tokens = ContainerUtil.newHashSet(visibilityToken(), modifiersToken()); + final ArrayList groupings = ContainerUtil.newArrayList( + new ArrangementGroupingRule(OVERRIDDEN_METHODS, BY_NAME)); + final ArrayList rules = ContainerUtil.newArrayList(section(true, FIELD)); + final StdArrangementExtendableSettings settings = extendableSettings(groupings, rules, tokens); + + final Set defaultTokens = ContainerUtil.newHashSet(visibilityToken()); + final StdArrangementExtendableSettings defaultSettings = extendableSettings(groupings, rules, defaultTokens); + + final Element holder = doSerializationTest(settings, defaultSettings); + assertTrue(holder.getChildren().size() == 1); + final Element tokenElement = holder.getChildren().get(0); + assertEquals(tokenElement.getName(), "tokens"); + assertTrue(tokenElement.getChildren().size() == 2); + final List tokenElements = tokenElement.getChildren(); + final Element first = tokenElements.get(0); + final Element second = tokenElements.get(1); + assertEquals(first.getName(), "token"); + assertEquals(second.getName(), "token"); + assertTrue(StringUtil.equals(first.getAttributeValue("id"), "visibility") || + StringUtil.equals(second.getAttributeValue("id"), "visibility")); + assertTrue(StringUtil.equals(first.getAttributeValue("id"), "modifiers") || + StringUtil.equals(second.getAttributeValue("id"), "modifiers")); + } + + @Test + public void testUseCustomTokenSerialize() { + final Set tokens = ContainerUtil.newHashSet(visibilityToken(), modifiersToken()); + final ArrayList groupings = ContainerUtil.newArrayList( + new ArrangementGroupingRule(OVERRIDDEN_METHODS, BY_NAME)); + final ArrayList rules = ContainerUtil.newArrayList(section(true, FIELD, customToken("visibility"))); + final StdArrangementExtendableSettings settings = extendableSettings(groupings, rules, tokens); + + final ArrayList defaultRules = ContainerUtil.newArrayList(section(true, FIELD)); + final StdArrangementExtendableSettings defaultSettings = extendableSettings(groupings, defaultRules, tokens); + + final Element holder = doSerializationTest(settings, defaultSettings); + assertTrue(holder.getChildren().size() == 1); + final Element tokenElement = holder.getChildren().get(0); + assertEquals(tokenElement.getName(), "rules"); + assertTrue(tokenElement.getChildren().size() == 1); + assertEquals(tokenElement.getChildren().get(0).getName(), "section"); + final Element rule = tokenElement.getChildren().get(0).getChildren().get(0); + assertEquals(rule.getName(), "rule"); + assertEquals(rule.getChildren().get(0).getName(), "match"); + final Element and = rule.getChildren().get(0).getChildren().get(0); + assertEquals(and.getName(), "AND"); + assertTrue(StringUtil.equals(and.getChildren().get(0).getName(), "visibility") || + StringUtil.equals(and.getChildren().get(1).getName(), "visibility")); + } + + @Test + public void testCustomTokenSerializeAndDeserialize() { + final Set tokens = ContainerUtil.newHashSet(visibilityToken(), modifiersToken()); + final ArrayList groupings = ContainerUtil.newArrayList( + new ArrangementGroupingRule(OVERRIDDEN_METHODS, BY_NAME)); + final ArrayList rules = ContainerUtil.newArrayList(section(true, FIELD, customToken("visibility"))); + final StdArrangementExtendableSettings settings = extendableSettings(groupings, rules, tokens); + final StdArrangementExtendableSettings defaultSettings = new StdArrangementExtendableSettings(); + doSerializationTest(settings, defaultSettings); + } + private static class TestArrangementSettingsSerializer extends DefaultArrangementSettingsSerializer { public TestArrangementSettingsSerializer(@NotNull StdArrangementSettings defaultSettings) { diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java index 48bf3f038877..8c64d7f0ed5d 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/ArrangementSettingsPanel.java @@ -42,6 +42,7 @@ import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.util.ArrayList; +import java.util.Collection; import java.util.List; @@ -155,7 +156,12 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { private StdArrangementSettings createSettings() { final List groupingRules = myGroupingRulesPanel.getRules(); - return new StdArrangementSettings(groupingRules, myMatchingRulesPanel.getSections()); + final List sections = myMatchingRulesPanel.getSections(); + final Collection tokens = myMatchingRulesPanel.getRulesAliases(); + if (tokens != null) { + return new StdArrangementExtendableSettings(groupingRules, sections, tokens); + } + return new StdArrangementSettings(groupingRules, sections); } @Override @@ -169,6 +175,10 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel { List groupings = s.getGroupings(); myGroupingRulesPanel.setRules(ContainerUtilRt.newArrayList(groupings)); myMatchingRulesPanel.setSections(copy(s.getSections())); + if (s instanceof StdArrangementExtendableSettings) { + myMatchingRulesPanel.setRulesAliases(((StdArrangementExtendableSettings)s).getRuleAliases()); + } + if (myForceArrangementPanel != null) { myForceArrangementPanel.setSelectedMode(settings.getCommonSettings(myLanguage).FORCE_REARRANGE_MODE); } diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditRuleAliasesDefinitionAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditRuleAliasesDefinitionAction.java new file mode 100644 index 000000000000..14bba060e22f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/EditRuleAliasesDefinitionAction.java @@ -0,0 +1,60 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.action; + +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementSectionRulesControl; +import com.intellij.application.options.codeStyle.arrangement.match.tokens.ArrangementRuleAliasDialog; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.actionSystem.AnAction; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.application.ApplicationBundle; +import org.jetbrains.annotations.NotNull; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class EditRuleAliasesDefinitionAction extends AnAction { + + public EditRuleAliasesDefinitionAction() { + getTemplatePresentation().setText(ApplicationBundle.message("arrangement.action.alias.rule.add.edit.text")); + getTemplatePresentation().setDescription(ApplicationBundle.message("arrangement.action.alias.rule.add.edit.description")); + getTemplatePresentation().setIcon(AllIcons.General.Gear); + } + + @Override + public void update(AnActionEvent e) { + final ArrangementSectionRulesControl control = ArrangementSectionRulesControl.KEY.getData(e.getDataContext()); + if (control == null) { + return; + } + e.getPresentation().setEnabledAndVisible(control.getRulesAliases() != null); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + ArrangementSectionRulesControl control = ArrangementSectionRulesControl.KEY.getData(e.getDataContext()); + if (control == null || control.getRulesAliases() == null) { + return; + } + + control.hideEditor(); + final ArrangementRuleAliasDialog dialog = control.createRuleAliasEditDialog(); + dialog.show(); + if (dialog.isOK() && dialog.isModified()) { + control.setRulesAliases(dialog.getRuleAliases()); + } + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/AddArrangementAliasRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/AddArrangementAliasRuleAction.java new file mode 100644 index 000000000000..b9c75620b8a1 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/AddArrangementAliasRuleAction.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.action.tokens; + +import com.intellij.application.options.codeStyle.arrangement.action.AddArrangementRuleAction; +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; +import com.intellij.application.options.codeStyle.arrangement.match.tokens.ArrangementRuleAliasControl; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.Nullable; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class AddArrangementAliasRuleAction extends AddArrangementRuleAction { + @Override + @Nullable + protected ArrangementMatchingRulesControl getRulesControl(AnActionEvent e) { + return ArrangementRuleAliasControl.KEY.getData(e.getDataContext()); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/EditArrangementAliasRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/EditArrangementAliasRuleAction.java new file mode 100644 index 000000000000..04a664c5b565 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/EditArrangementAliasRuleAction.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.action.tokens; + +import com.intellij.application.options.codeStyle.arrangement.action.EditArrangementRuleAction; +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; +import com.intellij.application.options.codeStyle.arrangement.match.tokens.ArrangementRuleAliasControl; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.Nullable; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class EditArrangementAliasRuleAction extends EditArrangementRuleAction { + @Override + @Nullable + protected ArrangementMatchingRulesControl getRulesControl(AnActionEvent e) { + return ArrangementRuleAliasControl.KEY.getData(e.getDataContext()); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/MoveArrangementAliasRuleDownAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/MoveArrangementAliasRuleDownAction.java new file mode 100644 index 000000000000..56d04edad22c --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/MoveArrangementAliasRuleDownAction.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.action.tokens; + +import com.intellij.application.options.codeStyle.arrangement.action.MoveArrangementMatchingRuleDownAction; +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; +import com.intellij.application.options.codeStyle.arrangement.match.tokens.ArrangementRuleAliasControl; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.Nullable; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class MoveArrangementAliasRuleDownAction extends MoveArrangementMatchingRuleDownAction { + @Override + @Nullable + protected ArrangementMatchingRulesControl getRulesControl(AnActionEvent e) { + return ArrangementRuleAliasControl.KEY.getData(e.getDataContext()); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/MoveArrangementAliasRuleUpAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/MoveArrangementAliasRuleUpAction.java new file mode 100644 index 000000000000..c362f38c110d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/MoveArrangementAliasRuleUpAction.java @@ -0,0 +1,34 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.action.tokens; + +import com.intellij.application.options.codeStyle.arrangement.action.MoveArrangementMatchingRuleUpAction; +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; +import com.intellij.application.options.codeStyle.arrangement.match.tokens.ArrangementRuleAliasControl; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.Nullable; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class MoveArrangementAliasRuleUpAction extends MoveArrangementMatchingRuleUpAction { + + @Override + @Nullable + protected ArrangementMatchingRulesControl getRulesControl(AnActionEvent e) { + return ArrangementRuleAliasControl.KEY.getData(e.getDataContext()); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/RemoveArrangementAliasRuleAction.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/RemoveArrangementAliasRuleAction.java new file mode 100644 index 000000000000..795eb6073c1b --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/action/tokens/RemoveArrangementAliasRuleAction.java @@ -0,0 +1,33 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.action.tokens; + +import com.intellij.application.options.codeStyle.arrangement.action.RemoveArrangementRuleAction; +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; +import com.intellij.application.options.codeStyle.arrangement.match.tokens.ArrangementRuleAliasControl; +import com.intellij.openapi.actionSystem.AnActionEvent; +import org.jetbrains.annotations.Nullable; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class RemoveArrangementAliasRuleAction extends RemoveArrangementRuleAction { + @Override + @Nullable + protected ArrangementMatchingRulesControl getRulesControl(AnActionEvent e) { + return ArrangementRuleAliasControl.KEY.getData(e.getDataContext()); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java index 6f5963fb4dac..6efdf23e795e 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesControl.java @@ -55,7 +55,7 @@ public class ArrangementMatchingRulesControl extends JBTable { @NotNull private final TIntArrayList mySelectedRows = new TIntArrayList(); @NotNull private final ArrangementMatchNodeComponentFactory myFactory; - @NotNull private final ArrangementMatchingRuleEditor myEditor; + @NotNull protected ArrangementMatchingRuleEditor myEditor; @NotNull private final RepresentationCallback myRepresentationCallback; @NotNull private final MatchingRulesRendererBase myRenderer; diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesPanel.java index 2042b7ed0ba4..629933fea317 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesPanel.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementMatchingRulesPanel.java @@ -23,6 +23,7 @@ import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.DataProvider; import com.intellij.openapi.application.ApplicationBundle; import com.intellij.psi.codeStyle.arrangement.match.ArrangementSectionRule; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementRuleAlias; import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; import com.intellij.ui.components.JBScrollPane; import com.intellij.util.ui.GridBag; @@ -32,6 +33,7 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; +import java.util.Collection; import java.util.List; /** @@ -101,6 +103,15 @@ public class ArrangementMatchingRulesPanel extends JPanel implements DataProvide myControl.setSections(rules); } + @Nullable + public Collection getRulesAliases() { + return myControl.getRulesAliases(); + } + + public void setRulesAliases(@Nullable Collection aliases) { + myControl.setRulesAliases(aliases); + } + @Nullable @Override public Object getData(@NonNls String dataId) { diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementSectionRulesControl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementSectionRulesControl.java index c6b4be1c7e9f..4285146cb4d4 100644 --- a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementSectionRulesControl.java +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/ArrangementSectionRulesControl.java @@ -17,6 +17,7 @@ package com.intellij.application.options.codeStyle.arrangement.match; import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; +import com.intellij.application.options.codeStyle.arrangement.match.tokens.ArrangementRuleAliasDialog; import com.intellij.lang.Language; import com.intellij.openapi.actionSystem.DataKey; import com.intellij.openapi.diagnostic.Logger; @@ -24,13 +25,20 @@ import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.codeStyle.arrangement.ArrangementUtil; import com.intellij.psi.codeStyle.arrangement.match.ArrangementSectionRule; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementCompositeMatchCondition; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; +import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchConditionVisitor; +import com.intellij.psi.codeStyle.arrangement.std.*; import com.intellij.util.containers.ContainerUtil; +import gnu.trove.THashSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Set; import static com.intellij.application.options.codeStyle.arrangement.match.ArrangementSectionRuleManager.ArrangementSectionRuleData; @@ -42,12 +50,19 @@ public class ArrangementSectionRulesControl extends ArrangementMatchingRulesCont @NotNull public static final DataKey KEY = DataKey.create("Arrangement.Rule.Match.Control"); @NotNull private static final Logger LOG = Logger.getInstance("#" + ArrangementSectionRulesControl.class.getName()); @Nullable private final ArrangementSectionRuleManager mySectionRuleManager; + @Nullable private ArrangementExtendableSettingsManager myRuleAliasesManager; - public ArrangementSectionRulesControl(@NotNull Language language, @NotNull ArrangementStandardSettingsManager settingsManager, + private ArrangementStandardSettingsManager mySettingsManager; + private ArrangementColorsProvider myColorsProvider; + + public ArrangementSectionRulesControl(@NotNull Language language, + @NotNull ArrangementStandardSettingsManager settingsManager, @NotNull ArrangementColorsProvider colorsProvider, @NotNull RepresentationCallback callback) { super(settingsManager, colorsProvider, callback); mySectionRuleManager = ArrangementSectionRuleManager.getInstance(language, settingsManager, colorsProvider, this); + mySettingsManager = settingsManager; + myColorsProvider = colorsProvider; } private static void appendBufferedSectionRules(@NotNull List result, @@ -145,6 +160,18 @@ public class ArrangementSectionRulesControl extends ArrangementMatchingRulesCont } } + @Nullable + public Collection getRulesAliases() { + return myRuleAliasesManager == null ? null : myRuleAliasesManager.getRuleAliases(); + } + + public void setRulesAliases(@Nullable Collection aliases) { + if (aliases != null) { + myRuleAliasesManager = new ArrangementExtendableSettingsManager(mySettingsManager.getDelegate(), myColorsProvider, aliases); + myEditor = new ArrangementMatchingRuleEditor(myRuleAliasesManager, myColorsProvider, this); + } + } + public void showEditor(int rowToEdit) { if (mySectionRuleManager != null && mySectionRuleManager.isSectionRule(getModel().getElementAt(rowToEdit))) { mySectionRuleManager.showEditor(rowToEdit); @@ -154,6 +181,35 @@ public class ArrangementSectionRulesControl extends ArrangementMatchingRulesCont } } + @NotNull + public ArrangementRuleAliasDialog createRuleAliasEditDialog() { + final Set tokenIds = new THashSet(); + final List sections = getSections(); + for (ArrangementSectionRule section : sections) { + for (StdArrangementMatchRule rule : section.getMatchRules()) { + rule.getMatcher().getCondition().invite(new ArrangementMatchConditionVisitor() { + @Override + public void visit(@NotNull ArrangementAtomMatchCondition condition) { + if (ArrangementUtil.isAliasedCondition(condition)) { + tokenIds.add(condition.getType().getId()); + } + } + + @Override + public void visit(@NotNull ArrangementCompositeMatchCondition condition) { + for (ArrangementMatchCondition operand : condition.getOperands()) { + operand.invite(this); + } + } + }); + } + } + + final Collection aliases = getRulesAliases(); + assert aliases != null; + return new ArrangementRuleAliasDialog(null, mySettingsManager, myColorsProvider, aliases, tokenIds); + } + private class MatchingRulesRenderer extends MatchingRulesRendererBase { @Override public boolean allowModifications(StdArrangementMatchRule rule) { diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasConfigurable.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasConfigurable.java new file mode 100644 index 000000000000..b1593f959b3a --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasConfigurable.java @@ -0,0 +1,108 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.match.tokens; + +import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; +import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.util.Disposer; +import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementRuleAlias; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.event.KeyEvent; +import java.util.List; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class ArrangementRuleAliasConfigurable implements UnnamedConfigurable { + private ArrangementRuleAlias myToken; + private ArrangementRuleAliasesPanel myTokenRulesPanel; + + public ArrangementRuleAliasConfigurable(@NotNull ArrangementStandardSettingsManager settingsManager, + @NotNull ArrangementColorsProvider colorsProvider, + @NotNull ArrangementRuleAlias token) { + myToken = token; + myTokenRulesPanel = new ArrangementRuleAliasesPanel(settingsManager, colorsProvider); + myTokenRulesPanel.setRuleSequences(token.getDefinitionRules()); + + registerShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_ADD, CommonShortcuts.getNew(), myTokenRulesPanel); + registerShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_REMOVE, CommonShortcuts.getDelete(), myTokenRulesPanel); + registerShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_MOVE_UP, CommonShortcuts.MOVE_UP, myTokenRulesPanel); + registerShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_MOVE_DOWN, CommonShortcuts.MOVE_DOWN, myTokenRulesPanel); + final CustomShortcutSet edit = new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_F2, 0)); + registerShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_EDIT, edit, myTokenRulesPanel); + } + + private static void registerShortcut(@NotNull String actionId, + @NotNull ShortcutSet shortcut, + @NotNull JComponent component) { + final AnAction action = ActionManager.getInstance().getAction(actionId); + if (action != null) { + action.registerCustomShortcutSet(shortcut, component); + } + } + + private static void unregisterShortcut(@NotNull String actionId, @NotNull JComponent component) { + final AnAction action = ActionManager.getInstance().getAction(actionId); + if (action != null) { + action.unregisterCustomShortcutSet(component); + } + } + + @Nullable + @Override + public JComponent createComponent() { + return myTokenRulesPanel; + } + + @Override + public boolean isModified() { + final List newRules = myTokenRulesPanel.getRuleSequences(); + return !newRules.equals(myToken.getDefinitionRules()); + } + + @Override + public void apply() throws ConfigurationException { + myToken.setDefinitionRules(myTokenRulesPanel.getRuleSequences()); + } + + @Override + public void reset() { + myTokenRulesPanel.setRuleSequences(myToken.getDefinitionRules()); + } + + @Override + public void disposeUIResources() { + Disposer.dispose(new Disposable() { + @Override + public void dispose() { + unregisterShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_ADD, myTokenRulesPanel); + unregisterShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_REMOVE, myTokenRulesPanel); + unregisterShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_MOVE_UP, myTokenRulesPanel); + unregisterShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_MOVE_DOWN, myTokenRulesPanel); + unregisterShortcut(ArrangementConstants.MATCHING_ALIAS_RULE_EDIT, myTokenRulesPanel); + } + }); + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasControl.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasControl.java new file mode 100644 index 000000000000..304683141a1d --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasControl.java @@ -0,0 +1,74 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.match.tokens; + +import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; +import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; +import com.intellij.openapi.actionSystem.DataKey; +import com.intellij.openapi.diagnostic.Logger; +import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class ArrangementRuleAliasControl extends ArrangementMatchingRulesControl { + @NotNull public static final DataKey KEY = DataKey.create("Arrangement.Alias.Rule.Control"); + @NotNull private static final Logger LOG = Logger.getInstance("#" + ArrangementRuleAliasControl.class.getName()); + + public ArrangementRuleAliasControl(@NotNull ArrangementStandardSettingsManager settingsManager, + @NotNull ArrangementColorsProvider colorsProvider, + @NotNull RepresentationCallback callback) { + super(settingsManager, colorsProvider, callback); + } + + public List getRuleSequences() { + final List rulesSequences = new ArrayList(); + for (int i = 0; i < getModel().getSize(); i++) { + Object element = getModel().getElementAt(i); + if (element instanceof StdArrangementMatchRule) { + rulesSequences.add((StdArrangementMatchRule)element); + } + } + return rulesSequences; + } + + public void setRuleSequences(Collection sequences) { + myComponents.clear(); + getModel().clear(); + + if (sequences == null) { + return; + } + + for (StdArrangementMatchRule rule : sequences) { + getModel().add(rule); + } + + if (ArrangementConstants.LOG_ALIAS_RULE_MODIFICATION) { + LOG.info("Arrangement rules sequences is refreshed. Given rules:"); + for (StdArrangementMatchRule rule : sequences) { + LOG.info(" " + rule.toString()); + } + } + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasDialog.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasDialog.java new file mode 100644 index 000000000000..23c89354b342 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasDialog.java @@ -0,0 +1,85 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.match.tokens; + +import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; +import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.openapi.options.ConfigurationException; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementRuleAlias; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; +import com.intellij.util.containers.ContainerUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Set; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class ArrangementRuleAliasDialog extends DialogWrapper { + private final ArrangementRuleAliasesListEditor myEditor; + private boolean myModified; + + public ArrangementRuleAliasDialog(@Nullable Project project, + @NotNull ArrangementStandardSettingsManager settingsManager, + @NotNull ArrangementColorsProvider colorsProvider, + @NotNull Collection tokens, + @NotNull Set tokensInUse) { + super(project, false); + + final ArrayList tokenList = ContainerUtil.newArrayList(tokens); + myEditor = new ArrangementRuleAliasesListEditor(settingsManager, colorsProvider, tokenList, tokensInUse); + if (!tokenList.isEmpty()) { + myEditor.selectItem(tokenList.get(0)); + } + + setTitle(ApplicationBundle.message("arrangement.settings.section.rule.custom.token.title")); + init(); + } + + public boolean isModified() { + return myModified; + } + + public Collection getRuleAliases() { + return myEditor.getItems(); + } + + @Nullable + @Override + protected JComponent createCenterPanel() { + return myEditor.createComponent(); + } + + @Override + protected void doOKAction() { + try { + myModified = myEditor.isModified(); + if (myModified) { + myEditor.apply(); + } + super.doOKAction(); + } + catch (ConfigurationException e) { + // show error + } + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasesListEditor.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasesListEditor.java new file mode 100644 index 000000000000..07df3822c09f --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasesListEditor.java @@ -0,0 +1,114 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.match.tokens; + +import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; +import com.intellij.openapi.options.UnnamedConfigurable; +import com.intellij.openapi.ui.NamedItemsListEditor; +import com.intellij.openapi.ui.Namer; +import com.intellij.openapi.util.Cloner; +import com.intellij.openapi.util.Comparing; +import com.intellij.openapi.util.Factory; +import com.intellij.psi.codeStyle.arrangement.ArrangementUtil; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementRuleAlias; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; +import gnu.trove.Equality; +import org.jetbrains.annotations.Nls; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Set; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class ArrangementRuleAliasesListEditor extends NamedItemsListEditor { + private static final Namer NAMER = new Namer() { + @Override + public String getName(ArrangementRuleAlias token) { + return token.getAliasToken().getRepresentationValue(); + } + + @Override + public boolean canRename(ArrangementRuleAlias item) { + return false; + } + + @Override + public void setName(ArrangementRuleAlias token, String name) { + token.setAliasToken(ArrangementUtil.createRuleAliasToken(name.replaceAll("\\s+", "_"), name.replaceAll("\\s+", " "))); + } + }; + private static final Factory FACTORY = new Factory() { + @Override + public ArrangementRuleAlias create() { + return new ArrangementRuleAlias(); + } + }; + private static final Cloner CLONER = new Cloner() { + @Override + public ArrangementRuleAlias cloneOf(ArrangementRuleAlias original) { + final ArrangementRuleAlias token = copyOf(original); + token.setAliasToken(original.getAliasToken()); + return token; + } + + @Override + public ArrangementRuleAlias copyOf(ArrangementRuleAlias original) { + final ArrangementRuleAlias token = new ArrangementRuleAlias(); + token.setDefinitionRules(original.getDefinitionRules()); + return token; + } + }; + private static final Equality COMPARER = new Equality() { + @Override + public boolean equals(ArrangementRuleAlias o1, ArrangementRuleAlias o2) { + return Comparing.equal(o1.getAliasToken().getId(), o2.getAliasToken().getId()); + } + }; + + @NotNull private Set myUsedTokenIds; + @NotNull private ArrangementStandardSettingsManager mySettingsManager; + @NotNull private ArrangementColorsProvider myColorsProvider; + + protected ArrangementRuleAliasesListEditor(@NotNull ArrangementStandardSettingsManager settingsManager, + @NotNull ArrangementColorsProvider colorsProvider, + @NotNull List items, + @NotNull Set usedTokenIds) { + super(NAMER, FACTORY, CLONER, COMPARER, items, false); + mySettingsManager = settingsManager; + myColorsProvider = colorsProvider; + myUsedTokenIds = usedTokenIds; + reset(); + initTree(); + } + + @Override + protected UnnamedConfigurable createConfigurable(ArrangementRuleAlias item) { + return new ArrangementRuleAliasConfigurable(mySettingsManager, myColorsProvider, item); + } + + @Override + protected boolean canDelete(ArrangementRuleAlias item) { + return !myUsedTokenIds.contains(item.getAliasToken().getId()); + } + + @Nls + @Override + public String getDisplayName() { + return "Custom Composite Tokens"; + } +} diff --git a/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasesPanel.java b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasesPanel.java new file mode 100644 index 000000000000..21000590d6f7 --- /dev/null +++ b/platform/lang-impl/src/com/intellij/application/options/codeStyle/arrangement/match/tokens/ArrangementRuleAliasesPanel.java @@ -0,0 +1,102 @@ +/* + * Copyright 2000-2014 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.application.options.codeStyle.arrangement.match.tokens; + +import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants; +import com.intellij.application.options.codeStyle.arrangement.color.ArrangementColorsProvider; +import com.intellij.application.options.codeStyle.arrangement.match.ArrangementMatchingRulesControl; +import com.intellij.application.options.codeStyle.arrangement.util.TitleWithToolbar; +import com.intellij.ide.ui.customization.CustomizationUtil; +import com.intellij.openapi.actionSystem.DataProvider; +import com.intellij.openapi.application.ApplicationBundle; +import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; +import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsManager; +import com.intellij.ui.components.JBScrollPane; +import com.intellij.util.ui.GridBag; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.swing.*; +import java.awt.*; +import java.util.Collection; +import java.util.List; + +/** + * @author Svetlana.Zemlyanskaya + */ +public class ArrangementRuleAliasesPanel extends JPanel implements DataProvider { + @NotNull protected final ArrangementRuleAliasControl myControl; + + public ArrangementRuleAliasesPanel(@NotNull ArrangementStandardSettingsManager settingsManager, + @NotNull ArrangementColorsProvider colorsProvider) { + super(new GridBagLayout()); + + JBScrollPane scrollPane = new JBScrollPane(); + final JViewport viewport = scrollPane.getViewport(); + ArrangementMatchingRulesControl.RepresentationCallback callback = new ArrangementMatchingRulesControl.RepresentationCallback() { + @Override + public void ensureVisible(@NotNull Rectangle r) { + Rectangle visibleRect = viewport.getViewRect(); + if (r.y <= visibleRect.y) { + return; + } + + int excessiveHeight = r.y + r.height - (visibleRect.y + visibleRect.height); + if (excessiveHeight <= 0) { + return; + } + + int verticalShift = Math.min(r.y - visibleRect.y, excessiveHeight); + if (verticalShift > 0) { + viewport.setViewPosition(new Point(visibleRect.x, visibleRect.y + verticalShift)); + } + } + }; + myControl = new ArrangementRuleAliasControl(settingsManager, colorsProvider, callback); + scrollPane.setViewportView(myControl); + CustomizationUtil.installPopupHandler( + myControl, ArrangementConstants.ALIAS_RULE_CONTEXT_MENU, ArrangementConstants.ALIAS_RULE_CONTROL_PLACE + ); + + TitleWithToolbar top = new TitleWithToolbar( + ApplicationBundle.message("arrangement.settings.section.rule.sequence"), + ArrangementConstants.ALIAS_RULE_CONTROL_TOOLBAR, + ArrangementConstants.ALIAS_RULE_CONTROL_TOOLBAR_PLACE, + myControl + ); + add(top, new GridBag().coverLine().fillCellHorizontally().weightx(1)); + add(scrollPane, new GridBag().fillCell().weightx(1).weighty(1).insets(0, ArrangementConstants.HORIZONTAL_PADDING, 0, 0)); + } + + @NotNull + public List getRuleSequences() { + return myControl.getRuleSequences(); + } + + public void setRuleSequences(@Nullable Collection rules) { + myControl.setRuleSequences(rules); + } + + @Nullable + @Override + public Object getData(@NonNls String dataId) { + if (ArrangementRuleAliasControl.KEY.is(dataId)) { + return myControl; + } + return null; + } +} diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java index 652caba73e61..62fe02cbf654 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/MemberOrderService.java @@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.codeStyle.CommonCodeStyleSettings; import com.intellij.psi.codeStyle.arrangement.engine.ArrangementEngine; import com.intellij.psi.codeStyle.arrangement.match.ArrangementMatchRule; +import com.intellij.psi.codeStyle.arrangement.match.ArrangementSectionRule; import com.intellij.psi.codeStyle.arrangement.std.ArrangementStandardSettingsAware; import com.intellij.util.containers.HashSet; import org.jetbrains.annotations.NotNull; @@ -89,7 +90,8 @@ public class MemberOrderService { entriesWithNew.add(memberEntry); //TODO: check insert new element final List rulesByPriority = arrangementSettings.getRulesSortedByPriority(); - List arranged = ArrangementEngine.arrange(entriesWithNew, arrangementSettings.getSections(), rulesByPriority, null); + final List extendedSectionRules = ArrangementUtil.getExtendedSectionRules(arrangementSettings); + List arranged = ArrangementEngine.arrange(entriesWithNew, extendedSectionRules, rulesByPriority, null); int i = arranged.indexOf(memberEntry); if (i <= 0) { diff --git a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java index 9d2c82c3c38c..21d21d91e48f 100644 --- a/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java +++ b/platform/lang-impl/src/com/intellij/psi/codeStyle/arrangement/engine/ArrangementEngine.java @@ -555,7 +555,7 @@ public class ArrangementEngine { changer = new DefaultChanger(); } final List rulesByPriority = arrangementSettings.getRulesSortedByPriority(); - final List sectionRules = arrangementSettings.getSections(); + final List sectionRules = ArrangementUtil.getExtendedSectionRules(arrangementSettings); return new Context(rearranger, wrappers, document, sectionRules, rulesByPriority, codeStyleSettings, changer); } } diff --git a/platform/platform-resources-en/src/messages/ApplicationBundle.properties b/platform/platform-resources-en/src/messages/ApplicationBundle.properties index c2a31ba4b1fc..66f2daad0b43 100644 --- a/platform/platform-resources-en/src/messages/ApplicationBundle.properties +++ b/platform/platform-resources-en/src/messages/ApplicationBundle.properties @@ -606,8 +606,12 @@ arrangement.action.rule.move.up.text=Move up arrangement.action.rule.move.up.description=Move selected arrangement rule(s) up arrangement.action.rule.move.down.text=Move down arrangement.action.rule.move.down.description=Move selected arrangement rule(s) down +arrangement.action.alias.rule.add.edit.text=Configure matching rules aliases +arrangement.action.alias.rule.add.edit.description=Configure aliases for arrangement matching rules arrangement.settings.section.groups=Grouping rules arrangement.settings.section.match=Matching rules +arrangement.settings.section.rule.custom.token.title=Rules Alias Definitions +arrangement.settings.section.rule.sequence=Rules alias definitions arrangement.settings.groups.property.field=Group property field with corresponding getter/setter arrangement.settings.groups.dependent.methods=Keep dependent methods together arrangement.settings.groups.overridden.methods=Keep overridden methods together @@ -621,6 +625,7 @@ arrangement.settings.text.general.modifier=Modifier: arrangement.settings.text.general.name=Name: arrangement.settings.text.general.text=Text: arrangement.settings.text.general.order=Order: +arrangement.settings.text.general.sequence=Aliases: arrangement.settings.text.general.xml.namespace=Namespace: arrangement.settings.text.entry.type.xml.tag=tag arrangement.settings.text.entry.type.xml.attribute=attribute diff --git a/platform/platform-resources/src/idea/LangActions.xml b/platform/platform-resources/src/idea/LangActions.xml index 07a06b8300bb..487955f38f00 100644 --- a/platform/platform-resources/src/idea/LangActions.xml +++ b/platform/platform-resources/src/idea/LangActions.xml @@ -874,11 +874,37 @@ class="com.intellij.application.options.codeStyle.arrangement.action.MoveArrangementMatchingRuleUpAction"/> + + + + + + + + + + + + + + + + + + + + @@ -892,6 +918,7 @@ + diff --git a/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java b/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java index b503f5cf1e59..6befba79cca2 100644 --- a/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java +++ b/platform/testFramework/testSrc/com/intellij/psi/codeStyle/arrangement/AbstractRearrangerTest.java @@ -31,9 +31,7 @@ import com.intellij.psi.codeStyle.arrangement.match.StdArrangementEntryMatcher; import com.intellij.psi.codeStyle.arrangement.match.StdArrangementMatchRule; import com.intellij.psi.codeStyle.arrangement.model.ArrangementAtomMatchCondition; import com.intellij.psi.codeStyle.arrangement.model.ArrangementMatchCondition; -import com.intellij.psi.codeStyle.arrangement.std.ArrangementSettingsToken; -import com.intellij.psi.codeStyle.arrangement.std.StdArrangementSettings; -import com.intellij.psi.codeStyle.arrangement.std.StdArrangementTokens; +import com.intellij.psi.codeStyle.arrangement.std.*; import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase; import com.intellij.util.Function; import com.intellij.util.containers.ContainerUtil; @@ -82,6 +80,10 @@ public abstract class AbstractRearrangerTest extends LightPlatformCodeInsightFix return ArrangementSectionRule.create(start, end, rules); } + protected static ArrangementRuleAlias alias(@NotNull String id, @NotNull StdArrangementMatchRule... rules) { + return new ArrangementRuleAlias(ArrangementUtil.createRuleAliasToken(id, id), ContainerUtil.newArrayList(rules)); + } + @NotNull protected static ArrangementGroupingRule group(@NotNull ArrangementSettingsToken type) { return group(type, KEEP); @@ -189,8 +191,14 @@ public abstract class AbstractRearrangerTest extends LightPlatformCodeInsightFix } }); + @SuppressWarnings("unchecked") + List aliases = (List)args.get("aliases"); CommonCodeStyleSettings settings = CodeStyleSettingsManager.getInstance(myFixture.getProject()).getCurrentSettings().getCommonSettings(language); - settings.setArrangementSettings(new StdArrangementSettings(groupingRules, sectionRules)); + final StdArrangementSettings arrangementSettings = + aliases == null ? + new StdArrangementSettings(groupingRules, sectionRules) : + new StdArrangementExtendableSettings(groupingRules, sectionRules, aliases); + settings.setArrangementSettings(arrangementSettings); ArrangementEngine engine = ServiceManager.getService(myFixture.getProject(), ArrangementEngine.class); engine.arrange(myFixture.getEditor(), myFixture.getFile(), info.ranges);