mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
support inline parent styles
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class AndroidAttributeInfo {
|
||||
private final String myName;
|
||||
private final String myPackage;
|
||||
|
||||
public AndroidAttributeInfo(@NotNull String name, @Nullable String aPackage) {
|
||||
myName = name;
|
||||
myPackage = aPackage;
|
||||
}
|
||||
|
||||
public boolean isSystem() {
|
||||
return AndroidUtils.SYSTEM_RESOURCE_PACKAGE.equals(myPackage);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getName() {
|
||||
return myName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getPackage() {
|
||||
return myPackage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AndroidAttributeInfo info = (AndroidAttributeInfo)o;
|
||||
|
||||
if (!myName.equals(info.myName)) {
|
||||
return false;
|
||||
}
|
||||
if (myPackage != null ? !myPackage.equals(info.myPackage) : info.myPackage != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = myName.hashCode();
|
||||
result = 31 * result + (myPackage != null ? myPackage.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getAttributeId() {
|
||||
return myPackage != null ? myPackage + ":" + myName : myName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getAttributeId();
|
||||
}
|
||||
}
|
||||
+11
-17
@@ -4,7 +4,6 @@ import com.intellij.lang.xml.XMLLanguage;
|
||||
import com.intellij.openapi.command.UndoConfirmationPolicy;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.roots.ProjectRootManager;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.io.FileUtil;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
@@ -22,10 +21,6 @@ import com.intellij.usageView.UsageViewBundle;
|
||||
import com.intellij.usageView.UsageViewDescriptor;
|
||||
import com.intellij.util.containers.HashSet;
|
||||
import com.intellij.util.containers.OrderedSet;
|
||||
import com.intellij.util.xml.GenericAttributeValue;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import org.jetbrains.android.dom.converters.AndroidResourceReference;
|
||||
import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidResourceUtil;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
@@ -40,16 +35,16 @@ import java.util.*;
|
||||
class AndroidInlineAllStyleUsagesProcessor extends BaseRefactoringProcessor {
|
||||
private final PsiElement myStyleElement;
|
||||
private final String myStyleName;
|
||||
private final Map<XmlName, String> myAttributeValues;
|
||||
private final AndroidInlineUtil.MyStyleRefData myParentStyleRef;
|
||||
private final Map<AndroidAttributeInfo, String> myAttributeValues;
|
||||
private final StyleRefData myParentStyleRef;
|
||||
private final XmlTag myStyleTag;
|
||||
|
||||
protected AndroidInlineAllStyleUsagesProcessor(@NotNull Project project,
|
||||
@NotNull PsiElement styleElement,
|
||||
@NotNull XmlTag styleTag,
|
||||
@NotNull String styleName,
|
||||
@NotNull Map<XmlName, String> attributeValues,
|
||||
@Nullable AndroidInlineUtil.MyStyleRefData parentStyleRef) {
|
||||
@NotNull Map<AndroidAttributeInfo, String> attributeValues,
|
||||
@Nullable StyleRefData parentStyleRef) {
|
||||
super(project);
|
||||
myStyleElement = styleElement;
|
||||
myStyleTag = styleTag;
|
||||
@@ -101,7 +96,7 @@ class AndroidInlineAllStyleUsagesProcessor extends BaseRefactoringProcessor {
|
||||
|
||||
@Override
|
||||
protected void performRefactoring(UsageInfo[] usages) {
|
||||
final List<AndroidInlineUtil.MyStyleUsageData> inlineInfos = new ArrayList<AndroidInlineUtil.MyStyleUsageData>();
|
||||
final List<StyleUsageData> inlineInfos = new ArrayList<StyleUsageData>();
|
||||
final List<PsiElement> nonXmlUsages = new ArrayList<PsiElement>();
|
||||
final List<PsiElement> unsupportedUsages = new ArrayList<PsiElement>();
|
||||
final List<PsiElement> unambiguousUsages = new ArrayList<PsiElement>();
|
||||
@@ -115,19 +110,18 @@ class AndroidInlineAllStyleUsagesProcessor extends BaseRefactoringProcessor {
|
||||
continue;
|
||||
}
|
||||
final XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
|
||||
final Pair<AndroidResourceReference, GenericAttributeValue<ResourceValue>> pair =
|
||||
tag != null ? AndroidInlineUtil.findStyleReference(tag) : null;
|
||||
final StyleUsageData usageData = tag != null ? AndroidInlineUtil.getUsageData(tag) : null;
|
||||
|
||||
if (pair == null) {
|
||||
if (usageData == null) {
|
||||
unsupportedUsages.add(element);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pair.getFirst().computeTargetElements().length > 1) {
|
||||
if (usageData.getReference().computeTargetElements().length > 1) {
|
||||
unambiguousUsages.add(element);
|
||||
continue;
|
||||
}
|
||||
inlineInfos.add(new AndroidInlineUtil.MyStyleUsageData(tag, pair.getSecond()));
|
||||
inlineInfos.add(usageData);
|
||||
}
|
||||
|
||||
if (nonXmlUsages.size() > 0 || unambiguousUsages.size() > 0 || unsupportedUsages.size() > 0) {
|
||||
@@ -136,8 +130,8 @@ class AndroidInlineAllStyleUsagesProcessor extends BaseRefactoringProcessor {
|
||||
return;
|
||||
}
|
||||
|
||||
for (AndroidInlineUtil.MyStyleUsageData info : inlineInfos) {
|
||||
AndroidInlineUtil.inlineStyleUsage(info, myAttributeValues, myParentStyleRef);
|
||||
for (StyleUsageData info : inlineInfos) {
|
||||
info.inline(myAttributeValues, myParentStyleRef);
|
||||
}
|
||||
myStyleTag.delete();
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.refactoring.inline.InlineOptionsDialog;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -17,8 +16,8 @@ import java.util.Map;
|
||||
class AndroidInlineStyleDialog extends InlineOptionsDialog {
|
||||
private final String myStyleName;
|
||||
private final boolean myInlineThisByDefault;
|
||||
private final Map<XmlName, String> myAttributeValues;
|
||||
private final AndroidInlineUtil.MyStyleRefData myParentStyleRef;
|
||||
private final Map<AndroidAttributeInfo, String> myAttributeValues;
|
||||
private final StyleRefData myParentStyleRef;
|
||||
private final XmlTag myStyleTag;
|
||||
|
||||
|
||||
@@ -26,8 +25,8 @@ class AndroidInlineStyleDialog extends InlineOptionsDialog {
|
||||
@NotNull PsiElement styleElement,
|
||||
@NotNull XmlTag styleTag,
|
||||
@NotNull String styleName,
|
||||
@NotNull Map<XmlName, String> attributeValues,
|
||||
@Nullable AndroidInlineUtil.MyStyleRefData parentStyleRef,
|
||||
@NotNull Map<AndroidAttributeInfo, String> attributeValues,
|
||||
@Nullable StyleRefData parentStyleRef,
|
||||
boolean inlineThisByDefault,
|
||||
boolean invokedOnReference) {
|
||||
super(project, true, styleElement);
|
||||
|
||||
+12
-28
@@ -7,13 +7,9 @@ import com.intellij.lang.xml.XMLLanguage;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import org.jetbrains.android.dom.layout.LayoutViewElement;
|
||||
import org.jetbrains.android.facet.AndroidFacet;
|
||||
import org.jetbrains.android.util.ErrorReporter;
|
||||
import org.jetbrains.android.util.HintBasedErrorReporter;
|
||||
@@ -42,45 +38,33 @@ public class AndroidInlineStyleHandler extends InlineActionHandler {
|
||||
public boolean canInlineElement(PsiElement element) {
|
||||
return element != null &&
|
||||
AndroidFacet.getInstance(element) != null &&
|
||||
element.getManager().isInProject(element) &&
|
||||
AndroidInlineUtil.getStyleDataFromContext(element) != null;
|
||||
AndroidInlineUtil.getInlinableStyleDataFromContext(element) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inlineElement(Project project, final Editor editor, PsiElement element) {
|
||||
final AndroidInlineUtil.MyStyleData data = AndroidInlineUtil.getStyleDataFromContext(element);
|
||||
final AndroidInlineUtil.MyStyleData data = AndroidInlineUtil.getInlinableStyleDataFromContext(element);
|
||||
|
||||
if (data != null) {
|
||||
final PsiReference reference = editor != null
|
||||
? TargetElementUtilBase.findReference(editor)
|
||||
: null;
|
||||
final PsiElement usageElement = reference != null ? reference.getElement() : null;
|
||||
final AndroidInlineUtil.MyStyleUsageData usageData = usageElement != null
|
||||
? getStyleUsageDataFromContext(project, usageElement)
|
||||
: null;
|
||||
final ErrorReporter reporter = editor != null
|
||||
? new HintBasedErrorReporter(editor)
|
||||
: new ProjectBasedErrorReporter(project);
|
||||
final StyleUsageData usageData = editor != null ? getUsageDataFromEditor(editor) : null;
|
||||
final ErrorReporter reporter = editor != null ? new HintBasedErrorReporter(editor) : new ProjectBasedErrorReporter(project);
|
||||
AndroidInlineUtil.doInlineStyleDeclaration(project, data, usageData, reporter, ourTestConfig);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AndroidInlineUtil.MyStyleUsageData getStyleUsageDataFromContext(@NotNull Project project, @NotNull PsiElement context) {
|
||||
final XmlTag tag = PsiTreeUtil.getParentOfType(context, XmlTag.class, false);
|
||||
private static StyleUsageData getUsageDataFromEditor(@NotNull Editor editor) {
|
||||
final PsiReference reference = TargetElementUtilBase.findReference(editor);
|
||||
|
||||
if (tag == null) {
|
||||
if (reference == null) {
|
||||
return null;
|
||||
}
|
||||
final DomElement element = DomManager.getDomManager(project).getDomElement(tag);
|
||||
final PsiElement usageElement = reference.getElement();
|
||||
|
||||
if (!(element instanceof LayoutViewElement)) {
|
||||
if (usageElement == null) {
|
||||
return null;
|
||||
}
|
||||
final PsiFile file = tag.getContainingFile();
|
||||
|
||||
if (file == null) {
|
||||
return null;
|
||||
}
|
||||
return new AndroidInlineUtil.MyStyleUsageData(tag, ((LayoutViewElement)element).getStyle());
|
||||
final XmlTag tag = PsiTreeUtil.getParentOfType(usageElement, XmlTag.class, false);
|
||||
return tag != null ? AndroidInlineUtil.getUsageData(tag) : null;
|
||||
}
|
||||
}
|
||||
|
||||
+18
-16
@@ -1,17 +1,18 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.xml.XmlFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.refactoring.RefactoringBundle;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomFileDescription;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import com.intellij.util.xml.GenericAttributeValue;
|
||||
import org.jetbrains.android.dom.converters.AndroidResourceReference;
|
||||
import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
import org.jetbrains.android.dom.layout.LayoutDomFileDescription;
|
||||
import org.jetbrains.android.dom.resources.ResourcesDomFileDescription;
|
||||
import org.jetbrains.android.dom.resources.Style;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
@@ -22,7 +23,7 @@ import org.jetbrains.annotations.TestOnly;
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
public class AndroidInlineStyleReferenceAction extends AndroidBaseLayoutRefactoringAction {
|
||||
public class AndroidInlineStyleReferenceAction extends AndroidBaseXmlRefactoringAction {
|
||||
public static final String ACTION_ID = "AndroidInlineStyleReferenceAction";
|
||||
|
||||
private final AndroidInlineTestConfig myTestConfig;
|
||||
@@ -43,18 +44,12 @@ public class AndroidInlineStyleReferenceAction extends AndroidBaseLayoutRefactor
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
final Pair<AndroidResourceReference, GenericAttributeValue<ResourceValue>> pair = AndroidInlineUtil
|
||||
.findStyleReference(tag);
|
||||
final StyleUsageData usageData = AndroidInlineUtil.getUsageData(tag);
|
||||
|
||||
if (pair == null) {
|
||||
return;
|
||||
}
|
||||
final AndroidResourceReference reference = pair.getFirst();
|
||||
final GenericAttributeValue<ResourceValue> styleAttribute = pair.getSecond();
|
||||
|
||||
if (reference == null || styleAttribute == null) {
|
||||
if (usageData == null) {
|
||||
return;
|
||||
}
|
||||
final AndroidResourceReference reference = usageData.getReference();
|
||||
final String title = AndroidBundle.message("android.inline.style.title");
|
||||
final PsiElement[] styleElements = reference.computeTargetElements();
|
||||
|
||||
@@ -83,13 +78,20 @@ public class AndroidInlineStyleReferenceAction extends AndroidBaseLayoutRefactor
|
||||
return;
|
||||
}
|
||||
AndroidInlineUtil.doInlineStyleDeclaration(project, new AndroidInlineUtil.MyStyleData(styleName, style, styleElement),
|
||||
new AndroidInlineUtil.MyStyleUsageData(tag, styleAttribute),
|
||||
usageData,
|
||||
new ProjectBasedErrorReporter(project), myTestConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isEnabled(@NotNull XmlTag tag) {
|
||||
return super.isEnabled(tag) &&
|
||||
AndroidInlineUtil.findStyleReference(tag) != null;
|
||||
return AndroidInlineUtil.getUsageData(tag) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isMyFile(PsiFile file) {
|
||||
final DomFileDescription<?> description = DomManager.getDomManager(file.getProject()).getDomFileDescription((XmlFile)file);
|
||||
|
||||
return description instanceof LayoutDomFileDescription ||
|
||||
description instanceof ResourcesDomFileDescription;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.intellij.codeInsight.PsiEquivalenceUtil;
|
||||
import com.intellij.openapi.application.Result;
|
||||
import com.intellij.openapi.command.UndoConfirmationPolicy;
|
||||
import com.intellij.openapi.command.WriteCommandAction;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiReference;
|
||||
@@ -19,7 +16,6 @@ import com.intellij.util.containers.HashMap;
|
||||
import com.intellij.util.xml.DomElement;
|
||||
import com.intellij.util.xml.DomManager;
|
||||
import com.intellij.util.xml.GenericAttributeValue;
|
||||
import com.intellij.util.xml.XmlName;
|
||||
import org.jetbrains.android.dom.converters.AndroidResourceReference;
|
||||
import org.jetbrains.android.dom.layout.LayoutViewElement;
|
||||
import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
@@ -27,6 +23,7 @@ import org.jetbrains.android.dom.resources.Style;
|
||||
import org.jetbrains.android.dom.resources.StyleItem;
|
||||
import org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper;
|
||||
import org.jetbrains.android.util.AndroidBundle;
|
||||
import org.jetbrains.android.util.AndroidUtils;
|
||||
import org.jetbrains.android.util.ErrorReporter;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -62,57 +59,54 @@ class AndroidInlineUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Pair<AndroidResourceReference, GenericAttributeValue<ResourceValue>> findStyleReference(@NotNull XmlTag tag) {
|
||||
final LayoutViewElement viewElement = AndroidBaseLayoutRefactoringAction.getLayoutViewElement(tag);
|
||||
if (viewElement == null) {
|
||||
static StyleUsageData getUsageData(@NotNull XmlTag tag) {
|
||||
final DomElement domElement = DomManager.getDomManager(tag.getProject()).getDomElement(tag);
|
||||
|
||||
if (domElement instanceof LayoutViewElement) {
|
||||
final GenericAttributeValue<ResourceValue> styleAttribute = ((LayoutViewElement)domElement).getStyle();
|
||||
final AndroidResourceReference reference = getAndroidResourceReference(styleAttribute);
|
||||
|
||||
if (reference != null) {
|
||||
return new ViewStyleUsageData(tag, styleAttribute, reference);
|
||||
}
|
||||
}
|
||||
else if (domElement instanceof Style) {
|
||||
final AndroidResourceReference reference = getAndroidResourceReference(((Style)domElement).getParentStyle());
|
||||
|
||||
if (reference != null) {
|
||||
return new ParentStyleUsageData((Style)domElement, reference);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static AndroidResourceReference getAndroidResourceReference(@Nullable GenericAttributeValue<ResourceValue> attribute) {
|
||||
if (attribute == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final GenericAttributeValue<ResourceValue> style = viewElement.getStyle();
|
||||
if (style == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final ResourceValue styleValue = style.getValue();
|
||||
final ResourceValue styleValue = attribute.getValue();
|
||||
if (styleValue == null || styleValue.getPackage() != null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final XmlAttributeValue styleAttributeValue = style.getXmlAttributeValue();
|
||||
final XmlAttributeValue styleAttributeValue = attribute.getXmlAttributeValue();
|
||||
if (styleAttributeValue == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (PsiReference reference : styleAttributeValue.getReferences()) {
|
||||
if (reference instanceof AndroidResourceReference) {
|
||||
return Pair.create((AndroidResourceReference)reference, style);
|
||||
return (AndroidResourceReference)reference;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
static void inlineStyleUsage(MyStyleUsageData usageData,
|
||||
Map<XmlName, String> attributeValues,
|
||||
MyStyleRefData parentStyleRef) {
|
||||
final XmlTag tag = usageData.myTag;
|
||||
final GenericAttributeValue<ResourceValue> styleAttribute = usageData.myStyleAttribute;
|
||||
|
||||
for (Map.Entry<XmlName, String> entry : attributeValues.entrySet()) {
|
||||
final XmlName name = entry.getKey();
|
||||
|
||||
if (tag.getAttribute(name.getLocalName(), name.getNamespaceKey()) == null) {
|
||||
tag.setAttribute(name.getLocalName(), name.getNamespaceKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
styleAttribute.setValue(parentStyleRef != null
|
||||
? ResourceValue.referenceTo('@', parentStyleRef.myStylePackage, ResourceType.STYLE.getName(),
|
||||
parentStyleRef.myStyleName)
|
||||
: null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Map<XmlName, String> computeAttributeMap(@NotNull Style style, @NotNull ErrorReporter errorReporter) {
|
||||
final Map<XmlName, String> attributeValues = new HashMap<XmlName, String>();
|
||||
static Map<AndroidAttributeInfo, String> computeAttributeMap(@NotNull Style style, @NotNull ErrorReporter errorReporter) {
|
||||
final Map<AndroidAttributeInfo, String> attributeValues = new HashMap<AndroidAttributeInfo, String>();
|
||||
|
||||
for (StyleItem item : style.getItems()) {
|
||||
final String attributeName = item.getName().getStringValue();
|
||||
@@ -124,13 +118,9 @@ class AndroidInlineUtil {
|
||||
final int idx = attributeName.indexOf(':');
|
||||
final String localName = idx >= 0 ? attributeName.substring(idx + 1) : attributeName;
|
||||
final String nsPrefix = idx >= 0 ? attributeName.substring(0, idx) : null;
|
||||
String namespace;
|
||||
|
||||
if (nsPrefix != null) {
|
||||
if ("android".equals(nsPrefix)) {
|
||||
namespace = SdkConstants.NS_RESOURCES;
|
||||
}
|
||||
else {
|
||||
if (!AndroidUtils.SYSTEM_RESOURCE_PACKAGE.equals(nsPrefix)) {
|
||||
errorReporter.report(RefactoringBundle.getCannotRefactorMessage("Unknown XML attribute prefix '" + nsPrefix + ":'"),
|
||||
AndroidBundle.message("android.inline.style.title"));
|
||||
return null;
|
||||
@@ -142,22 +132,22 @@ class AndroidInlineUtil {
|
||||
AndroidBundle.message("android.inline.style.title"));
|
||||
return null;
|
||||
}
|
||||
attributeValues.put(new XmlName(localName, namespace), attributeValue);
|
||||
attributeValues.put(new AndroidAttributeInfo(localName, nsPrefix), attributeValue);
|
||||
}
|
||||
return attributeValues;
|
||||
}
|
||||
|
||||
static void doInlineStyleDeclaration(@NotNull Project project,
|
||||
@NotNull MyStyleData data,
|
||||
@Nullable final MyStyleUsageData usageData,
|
||||
@Nullable final StyleUsageData usageData,
|
||||
@NotNull ErrorReporter errorReporter,
|
||||
@Nullable AndroidInlineTestConfig testConfig) {
|
||||
final Style style = data.myStyleElement;
|
||||
final Map<XmlName, String> attributeValues = computeAttributeMap(style, errorReporter);
|
||||
final Map<AndroidAttributeInfo, String> attributeValues = computeAttributeMap(style, errorReporter);
|
||||
if (attributeValues == null) {
|
||||
return;
|
||||
}
|
||||
final MyStyleRefData parentStyleRef = getParentStyle(style);
|
||||
final StyleRefData parentStyleRef = getParentStyle(style);
|
||||
boolean inlineThisOnly;
|
||||
|
||||
if (testConfig != null) {
|
||||
@@ -178,7 +168,7 @@ class AndroidInlineUtil {
|
||||
|
||||
if (inlineThisOnly) {
|
||||
assert usageData != null;
|
||||
final PsiFile file = usageData.myTag.getContainingFile();
|
||||
final PsiFile file = usageData.getFile();
|
||||
|
||||
if (file == null) {
|
||||
return;
|
||||
@@ -186,7 +176,7 @@ class AndroidInlineUtil {
|
||||
new WriteCommandAction(project, AndroidBundle.message("android.inline.style.command.name", data.myStyleName), file) {
|
||||
@Override
|
||||
protected void run(final Result result) throws Throwable {
|
||||
inlineStyleUsage(usageData, attributeValues, parentStyleRef);
|
||||
usageData.inline(attributeValues, parentStyleRef);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -204,14 +194,14 @@ class AndroidInlineUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static MyStyleRefData getParentStyle(@NotNull Style style) {
|
||||
static StyleRefData getParentStyle(@NotNull Style style) {
|
||||
final ResourceValue parentStyleRefValue = style.getParentStyle().getValue();
|
||||
|
||||
if (parentStyleRefValue != null) {
|
||||
final String parentStyleName = parentStyleRefValue.getResourceName();
|
||||
|
||||
if (parentStyleName != null) {
|
||||
return new MyStyleRefData(parentStyleName, parentStyleRefValue.getPackage());
|
||||
return new StyleRefData(parentStyleName, parentStyleRefValue.getPackage());
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -221,7 +211,7 @@ class AndroidInlineUtil {
|
||||
final int idx = styleName.lastIndexOf('.');
|
||||
|
||||
if (idx > 0) {
|
||||
return new MyStyleRefData(styleName.substring(0, idx), null);
|
||||
return new StyleRefData(styleName.substring(0, idx), null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,11 +219,11 @@ class AndroidInlineUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static MyStyleData getStyleDataFromContext(@Nullable PsiElement context) {
|
||||
static MyStyleData getInlinableStyleDataFromContext(@Nullable PsiElement context) {
|
||||
if (context instanceof LazyValueResourceElementWrapper) {
|
||||
context = ((LazyValueResourceElementWrapper)context).computeElement();
|
||||
}
|
||||
if (context == null) {
|
||||
if (context == null || !context.getManager().isInProject(context)) {
|
||||
return null;
|
||||
}
|
||||
final XmlAttributeValue attrValue = PsiTreeUtil.getParentOfType(context, XmlAttributeValue.class, false);
|
||||
@@ -258,24 +248,4 @@ class AndroidInlineUtil {
|
||||
myReferredElement = referredElement;
|
||||
}
|
||||
}
|
||||
|
||||
static class MyStyleRefData {
|
||||
private final String myStyleName;
|
||||
private final String myStylePackage;
|
||||
|
||||
MyStyleRefData(@NotNull String styleName, @Nullable String stylePackage) {
|
||||
myStyleName = styleName;
|
||||
myStylePackage = stylePackage;
|
||||
}
|
||||
}
|
||||
|
||||
static class MyStyleUsageData {
|
||||
private final XmlTag myTag;
|
||||
private final GenericAttributeValue<ResourceValue> myStyleAttribute;
|
||||
|
||||
MyStyleUsageData(XmlTag tag, GenericAttributeValue<ResourceValue> styleAttribute) {
|
||||
myTag = tag;
|
||||
myStyleAttribute = styleAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import org.jetbrains.android.dom.converters.AndroidResourceReference;
|
||||
import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
import org.jetbrains.android.dom.resources.Style;
|
||||
import org.jetbrains.android.dom.resources.StyleItem;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class ParentStyleUsageData implements StyleUsageData {
|
||||
private final AndroidResourceReference myReference;
|
||||
private final Style myStyle;
|
||||
|
||||
public ParentStyleUsageData(@NotNull Style style,
|
||||
@NotNull AndroidResourceReference reference) {
|
||||
myReference = reference;
|
||||
myStyle = style;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PsiFile getFile() {
|
||||
final XmlTag tag = myStyle.getXmlTag();
|
||||
return tag != null ? tag.getContainingFile() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inline(@NotNull Map<AndroidAttributeInfo, String> attributeValues, @Nullable StyleRefData parentStyleRef) {
|
||||
final Map<String, String> id2Value = toId2ValueMap(attributeValues);
|
||||
|
||||
for (StyleItem item : myStyle.getItems()) {
|
||||
final String name = item.getName().getStringValue();
|
||||
|
||||
if (name != null) {
|
||||
id2Value.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, String> entry : id2Value.entrySet()) {
|
||||
final StyleItem newItem = myStyle.addItem();
|
||||
newItem.getName().setStringValue(entry.getKey());
|
||||
newItem.setStringValue(entry.getValue());
|
||||
}
|
||||
myStyle.getParentStyle().setValue(parentStyleRef != null
|
||||
? ResourceValue.referenceTo((char)0, parentStyleRef.getStylePackage(), null,
|
||||
parentStyleRef.getStyleName())
|
||||
: null);
|
||||
}
|
||||
|
||||
private static Map<String, String> toId2ValueMap(Map<AndroidAttributeInfo, String> info2ValueMap) {
|
||||
final Map<String, String> result = new HashMap<String, String>(info2ValueMap.size());
|
||||
|
||||
for (Map.Entry<AndroidAttributeInfo, String> entry : info2ValueMap.entrySet()) {
|
||||
result.put(entry.getKey().getAttributeId(), entry.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public AndroidResourceReference getReference() {
|
||||
return myReference;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class StyleRefData {
|
||||
private final String myStyleName;
|
||||
private final String myStylePackage;
|
||||
|
||||
StyleRefData(@NotNull String styleName, @Nullable String stylePackage) {
|
||||
myStyleName = styleName;
|
||||
myStylePackage = stylePackage;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public String getStyleName() {
|
||||
return myStyleName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getStylePackage() {
|
||||
return myStylePackage;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.android.dom.converters.AndroidResourceReference;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
interface StyleUsageData {
|
||||
@Nullable
|
||||
PsiFile getFile();
|
||||
|
||||
void inline(@NotNull Map<AndroidAttributeInfo, String> attributeValues, @Nullable StyleRefData parentStyleRef);
|
||||
|
||||
@NotNull
|
||||
AndroidResourceReference getReference();
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package org.jetbrains.android.refactoring;
|
||||
|
||||
import com.android.resources.ResourceType;
|
||||
import com.android.sdklib.SdkConstants;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.xml.XmlTag;
|
||||
import com.intellij.util.xml.GenericAttributeValue;
|
||||
import org.jetbrains.android.dom.converters.AndroidResourceReference;
|
||||
import org.jetbrains.android.dom.resources.ResourceValue;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Eugene.Kudelevsky
|
||||
*/
|
||||
class ViewStyleUsageData implements StyleUsageData {
|
||||
private final XmlTag myTag;
|
||||
private final GenericAttributeValue<ResourceValue> myStyleAttribute;
|
||||
private final AndroidResourceReference myReference;
|
||||
|
||||
ViewStyleUsageData(@NotNull XmlTag tag,
|
||||
@NotNull GenericAttributeValue<ResourceValue> styleAttribute,
|
||||
@NotNull AndroidResourceReference reference) {
|
||||
myTag = tag;
|
||||
myStyleAttribute = styleAttribute;
|
||||
myReference = reference;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PsiFile getFile() {
|
||||
return myTag.getContainingFile();
|
||||
}
|
||||
|
||||
public void inline(@NotNull Map<AndroidAttributeInfo, String> attributeValues, @Nullable StyleRefData parentStyleRef) {
|
||||
for (Map.Entry<AndroidAttributeInfo, String> entry : attributeValues.entrySet()) {
|
||||
final AndroidAttributeInfo info = entry.getKey();
|
||||
final String localName = info.getName();
|
||||
final String namespace = info.isSystem() ? SdkConstants.NS_RESOURCES : null;
|
||||
|
||||
if (myTag.getAttribute(localName, namespace) == null) {
|
||||
myTag.setAttribute(localName, namespace, entry.getValue());
|
||||
}
|
||||
}
|
||||
myStyleAttribute.setValue(parentStyleRef != null
|
||||
? ResourceValue.referenceTo('@', parentStyleRef.getStylePackage(), ResourceType.STYLE.getName(),
|
||||
parentStyleRef.getStyleName())
|
||||
: null);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public AndroidResourceReference getReference() {
|
||||
return myReference;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<resources>
|
||||
<style name="parentStyle">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle" parent="par<caret>entStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle1" parent="parentStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,17 @@
|
||||
<resources>
|
||||
<style name="parentStyle">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle1" parent="parentStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,15 @@
|
||||
<resources>
|
||||
<style name="parentStyle">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<sty<caret>le name="myStyle" parent="parentStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle1" parent="parentStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,17 @@
|
||||
<resources>
|
||||
<style name="parentStyle">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle1" parent="parentStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,15 @@
|
||||
<resources>
|
||||
<style name="parentStyle" parent="android:Widget.Button">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<sty<caret>le name="myStyle" parent="parentStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle1" parent="parentStyle">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,14 @@
|
||||
<resources>
|
||||
|
||||
<style name="myStyle" parent="android:Widget.Button">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
|
||||
<style name="myStyle1" parent="android:Widget.Button">
|
||||
<item name="android:textColor">@android:color/green</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
</resources>
|
||||
@@ -0,0 +1,7 @@
|
||||
<resources>
|
||||
<style name="myStyle" parent="android:Widget.But<caret>ton">
|
||||
<item name="android:textColor">@android:color/black</item>
|
||||
<item name="android:background">@android:color/white</item>
|
||||
<item name="android:color">@android:color/red</item>
|
||||
</style>
|
||||
</resources>
|
||||
+40
-8
@@ -111,10 +111,7 @@ public class AndroidInlineStyleTest extends AndroidTestCase {
|
||||
final VirtualFile f = myFixture
|
||||
.copyFileToProject(BASE_PATH + testName + ".xml", libModuleDir + "/res/layout/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
final Presentation p =
|
||||
myFixture.testAction(new AndroidInlineStyleReferenceAction(new AndroidInlineTestConfig(false)));
|
||||
assertTrue(p.isEnabled());
|
||||
assertTrue(p.isVisible());
|
||||
doInlineStyleReferenceAction(false, true);
|
||||
|
||||
myFixture.checkResultByFile(BASE_PATH + testName + "_after.xml");
|
||||
myFixture.checkResultByFile(appLayoutPath, BASE_PATH + getTestName(true) + "_1_after.xml", true);
|
||||
@@ -232,6 +229,37 @@ public class AndroidInlineStyleTest extends AndroidTestCase {
|
||||
myFixture.checkResultByFile("res/values/styles.xml", BASE_PATH + testName + "_styles_after.xml", true);
|
||||
}
|
||||
|
||||
public void test24() {
|
||||
final String testName = getTestName(true);
|
||||
final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + testName + ".xml", "res/values/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
doCommonInlineAction(true);
|
||||
myFixture.checkResultByFile(BASE_PATH + testName + "_after.xml");
|
||||
}
|
||||
|
||||
public void test25() {
|
||||
final String testName = getTestName(true);
|
||||
final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + testName + ".xml", "res/values/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
doInlineStyleReferenceAction(true, true);
|
||||
myFixture.checkResultByFile(BASE_PATH + testName + "_after.xml");
|
||||
}
|
||||
|
||||
public void test26() {
|
||||
final String testName = getTestName(true);
|
||||
final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + testName + ".xml", "res/values/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
doInlineStyleReferenceAction(false, true);
|
||||
myFixture.checkResultByFile(BASE_PATH + testName + "_after.xml");
|
||||
}
|
||||
|
||||
public void test27() {
|
||||
final String testName = getTestName(true);
|
||||
final VirtualFile f = myFixture.copyFileToProject(BASE_PATH + testName + ".xml", "res/values/test.xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
doInlineStyleReferenceAction(false, false);
|
||||
}
|
||||
|
||||
private void doTest(boolean inlineThisOnly) {
|
||||
doTest(inlineThisOnly, "res/layout");
|
||||
}
|
||||
@@ -242,15 +270,19 @@ public class AndroidInlineStyleTest extends AndroidTestCase {
|
||||
final VirtualFile f = myFixture
|
||||
.copyFileToProject(BASE_PATH + testName + ".xml", dirToCopy + "/test" + testName + "_" + Boolean.toString(inlineThisOnly) + ".xml");
|
||||
myFixture.configureFromExistingVirtualFile(f);
|
||||
final Presentation p =
|
||||
myFixture.testAction(new AndroidInlineStyleReferenceAction(new AndroidInlineTestConfig(inlineThisOnly)));
|
||||
assertTrue(p.isEnabled());
|
||||
assertTrue(p.isVisible());
|
||||
doInlineStyleReferenceAction(inlineThisOnly, true);
|
||||
myFixture.checkResultByFile(BASE_PATH + testName + "_after.xml");
|
||||
myFixture.checkResultByFile("res/values/styles.xml", BASE_PATH + testName + (
|
||||
inlineThisOnly ? "_styles.xml" : "_styles_after.xml"), true);
|
||||
}
|
||||
|
||||
private void doInlineStyleReferenceAction(boolean inlineThisOnly, boolean enabled) {
|
||||
final Presentation p =
|
||||
myFixture.testAction(new AndroidInlineStyleReferenceAction(new AndroidInlineTestConfig(inlineThisOnly)));
|
||||
assertEquals(enabled, p.isEnabled());
|
||||
assertTrue(p.isVisible());
|
||||
}
|
||||
|
||||
private void doTestErrorMessageShown(boolean testInlineThis, boolean testInlineAll, boolean copyStyles, String dirToCopy) {
|
||||
if (copyStyles) {
|
||||
myFixture.copyFileToProject(BASE_PATH + getTestName(true) + "_styles.xml",
|
||||
|
||||
Reference in New Issue
Block a user