mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -16,11 +16,13 @@
|
||||
package com.intellij.psi.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.*;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettingsGrouper;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
|
||||
import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -32,7 +34,9 @@ import java.util.*;
|
||||
* @author Denis Zhdanov
|
||||
* @since 7/20/12 2:31 PM
|
||||
*/
|
||||
public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>, ArrangementStandardSettingsAware {
|
||||
public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>, ArrangementStandardSettingsAware,
|
||||
ArrangementSettingsGrouper
|
||||
{
|
||||
|
||||
// Type
|
||||
@NotNull private static final Set<ArrangementEntryType> SUPPORTED_TYPES = EnumSet.of(
|
||||
@@ -80,35 +84,87 @@ public class JavaRearranger implements Rearranger<JavaElementArrangementEntry>,
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNameFilterEnabled(@Nullable ArrangementMatcherSettings settings) {
|
||||
public boolean isNameFilterEnabled(@Nullable ArrangementSettingsNode current) {
|
||||
// TODO den implement
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings settings) {
|
||||
public boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementSettingsNode current) {
|
||||
return SUPPORTED_TYPES.contains(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings settings) {
|
||||
if (settings == null) {
|
||||
public boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementSettingsNode current) {
|
||||
if (current == null) {
|
||||
return SUPPORTED_MODIFIERS.contains(modifier);
|
||||
}
|
||||
Object key = NO_TYPE;
|
||||
for (ArrangementEntryType type : ArrangementEntryType.values()) {
|
||||
if (settings.hasCondition(type)) {
|
||||
key = type;
|
||||
break;
|
||||
|
||||
final Ref<Object> typeRef = new Ref<Object>();
|
||||
current.invite(new ArrangementSettingsNodeVisitor() {
|
||||
@Override
|
||||
public void visit(@NotNull ArrangementSettingsAtomNode node) {
|
||||
if (node.getType() == ArrangementSettingType.TYPE) {
|
||||
typeRef.set(node.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull ArrangementSettingsCompositeNode node) {
|
||||
for (ArrangementSettingsNode n : node.getOperands()) {
|
||||
if (typeRef.get() != null) {
|
||||
return;
|
||||
}
|
||||
n.invite(this);
|
||||
}
|
||||
}
|
||||
});
|
||||
Object key = typeRef.get() == null ? NO_TYPE : typeRef.get();
|
||||
Set<ArrangementModifier> modifiers = MODIFIERS_BY_TYPE.get(key);
|
||||
return modifiers != null && modifiers.contains(modifier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings settings) {
|
||||
public boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementSettingsNode current) {
|
||||
// TODO den implement
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HierarchicalArrangementSettingsNode group(@NotNull ArrangementSettingsNode node) {
|
||||
final Ref<HierarchicalArrangementSettingsNode> result = new Ref<HierarchicalArrangementSettingsNode>();
|
||||
node.invite(new ArrangementSettingsNodeVisitor() {
|
||||
@Override
|
||||
public void visit(@NotNull ArrangementSettingsAtomNode node) {
|
||||
result.set(new HierarchicalArrangementSettingsNode(node));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull ArrangementSettingsCompositeNode node) {
|
||||
ArrangementSettingsNode typeNode = null;
|
||||
for (ArrangementSettingsNode n : node.getOperands()) {
|
||||
if (n instanceof ArrangementSettingsAtomNode && ((ArrangementSettingsAtomNode)n).getType() == ArrangementSettingType.TYPE) {
|
||||
typeNode = n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (typeNode == null) {
|
||||
result.set(new HierarchicalArrangementSettingsNode(node));
|
||||
}
|
||||
else {
|
||||
HierarchicalArrangementSettingsNode parent = new HierarchicalArrangementSettingsNode(typeNode);
|
||||
ArrangementSettingsCompositeNode compositeWithoutType = new ArrangementSettingsCompositeNode(node.getOperator());
|
||||
for (ArrangementSettingsNode n : node.getOperands()) {
|
||||
if (n != typeNode) {
|
||||
compositeWithoutType.addOperand(n);
|
||||
}
|
||||
}
|
||||
parent.addChild(new HierarchicalArrangementSettingsNode(compositeWithoutType));
|
||||
result.set(parent);
|
||||
}
|
||||
}
|
||||
});
|
||||
return result.get();
|
||||
}
|
||||
}
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.ArrangementUtil;
|
||||
import com.intellij.psi.codeStyle.arrangement.JavaRearranger;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
import static com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier.PUBLIC;
|
||||
import static com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier.STATIC;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 08/15/2012
|
||||
*/
|
||||
public class ArrangementRuleEditingModelBuilderTest {
|
||||
|
||||
@NotNull private ArrangementRuleEditingModelBuilder myBuilder;
|
||||
@NotNull private DefaultMutableTreeNode myRoot;
|
||||
@NotNull private TIntObjectHashMap<ArrangementRuleEditingModel> myRowMappings;
|
||||
@NotNull private JavaRearranger myGrouper;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
myBuilder = new ArrangementRuleEditingModelBuilder();
|
||||
myRoot = new DefaultMutableTreeNode();
|
||||
myRowMappings = new TIntObjectHashMap<ArrangementRuleEditingModel>();
|
||||
myGrouper = new JavaRearranger();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mapToTheSameLayer() {
|
||||
build(ArrangementUtil.and(atom(PUBLIC), atom(STATIC)));
|
||||
// TODO den uncomment
|
||||
//assertEquals(1, myRowMappings.size());
|
||||
}
|
||||
|
||||
private void build(@NotNull ArrangementSettingsNode node) {
|
||||
myBuilder.build(node, myRoot, myGrouper, myRowMappings);
|
||||
}
|
||||
|
||||
private static ArrangementSettingsAtomNode atom(@NotNull Object condition) {
|
||||
final ArrangementSettingType type;
|
||||
if (condition instanceof ArrangementEntryType) {
|
||||
type = ArrangementSettingType.TYPE;
|
||||
}
|
||||
else if (condition instanceof ArrangementModifier) {
|
||||
type = ArrangementSettingType.MODIFIER;
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(String.format("Unexpected condition of class %s: %s", condition.getClass(), condition));
|
||||
}
|
||||
return new ArrangementSettingsAtomNode(type, condition);
|
||||
}
|
||||
}
|
||||
@@ -16,10 +16,15 @@
|
||||
package com.intellij.psi.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.lang.Language;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.CompositeArrangementEntryMatcher;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsCompositeNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNodeVisitor;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -108,17 +113,48 @@ public class ArrangementUtil {
|
||||
}
|
||||
//endregion
|
||||
|
||||
//region Matchers composition
|
||||
//region Rule composition
|
||||
|
||||
@NotNull
|
||||
public static ArrangementSettingsNode and(@NotNull ArrangementSettingsNode... nodes) {
|
||||
final ArrangementSettingsCompositeNode result = new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND);
|
||||
final ArrangementSettingsNodeVisitor visitor = new ArrangementSettingsNodeVisitor() {
|
||||
@Override
|
||||
public void visit(@NotNull ArrangementSettingsAtomNode node) {
|
||||
result.addOperand(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(@NotNull ArrangementSettingsCompositeNode node) {
|
||||
if (node.getOperator() == ArrangementSettingsCompositeNode.Operator.AND) {
|
||||
for (ArrangementSettingsNode operand : node.getOperands()) {
|
||||
operand.invite(this);
|
||||
}
|
||||
}
|
||||
else {
|
||||
result.addOperand(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
for (ArrangementSettingsNode node : nodes) {
|
||||
node.invite(visitor);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO den remove
|
||||
@NotNull
|
||||
public static ArrangementEntryMatcher or(@NotNull ArrangementEntryMatcher... matchers) {
|
||||
return combine(CompositeArrangementEntryMatcher.Operator.OR, matchers);
|
||||
}
|
||||
|
||||
// TODO den remove
|
||||
@NotNull
|
||||
public static ArrangementEntryMatcher and(@NotNull ArrangementEntryMatcher... matchers) {
|
||||
return combine(CompositeArrangementEntryMatcher.Operator.AND, matchers);
|
||||
}
|
||||
|
||||
// TODO den remove
|
||||
@NotNull
|
||||
private static ArrangementEntryMatcher combine(@NotNull CompositeArrangementEntryMatcher.Operator operator,
|
||||
@NotNull ArrangementEntryMatcher... matchers)
|
||||
|
||||
+1
@@ -90,6 +90,7 @@ public class ArrangementSettingsAtomNode implements ArrangementSettingsNode {
|
||||
return true;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrangementSettingsAtomNode clone() {
|
||||
ArrangementSettingsAtomNode result = new ArrangementSettingsAtomNode(myType, myValue);
|
||||
|
||||
+6
-6
@@ -16,11 +16,10 @@
|
||||
package com.intellij.psi.codeStyle.arrangement.model;
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* // TODO den add doc
|
||||
@@ -30,7 +29,7 @@ import java.util.List;
|
||||
*/
|
||||
public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode {
|
||||
|
||||
@NotNull private final List<ArrangementSettingsNode> myOperands = new ArrayList<ArrangementSettingsNode>();
|
||||
@NotNull private final Set<ArrangementSettingsNode> myOperands = new HashSet<ArrangementSettingsNode>();
|
||||
@NotNull private final Operator myOperator;
|
||||
|
||||
public ArrangementSettingsCompositeNode(@NotNull Operator operator) {
|
||||
@@ -38,7 +37,7 @@ public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public List<ArrangementSettingsNode> getOperands() {
|
||||
public Set<ArrangementSettingsNode> getOperands() {
|
||||
return myOperands;
|
||||
}
|
||||
|
||||
@@ -57,6 +56,7 @@ public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode
|
||||
visitor.visit(this);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrangementSettingsCompositeNode clone() {
|
||||
ArrangementSettingsCompositeNode result = new ArrangementSettingsCompositeNode(myOperator);
|
||||
@@ -70,7 +70,7 @@ public class ArrangementSettingsCompositeNode implements ArrangementSettingsNode
|
||||
public String toString() {
|
||||
return StringUtil.join(myOperands, myOperator == Operator.AND ? " and " : " or ");
|
||||
}
|
||||
|
||||
|
||||
public enum Operator {
|
||||
AND, OR
|
||||
}
|
||||
|
||||
+1
@@ -27,5 +27,6 @@ public interface ArrangementSettingsNode extends Cloneable {
|
||||
|
||||
void invite(@NotNull ArrangementSettingsNodeVisitor visitor);
|
||||
|
||||
@NotNull
|
||||
ArrangementSettingsNode clone();
|
||||
}
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.settings;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Strategy which hints on how arrangement settings should be grouped at the UI.
|
||||
* <p/>
|
||||
* Implementations of this interface are expected to be thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/15/12 4:21 PM
|
||||
*/
|
||||
public interface ArrangementSettingsGrouper {
|
||||
|
||||
/**
|
||||
* Allows to answer if and how should be grouped given settings.
|
||||
* <p/>
|
||||
* Example: given settings node is a composite <code>'AND'</code> node with the following conditions:
|
||||
* <code>'type: field; modifier: public; modifier: static; modifier: final'</code>. We might want to show it like below:
|
||||
* <pre>
|
||||
* field
|
||||
* |
|
||||
* ---public---static---final
|
||||
* </pre>
|
||||
* That means that we'll return a {@link HierarchicalArrangementSettingsNode} with condition <code>'type: field'</code> and
|
||||
* a single child node with composite <code>'AND'</code> condition <code>'modifier: public; modifier: static; modifier: final'</code>.
|
||||
*
|
||||
* @param node settings node which conditions should be grouped
|
||||
* @return grouping-aware node
|
||||
*/
|
||||
@NotNull
|
||||
HierarchicalArrangementSettingsNode group(@NotNull ArrangementSettingsNode node);
|
||||
}
|
||||
+5
-4
@@ -17,6 +17,7 @@ package com.intellij.psi.codeStyle.arrangement.settings;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.sort.ArrangementEntrySortType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -33,14 +34,14 @@ import java.util.List;
|
||||
public interface ArrangementStandardSettingsAware {
|
||||
|
||||
// TODO den add doc
|
||||
boolean isNameFilterEnabled(@Nullable ArrangementMatcherSettings current);
|
||||
boolean isNameFilterEnabled(@Nullable ArrangementSettingsNode current);
|
||||
|
||||
// TODO den add doc
|
||||
boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementMatcherSettings current);
|
||||
boolean isEnabled(@NotNull ArrangementEntryType type, @Nullable ArrangementSettingsNode current);
|
||||
|
||||
// TODO den add doc
|
||||
boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementMatcherSettings current);
|
||||
boolean isEnabled(@NotNull ArrangementModifier modifier, @Nullable ArrangementSettingsNode current);
|
||||
|
||||
// TODO den add doc
|
||||
boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementMatcherSettings current);
|
||||
boolean isEnabled(@NotNull ArrangementEntrySortType type, @Nullable ArrangementSettingsNode current);
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.settings;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/15/12 4:23 PM
|
||||
*/
|
||||
public class DefaultArrangementSettingsGrouper implements ArrangementSettingsGrouper {
|
||||
|
||||
@NotNull public static final DefaultArrangementSettingsGrouper INSTANCE = new DefaultArrangementSettingsGrouper();
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public HierarchicalArrangementSettingsNode group(@NotNull ArrangementSettingsNode node) {
|
||||
// Don't group.
|
||||
return new HierarchicalArrangementSettingsNode(node);
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* 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.settings.group;
|
||||
|
||||
/**
|
||||
* // TODO den add doc
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/8/12 12:29 PM
|
||||
*/
|
||||
public interface ArrangementSettingsNodeGrouper {
|
||||
}
|
||||
+1
-1
@@ -135,7 +135,7 @@ public class ArrangementAndNodeComponent extends JPanel implements ArrangementNo
|
||||
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
Point point = ArrangementSettingsUtil.getLocationOnScreen(this);
|
||||
Point point = ArrangementConfigUtil.getLocationOnScreen(this);
|
||||
if (point != null) {
|
||||
Rectangle bounds = getBounds();
|
||||
myScreenBounds = new Rectangle(point.x, point.y, bounds.width, bounds.height);
|
||||
|
||||
+2
-3
@@ -16,7 +16,6 @@
|
||||
package com.intellij.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.ui.IdeBorderFactory;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.util.ui.GridBag;
|
||||
@@ -40,7 +39,7 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
|
||||
@NotNull private final JPanel myRenderer = new JPanel(new GridBagLayout()) {
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
Point point = ArrangementSettingsUtil.getLocationOnScreen(this);
|
||||
Point point = ArrangementConfigUtil.getLocationOnScreen(this);
|
||||
if (point != null) {
|
||||
Rectangle bounds = myRenderer.getBounds();
|
||||
myScreenBounds = new Rectangle(point.x, point.y, bounds.width, bounds.height);
|
||||
@@ -114,7 +113,7 @@ public class ArrangementAtomNodeComponent implements ArrangementNodeComponent {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrangementSettingsNode getSettingsNode() {
|
||||
public ArrangementSettingsAtomNode getSettingsNode() {
|
||||
return mySettingsNode;
|
||||
}
|
||||
|
||||
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Contains various utility methods to be used during showing arrangement settings.
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/8/12 9:14 AM
|
||||
*/
|
||||
public class ArrangementConfigUtil {
|
||||
|
||||
private ArrangementConfigUtil() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to answer what new settings are available for a particular {@link ArrangementMatcherSettings arrangement matcher rules}.
|
||||
*
|
||||
* @param filter filter to use
|
||||
* @param settings object that encapsulates information about current arrangement matcher settings
|
||||
* @return map which contains information on what new new settings are available at the current situation
|
||||
*/
|
||||
@NotNull
|
||||
public static Map<ArrangementSettingType, Collection<?>> buildAvailableOptions(@NotNull ArrangementStandardSettingsAware filter,
|
||||
@Nullable ArrangementSettingsNode settings)
|
||||
{
|
||||
Map<ArrangementSettingType, Collection<?>> result = new EnumMap<ArrangementSettingType, Collection<?>>(ArrangementSettingType.class);
|
||||
processData(filter, settings, result, ArrangementSettingType.TYPE, ArrangementEntryType.values());
|
||||
processData(filter, settings, result, ArrangementSettingType.MODIFIER, ArrangementModifier.values());
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <T> void processData(@NotNull ArrangementStandardSettingsAware filter,
|
||||
@Nullable ArrangementSettingsNode settings,
|
||||
@NotNull Map<ArrangementSettingType, Collection<?>> result,
|
||||
@NotNull ArrangementSettingType type,
|
||||
@NotNull T[] values)
|
||||
{
|
||||
List<T> data = null;
|
||||
for (T v : values) {
|
||||
if (!isEnabled(v, filter, settings)) {
|
||||
continue;
|
||||
}
|
||||
if (data == null) {
|
||||
data = new ArrayList<T>();
|
||||
}
|
||||
data.add(v);
|
||||
}
|
||||
if (data != null) {
|
||||
result.put(type, data);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isEnabled(@NotNull Object conditionId,
|
||||
@NotNull ArrangementStandardSettingsAware filter,
|
||||
@Nullable ArrangementSettingsNode settings)
|
||||
{
|
||||
if (conditionId instanceof ArrangementEntryType) {
|
||||
return filter.isEnabled((ArrangementEntryType)conditionId, settings);
|
||||
}
|
||||
else if (conditionId instanceof ArrangementModifier) {
|
||||
return filter.isEnabled((ArrangementModifier)conditionId, settings);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Point getLocationOnScreen(@NotNull JComponent component) {
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
for (Container c = component; c != null; c = c.getParent()) {
|
||||
if (c.isShowing()) {
|
||||
Point locationOnScreen = c.getLocationOnScreen();
|
||||
locationOnScreen.translate(dx, dy);
|
||||
return locationOnScreen;
|
||||
}
|
||||
else {
|
||||
Point location = c.getLocation();
|
||||
dx += location.x;
|
||||
dy += location.y;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+63
-41
@@ -16,11 +16,8 @@
|
||||
package com.intellij.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryMatcher;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
|
||||
import com.intellij.util.ui.GridBag;
|
||||
import com.intellij.util.ui.MultiRowFlowPanel;
|
||||
@@ -29,6 +26,8 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
@@ -47,18 +46,25 @@ public class ArrangementMatcherRuleEditor extends JPanel {
|
||||
new HashMap<Object, ArrangementAtomNodeComponent>();
|
||||
|
||||
@NotNull private final ArrangementStandardSettingsAware myFilter;
|
||||
@Nullable private ArrangementRuleEditingModel myModel;
|
||||
|
||||
public ArrangementMatcherRuleEditor(@NotNull ArrangementStandardSettingsAware filter,
|
||||
@NotNull ArrangementNodeDisplayManager displayManager)
|
||||
{
|
||||
myFilter = filter;
|
||||
init(displayManager);
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
onMouseClicked(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void init(@NotNull ArrangementNodeDisplayManager displayManager) {
|
||||
setLayout(new GridBagLayout());
|
||||
|
||||
Map<ArrangementSettingType, Collection<?>> supportedSettings = ArrangementSettingsUtil.buildAvailableOptions(myFilter, null);
|
||||
Map<ArrangementSettingType, Collection<?>> supportedSettings = ArrangementConfigUtil.buildAvailableOptions(myFilter, null);
|
||||
addRowIfPossible(ArrangementSettingType.TYPE, supportedSettings, displayManager);
|
||||
addRowIfPossible(ArrangementSettingType.MODIFIER, supportedSettings, displayManager);
|
||||
}
|
||||
@@ -78,7 +84,7 @@ public class ArrangementMatcherRuleEditor extends JPanel {
|
||||
myComponents.put(value, component);
|
||||
valuesPanel.add(component.getUiComponent());
|
||||
}
|
||||
|
||||
|
||||
int top = ArrangementAtomNodeComponent.PADDING;
|
||||
add(new JLabel(manager.getDisplayLabel(key) + ":"), new GridBag().anchor(GridBagConstraints.NORTHWEST).insets(top, 0, 0, 0));
|
||||
add(valuesPanel, new GridBag().anchor(GridBagConstraints.WEST).weightx(1).fillCellHorizontally().coverLine());
|
||||
@@ -89,52 +95,68 @@ public class ArrangementMatcherRuleEditor extends JPanel {
|
||||
* Asks current editor to refresh its state in accordance with the given arguments (e.g. when new rule is selected and
|
||||
* we want to show only available conditions).
|
||||
*
|
||||
* @param settings current rule settings if defined; null as an indication that no settings should be active
|
||||
* @param model current rule settings model if defined; null as an indication that no settings should be active
|
||||
*/
|
||||
public void updateState(@Nullable ArrangementMatcherSettings settings) {
|
||||
for (ArrangementEntryType type : ArrangementEntryType.values()) {
|
||||
ArrangementAtomNodeComponent component = myComponents.get(type);
|
||||
if (component == null) {
|
||||
continue;
|
||||
}
|
||||
boolean enabled;
|
||||
boolean selected;
|
||||
if (settings == null) {
|
||||
enabled = false;
|
||||
selected = false;
|
||||
}
|
||||
else {
|
||||
enabled = myFilter.isEnabled(type, settings);
|
||||
selected = settings.hasCondition(type);
|
||||
}
|
||||
component.setEnabled(enabled);
|
||||
component.setSelected(selected);
|
||||
public void updateState(@Nullable ArrangementRuleEditingModel model) {
|
||||
myModel = model;
|
||||
|
||||
// Reset state.
|
||||
for (ArrangementAtomNodeComponent component : myComponents.values()) {
|
||||
component.setEnabled(false);
|
||||
component.setSelected(false);
|
||||
}
|
||||
for (ArrangementModifier modifier : ArrangementModifier.values()) {
|
||||
ArrangementAtomNodeComponent component = myComponents.get(modifier);
|
||||
if (component == null) {
|
||||
continue;
|
||||
|
||||
if (model == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<ArrangementSettingType, Collection<?>> available = ArrangementConfigUtil.buildAvailableOptions(myFilter, model.getSettingsNode());
|
||||
for (Collection<?> ids : available.values()) {
|
||||
for (Object id : ids) {
|
||||
ArrangementAtomNodeComponent component = myComponents.get(id);
|
||||
if (component != null) {
|
||||
component.setEnabled(true);
|
||||
component.setSelected(model.hasCondition(id));
|
||||
}
|
||||
}
|
||||
boolean enabled;
|
||||
boolean selected;
|
||||
if (settings == null) {
|
||||
enabled = false;
|
||||
selected = false;
|
||||
}
|
||||
else {
|
||||
enabled = myFilter.isEnabled(modifier, settings);
|
||||
selected = settings.hasCondition(modifier);
|
||||
}
|
||||
component.setEnabled(enabled);
|
||||
component.setSelected(selected);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public void applyBackground(@NotNull Color color) {
|
||||
setBackground(color);
|
||||
for (JComponent component : myColoredComponents) {
|
||||
component.setBackground(color);
|
||||
}
|
||||
}
|
||||
|
||||
private void onMouseClicked(@NotNull MouseEvent e) {
|
||||
if (myModel == null) {
|
||||
return;
|
||||
}
|
||||
ArrangementAtomNodeComponent component = getNodeComponentAt(e.getLocationOnScreen());
|
||||
if (component == null) {
|
||||
return;
|
||||
}
|
||||
ArrangementSettingsAtomNode settingsNode = component.getSettingsNode();
|
||||
boolean remove = myModel.hasCondition(settingsNode.getValue());
|
||||
component.setSelected(!remove);
|
||||
if (remove) {
|
||||
myModel.removeAndCondition(settingsNode);
|
||||
}
|
||||
else {
|
||||
myModel.addAndCondition(settingsNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private ArrangementAtomNodeComponent getNodeComponentAt(@NotNull Point screenPoint) {
|
||||
for (ArrangementAtomNodeComponent component : myComponents.values()) {
|
||||
Rectangle screenBounds = component.getScreenBounds();
|
||||
if (screenBounds != null && screenBounds.contains(screenPoint)) {
|
||||
return component;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ public class ArrangementNodeDisplayManager {
|
||||
@NotNull ArrangementStandardSettingsRepresentationAware representationManager)
|
||||
{
|
||||
myRepresentationManager = representationManager;
|
||||
Map<ArrangementSettingType, Collection<?>> map = ArrangementSettingsUtil.buildAvailableOptions(filter, null);
|
||||
Map<ArrangementSettingType, Collection<?>> map = ArrangementConfigUtil.buildAvailableOptions(filter, null);
|
||||
for (Map.Entry<ArrangementSettingType, Collection<?>> entry : map.entrySet()) {
|
||||
myMaxWidths.put(entry.getKey(), maxWidth(entry.getValue()));
|
||||
}
|
||||
|
||||
+2
-3
@@ -15,16 +15,15 @@
|
||||
*/
|
||||
package com.intellij.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/15/12 9:14 AM
|
||||
*/
|
||||
public interface ArrangementMatcherEditingListener {
|
||||
public interface ArrangementRuleEditingListener {
|
||||
|
||||
void startEditing(@NotNull ArrangementMatcherSettings settings);
|
||||
void startEditing(@NotNull ArrangementRuleEditingModel settings);
|
||||
|
||||
void stopEditing();
|
||||
}
|
||||
+51
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* Combines and encapsulates information about arrangement matcher rules representation (tree nodes) and
|
||||
* underlying {@link ArrangementSettingsNode data model}.
|
||||
* <p/>
|
||||
* Implementations of this interface are not obliged to be thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/15/12 1:04 PM
|
||||
*/
|
||||
public interface ArrangementRuleEditingModel {
|
||||
|
||||
@NotNull
|
||||
ArrangementSettingsNode getSettingsNode();
|
||||
|
||||
/**
|
||||
* Allows to answer if current model has a registered condition for the given key. A key is expected to be one of the standard
|
||||
* keys, e.g. {@link ArrangementEntryType type}, {@link ArrangementModifier modifier} etc.
|
||||
*
|
||||
* @param key target key
|
||||
* @return <code>true</code> if current model has a registered mapping for the given key;
|
||||
* <code>false</code> otherwise
|
||||
*/
|
||||
boolean hasCondition(@NotNull Object key);
|
||||
|
||||
void addAndCondition(@NotNull ArrangementSettingsAtomNode node);
|
||||
|
||||
void removeAndCondition(@NotNull ArrangementSettingsNode node);
|
||||
}
|
||||
+71
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettingsGrouper;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsRepresentationAware;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
/**
|
||||
* Holds glue logic between arrangement settings and their representation -
|
||||
* '{@link ArrangementSettingsNode} -> {@link ArrangementRuleEditingModel}'
|
||||
* <p/>
|
||||
* Thread-safe.
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/15/12 2:50 PM
|
||||
*/
|
||||
public class ArrangementRuleEditingModelBuilder {
|
||||
|
||||
/**
|
||||
* Does the following:
|
||||
* <pre>
|
||||
* <ol>
|
||||
* <li>
|
||||
* {@link HierarchicalArrangementSettingsNode Groups} given {@link ArrangementSettingsNode settings} using
|
||||
* the given {@link ArrangementStandardSettingsRepresentationAware#group(ArrangementSettingsNode) strategy};
|
||||
* </li>
|
||||
* <li>
|
||||
* Build {@link DefaultMutableTreeNode tree nodes} for the {@link HierarchicalArrangementSettingsNode groiping-aware nodes}
|
||||
* and register them within the target tree structure (denoted by the given settings root element);
|
||||
* </li>
|
||||
* <li>
|
||||
* Build necessary {@link ArrangementRuleEditingModel editing models} and store them at the given container (a key is a node row);
|
||||
* </li>
|
||||
* </ol>
|
||||
* </pre>
|
||||
*
|
||||
* @param setting target settings to process
|
||||
* @param root UI tree settings root to use
|
||||
* @param grouper strategy that knows how to
|
||||
* {@link ArrangementStandardSettingsRepresentationAware#getDisplayValue(ArrangementModifier) group} setting
|
||||
* nodes for UI representation
|
||||
* @param rowMappings container to hold built {@link ArrangementRuleEditingModel editing models} (UI tree row numbers are used as keys)
|
||||
*/
|
||||
public void build(@NotNull ArrangementSettingsNode setting,
|
||||
@NotNull DefaultMutableTreeNode root,
|
||||
@NotNull ArrangementSettingsGrouper grouper,
|
||||
@NotNull TIntObjectHashMap<ArrangementRuleEditingModel> rowMappings)
|
||||
{
|
||||
HierarchicalArrangementSettingsNode grouped = grouper.group(setting);
|
||||
}
|
||||
}
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/15/12 2:40 PM
|
||||
*/
|
||||
public class ArrangementRuleEditingModelImpl implements ArrangementRuleEditingModel {
|
||||
|
||||
@NotNull private ArrangementSettingsNode mySettingsNode;
|
||||
|
||||
public ArrangementRuleEditingModelImpl(@NotNull ArrangementSettingsNode node) {
|
||||
mySettingsNode = node;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrangementSettingsNode getSettingsNode() {
|
||||
return mySettingsNode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCondition(@NotNull Object key) {
|
||||
// TODO den implement
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAndCondition(@NotNull ArrangementSettingsAtomNode node) {
|
||||
// TODO den implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAndCondition(@NotNull ArrangementSettingsNode node) {
|
||||
// TODO den implement
|
||||
}
|
||||
}
|
||||
+52
-77
@@ -17,8 +17,11 @@ package com.intellij.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.*;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsAtomNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsCompositeNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementSettingsGrouper;
|
||||
import com.intellij.ui.awt.RelativePoint;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
@@ -43,18 +46,20 @@ import java.util.List;
|
||||
*/
|
||||
public class ArrangementRuleTree {
|
||||
|
||||
@NotNull private final List<ArrangementMatcherEditingListener> myListeners = new ArrayList<ArrangementMatcherEditingListener>();
|
||||
@NotNull private final TreeSelectionModel mySelectionModel = new MySelectionModel();
|
||||
@NotNull private final TIntObjectHashMap<ArrangementNodeComponent> myRenderers = new TIntObjectHashMap<ArrangementNodeComponent>();
|
||||
@NotNull private final TIntObjectHashMap<ArrangementMatcherSettings> mySettings =
|
||||
new TIntObjectHashMap<ArrangementMatcherSettings>();
|
||||
@NotNull private final List<ArrangementRuleEditingListener> myListeners = new ArrayList<ArrangementRuleEditingListener>();
|
||||
@NotNull private final TreeSelectionModel mySelectionModel = new MySelectionModel();
|
||||
|
||||
@NotNull private final Tree myTree;
|
||||
@NotNull private final ArrangementNodeComponentFactory myFactory;
|
||||
@NotNull private final TIntObjectHashMap<ArrangementNodeComponent> myRenderers =
|
||||
new TIntObjectHashMap<ArrangementNodeComponent>();
|
||||
@NotNull private final TIntObjectHashMap<ArrangementRuleEditingModel> myModels =
|
||||
new TIntObjectHashMap<ArrangementRuleEditingModel>();
|
||||
|
||||
@NotNull private final Tree myTree;
|
||||
@NotNull private final ArrangementNodeComponentFactory myFactory;
|
||||
|
||||
private boolean mySkipSelectionChange;
|
||||
|
||||
public ArrangementRuleTree(@NotNull ArrangementNodeDisplayManager displayManager) {
|
||||
public ArrangementRuleTree(@NotNull ArrangementSettingsGrouper grouper, @NotNull ArrangementNodeDisplayManager displayManager) {
|
||||
myFactory = new ArrangementNodeComponentFactory(displayManager);
|
||||
DefaultMutableTreeNode root = new DefaultMutableTreeNode();
|
||||
DefaultTreeModel treeModel = new DefaultTreeModel(root);
|
||||
@@ -102,32 +107,23 @@ public class ArrangementRuleTree {
|
||||
onMouseClicked(e);
|
||||
}
|
||||
});
|
||||
|
||||
ArrangementSettingsCompositeNode constants = new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND);
|
||||
constants.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC));
|
||||
constants.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.STATIC));
|
||||
constants.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.FINAL));
|
||||
|
||||
ArrangementSettingsCompositeNode privateFields = new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND);
|
||||
privateFields.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE));
|
||||
|
||||
HierarchicalArrangementSettingsNode fields = new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode(
|
||||
ArrangementSettingType.TYPE, ArrangementEntryType.FIELD
|
||||
));
|
||||
fields.addChild(new HierarchicalArrangementSettingsNode(constants));
|
||||
fields.addChild(new HierarchicalArrangementSettingsNode(privateFields));
|
||||
int row = map(root, fields, null, 0);
|
||||
|
||||
HierarchicalArrangementSettingsNode methods = new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode(
|
||||
ArrangementSettingType.TYPE, ArrangementEntryType.METHOD
|
||||
));
|
||||
methods.addChild(new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode(
|
||||
ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC
|
||||
)));
|
||||
methods.addChild(new HierarchicalArrangementSettingsNode(new ArrangementSettingsAtomNode(
|
||||
ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE
|
||||
)));
|
||||
map(root, methods, null, row);
|
||||
|
||||
List<ArrangementSettingsNode> rules = new ArrayList<ArrangementSettingsNode>();
|
||||
rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND)
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.FIELD))
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC))
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.STATIC))
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.FINAL)));
|
||||
rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND)
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.FIELD))
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE)));
|
||||
rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND)
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.METHOD))
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PUBLIC)));
|
||||
rules.add(new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND)
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.TYPE, ArrangementEntryType.METHOD))
|
||||
.addOperand(new ArrangementSettingsAtomNode(ArrangementSettingType.MODIFIER, ArrangementModifier.PRIVATE)));
|
||||
map(root, rules, grouper);
|
||||
|
||||
expandAll(myTree, new TreePath(root));
|
||||
myTree.setRootVisible(false);
|
||||
@@ -168,58 +164,37 @@ public class ArrangementRuleTree {
|
||||
tree.expandPath(parent);
|
||||
}
|
||||
|
||||
private int map(@NotNull DefaultMutableTreeNode parentTreeNode,
|
||||
@NotNull HierarchicalArrangementSettingsNode settingsNode,
|
||||
@Nullable ArrangementSettingsCompositeNode template,
|
||||
int row)
|
||||
private void map(@NotNull DefaultMutableTreeNode root,
|
||||
@NotNull List<ArrangementSettingsNode> settings,
|
||||
@NotNull ArrangementSettingsGrouper grouper)
|
||||
{
|
||||
DefaultMutableTreeNode childTreeNode = new DefaultMutableTreeNode(settingsNode.getCurrent());
|
||||
parentTreeNode.add(childTreeNode);
|
||||
List<HierarchicalArrangementSettingsNode> children = settingsNode.getChildren();
|
||||
if (children.isEmpty()) {
|
||||
ArrangementMatcherSettings settings = new ArrangementMatcherSettings();
|
||||
ArrangementSettingsNode condition;
|
||||
if (template == null) {
|
||||
condition = settingsNode.getCurrent();
|
||||
}
|
||||
else {
|
||||
condition = template.clone().addOperand(settingsNode.getCurrent());
|
||||
}
|
||||
settings.addCondition(condition);
|
||||
mySettings.put(row, settings);
|
||||
return row + 1;
|
||||
}
|
||||
else {
|
||||
row++;
|
||||
ArrangementSettingsCompositeNode newTemplate =
|
||||
template == null ? new ArrangementSettingsCompositeNode(ArrangementSettingsCompositeNode.Operator.AND)
|
||||
: template.clone();
|
||||
newTemplate.addOperand(settingsNode.getCurrent());
|
||||
for (HierarchicalArrangementSettingsNode node : children) {
|
||||
row = map(childTreeNode, node, newTemplate, row);
|
||||
}
|
||||
return row;
|
||||
ArrangementRuleEditingModelBuilder builder = new ArrangementRuleEditingModelBuilder();
|
||||
for (ArrangementSettingsNode setting : settings) {
|
||||
builder.build(setting, root, grouper, myModels);
|
||||
}
|
||||
}
|
||||
|
||||
public void addEditingListener(@NotNull ArrangementMatcherEditingListener listener) {
|
||||
public void addEditingListener(@NotNull ArrangementRuleEditingListener listener) {
|
||||
myListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return matcher settings for the selected tree row(s) if any; null otherwise
|
||||
* @return matcher model for the selected tree row(s) if any; null otherwise
|
||||
*/
|
||||
@Nullable
|
||||
public ArrangementMatcherSettings getActiveSettings() {
|
||||
public ArrangementRuleEditingModel getActiveModel() {
|
||||
TreePath[] paths = mySelectionModel.getSelectionPaths();
|
||||
if (paths == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// There is a possible case that particular settings node is represented on multiple rows and that non-leaf nodes are served
|
||||
// for more than one rule. No model is registered for them then and we want just to skip them.
|
||||
for (int i = paths.length - 1; i >= 0; i--) {
|
||||
int row = myTree.getRowForPath(paths[i]);
|
||||
ArrangementMatcherSettings settings = mySettings.get(row);
|
||||
if (settings != null) {
|
||||
return settings;
|
||||
ArrangementRuleEditingModel model = myModels.get(row);
|
||||
if (model != null) {
|
||||
return model;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -296,13 +271,13 @@ public class ArrangementRuleTree {
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyEditingListeners(@Nullable ArrangementMatcherSettings settings) {
|
||||
for (ArrangementMatcherEditingListener listener : myListeners) {
|
||||
if (settings == null) {
|
||||
private void notifyEditingListeners(@Nullable ArrangementRuleEditingModel model) {
|
||||
for (ArrangementRuleEditingListener listener : myListeners) {
|
||||
if (model == null) {
|
||||
listener.stopEditing();
|
||||
}
|
||||
else {
|
||||
listener.startEditing(settings);
|
||||
listener.startEditing(model);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,7 +303,7 @@ public class ArrangementRuleTree {
|
||||
public void setSelectionPath(TreePath path) {
|
||||
if (!mySkipSelectionChange) {
|
||||
super.setSelectionPath(path);
|
||||
notifyEditingListeners(getActiveSettings());
|
||||
notifyEditingListeners(getActiveModel());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-8
@@ -22,10 +22,7 @@ import com.intellij.openapi.editor.colors.EditorColorsScheme;
|
||||
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.psi.codeStyle.CodeStyleSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsRepresentationAware;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.DefaultArrangementSettingsRepresentationManager;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.*;
|
||||
import com.intellij.ui.components.JBScrollPane;
|
||||
import com.intellij.ui.treeStructure.Tree;
|
||||
import com.intellij.util.ui.GridBag;
|
||||
@@ -54,8 +51,12 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel {
|
||||
representationManager = (ArrangementStandardSettingsRepresentationAware)filter;
|
||||
}
|
||||
ArrangementNodeDisplayManager displayManager = new ArrangementNodeDisplayManager(filter, representationManager);
|
||||
ArrangementSettingsGrouper grouper = DefaultArrangementSettingsGrouper.INSTANCE;
|
||||
if (filter instanceof ArrangementSettingsGrouper) {
|
||||
grouper = (ArrangementSettingsGrouper)filter;
|
||||
}
|
||||
|
||||
final ArrangementRuleTree ruleTree = new ArrangementRuleTree(displayManager);
|
||||
final ArrangementRuleTree ruleTree = new ArrangementRuleTree(grouper, displayManager);
|
||||
Tree component = ruleTree.getTreeComponent();
|
||||
myContent.add(new JBScrollPane(component), new GridBag().weightx(1).weighty(1).fillCell().coverLine());
|
||||
CustomizationUtil.installPopupHandler(
|
||||
@@ -78,10 +79,10 @@ public abstract class ArrangementSettingsPanel extends CodeStyleAbstractPanel {
|
||||
}
|
||||
}
|
||||
});
|
||||
ruleTree.addEditingListener(new ArrangementMatcherEditingListener() {
|
||||
ruleTree.addEditingListener(new ArrangementRuleEditingListener() {
|
||||
@Override
|
||||
public void startEditing(@NotNull ArrangementMatcherSettings settings) {
|
||||
ruleEditor.updateState(settings);
|
||||
public void startEditing(@NotNull ArrangementRuleEditingModel model) {
|
||||
ruleEditor.updateState(model);
|
||||
resetEditor.set(Boolean.FALSE);
|
||||
try {
|
||||
editorPane.setCollapsed(false);
|
||||
|
||||
-177
@@ -1,177 +0,0 @@
|
||||
/*
|
||||
* 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.application.options.codeStyle.arrangement;
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext;
|
||||
import com.intellij.openapi.actionSystem.DataKey;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementEntryType;
|
||||
import com.intellij.psi.codeStyle.arrangement.match.ArrangementModifier;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingType;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.ArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.model.HierarchicalArrangementSettingsNode;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementMatcherSettings;
|
||||
import com.intellij.psi.codeStyle.arrangement.settings.ArrangementStandardSettingsAware;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import javax.swing.*;
|
||||
import java.awt.*;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* // TODO den add doc
|
||||
*
|
||||
* @author Denis Zhdanov
|
||||
* @since 8/8/12 9:14 AM
|
||||
*/
|
||||
public class ArrangementSettingsUtil {
|
||||
|
||||
public static final DataKey<ArrangementNodeComponent> NODE_COMPONENT = DataKey.create("Arrangement.Rule.Editor.Node.Component");
|
||||
public static final DataKey<ArrangementStandardSettingsAware> FILTER = DataKey.create("Arrangement.Rule.Editor.Settings.Filter");
|
||||
public static final DataKey<ArrangementNodeDisplayManager> DISPLAY_MANAGER = DataKey.create("Arrangement.Rule.Editor.Display.Manager");
|
||||
public static final DataKey<ArrangementMatcherSettings> SETTINGS = DataKey.create("Arrangement.Rule.Editor.Matcher.Settings");
|
||||
public static final DataKey<JComponent> TREE = DataKey.create("Arrangement.Rule.Editor.Tree");
|
||||
|
||||
private static final EntryTypeHelper ENTRY_TYPE_HELPER = new EntryTypeHelper();
|
||||
private static final ModifierHelper MODIFIER_HELPER = new ModifierHelper();
|
||||
|
||||
private ArrangementSettingsUtil() {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static ArrangementSettingsNode getSettingsNode(@NotNull DataContext context) {
|
||||
ArrangementNodeComponent nodeComponent = NODE_COMPONENT.getData(context);
|
||||
return nodeComponent == null ? null : nodeComponent.getSettingsNode();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static HierarchicalArrangementSettingsNode buildTreeStructure(@NotNull ArrangementSettingsNode modelNode) {
|
||||
// TODO den implement
|
||||
return new HierarchicalArrangementSettingsNode(modelNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Serves for the same purposes as {@link #buildAvailableOptions(ArrangementStandardSettingsAware, ArrangementMatcherSettings)} but
|
||||
* retrieves necessary information from the given context.
|
||||
*
|
||||
* @param context target information holder
|
||||
* @return map which contains information on what new new settings are available at the current situation
|
||||
*/
|
||||
@NotNull
|
||||
public static Map<ArrangementSettingType, Collection<?>> buildAvailableOptions(@NotNull DataContext context) {
|
||||
ArrangementStandardSettingsAware filter = FILTER.getData(context);
|
||||
if (filter == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
return buildAvailableOptions(filter, SETTINGS.getData(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows to answer what new settings are available for a particular {@link ArrangementMatcherSettings arrangement matcher rules}.
|
||||
*
|
||||
* @param filter filter to use
|
||||
* @param settings object that encapsulates information about current arrangement matcher settings
|
||||
* @return map which contains information on what new new settings are available at the current situation
|
||||
*/
|
||||
@NotNull
|
||||
public static Map<ArrangementSettingType, Collection<?>> buildAvailableOptions(@NotNull ArrangementStandardSettingsAware filter,
|
||||
@Nullable ArrangementMatcherSettings settings)
|
||||
{
|
||||
Map<ArrangementSettingType, Collection<?>> result = new EnumMap<ArrangementSettingType, Collection<?>>(ArrangementSettingType.class);
|
||||
processData(filter, settings, result, ArrangementEntryType.values(), ENTRY_TYPE_HELPER);
|
||||
processData(filter, settings, result, ArrangementModifier.values(), MODIFIER_HELPER);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static <T> void processData(@NotNull ArrangementStandardSettingsAware filter,
|
||||
@Nullable ArrangementMatcherSettings settings,
|
||||
Map<ArrangementSettingType, Collection<?>> result,
|
||||
@NotNull T[] values,
|
||||
@NotNull Helper<T> helper)
|
||||
{
|
||||
List<T> data = null;
|
||||
for (T v : values) {
|
||||
if (!helper.isEnabled(v, filter, settings)) {
|
||||
continue;
|
||||
}
|
||||
if (data == null) {
|
||||
data = new ArrayList<T>();
|
||||
}
|
||||
data.add(v);
|
||||
}
|
||||
if (data != null) {
|
||||
result.put(helper.getType(), data);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Point getLocationOnScreen(@NotNull JComponent component) {
|
||||
int dx = 0;
|
||||
int dy = 0;
|
||||
for (Container c = component; c != null; c = c.getParent()) {
|
||||
if (c.isShowing()) {
|
||||
Point locationOnScreen = c.getLocationOnScreen();
|
||||
locationOnScreen.translate(dx, dy);
|
||||
return locationOnScreen;
|
||||
}
|
||||
else {
|
||||
Point location = c.getLocation();
|
||||
dx += location.x;
|
||||
dy += location.y;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private interface Helper<T> {
|
||||
@NotNull ArrangementSettingType getType();
|
||||
boolean isEnabled(@NotNull T data, @NotNull ArrangementStandardSettingsAware filter, @Nullable ArrangementMatcherSettings settings);
|
||||
}
|
||||
|
||||
private static class EntryTypeHelper implements Helper<ArrangementEntryType> {
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrangementSettingType getType() {
|
||||
return ArrangementSettingType.TYPE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NotNull ArrangementEntryType data,
|
||||
@NotNull ArrangementStandardSettingsAware filter,
|
||||
@Nullable ArrangementMatcherSettings settings)
|
||||
{
|
||||
return filter.isEnabled(data, settings);
|
||||
}
|
||||
}
|
||||
|
||||
private static class ModifierHelper implements Helper<ArrangementModifier> {
|
||||
@NotNull
|
||||
@Override
|
||||
public ArrangementSettingType getType() {
|
||||
return ArrangementSettingType.MODIFIER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(@NotNull ArrangementModifier data,
|
||||
@NotNull ArrangementStandardSettingsAware filter,
|
||||
@Nullable ArrangementMatcherSettings settings)
|
||||
{
|
||||
return filter.isEnabled(data, settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,7 +173,8 @@ public class StructureViewWrapperImpl implements StructureViewWrapper, Disposabl
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
public void dispose() {
|
||||
rebuild();
|
||||
//we don't really need it
|
||||
//rebuild();
|
||||
}
|
||||
|
||||
public boolean selectCurrentElement(final FileEditor fileEditor, final VirtualFile file, final boolean requestFocus) {
|
||||
|
||||
@@ -415,10 +415,10 @@ checkbox.indent.absolute.label.indent=Absolute label indent
|
||||
checkbox.do.not.indent.top.level.class.members=Do not indent top level class members
|
||||
checkbox.use.relative.indents=Use indents relative to expression start
|
||||
tooltip.indent.must.be.multiple.of.tab.size.for.smart.tabs.to.operate=Indent must be multiple of tab size for smart tabs to operate
|
||||
combobox.crlf.system.dependent=System Dependent
|
||||
combobox.crlf.unix=Unix \n
|
||||
combobox.crlf.windows=Windows \r\n
|
||||
combobox.crlf.mac=Mac \r
|
||||
combobox.crlf.system.dependent=System-Dependent
|
||||
combobox.crlf.unix=Unix and OS X (\\n)
|
||||
combobox.crlf.windows=Windows (\\r\\n)
|
||||
combobox.crlf.mac=Classic Mac (\\r)
|
||||
group.tabs.and.indents=Tabs and Indents
|
||||
checkbox.indent.use.same.settings.for.all.file.types=Use default indent options (General)
|
||||
tab.indent.other=Other
|
||||
@@ -554,4 +554,4 @@ arrangement.title.settings.tab=Arrangement
|
||||
arrangement.title.editor=Edit rule
|
||||
arrangement.text.type=Type
|
||||
arrangement.text.modifier=Modifier
|
||||
arrangement.text.negate=Negate
|
||||
arrangement.text.negate=Negate
|
||||
|
||||
@@ -216,7 +216,9 @@
|
||||
serviceImplementation="org.jetbrains.android.exportSignedPackage.GenerateSignedApkSettings"/>
|
||||
<compilerSettingsFactory implementation="org.jetbrains.android.compiler.AndroidDexCompilerSettingsFactory"/>
|
||||
<problemFileHighlightFilter implementation="org.jetbrains.android.AndroidProblemFileHighlightingFilter"/>
|
||||
|
||||
<lang.documentationProvider language="JAVA" implementationClass="org.jetbrains.android.AndroidDocumentationProvider" order="first"/>
|
||||
<lang.documentationProvider language="XML" implementationClass="org.jetbrains.android.dom.AndroidXmlDocumentationProvider" order="first"/>
|
||||
|
||||
<sdkType implementation="org.jetbrains.android.sdk.AndroidSdkType"/>
|
||||
<gotoDeclarationHandler implementation="org.jetbrains.android.AndroidGotoDeclarationHandler"/>
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.jetbrains.android.dom;
|
||||
|
||||
import com.intellij.lang.documentation.DocumentationProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper;
|
||||
import org.jetbrains.android.resourceManagers.ValueResourceInfo;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidXmlDocumentationProvider implements DocumentationProvider {
|
||||
@Override
|
||||
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
|
||||
if (element instanceof LazyValueResourceElementWrapper) {
|
||||
final ValueResourceInfo info = ((LazyValueResourceElementWrapper)element).getResourceInfo();
|
||||
return "value resource '" + info.getName() + "' [" + info.getContainingFile().getName() + "]";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getUrlFor(PsiElement element, PsiElement originalElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getDocumentationElementForLookupItem(PsiManager psiManager, Object object, PsiElement element) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiElement getDocumentationElementForLink(PsiManager psiManager, String link, PsiElement context) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+5
-1
@@ -425,14 +425,18 @@ public class AndroidLayoutPreviewToolWindowManager implements ProjectComponent {
|
||||
catch (RenderingException e) {
|
||||
LOG.debug(e);
|
||||
String message = e.getPresentableMessage();
|
||||
message = message != null ? message : AndroidBundle.message("android.layout.preview.default.error.message");
|
||||
final Throwable[] causes = e.getCauses();
|
||||
message = message != null ? message : AndroidBundle.message("android.layout.preview.default.error.message");
|
||||
errorMessage = causes.length > 0 ? new FixableIssueMessage(message + ' ', "Details", "", new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showStackStace(causes);
|
||||
}
|
||||
}) : new FixableIssueMessage(message);
|
||||
|
||||
if (causes.length == 0) {
|
||||
warnMessages.addAll(e.getWarnMessages());
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
|
||||
@@ -23,11 +23,16 @@ import com.android.ide.common.resources.IntArrayWrapper;
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.android.util.Pair;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.module.Module;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import gnu.trove.TIntObjectHashMap;
|
||||
import gnu.trove.TObjectIntHashMap;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -50,6 +55,7 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback {
|
||||
private final Set<String> myClassesWithIncorrectFormat = new HashSet<String>();
|
||||
|
||||
private final Map<String, Class<?>> myLoadedClasses = new HashMap<String, Class<?>>();
|
||||
private boolean myHasProjectLoadedClasses = false;
|
||||
|
||||
private ProjectClassLoader myProjectClassLoader = null;
|
||||
private final ClassLoader myParentClassLoader;
|
||||
@@ -104,14 +110,14 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback {
|
||||
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
|
||||
@Nullable
|
||||
public Object loadView(String className, Class[] constructorSignature, Object[] constructorArgs)
|
||||
throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException {
|
||||
throws ClassNotFoundException {
|
||||
|
||||
Class<?> aClass = myLoadedClasses.get(className);
|
||||
if (aClass != null) {
|
||||
return createNewInstance(aClass, constructorSignature, constructorArgs);
|
||||
}
|
||||
|
||||
try {
|
||||
if (aClass != null) {
|
||||
return createNewInstance(aClass, constructorSignature, constructorArgs);
|
||||
}
|
||||
aClass = loadClass(className);
|
||||
|
||||
if (aClass != null) {
|
||||
@@ -152,6 +158,11 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback {
|
||||
}
|
||||
|
||||
try {
|
||||
final Object o = createViewFromSuperclass(className, constructorSignature, constructorArgs);
|
||||
|
||||
if (o != null) {
|
||||
return o;
|
||||
}
|
||||
return createMockView(className, constructorSignature, constructorArgs);
|
||||
}
|
||||
catch (ClassNotFoundException e) {
|
||||
@@ -195,6 +206,56 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback {
|
||||
return myClassesWithIncorrectFormat.size() > 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Object createViewFromSuperclass(final String className, final Class[] constructorSignature, final Object[] constructorArgs) {
|
||||
return ApplicationManager.getApplication().runReadAction(new Computable<Object>() {
|
||||
@Nullable
|
||||
@Override
|
||||
public Object compute() {
|
||||
final JavaPsiFacade facade = JavaPsiFacade.getInstance(myModule.getProject());
|
||||
PsiClass psiClass = facade.findClass(className, myModule.getModuleWithDependenciesAndLibrariesScope(false));
|
||||
|
||||
if (psiClass == null) {
|
||||
return null;
|
||||
}
|
||||
psiClass = psiClass.getSuperClass();
|
||||
final Set<String> visited = new HashSet<String>();
|
||||
|
||||
while (psiClass != null) {
|
||||
final String qName = psiClass.getQualifiedName();
|
||||
|
||||
if (qName == null || !visited.add(qName)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!AndroidUtils.isAbstract(psiClass)) {
|
||||
try {
|
||||
Class<?> aClass = myLoadedClasses.get(qName);
|
||||
if (aClass == null) {
|
||||
aClass = myParentClassLoader.loadClass(qName);
|
||||
if (aClass != null) {
|
||||
myLoadedClasses.put(qName, aClass);
|
||||
}
|
||||
}
|
||||
if (aClass != null) {
|
||||
final Object instance = createNewInstance(aClass, constructorSignature, constructorArgs);
|
||||
|
||||
if (instance != null) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
LOG.debug(e);
|
||||
}
|
||||
}
|
||||
psiClass = psiClass.getSuperClass();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Object createMockView(String className, Class[] constructorSignature, Object[] constructorArgs)
|
||||
throws
|
||||
ClassNotFoundException,
|
||||
@@ -345,7 +406,7 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback {
|
||||
}
|
||||
|
||||
public boolean hasLoadedClasses() {
|
||||
return myLoadedClasses.size() > 0;
|
||||
return myHasProjectLoadedClasses;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -371,6 +432,7 @@ class ProjectCallback extends LegacyCallback implements IProjectCallback {
|
||||
|
||||
if (aClass != null) {
|
||||
myLoadedClasses.put(className, aClass);
|
||||
myHasProjectLoadedClasses = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -179,8 +179,7 @@ public class RenderUtil {
|
||||
if (exception != null) {
|
||||
final List<Throwable> exceptionsFromWarnings = getNonNullValues(callback.getBrokenClasses());
|
||||
|
||||
if (exceptionsFromWarnings.size() > 0 &&
|
||||
exception instanceof ClassCastException &&
|
||||
if (exception instanceof ClassCastException &&
|
||||
(SdkConstants.CLASS_MOCK_VIEW + " cannot be cast to " + SdkConstants.CLASS_VIEWGROUP)
|
||||
.equalsIgnoreCase(exception.getMessage())) {
|
||||
throw new RenderingException(exceptionsFromWarnings.toArray(new Throwable[exceptionsFromWarnings.size()]))
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.io.PrintStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -12,7 +13,7 @@ import java.util.List;
|
||||
public class RenderingException extends Exception {
|
||||
private final String myPresentableMessage;
|
||||
private final Throwable[] myCauses;
|
||||
private List<FixableIssueMessage> myWarnMessages;
|
||||
private List<FixableIssueMessage> myWarnMessages = Collections.emptyList();
|
||||
|
||||
public RenderingException() {
|
||||
super();
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<resources>
|
||||
<string name="myString">Hello</string>
|
||||
</resources>
|
||||
@@ -0,0 +1,3 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<TextView android:text="@string/myStri<caret>ng"/>
|
||||
</LinearLayout>
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.android;
|
||||
|
||||
import com.intellij.codeInsight.navigation.CtrlMouseHandler;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidDocumentationTest extends AndroidTestCase {
|
||||
private static final String BASE_PATH = "documentation/";
|
||||
|
||||
public void testValueResourceReferenceQuickDoc() {
|
||||
myFixture.copyFileToProject(BASE_PATH + "strings.xml", "res/values/strings.xml");
|
||||
final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + getTestName(true) + ".xml", "res/layout/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
final PsiReference ref = myFixture.getFile().findReferenceAt(myFixture.getEditor().getCaretModel().getOffset());
|
||||
assert ref != null;
|
||||
assertEquals("value resource 'myString' [strings.xml]", CtrlMouseHandler.getInfo(ref.resolve(), ref.getElement()));
|
||||
}
|
||||
}
|
||||
@@ -71,7 +71,7 @@ public abstract class AbstractDomChildDescriptionImpl implements AbstractDomChil
|
||||
|
||||
if (myCustomAnnotations != null ? !myCustomAnnotations.equals(that.myCustomAnnotations) : that.myCustomAnnotations != null)
|
||||
return false;
|
||||
if (!myType.equals(that.myType)) return false;
|
||||
if (!getType().equals(that.getType())) return false;
|
||||
if (myUserMap != null ? !myUserMap.equals(that.myUserMap) : that.myUserMap != null) return false;
|
||||
|
||||
return true;
|
||||
@@ -79,7 +79,7 @@ public abstract class AbstractDomChildDescriptionImpl implements AbstractDomChil
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myType.hashCode();
|
||||
int result = getType().hashCode();
|
||||
result = 31 * result + (myCustomAnnotations != null ? myCustomAnnotations.hashCode() : 0);
|
||||
result = 31 * result + (myUserMap != null ? myUserMap.hashCode() : 0);
|
||||
return result;
|
||||
@@ -126,7 +126,7 @@ public abstract class AbstractDomChildDescriptionImpl implements AbstractDomChil
|
||||
|
||||
@NotNull
|
||||
public DomNameStrategy getDomNameStrategy(@NotNull DomElement parent) {
|
||||
final DomNameStrategy strategy = DomImplUtil.getDomNameStrategy(ReflectionUtil.getRawType(myType), false);
|
||||
final DomNameStrategy strategy = DomImplUtil.getDomNameStrategy(ReflectionUtil.getRawType(getType()), false);
|
||||
return strategy == null ? parent.getNameStrategy() : strategy;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ public class AttributeChildDescriptionImpl extends DomChildDescriptionImpl imple
|
||||
myGetterMethod = getter;
|
||||
}
|
||||
|
||||
protected AttributeChildDescriptionImpl(final XmlName attributeName, @NotNull Type type) {
|
||||
public AttributeChildDescriptionImpl(final XmlName attributeName, @NotNull Type type) {
|
||||
super(attributeName, type);
|
||||
myGetterMethod = null;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.NotNullFunction;
|
||||
import com.intellij.util.xml.*;
|
||||
import com.intellij.util.xml.reflect.CustomDomChildrenDescription;
|
||||
import com.intellij.util.xml.reflect.DomExtensionImpl;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -39,16 +40,27 @@ public class CustomDomChildrenDescriptionImpl extends AbstractDomChildDescriptio
|
||||
return DomImplUtil.getCustomSubTags(handler, handler.getXmlTag().getSubTags(), handler.getFile());
|
||||
}
|
||||
};
|
||||
|
||||
private final TagNameDescriptor myTagNameDescriptor;
|
||||
private final AttributeDescriptor myAttributeDescriptor;
|
||||
|
||||
|
||||
public CustomDomChildrenDescriptionImpl(@NotNull final JavaMethod getter) {
|
||||
this(getter, DomReflectionUtil.extractCollectionElementType(getter.getGenericReturnType()), TagNameDescriptor.EMPTY);
|
||||
this(getter, DomReflectionUtil.extractCollectionElementType(getter.getGenericReturnType()),
|
||||
TagNameDescriptor.EMPTY, TagNameDescriptor.EMPTY);
|
||||
}
|
||||
|
||||
public CustomDomChildrenDescriptionImpl(@Nullable final JavaMethod getter, @NotNull Type type, @NotNull TagNameDescriptor descriptor) {
|
||||
public CustomDomChildrenDescriptionImpl(DomExtensionImpl custom) {
|
||||
this(null, custom.getType(), custom.getTagNameDescriptor(), custom.getAttributesDescriptor());
|
||||
}
|
||||
|
||||
private CustomDomChildrenDescriptionImpl(@Nullable final JavaMethod getter, @NotNull Type type,
|
||||
@Nullable TagNameDescriptor descriptor,
|
||||
@Nullable AttributeDescriptor attributesDescriptor) {
|
||||
super(type);
|
||||
myGetter = getter;
|
||||
myTagNameDescriptor = descriptor;
|
||||
myAttributeDescriptor = attributesDescriptor;
|
||||
}
|
||||
|
||||
@Nullable public JavaMethod getGetterMethod() {
|
||||
@@ -84,12 +96,16 @@ public class CustomDomChildrenDescriptionImpl extends AbstractDomChildDescriptio
|
||||
return new DummyEvaluatedXmlName(childTag.getLocalName(), childTag.getNamespace());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TagNameDescriptor getTagNameDescriptor() {
|
||||
return myTagNameDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeDescriptor getCustomAttributeDescriptor() {
|
||||
return myAttributeDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return obj instanceof CustomDomChildrenDescriptionImpl;
|
||||
|
||||
@@ -42,9 +42,9 @@ public class DomFileElementImpl<T extends DomElement> implements DomFileElement<
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CustomDomChildrenDescription getCustomNameChildrenDescription() {
|
||||
return null;
|
||||
@NotNull
|
||||
public List<? extends CustomDomChildrenDescription> getCustomNameChildrenDescription() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.intellij.util.xml.EvaluatedXmlName;
|
||||
import com.intellij.util.xml.JavaMethod;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import com.intellij.util.xml.reflect.AbstractDomChildrenDescription;
|
||||
import com.intellij.util.xml.reflect.CustomDomChildrenDescription;
|
||||
import com.intellij.util.xml.reflect.DomGenericInfo;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -55,7 +56,17 @@ public abstract class DomGenericInfoEx implements DomGenericInfo {
|
||||
}
|
||||
}
|
||||
}
|
||||
return attribute ? null : getCustomNameChildrenDescription();
|
||||
|
||||
List<? extends CustomDomChildrenDescription> list = getCustomNameChildrenDescription();
|
||||
for (CustomDomChildrenDescription description : list) {
|
||||
if (attribute) {
|
||||
// todo
|
||||
}
|
||||
else if (description.getTagNameDescriptor() != null) {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public abstract boolean processAttributeChildrenDescriptions(Processor<AttributeChildDescriptionImpl> processor);
|
||||
|
||||
@@ -42,10 +42,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.*;
|
||||
|
||||
import static com.intellij.patterns.XmlPatterns.*;
|
||||
|
||||
@@ -160,8 +157,8 @@ public class DomSemContributor extends SemContributor {
|
||||
if (parent == null) return null;
|
||||
|
||||
DomGenericInfoEx info = parent.getGenericInfo();
|
||||
final CustomDomChildrenDescription customDescription = info.getCustomNameChildrenDescription();
|
||||
if (customDescription == null) return null;
|
||||
final List<? extends CustomDomChildrenDescription> customs = info.getCustomNameChildrenDescription();
|
||||
if (customs.isEmpty()) return null;
|
||||
|
||||
if (mySemService.getSemElement(DomManagerImpl.DOM_INDEXED_HANDLER_KEY, tag) == null &&
|
||||
mySemService.getSemElement(DomManagerImpl.DOM_COLLECTION_HANDLER_KEY, tag) == null) {
|
||||
@@ -174,10 +171,13 @@ public class DomSemContributor extends SemContributor {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
AbstractCollectionChildDescription desc = (AbstractCollectionChildDescription)customDescription;
|
||||
Type type = customDescription.getType();
|
||||
return new CollectionElementInvocationHandler(type, tag, desc, parent, null);
|
||||
for (CustomDomChildrenDescription description : customs) {
|
||||
if (description.getTagNameDescriptor() != null) {
|
||||
AbstractCollectionChildDescription desc = (AbstractCollectionChildDescription)description;
|
||||
Type type = description.getType();
|
||||
return new CollectionElementInvocationHandler(type, tag, desc, parent, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -24,6 +24,7 @@ import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.psi.xml.XmlElement;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.Function;
|
||||
import com.intellij.util.Processor;
|
||||
import com.intellij.util.containers.ConcurrentWeakHashMap;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
@@ -53,7 +54,7 @@ public class DynamicGenericInfo extends DomGenericInfoEx {
|
||||
private volatile ChildrenDescriptionsHolder<AttributeChildDescriptionImpl> myAttributes;
|
||||
private volatile ChildrenDescriptionsHolder<FixedChildDescriptionImpl> myFixeds;
|
||||
private volatile ChildrenDescriptionsHolder<CollectionChildDescriptionImpl> myCollections;
|
||||
private volatile CustomDomChildrenDescriptionImpl myCustomChildren;
|
||||
private volatile List<CustomDomChildrenDescriptionImpl> myCustomChildren;
|
||||
|
||||
public DynamicGenericInfo(@NotNull final DomInvocationHandler handler, final StaticGenericInfo staticGenericInfo) {
|
||||
myInvocationHandler = handler;
|
||||
@@ -126,10 +127,13 @@ public class DynamicGenericInfo extends DomGenericInfoEx {
|
||||
myCollections = internChildrenHolder(file, newCollections);
|
||||
}
|
||||
|
||||
final DomExtensionImpl extension = registrar.getCustomChildrenType();
|
||||
if (extension != null) {
|
||||
myCustomChildren = new CustomDomChildrenDescriptionImpl(null, extension.getType(), extension.getTagNameDescriptor());
|
||||
}
|
||||
final List<DomExtensionImpl> customs = registrar.getCustoms();
|
||||
myCustomChildren = customs.isEmpty() ? null : ContainerUtil.map(customs, new Function<DomExtensionImpl, CustomDomChildrenDescriptionImpl>() {
|
||||
@Override
|
||||
public CustomDomChildrenDescriptionImpl fun(DomExtensionImpl extension) {
|
||||
return new CustomDomChildrenDescriptionImpl(extension);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static <T extends DomChildDescriptionImpl> ChildrenDescriptionsHolder<T> internChildrenHolder(XmlFile file, ChildrenDescriptionsHolder<T> holder) {
|
||||
@@ -177,8 +181,8 @@ public class DynamicGenericInfo extends DomGenericInfoEx {
|
||||
return myStaticGenericInfo.getNameDomElement(element);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CustomDomChildrenDescriptionImpl getCustomNameChildrenDescription() {
|
||||
@NotNull
|
||||
public List<? extends CustomDomChildrenDescription> getCustomNameChildrenDescription() {
|
||||
checkInitialized();
|
||||
if (myCustomChildren != null) return myCustomChildren;
|
||||
return myStaticGenericInfo.getCustomNameChildrenDescription();
|
||||
@@ -195,7 +199,7 @@ public class DynamicGenericInfo extends DomGenericInfoEx {
|
||||
myAttributes.dumpDescriptions(list);
|
||||
myFixeds.dumpDescriptions(list);
|
||||
myCollections.dumpDescriptions(list);
|
||||
ContainerUtil.addIfNotNull(myStaticGenericInfo.getCustomNameChildrenDescription(), list);
|
||||
list.addAll(myStaticGenericInfo.getCustomNameChildrenDescription());
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -215,9 +215,9 @@ public class StaticGenericInfo extends DomGenericInfoEx {
|
||||
return o instanceof GenericDomValue ? (GenericDomValue)o : null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CustomDomChildrenDescriptionImpl getCustomNameChildrenDescription() {
|
||||
return myCustomDescription;
|
||||
@NotNull
|
||||
public List<? extends CustomDomChildrenDescriptionImpl> getCustomNameChildrenDescription() {
|
||||
return myCustomDescription == null ? Collections.<CustomDomChildrenDescriptionImpl>emptyList() : Collections.singletonList(myCustomDescription);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -239,7 +239,7 @@ public class StaticGenericInfo extends DomGenericInfoEx {
|
||||
myAttributes.dumpDescriptions(list);
|
||||
myFixed.dumpDescriptions(list);
|
||||
myCollections.dumpDescriptions(list);
|
||||
ContainerUtil.addIfNotNull(getCustomNameChildrenDescription(), list);
|
||||
list.addAll(getCustomNameChildrenDescription());
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ public class DomExtensionImpl implements DomExtension {
|
||||
private int myCount = 1;
|
||||
private Map myUserMap;
|
||||
private CustomDomChildrenDescription.TagNameDescriptor myTagNameDescriptor = CustomDomChildrenDescription.TagNameDescriptor.EMPTY;
|
||||
private CustomDomChildrenDescription.AttributeDescriptor myAttributesDescriptor;
|
||||
|
||||
public DomExtensionImpl(final Type type, final XmlName xmlName) {
|
||||
myType = type;
|
||||
@@ -64,6 +65,14 @@ public class DomExtensionImpl implements DomExtension {
|
||||
return myTagNameDescriptor;
|
||||
}
|
||||
|
||||
public CustomDomChildrenDescription.AttributeDescriptor getAttributesDescriptor() {
|
||||
return myAttributesDescriptor;
|
||||
}
|
||||
|
||||
public void setAttributesDescriptor(CustomDomChildrenDescription.AttributeDescriptor attributesDescriptor) {
|
||||
myAttributesDescriptor = attributesDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public XmlName getXmlName() {
|
||||
return myXmlName;
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.intellij.util.xml.GenericAttributeValue;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
@@ -36,7 +37,7 @@ public class DomExtensionsRegistrarImpl implements DomExtensionsRegistrar {
|
||||
private final List<DomExtensionImpl> myFixeds = new SmartList<DomExtensionImpl>();
|
||||
private final List<DomExtensionImpl> myCollections = new SmartList<DomExtensionImpl>();
|
||||
private final Set<Object> myDependencies = new THashSet<Object>();
|
||||
private DomExtensionImpl myCustomChildrenType;
|
||||
private final List<DomExtensionImpl> myCustoms = new SmartList<DomExtensionImpl>();
|
||||
|
||||
public List<DomExtensionImpl> getAttributes() {
|
||||
return myAttributes;
|
||||
@@ -49,8 +50,8 @@ public class DomExtensionsRegistrarImpl implements DomExtensionsRegistrar {
|
||||
return myCollections;
|
||||
}
|
||||
|
||||
public DomExtensionImpl getCustomChildrenType() {
|
||||
return myCustomChildrenType;
|
||||
public List<DomExtensionImpl> getCustoms() {
|
||||
return myCustoms;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -89,13 +90,22 @@ public class DomExtensionsRegistrarImpl implements DomExtensionsRegistrar {
|
||||
@Override
|
||||
public DomExtension registerCustomChildrenExtension(@NotNull Type type,
|
||||
@NotNull CustomDomChildrenDescription.TagNameDescriptor descriptor) {
|
||||
assert myCustomChildrenType == null;
|
||||
myCustomChildrenType = new DomExtensionImpl(type, null);
|
||||
myCustomChildrenType.setTagNameDescriptor(descriptor);
|
||||
return myCustomChildrenType;
|
||||
DomExtensionImpl extension = addExtension(myCustoms, null, type);
|
||||
extension.setTagNameDescriptor(descriptor);
|
||||
return extension;
|
||||
}
|
||||
|
||||
private static DomExtensionImpl addExtension(final List<DomExtensionImpl> list, final XmlName name, final Type type) {
|
||||
@NotNull
|
||||
@Override
|
||||
public DomExtension registerCustomChildrenExtension(@NotNull Type type,
|
||||
@NotNull CustomDomChildrenDescription.AttributeDescriptor attributeDescriptor) {
|
||||
|
||||
DomExtensionImpl extension = addExtension(myCustoms, null, type);
|
||||
extension.setAttributesDescriptor(attributeDescriptor);
|
||||
return extension;
|
||||
}
|
||||
|
||||
private static DomExtensionImpl addExtension(final List<DomExtensionImpl> list, @Nullable final XmlName name, final Type type) {
|
||||
final DomExtensionImpl extension = new DomExtensionImpl(type, name);
|
||||
list.add(extension);
|
||||
return extension;
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import com.intellij.util.xml.EvaluatedXmlName;
|
||||
import com.intellij.util.xml.impl.AttributeChildDescriptionImpl;
|
||||
import com.intellij.util.xml.reflect.*;
|
||||
import com.intellij.xml.XmlAttributeDescriptor;
|
||||
import com.intellij.xml.XmlElementDescriptor;
|
||||
@@ -47,14 +48,15 @@ public abstract class AbstractDomChildrenDescriptor implements XmlElementDescrip
|
||||
xmlElementDescriptors.add(new DomElementXmlDescriptor(childrenDescription, myManager));
|
||||
}
|
||||
|
||||
final CustomDomChildrenDescription customDescription = domElement.getGenericInfo().getCustomNameChildrenDescription();
|
||||
if (customDescription != null) {
|
||||
final List<? extends CustomDomChildrenDescription> customs = domElement.getGenericInfo().getCustomNameChildrenDescription();
|
||||
|
||||
for (final CustomDomChildrenDescription custom : customs) {
|
||||
final XmlTag xmlTag = domElement.getXmlTag();
|
||||
for (final EvaluatedXmlName name : customDescription.getTagNameDescriptor().getCompletionVariants(domElement)) {
|
||||
xmlElementDescriptors.add(new AbstractDomChildrenDescriptor(myManager) {
|
||||
for (final EvaluatedXmlName name : custom.getTagNameDescriptor().getCompletionVariants(domElement)) {
|
||||
AbstractDomChildrenDescriptor descriptor = new AbstractDomChildrenDescriptor(myManager) {
|
||||
@Override
|
||||
public String getDefaultName() {
|
||||
final String ns = xmlTag != null? name.getNamespace(xmlTag, (XmlFile)xmlTag.getContainingFile()) : null;
|
||||
final String ns = xmlTag != null ? name.getNamespace(xmlTag, (XmlFile)xmlTag.getContainingFile()) : null;
|
||||
if (ns != null) {
|
||||
final String prefix = xmlTag.getPrefixByNamespace(ns);
|
||||
if (prefix != null) {
|
||||
@@ -67,11 +69,11 @@ public abstract class AbstractDomChildrenDescriptor implements XmlElementDescrip
|
||||
@Override
|
||||
@Nullable
|
||||
public PsiElement getDeclaration() {
|
||||
final PomTarget target = customDescription.getTagNameDescriptor().findDeclaration(domElement, name);
|
||||
final PomTarget target = custom.getTagNameDescriptor().findDeclaration(domElement, name);
|
||||
return target == null ? null : PomService.convertToPsi(context.getProject(), target);
|
||||
}
|
||||
|
||||
});
|
||||
};
|
||||
xmlElementDescriptors.add(descriptor);
|
||||
}
|
||||
|
||||
xmlElementDescriptors.add(new AnyXmlElementDescriptor(this, getNSDescriptor()));
|
||||
@@ -140,7 +142,16 @@ public abstract class AbstractDomChildrenDescriptor implements XmlElementDescrip
|
||||
for (DomAttributeChildDescription description : descriptions) {
|
||||
descriptors.add(new DomAttributeXmlDescriptor(description, myManager.getProject()));
|
||||
}
|
||||
|
||||
List<? extends CustomDomChildrenDescription> customs = domElement.getGenericInfo().getCustomNameChildrenDescription();
|
||||
for (CustomDomChildrenDescription custom : customs) {
|
||||
CustomDomChildrenDescription.AttributeDescriptor list = custom.getCustomAttributeDescriptor();
|
||||
if (list != null) {
|
||||
for (EvaluatedXmlName variant : list.getCompletionVariants(domElement)) {
|
||||
AttributeChildDescriptionImpl childDescription = new AttributeChildDescriptionImpl(variant.getXmlName(), String.class);
|
||||
descriptors.add(new DomAttributeXmlDescriptor(childDescription, myManager.getProject()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return descriptors.toArray(new XmlAttributeDescriptor[descriptors.size()]);
|
||||
}
|
||||
|
||||
|
||||
+22
-20
@@ -22,6 +22,7 @@ import com.intellij.util.xml.EvaluatedXmlName;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -29,35 +30,36 @@ import java.util.Set;
|
||||
* @author peter
|
||||
*/
|
||||
public interface CustomDomChildrenDescription extends AbstractDomChildrenDescription {
|
||||
@NotNull
|
||||
@Nullable
|
||||
TagNameDescriptor getTagNameDescriptor();
|
||||
|
||||
abstract class TagNameDescriptor {
|
||||
public static final TagNameDescriptor EMPTY = new TagNameDescriptor() {
|
||||
@Override
|
||||
public Set<EvaluatedXmlName> getCompletionVariants(@NotNull DomElement parent) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
@Nullable
|
||||
AttributeDescriptor getCustomAttributeDescriptor();
|
||||
|
||||
@Override
|
||||
public PomTarget findDeclaration(DomElement parent, @NotNull EvaluatedXmlName name) {
|
||||
return null;
|
||||
}
|
||||
class TagNameDescriptor {
|
||||
|
||||
@Override
|
||||
public PomTarget findDeclaration(@NotNull DomElement child) {
|
||||
return child.getChildDescription();
|
||||
}
|
||||
};
|
||||
public static final AttributeDescriptor EMPTY = new AttributeDescriptor();
|
||||
|
||||
public abstract Set<EvaluatedXmlName> getCompletionVariants(@NotNull DomElement parent);
|
||||
public Set<EvaluatedXmlName> getCompletionVariants(@NotNull DomElement parent) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract PomTarget findDeclaration(DomElement parent, @NotNull EvaluatedXmlName name);
|
||||
public PomTarget findDeclaration(DomElement parent, @NotNull EvaluatedXmlName name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public abstract PomTarget findDeclaration(@NotNull DomElement child);
|
||||
public PomTarget findDeclaration(@NotNull DomElement child) {
|
||||
return child.getChildDescription();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
class AttributeDescriptor extends TagNameDescriptor {
|
||||
|
||||
public Type getElementType(DomElement child) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,10 @@ public interface DomExtensionsRegistrar {
|
||||
*/
|
||||
@NotNull DomExtension registerCustomChildrenExtension(@NotNull final Type type);
|
||||
|
||||
@NotNull DomExtension registerCustomChildrenExtension(@NotNull final Type type, @NotNull CustomDomChildrenDescription.TagNameDescriptor descriptor);
|
||||
@NotNull DomExtension registerCustomChildrenExtension(@NotNull final Type type,
|
||||
@NotNull CustomDomChildrenDescription.TagNameDescriptor descriptor);
|
||||
|
||||
@NotNull DomExtension registerCustomChildrenExtension(@NotNull final Type type,
|
||||
@NotNull CustomDomChildrenDescription.AttributeDescriptor attributeDescriptor);
|
||||
|
||||
}
|
||||
|
||||
@@ -75,6 +75,6 @@ public interface DomGenericInfo {
|
||||
@Nullable
|
||||
GenericDomValue getNameDomElement(DomElement element);
|
||||
|
||||
@Nullable
|
||||
CustomDomChildrenDescription getCustomNameChildrenDescription();
|
||||
@NotNull
|
||||
List<? extends CustomDomChildrenDescription> getCustomNameChildrenDescription();
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ public class DomChildrenTest extends DomTestCase {
|
||||
final MyElement myElement = createElement("<a><foo/><bar/><foo xmlns=\"z\"/></a>", MyElement.class);
|
||||
final XmlTag tag = myElement.getXmlTag();
|
||||
final List<MyElement> customChildren = myElement.getCustomChildren();
|
||||
assertOrderedEquals(customChildren, myElement.getGenericInfo().getCustomNameChildrenDescription().getValues(myElement));
|
||||
assertOrderedEquals(customChildren, myElement.getGenericInfo().getCustomNameChildrenDescription().get(0).getValues(myElement));
|
||||
assertOrderedCollection(customChildren, new Consumer<MyElement>() {
|
||||
@Override
|
||||
public void consume(final MyElement element) {
|
||||
|
||||
Reference in New Issue
Block a user