improve extract style refactoring: use style where possible after is is extracted

This commit is contained in:
Eugene Kudelevsky
2012-11-15 23:24:59 +01:00
parent cc6afbe5a2
commit e0666433e4
14 changed files with 997 additions and 107 deletions
@@ -433,4 +433,5 @@ android.inline.file.inline.all.text=Inline &all references and remove the file
android.inline.file.inline.this.text=Inline &this usage and keep the file
android.inline.layout.title=Inline Android Layout
android.facet.importing.notification.group=Importing Error
android.facet.importing.title=Error when importing module ''{0}''
android.facet.importing.title=Error when importing module ''{0}''
android.find.style.applications.title=Use Style Where Possible
+4
View File
@@ -97,6 +97,10 @@
</action>
<action id="AndroidInlineIncludeAction" class="org.jetbrains.android.refactoring.AndroidInlineIncludeAction"
text="Inline _Layout..." description="Inlines included Android layout"/>
<action id="AndroidFindStyleApplicationsAction" class="org.jetbrains.android.refactoring.AndroidFindStyleApplicationsAction"
text="Use style _where possible..." description="Replaces attributes by Android style reference where possible">
<add-to-group group-id="RefactoringMenu"/>
</action>
</actions>
<depends>JUnit</depends>
@@ -20,14 +20,13 @@ import com.android.resources.ResourceType;
import com.android.sdklib.SdkConstants;
import com.intellij.openapi.module.Module;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiReference;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.xml.Converter;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.ResolvingConverter;
import com.intellij.util.xml.XmlName;
import com.intellij.util.xml.*;
import org.jetbrains.android.dom.attrs.AttributeDefinition;
import org.jetbrains.android.dom.attrs.AttributeDefinitions;
import org.jetbrains.android.dom.attrs.AttributeFormat;
@@ -358,4 +357,29 @@ public class AndroidDomUtil {
}
return class2Name.values();
}
@Nullable
public static AndroidResourceReferenceBase getAndroidResourceReference(@Nullable GenericAttributeValue<ResourceValue> attribute,
boolean localOnly) {
if (attribute == null) {
return null;
}
final ResourceValue resValue = attribute.getValue();
if (resValue == null || (localOnly && resValue.getPackage() != null)) {
return null;
}
final XmlAttributeValue value = attribute.getXmlAttributeValue();
if (value == null) {
return null;
}
for (PsiReference reference : value.getReferences()) {
if (reference instanceof AndroidResourceReferenceBase) {
return (AndroidResourceReferenceBase)reference;
}
}
return null;
}
}
@@ -1,5 +1,6 @@
package org.jetbrains.android.refactoring;
import com.android.sdklib.SdkConstants;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -16,8 +17,9 @@ class AndroidAttributeInfo {
myPackage = aPackage;
}
public boolean isSystem() {
return AndroidUtils.SYSTEM_RESOURCE_PACKAGE.equals(myPackage);
public String getNamespace() {
final boolean system = AndroidUtils.SYSTEM_RESOURCE_PACKAGE.equals(myPackage);
return system ? SdkConstants.NS_RESOURCES : null;
}
@NotNull
@@ -10,10 +10,11 @@ import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.Processor;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.dom.AndroidDomUtil;
@@ -106,6 +107,7 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
final String styleName;
final List<XmlAttribute> styledAttributes;
final Module chosenModule;
final boolean searchStyleApplications;
if (testConfig == null) {
final ExtractStyleDialog dialog =
@@ -116,6 +118,7 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
if (!dialog.isOK()) {
return null;
}
searchStyleApplications = dialog.isToSearchStyleApplications();
chosenModule = dialog.getChosenModule();
assert chosenModule != null;
@@ -135,8 +138,10 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
styledAttributes.add(attribute);
}
}
searchStyleApplications = false;
}
final boolean[] success = {false};
final Ref<Style> createdStyleRef = Ref.create();
final boolean finalSupportImplicitParent = supportImplicitParent;
new WriteCommandAction(project, "Extract Android Style '" + styleName + "'", file) {
@@ -150,6 +155,7 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
public boolean process(ResourceElement element) {
assert element instanceof Style;
final Style style = (Style)element;
createdStyleRef.set(style);
for (XmlAttribute attribute : styledAttributes) {
if (SdkConstants.NS_RESOURCES.equals(attribute.getNamespace())) {
@@ -162,7 +168,7 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
if (parentStyleValue != null && (!finalSupportImplicitParent || !styleName.startsWith(parentStyle + "."))) {
final String aPackage = parentStyleValue.getPackage();
style.getParentStyle().setStringValue((aPackage != null ? aPackage + ":" : "") + parentStyle);
style.getParentStyle().setStringValue((aPackage != null ? aPackage + ":" : "") + parentStyle);
}
return true;
}
@@ -192,7 +198,28 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
}
}.execute();
return success[0] ? styleName : null;
if (!success[0]) {
return null;
}
final Style createdStyle = createdStyleRef.get();
final XmlTag createdStyleTag = createdStyle != null ? createdStyle.getXmlTag() : null;
if (createdStyleTag != null) {
final AndroidFindStyleApplicationsAction.MyStyleData createdStyleData =
AndroidFindStyleApplicationsAction.getStyleData(createdStyleTag);
if (createdStyleData != null && searchStyleApplications) {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
AndroidFindStyleApplicationsAction.doRefactoringForTag(
project, createdStyleTag, createdStyleData, file, null);
}
});
}
}
return styleName;
}
@NotNull
@@ -212,7 +239,7 @@ public class AndroidExtractStyleAction extends AndroidBaseLayoutRefactoringActio
return false;
}
final String name = attribute.getLocalName();
if (ArrayUtil.find(NON_EXTRACTABLE_ATTRIBUTES, name) >= 0) {
if (ArrayUtilRt.find(NON_EXTRACTABLE_ATTRIBUTES, name) >= 0) {
return false;
}
if (name.startsWith(AndroidDomUtil.ATTR_STYLE)) {
@@ -0,0 +1,203 @@
package org.jetbrains.android.refactoring;
import com.android.resources.ResourceType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomManager;
import com.intellij.util.xml.GenericAttributeValue;
import org.jetbrains.android.dom.resources.ResourcesDomFileDescription;
import org.jetbrains.android.dom.resources.Style;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.android.resourceManagers.ValueResourceInfoImpl;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.ErrorReporter;
import org.jetbrains.android.util.ProjectBasedErrorReporter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.Map;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidFindStyleApplicationsAction extends AndroidBaseXmlRefactoringAction {
private final MyTestConfig myTestConfig;
public AndroidFindStyleApplicationsAction() {
this(null);
}
public AndroidFindStyleApplicationsAction(@Nullable MyTestConfig testConfig) {
myTestConfig = testConfig;
}
@Override
protected boolean isEnabledForTags(@NotNull XmlTag[] tags) {
if (tags.length != 1) {
return false;
}
final MyStyleData data = getStyleData(tags[0]);
return data != null && data.getStyle().getItems().size() > 0;
}
@Override
protected boolean isMyFile(PsiFile file) {
return DomManager.getDomManager(file.getProject()).getDomFileDescription(
(XmlFile)file) instanceof ResourcesDomFileDescription;
}
@Override
protected void doRefactorForTags(@NotNull Project project, @NotNull XmlTag[] tags) {
assert tags.length == 1;
final XmlTag tag = tags[0];
final MyStyleData styleData = getStyleData(tag);
assert styleData != null;
doRefactoringForTag(project, tag, styleData, null, myTestConfig);
}
static void doRefactoringForTag(Project project, XmlTag tag, MyStyleData styleData, PsiFile context, MyTestConfig testConfig) {
final ErrorReporter errorReporter = new ProjectBasedErrorReporter(project);
final Style style = styleData.getStyle();
final Map<AndroidAttributeInfo, String> attrMap =
AndroidRefactoringUtil.computeAttributeMap(style, new ProjectBasedErrorReporter(project),
AndroidBundle.message("android.find.style.applications.title"));
if (attrMap == null || attrMap.size() == 0) {
return;
}
final AndroidFacet facet = styleData.getFacet();
final Module module = facet.getModule();
final StyleRefData parentStyleRef = AndroidRefactoringUtil.getParentStyle(style);
PsiElement parentStyleAttrName = null;
if (parentStyleRef != null) {
parentStyleAttrName = resolveStyleRef(parentStyleRef, facet);
if (parentStyleAttrName == null) {
errorReporter.report("Cannot resolve parent style '" + parentStyleRef.getStyleName() + "'",
AndroidBundle.message("android.find.style.applications.title"));
return;
}
}
final AndroidFindStyleApplicationsProcessor processor = new AndroidFindStyleApplicationsProcessor(
module, attrMap, styleData.getName(), tag, styleData.getNameAttrValue(), parentStyleAttrName, context);
final VirtualFile contextVFile = context != null ? context.getVirtualFile() : null;
if (testConfig != null) {
processor.configureScope(testConfig.getScope(), contextVFile);
processor.run();
return;
}
processor.setPreviewUsages(true);
final boolean showModuleRadio = AndroidFindStyleApplicationsProcessor.getAllModulesToScan(module).size() > 1;
if (showModuleRadio || contextVFile != null) {
final AndroidFindStyleApplicationsDialog dialog = new AndroidFindStyleApplicationsDialog(
contextVFile, processor, showModuleRadio);
dialog.show();
}
else {
processor.run();
}
}
private static PsiElement resolveStyleRef(StyleRefData styleRef, AndroidFacet facet) {
final ResourceManager resourceManager = facet.getResourceManager(styleRef.getStylePackage());
if (resourceManager == null) {
return null;
}
final List<ValueResourceInfoImpl> infos = resourceManager.findValueResourceInfos(
ResourceType.STYLE.getName(), styleRef.getStyleName(), true, false);
return infos.size() == 1 ? infos.get(0).computeXmlElement() : null;
}
@Nullable
static MyStyleData getStyleData(@NotNull XmlTag tag) {
final DomElement element = DomManager.getDomManager(tag.getProject()).getDomElement(tag);
if (!(element instanceof Style)) {
return null;
}
final Style style = (Style)element;
final GenericAttributeValue<String> styleNameDomAttr = style.getName();
final String styleName = styleNameDomAttr.getStringValue();
final XmlAttributeValue styleNameAttrValue = styleNameDomAttr.getXmlAttributeValue();
if (styleName == null ||
styleName.length() == 0 ||
styleNameAttrValue == null) {
return null;
}
final AndroidFacet facet = AndroidFacet.getInstance(tag);
if (facet == null) {
return null;
}
return new MyStyleData(style, styleName, facet, styleNameAttrValue);
}
static class MyStyleData {
private final Style myStyle;
private final String myName;
private final XmlAttributeValue myNameAttrValue;
private final AndroidFacet myFacet;
private MyStyleData(@NotNull Style style,
@NotNull String name,
@NotNull AndroidFacet facet,
@NotNull XmlAttributeValue nameAttrValue) {
myStyle = style;
myName = name;
myFacet = facet;
myNameAttrValue = nameAttrValue;
}
@NotNull
public Style getStyle() {
return myStyle;
}
@NotNull
public String getName() {
return myName;
}
@NotNull
public AndroidFacet getFacet() {
return myFacet;
}
@NotNull
public XmlAttributeValue getNameAttrValue() {
return myNameAttrValue;
}
}
static class MyTestConfig {
private final AndroidFindStyleApplicationsProcessor.MyScope myScope;
MyTestConfig(@NotNull AndroidFindStyleApplicationsProcessor.MyScope scope) {
myScope = scope;
}
@NotNull
public AndroidFindStyleApplicationsProcessor.MyScope getScope() {
return myScope;
}
}
}
@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.android.refactoring.AndroidFindStyleApplicationsDialog">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="500" height="173"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="72d68" class="com.intellij.ui.components.JBLabel" binding="myCaptionLabel">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value=""/>
</properties>
</component>
<vspacer id="3bf55">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="6" hsize-policy="1" anchor="0" fill="2" indent="0" use-parent-layout="false"/>
</constraints>
</vspacer>
<grid id="ca999" layout-manager="GridLayoutManager" row-count="3" column-count="1" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
<border type="none"/>
<children>
<component id="f9ca5" class="com.intellij.ui.components.JBRadioButton" binding="myProjectScopeRadio">
<constraints>
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&amp;Whole project"/>
</properties>
</component>
<component id="4ebf" class="com.intellij.ui.components.JBRadioButton" binding="myModuleScopeRadio">
<constraints>
<grid row="1" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties/>
</component>
<component id="235b" class="com.intellij.ui.components.JBRadioButton" binding="myFileScopeRadio">
<constraints>
<grid row="2" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="Current &amp;file"/>
</properties>
</component>
</children>
</grid>
</children>
</grid>
<buttonGroups>
<group name="myGroup1">
<member id="f9ca5"/>
<member id="4ebf"/>
<member id="235b"/>
</group>
</buttonGroups>
</form>
@@ -0,0 +1,112 @@
package org.jetbrains.android.refactoring;
import com.intellij.analysis.AnalysisScopeBundle;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.components.JBLabel;
import com.intellij.ui.components.JBRadioButton;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidFindStyleApplicationsDialog extends DialogWrapper {
private JPanel myPanel;
private JBRadioButton myModuleScopeRadio;
private JBRadioButton myFileScopeRadio;
private JBRadioButton myProjectScopeRadio;
private JBLabel myCaptionLabel;
private final VirtualFile myFile;
private final AndroidFindStyleApplicationsProcessor myProcessor;
private static final String FIND_STYLE_APPLICATIONS_SCOPE_PROPERTY = "ANDROID_FIND_STYLE_APPLICATION_SCOPE";
protected AndroidFindStyleApplicationsDialog(@Nullable VirtualFile file,
@NotNull AndroidFindStyleApplicationsProcessor processor,
boolean showModuleRadio) {
super(processor.getModule().getProject(), true);
myFile = file;
myProcessor = processor;
final Module module = processor.getModule();
myModuleScopeRadio.setText(AnalysisScopeBundle.message("scope.option.module.with.mnemonic", module.getName()));
myModuleScopeRadio.setVisible(showModuleRadio);
if (file != null) {
myFileScopeRadio.setText("File '" + file.getName() + "'");
}
else {
myFileScopeRadio.setVisible(false);
}
final String scopeValue = PropertiesComponent.getInstance().getValue(FIND_STYLE_APPLICATIONS_SCOPE_PROPERTY);
AndroidFindStyleApplicationsProcessor.MyScope scope;
try {
scope = Enum.valueOf(AndroidFindStyleApplicationsProcessor.MyScope.class, scopeValue);
}
catch (IllegalArgumentException e) {
scope = null;
}
if (scope == null) {
scope = AndroidFindStyleApplicationsProcessor.MyScope.FILE;
}
switch (scope) {
case PROJECT:
myProjectScopeRadio.setSelected(true);
break;
case MODULE:
myModuleScopeRadio.setSelected(true);
break;
case FILE:
myFileScopeRadio.setSelected(true);
break;
}
if (myModuleScopeRadio.isSelected() && !myModuleScopeRadio.isVisible() ||
myFileScopeRadio.isSelected() && !myFileScopeRadio.isVisible()) {
myProjectScopeRadio.setSelected(true);
}
myCaptionLabel.setText("Choose a scope where to search possible applications of style '" + myProcessor.getStyleName() + "'");
setTitle(AndroidBundle.message("android.find.style.applications.title"));
init();
}
@Override
protected void doOKAction() {
AndroidFindStyleApplicationsProcessor.MyScope scope;
if (myModuleScopeRadio.isSelected()) {
scope = AndroidFindStyleApplicationsProcessor.MyScope.MODULE;
}
else if (myProjectScopeRadio.isSelected()) {
scope = AndroidFindStyleApplicationsProcessor.MyScope.PROJECT;
}
else {
scope = AndroidFindStyleApplicationsProcessor.MyScope.FILE;
}
PropertiesComponent.getInstance().setValue(FIND_STYLE_APPLICATIONS_SCOPE_PROPERTY, scope.name());
myProcessor.configureScope(scope, myFile);
myProcessor.setPrepareSuccessfulSwingThreadCallback(new Runnable() {
public void run() {
close(DialogWrapper.OK_EXIT_CODE);
}
});
myProcessor.run();
}
@Nullable
@Override
protected JComponent createCenterPanel() {
return myPanel;
}
}
@@ -0,0 +1,427 @@
package org.jetbrains.android.refactoring;
import com.android.resources.ResourceType;
import com.intellij.ide.highlighter.XmlFileType;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.undo.UndoUtil;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectUtil;
import com.intellij.openapi.roots.ModuleRootManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.psi.XmlRecursiveElementVisitor;
import com.intellij.psi.impl.cache.CacheManager;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.UsageSearchContext;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.refactoring.BaseRefactoringProcessor;
import com.intellij.refactoring.ui.UsageViewDescriptorAdapter;
import com.intellij.usageView.UsageInfo;
import com.intellij.usageView.UsageViewBundle;
import com.intellij.usageView.UsageViewDescriptor;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomManager;
import org.jetbrains.android.dom.AndroidDomUtil;
import org.jetbrains.android.dom.converters.AndroidResourceReferenceBase;
import org.jetbrains.android.dom.layout.LayoutDomFileDescription;
import org.jetbrains.android.dom.layout.LayoutViewElement;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.resourceManagers.ValueResourceInfoImpl;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidFindStyleApplicationsProcessor extends BaseRefactoringProcessor {
private final Module myModule;
private final Map<AndroidAttributeInfo, String> myAttrMap;
private final String myStyleName;
private final XmlTag myStyleTag;
private final XmlAttributeValue myStyleNameAttrValue;
private final PsiElement myParentStyleNameAttrValue;
private final PsiFile myContext;
private boolean mySearchOnlyInCurrentModule;
private VirtualFile myFileToScan;
protected AndroidFindStyleApplicationsProcessor(@NotNull Module module,
@NotNull Map<AndroidAttributeInfo, String> attrMap,
@NotNull String styleName,
@NotNull XmlTag styleTag,
@NotNull XmlAttributeValue styleNameAttrValue,
@Nullable PsiElement parentStyleNameAttrValue,
@Nullable PsiFile context) {
super(module.getProject());
myModule = module;
myAttrMap = attrMap;
myStyleName = styleName;
myStyleTag = styleTag;
myParentStyleNameAttrValue = parentStyleNameAttrValue;
myStyleNameAttrValue = styleNameAttrValue;
myContext = context;
}
@NotNull
@Override
protected UsageViewDescriptor createUsageViewDescriptor(UsageInfo[] usages) {
return new UsageViewDescriptorAdapter() {
@NotNull
@Override
public PsiElement[] getElements() {
return new PsiElement[]{myStyleTag};
}
@Override
public String getProcessedElementsHeader() {
return "Style to use";
}
@Override
public String getCodeReferencesText(int usagesCount, int filesCount) {
return "Tags the reference to the style will be added to " +
UsageViewBundle.getOccurencesString(usagesCount, filesCount);
}
};
}
@NotNull
@Override
protected UsageInfo[] findUsages() {
final List<UsageInfo> usages = findAllStyleApplications();
return usages.toArray(new UsageInfo[usages.size()]);
}
@Override
protected boolean preprocessUsages(Ref<UsageInfo[]> refUsages) {
super.preprocessUsages(refUsages);
if (refUsages.get().length == 0) {
Messages.showInfoMessage(myProject, "IDEA has not found any possible applications of style '" + myStyleName + "'",
AndroidBundle.message("android.find.style.applications.title"));
return false;
}
return true;
}
@Override
protected void performRefactoring(UsageInfo[] usages) {
final Set<Pair<String, String>> attrsInStyle = new HashSet<Pair<String, String>>();
for (AndroidAttributeInfo info : myAttrMap.keySet()) {
attrsInStyle.add(Pair.create(info.getNamespace(), info.getName()));
}
for (UsageInfo usage : usages) {
final PsiElement element = usage.getElement();
final DomElement domElement = element instanceof XmlTag
? DomManager.getDomManager(myProject).getDomElement((XmlTag)element)
: null;
if (domElement instanceof LayoutViewElement) {
final List<XmlAttribute> attributesToDelete = new ArrayList<XmlAttribute>();
for (XmlAttribute attribute : ((XmlTag)element).getAttributes()) {
if (attrsInStyle.contains(Pair.create(attribute.getNamespace(),
attribute.getLocalName()))) {
attributesToDelete.add(attribute);
}
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (XmlAttribute attribute : attributesToDelete) {
attribute.delete();
}
((LayoutViewElement)domElement).getStyle().setStringValue("@style/" + myStyleName);
}
});
}
}
final PsiFile file = myStyleTag.getContainingFile();
if (file != null) {
UndoUtil.markPsiFileForUndo(file);
}
if (myContext != null) {
UndoUtil.markPsiFileForUndo(myContext);
}
}
@Override
protected String getCommandName() {
return "Use Style '" + myStyleName + "' Where Possible";
}
@NotNull
static List<Module> getAllModulesToScan(@NotNull Module module) {
final List<Module> result = new ArrayList<Module>();
for (Module m : ModuleManager.getInstance(module.getProject()).getModules()) {
if (m.equals(module) || ModuleRootManager.getInstance(m).isDependsOn(module)) {
result.add(module);
}
}
return result;
}
@NotNull
private List<UsageInfo> findAllStyleApplications() {
final ProgressIndicator indicator = ProgressManager.getInstance().getProgressIndicator();
final Project project = myModule.getProject();
final List<VirtualFile> resDirs = new ArrayList<VirtualFile>();
if (mySearchOnlyInCurrentModule) {
collectResDir(myModule, myStyleNameAttrValue, myStyleName, resDirs);
}
else {
for (Module m : getAllModulesToScan(myModule)) {
collectResDir(m, myStyleNameAttrValue, myStyleName, resDirs);
}
}
final List<VirtualFile> subdirs = AndroidResourceUtil.getResourceSubdirs(
ResourceType.LAYOUT.getName(), resDirs.toArray(new VirtualFile[resDirs.size()]));
List<VirtualFile> filesToProcess = new ArrayList<VirtualFile>();
for (VirtualFile subdir : subdirs) {
for (VirtualFile child : subdir.getChildren()) {
if (child.getFileType() == XmlFileType.INSTANCE &&
(myFileToScan == null || myFileToScan.equals(child))) {
filesToProcess.add(child);
}
}
}
if (filesToProcess.size() == 0) {
return Collections.emptyList();
}
final Set<PsiFile> psiFilesToProcess = new HashSet<PsiFile>();
for (VirtualFile file : filesToProcess) {
final PsiFile psiFile = PsiManager.getInstance(project).findFile(file);
if (psiFile != null) {
psiFilesToProcess.add(psiFile);
}
}
final CacheManager cacheManager = CacheManager.SERVICE.getInstance(project);
final GlobalSearchScope projectScope = GlobalSearchScope.projectScope(project);
for (Map.Entry<AndroidAttributeInfo, String> entry : myAttrMap.entrySet()) {
filterFilesToScan(cacheManager, entry.getKey().getName(), psiFilesToProcess, projectScope);
filterFilesToScan(cacheManager, entry.getValue(), psiFilesToProcess, projectScope);
}
if (psiFilesToProcess.size() == 0) {
return Collections.emptyList();
}
final int n = psiFilesToProcess.size();
int i = 0;
if (indicator != null) {
indicator.setText("Searching for style applications");
}
final List<UsageInfo> usages = new ArrayList<UsageInfo>();
for (PsiFile psiFile : psiFilesToProcess) {
ProgressManager.checkCanceled();
final VirtualFile vFile = psiFile.getVirtualFile();
if (vFile == null) {
continue;
}
if (indicator != null) {
indicator.setFraction((double)i / n);
indicator.setText2(ProjectUtil.calcRelativeToProjectPath(vFile, project));
}
findAllStyleApplications(project, vFile, myAttrMap, myParentStyleNameAttrValue, usages);
}
return usages;
}
private static void collectResDir(Module module, XmlAttributeValue styleNameAttrValue, String styleName, List<VirtualFile> resDirs) {
final AndroidFacet f = AndroidFacet.getInstance(module);
final VirtualFile resDir = f != null
? f.getLocalResourceManager().getResourceDir()
: null;
if (resDir != null) {
final List<ValueResourceInfoImpl> resolvedStyles = f.getLocalResourceManager().findValueResourceInfos(
ResourceType.STYLE.getName(), styleName, true, false);
if (resolvedStyles.size() == 1) {
final XmlAttributeValue resolvedStyleNameElement = resolvedStyles.get(0).computeXmlElement();
if (resolvedStyleNameElement != null &&
resolvedStyleNameElement.equals(styleNameAttrValue)) {
resDirs.add(resDir);
}
}
}
}
private static void filterFilesToScan(CacheManager cacheManager,
String s,
Set<PsiFile> result,
GlobalSearchScope scope) {
for (String word : StringUtil.getWordsInStringLongestFirst(s)) {
final PsiFile[] files = cacheManager.getFilesWithWord(word, UsageSearchContext.ANY, scope, true);
result.retainAll(Arrays.asList(files));
}
}
private static void findAllStyleApplications(final Project project,
final VirtualFile layoutVFile,
final Map<AndroidAttributeInfo, String> attrMap,
final PsiElement parentStyleNameAttrValue,
final List<UsageInfo> usages) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
final PsiFile layoutFile = PsiManager.getInstance(project).findFile(layoutVFile);
if (!(layoutFile instanceof XmlFile)) {
return;
}
if (!(DomManager.getDomManager(project).getDomFileDescription(
(XmlFile)layoutFile) instanceof LayoutDomFileDescription)) {
return;
}
layoutFile.accept(new XmlRecursiveElementVisitor() {
@Override
public void visitXmlTag(XmlTag tag) {
super.visitXmlTag(tag);
if (isPossibleApplicationOfStyle(project, tag, attrMap, parentStyleNameAttrValue)) {
usages.add(new UsageInfo(tag));
}
}
});
PsiManager.getInstance(project).dropResolveCaches();
InjectedLanguageManager.getInstance(project).dropFileCaches(layoutFile);
}
});
}
@Nullable
private static PsiElement getStyleNameAttrValueForTag(@NotNull LayoutViewElement element) {
final AndroidResourceReferenceBase styleRef = AndroidDomUtil.
getAndroidResourceReference(element.getStyle(), false);
if (styleRef != null) {
final PsiElement[] styleElements = styleRef.computeTargetElements();
if (styleElements.length == 1) {
return styleElements[0];
}
}
return null;
}
private static boolean isPossibleApplicationOfStyle(Project project,
XmlTag candidate,
Map<AndroidAttributeInfo, String> attrMap,
PsiElement parentStyleNameAttrValue) {
final DomElement domCandidate = DomManager.getDomManager(project).getDomElement(candidate);
if (!(domCandidate instanceof LayoutViewElement)) {
return false;
}
final LayoutViewElement candidateView = (LayoutViewElement)domCandidate;
final Map<Pair<String, String>, String> attrsInCandidateMap = new HashMap<Pair<String, String>, String>();
final List<XmlAttribute> attrsInCandidate = AndroidExtractStyleAction.getExtractableAttributes(candidate);
if (attrsInCandidate.size() < attrMap.size()) {
return false;
}
for (XmlAttribute attribute : attrsInCandidate) {
final String attrValue = attribute.getValue();
if (attrValue != null) {
attrsInCandidateMap.put(Pair.create(attribute.getNamespace(), attribute.getLocalName()), attrValue);
}
}
for (Map.Entry<AndroidAttributeInfo, String> entry : attrMap.entrySet()) {
final String ns = entry.getKey().getNamespace();
final String name = entry.getKey().getName();
final String value = entry.getValue();
final String valueInCandidate = attrsInCandidateMap.get(Pair.create(ns, name));
if (valueInCandidate == null || !valueInCandidate.equals(value)) {
return false;
}
}
if (candidateView.getStyle().getStringValue() != null) {
if (parentStyleNameAttrValue == null) {
return false;
}
final PsiElement styleNameAttrValueForTag = getStyleNameAttrValueForTag(candidateView);
if (styleNameAttrValueForTag == null ||
!parentStyleNameAttrValue.equals(styleNameAttrValueForTag)) {
return false;
}
}
else if (parentStyleNameAttrValue != null) {
return false;
}
return true;
}
public void setSearchOnlyInCurrentModule(boolean searchOnlyInCurrentModule) {
mySearchOnlyInCurrentModule = searchOnlyInCurrentModule;
}
public void setFileToScan(VirtualFile fileToScan) {
myFileToScan = fileToScan;
}
@NotNull
public Module getModule() {
return myModule;
}
@NotNull
public String getStyleName() {
return myStyleName;
}
public void configureScope(MyScope scope, @Nullable VirtualFile context) {
if (scope == MyScope.MODULE) {
setSearchOnlyInCurrentModule(true);
}
else if (scope == MyScope.FILE) {
setSearchOnlyInCurrentModule(true);
setFileToScan(context);
}
}
enum MyScope {
PROJECT, MODULE, FILE
}
}
@@ -13,22 +13,19 @@ import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.usageView.UsageInfo;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.MultiMap;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomManager;
import com.intellij.util.xml.GenericAttributeValue;
import org.jetbrains.android.dom.AndroidDomUtil;
import org.jetbrains.android.dom.converters.AndroidResourceReferenceBase;
import org.jetbrains.android.dom.layout.Include;
import org.jetbrains.android.dom.layout.LayoutViewElement;
import org.jetbrains.android.dom.resources.ResourceValue;
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;
@@ -70,14 +67,14 @@ class AndroidInlineUtil {
if (domElement instanceof LayoutViewElement) {
final GenericAttributeValue<ResourceValue> styleAttribute = ((LayoutViewElement)domElement).getStyle();
final AndroidResourceReferenceBase reference = getAndroidResourceReference(styleAttribute);
final AndroidResourceReferenceBase reference = AndroidDomUtil.getAndroidResourceReference(styleAttribute, true);
if (reference != null) {
return new ViewStyleUsageData(tag, styleAttribute, reference);
}
}
else if (domElement instanceof Style) {
final AndroidResourceReferenceBase reference = getAndroidResourceReference(((Style)domElement).getParentStyle());
final AndroidResourceReferenceBase reference = AndroidDomUtil.getAndroidResourceReference(((Style)domElement).getParentStyle(), true);
if (reference != null) {
return new ParentStyleUsageData((Style)domElement, reference);
@@ -93,7 +90,7 @@ class AndroidInlineUtil {
if (domElement instanceof Include) {
final GenericAttributeValue<ResourceValue> layoutAttribute = ((Include)domElement).getLayout();
final AndroidResourceReferenceBase reference = getAndroidResourceReference(layoutAttribute);
final AndroidResourceReferenceBase reference = AndroidDomUtil.getAndroidResourceReference(layoutAttribute, true);
if (reference != null) {
return new LayoutUsageData(project, tag, reference);
@@ -102,74 +99,19 @@ class AndroidInlineUtil {
return null;
}
@Nullable
private static AndroidResourceReferenceBase getAndroidResourceReference(@Nullable GenericAttributeValue<ResourceValue> attribute) {
if (attribute == null) {
return null;
}
final ResourceValue resValue = attribute.getValue();
if (resValue == null || resValue.getPackage() != null) {
return null;
}
final XmlAttributeValue value = attribute.getXmlAttributeValue();
if (value == null) {
return null;
}
for (PsiReference reference : value.getReferences()) {
if (reference instanceof AndroidResourceReferenceBase) {
return (AndroidResourceReferenceBase)reference;
}
}
return null;
}
@Nullable
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();
String attributeValue = item.getStringValue();
if (attributeName == null || attributeName.length() <= 0 || attributeValue == null) {
continue;
}
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;
if (nsPrefix != null) {
if (!AndroidUtils.SYSTEM_RESOURCE_PACKAGE.equals(nsPrefix)) {
errorReporter.report(RefactoringBundle.getCannotRefactorMessage("Unknown XML attribute prefix '" + nsPrefix + ":'"),
AndroidBundle.message("android.inline.style.title"));
return null;
}
}
else {
errorReporter.report(
RefactoringBundle.getCannotRefactorMessage("The style contains attribute without 'android' prefix."),
AndroidBundle.message("android.inline.style.title"));
return null;
}
attributeValues.put(new AndroidAttributeInfo(localName, nsPrefix), attributeValue);
}
return attributeValues;
}
static void doInlineStyleDeclaration(@NotNull Project project,
@NotNull MyStyleData data,
@Nullable final StyleUsageData usageData,
@NotNull ErrorReporter errorReporter,
@Nullable AndroidInlineTestConfig testConfig) {
final Style style = data.myStyleElement;
final Map<AndroidAttributeInfo, String> attributeValues = computeAttributeMap(style, errorReporter);
final Map<AndroidAttributeInfo, String> attributeValues = AndroidRefactoringUtil.computeAttributeMap(style, errorReporter,
AndroidBundle.message(
"android.inline.style.title"));
if (attributeValues == null) {
return;
}
final StyleRefData parentStyleRef = getParentStyle(style);
final StyleRefData parentStyleRef = AndroidRefactoringUtil.getParentStyle(style);
boolean inlineThisOnly;
if (testConfig != null) {
@@ -216,31 +158,6 @@ class AndroidInlineUtil {
}
}
@Nullable
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 StyleRefData(parentStyleName, parentStyleRefValue.getPackage());
}
}
else {
final String styleName = style.getName().getStringValue();
if (styleName != null) {
final int idx = styleName.lastIndexOf('.');
if (idx > 0) {
return new StyleRefData(styleName.substring(0, idx), null);
}
}
}
return null;
}
@Nullable
static MyStyleData getInlinableStyleDataFromContext(@Nullable PsiElement context) {
if (context instanceof LazyValueResourceElementWrapper) {
@@ -0,0 +1,81 @@
package org.jetbrains.android.refactoring;
import com.intellij.refactoring.RefactoringBundle;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.dom.resources.ResourceValue;
import org.jetbrains.android.dom.resources.Style;
import org.jetbrains.android.dom.resources.StyleItem;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.android.util.ErrorReporter;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
/**
* @author Eugene.Kudelevsky
*/
public class AndroidRefactoringUtil {
private AndroidRefactoringUtil() {
}
@Nullable
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 StyleRefData(parentStyleName, parentStyleRefValue.getPackage());
}
}
else {
final String styleName = style.getName().getStringValue();
if (styleName != null) {
final int idx = styleName.lastIndexOf('.');
if (idx > 0) {
return new StyleRefData(styleName.substring(0, idx), null);
}
}
}
return null;
}
@Nullable
static Map<AndroidAttributeInfo, String> computeAttributeMap(@NotNull Style style,
@NotNull ErrorReporter errorReporter,
@NotNull String errorReportTitle) {
final Map<AndroidAttributeInfo, String> attributeValues = new HashMap<AndroidAttributeInfo, String>();
for (StyleItem item : style.getItems()) {
final String attributeName = item.getName().getStringValue();
String attributeValue = item.getStringValue();
if (attributeName == null || attributeName.length() <= 0 || attributeValue == null) {
continue;
}
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;
if (nsPrefix != null) {
if (!AndroidUtils.SYSTEM_RESOURCE_PACKAGE.equals(nsPrefix)) {
errorReporter.report(RefactoringBundle.getCannotRefactorMessage("Unknown XML attribute prefix '" + nsPrefix + ":'"),
errorReportTitle);
return null;
}
}
else {
errorReporter.report(
RefactoringBundle.getCannotRefactorMessage("The style contains attribute without 'android' prefix."),
errorReportTitle);
return null;
}
attributeValues.put(new AndroidAttributeInfo(localName, nsPrefix), attributeValue);
}
return attributeValues;
}
}
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="org.jetbrains.android.refactoring.ExtractStyleDialog">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="4" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="5" column-count="2" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
<margin top="0" left="0" bottom="0" right="0"/>
<constraints>
<xy x="20" y="20" width="337" height="400"/>
<xy x="20" y="20" width="380" height="400"/>
</constraints>
<properties/>
<border type="none"/>
@@ -27,7 +27,7 @@
</component>
<grid id="8a6e9" binding="myAttributeListWrapper" layout-manager="BorderLayout" hgap="0" vgap="0">
<constraints>
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
<grid row="4" column="0" row-span="1" col-span="2" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false">
<preferred-size width="-1" height="200"/>
</grid>
</constraints>
@@ -37,7 +37,7 @@
</grid>
<component id="7f54d" class="com.intellij.ui.components.JBLabel" binding="myAttributesLabel">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
<grid row="3" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="8" fill="0" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&amp;Attributes:"/>
@@ -58,6 +58,14 @@
</constraints>
<properties/>
</component>
<component id="93b91" class="com.intellij.ui.components.JBCheckBox" binding="mySearchForStyleApplicationsAfter">
<constraints>
<grid row="2" column="0" row-span="1" col-span="2" vsize-policy="0" hsize-policy="0" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
</constraints>
<properties>
<text value="&amp;Launch 'Use Style Where Possible' refactoring after the style is extracted"/>
</properties>
</component>
</children>
</grid>
</form>
@@ -16,6 +16,7 @@
package org.jetbrains.android.refactoring;
import com.android.resources.ResourceType;
import com.intellij.ide.util.PropertiesComponent;
import com.intellij.openapi.actionSystem.ActionToolbarPosition;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.module.Module;
@@ -23,6 +24,7 @@ import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.ValidationInfo;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.ui.*;
import com.intellij.ui.components.JBCheckBox;
import com.intellij.ui.components.JBLabel;
import com.intellij.util.PlatformIcons;
import com.intellij.util.containers.Convertor;
@@ -52,6 +54,7 @@ class ExtractStyleDialog extends DialogWrapper {
private JBLabel myAttributesLabel;
private JBLabel myModuleLabel;
private JComboBox myModuleCombo;
private JBCheckBox mySearchForStyleApplicationsAfter;
private final Module myModule;
private final String myFileName;
@@ -60,6 +63,8 @@ class ExtractStyleDialog extends DialogWrapper {
private final CheckboxTree myTree;
private final CheckedTreeNode myRootNode;
private static final String SEARCH_STYLE_APPLICATIONS_PROPERTY = "AndroidExtractStyleSearchStyleApplications";
public ExtractStyleDialog(@NotNull Module module,
@NotNull String fileName,
@Nullable String parentStyleName,
@@ -167,6 +172,9 @@ class ExtractStyleDialog extends DialogWrapper {
decorator.addExtraAction(unselectAll);
myAttributeListWrapper.add(decorator.createPanel());
final String value = PropertiesComponent.getInstance().getValue(SEARCH_STYLE_APPLICATIONS_PROPERTY);
mySearchForStyleApplicationsAfter.setSelected(Boolean.parseBoolean(value));
init();
}
@@ -184,6 +192,13 @@ class ExtractStyleDialog extends DialogWrapper {
return myPanel;
}
@Override
protected void doOKAction() {
super.doOKAction();
PropertiesComponent.getInstance().setValue(
SEARCH_STYLE_APPLICATIONS_PROPERTY, Boolean.toString(mySearchForStyleApplicationsAfter.isSelected()));
}
@Override
public JComponent getPreferredFocusedComponent() {
return myStyleNameField;
@@ -230,4 +245,8 @@ class ExtractStyleDialog extends DialogWrapper {
public Module getChosenModule() {
return myModule != null ? myModule : (Module)myModuleCombo.getSelectedItem();
}
public boolean isToSearchStyleApplications() {
return mySearchForStyleApplicationsAfter.isSelected();
}
}
@@ -37,7 +37,7 @@ class ViewStyleUsageData implements StyleUsageData {
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;
final String namespace = info.getNamespace();
if (myTag.getAttribute(localName, namespace) == null) {
myTag.setAttribute(localName, namespace, entry.getValue());