use of org.jetbrains.android.dom.resources.ResourceElement in project android by JetBrains.
the class AndroidResourceRenameResourceProcessor method getResourceName.
/** Looks up the resource name for the given refactored element. Uses the same
* instanceof chain checkups as is done in {@link #canProcessElement} */
@Nullable
private static String getResourceName(PsiElement originalElement) {
PsiElement element = LazyValueResourceElementWrapper.computeLazyElement(originalElement);
if (element == null) {
return null;
}
if (element instanceof PsiFile) {
PsiFile file = (PsiFile) element;
LocalResourceManager manager = LocalResourceManager.getInstance(element);
if (manager != null) {
String type = manager.getFileResourceType(file);
if (type != null) {
String name = file.getName();
return AndroidCommonUtils.getResourceName(type, name);
}
}
return LintUtils.getBaseName(file.getName());
} else if (element instanceof PsiField) {
PsiField field = (PsiField) element;
return field.getName();
} else if (element instanceof XmlAttributeValue) {
if (AndroidResourceUtil.isIdDeclaration((XmlAttributeValue) element)) {
return AndroidResourceUtil.getResourceNameByReferenceText(((XmlAttributeValue) element).getValue());
}
XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
if (tag != null) {
DomElement domElement = DomManager.getDomManager(tag.getProject()).getDomElement(tag);
if (domElement instanceof ResourceElement) {
return ((ResourceElement) domElement).getName().getValue();
}
}
}
return null;
}
use of org.jetbrains.android.dom.resources.ResourceElement in project android by JetBrains.
the class AndroidExtractStyleAction method doExtractStyle.
@Nullable
public static String doExtractStyle(@NotNull Module module, @NotNull final XmlTag viewTag, final boolean addStyleAttributeToTag, @Nullable MyTestConfig testConfig) {
final PsiFile file = viewTag.getContainingFile();
if (file == null) {
return null;
}
final String dialogTitle = AndroidBundle.message("android.extract.style.title");
final String fileName = AndroidResourceUtil.getDefaultResourceFileName(ResourceType.STYLE);
assert fileName != null;
final List<String> dirNames = Collections.singletonList(ResourceFolderType.VALUES.getName());
final List<XmlAttribute> extractableAttributes = getExtractableAttributes(viewTag);
final Project project = module.getProject();
if (extractableAttributes.size() == 0) {
AndroidUtils.reportError(project, "The tag doesn't contain any attributes that can be extracted", dialogTitle);
return null;
}
final LayoutViewElement viewElement = getLayoutViewElement(viewTag);
assert viewElement != null;
final ResourceValue parentStyleValue = viewElement.getStyle().getValue();
final String parentStyle;
boolean supportImplicitParent = false;
if (parentStyleValue != null) {
parentStyle = parentStyleValue.getResourceName();
if (ResourceType.STYLE != parentStyleValue.getType() || parentStyle == null || parentStyle.length() == 0) {
AndroidUtils.reportError(project, "Invalid parent style reference " + parentStyleValue.toString(), dialogTitle);
return null;
}
supportImplicitParent = parentStyleValue.getNamespace() == null;
} else {
parentStyle = null;
}
final String styleName;
final List<XmlAttribute> styledAttributes;
final VirtualFile chosenDirectory;
final boolean searchStyleApplications;
if (testConfig == null) {
final ExtractStyleDialog dialog = new ExtractStyleDialog(module, fileName, supportImplicitParent ? parentStyle : null, dirNames, extractableAttributes);
dialog.setTitle(dialogTitle);
if (!dialog.showAndGet()) {
return null;
}
searchStyleApplications = dialog.isToSearchStyleApplications();
chosenDirectory = dialog.getResourceDirectory();
if (chosenDirectory == null) {
AndroidUtils.reportError(project, AndroidBundle.message("check.resource.dir.error", module.getName()));
return null;
}
styledAttributes = dialog.getStyledAttributes();
styleName = dialog.getStyleName();
} else {
testConfig.validate(extractableAttributes);
chosenDirectory = testConfig.getResourceDirectory();
styleName = testConfig.getStyleName();
final Set<String> attrsToExtract = new HashSet<String>(Arrays.asList(testConfig.getAttributesToExtract()));
styledAttributes = new ArrayList<XmlAttribute>();
for (XmlAttribute attribute : extractableAttributes) {
if (attrsToExtract.contains(attribute.getName())) {
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) {
@Override
protected void run(@NotNull final Result result) throws Throwable {
final List<XmlAttribute> attributesToDelete = new ArrayList<XmlAttribute>();
if (!AndroidResourceUtil.createValueResource(project, chosenDirectory, styleName, null, ResourceType.STYLE, fileName, dirNames, new Processor<ResourceElement>() {
@Override
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())) {
final StyleItem item = style.addItem();
item.getName().setStringValue("android:" + attribute.getLocalName());
item.setStringValue(attribute.getValue());
attributesToDelete.add(attribute);
}
}
if (parentStyleValue != null && (!finalSupportImplicitParent || !styleName.startsWith(parentStyle + "."))) {
final String aPackage = parentStyleValue.getNamespace();
style.getParentStyle().setStringValue((aPackage != null ? aPackage + ":" : "") + parentStyle);
}
return true;
}
})) {
return;
}
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
for (XmlAttribute attribute : attributesToDelete) {
attribute.delete();
}
if (addStyleAttributeToTag) {
final LayoutViewElement viewElement = getLayoutViewElement(viewTag);
assert viewElement != null;
viewElement.getStyle().setStringValue("@style/" + styleName);
}
}
});
success[0] = true;
}
@Override
protected UndoConfirmationPolicy getUndoConfirmationPolicy() {
return UndoConfirmationPolicy.REQUEST_CONFIRMATION;
}
}.execute();
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(createdStyleTag, createdStyleData, file, null);
}
});
}
}
return styleName;
}
use of org.jetbrains.android.dom.resources.ResourceElement in project android by JetBrains.
the class AndroidResourceRenameResourceProcessor method prepareValueResourceRenaming.
private static void prepareValueResourceRenaming(PsiElement element, String newName, Map<PsiElement, String> allRenames, final AndroidFacet facet) {
ResourceManager manager = facet.getLocalResourceManager();
XmlTag tag = PsiTreeUtil.getParentOfType(element, XmlTag.class);
assert tag != null;
String type = manager.getValueResourceType(tag);
assert type != null;
Project project = tag.getProject();
DomElement domElement = DomManager.getDomManager(project).getDomElement(tag);
assert domElement instanceof ResourceElement;
String name = ((ResourceElement) domElement).getName().getValue();
assert name != null;
List<ResourceElement> resources = manager.findValueResources(type, name);
for (ResourceElement resource : resources) {
XmlElement xmlElement = resource.getName().getXmlAttributeValue();
if (!element.getManager().areElementsEquivalent(element, xmlElement)) {
allRenames.put(xmlElement, newName);
}
}
if (getResourceType(element) == ResourceType.STYLE) {
// For styles, try also to find child styles defined by name (i.e. "ParentName.StyleName") and add them
// to the rename list. This will allow the rename processor to also handle the references to those. For example,
// If you rename "MyTheme" and your manifest theme is "MyTheme.NoActionBar", this will make sure that
// the reference from the manifest is also updated by adding "MyTheme.NoActionBar" to the rename list.
// We iterate the styles in order to cascade any changes to children down the hierarchy.
// List of styles that will be renamed.
HashSet<String> renamedStyles = Sets.newHashSet();
renamedStyles.add(name);
final String stylePrefix = name + ".";
Collection<String> renameCandidates;
ResourceType resourceType = ResourceType.getEnum(type);
if (resourceType == null) {
renameCandidates = Collections.emptyList();
} else {
renameCandidates = Collections2.filter(manager.getResourceNames(resourceType), new Predicate<String>() {
@Override
public boolean apply(String input) {
return input.startsWith(stylePrefix);
}
});
}
for (String resourceName : ORDER_BY_LENGTH.sortedCopy(renameCandidates)) {
// resourceName.lastIndexOf will never return -1 because we've filtered all names that
// do not contain stylePrefix
String parentName = resourceName.substring(0, resourceName.lastIndexOf('.'));
if (!renamedStyles.contains(parentName)) {
// This resource's parent wasn't affected by the rename
continue;
}
for (ResourceElement resource : manager.findValueResources(type, resourceName)) {
if (!(resource instanceof Style) || ((Style) resource).getParentStyle().getXmlAttributeValue() != null) {
// This element is not a style or does have an explicit parent so we do not rename it.
continue;
}
XmlAttributeValue xmlElement = resource.getName().getXmlAttributeValue();
if (xmlElement != null) {
String newStyleName = newName + StringUtil.trimStart(resourceName, name);
allRenames.put(new ValueResourceElementWrapper(xmlElement), newStyleName);
renamedStyles.add(resourceName);
}
}
}
}
PsiField[] resFields = AndroidResourceUtil.findResourceFieldsForValueResource(tag, false);
for (PsiField resField : resFields) {
String escaped = AndroidResourceUtil.getFieldNameByResourceName(newName);
allRenames.put(resField, escaped);
}
// Also rename the dependent fields, e.g. if you rename <declare-styleable name="Foo">,
// we have to rename not just R.styleable.Foo but the also R.styleable.Foo_* attributes
PsiField[] styleableFields = AndroidResourceUtil.findStyleableAttributeFields(tag, false);
if (styleableFields.length > 0) {
String tagName = tag.getName();
boolean isDeclareStyleable = tagName.equals(TAG_DECLARE_STYLEABLE);
boolean isAttr = !isDeclareStyleable && tagName.equals(TAG_ATTR) && tag.getParentTag() != null;
assert isDeclareStyleable || isAttr;
String style = isAttr ? tag.getParentTag().getAttributeValue(ATTR_NAME) : null;
for (PsiField resField : styleableFields) {
String fieldName = resField.getName();
String newAttributeName;
if (isDeclareStyleable && fieldName.startsWith(name)) {
newAttributeName = newName + fieldName.substring(name.length());
} else if (isAttr && style != null) {
newAttributeName = style + '_' + newName;
} else {
newAttributeName = name;
}
String escaped = AndroidResourceUtil.getFieldNameByResourceName(newAttributeName);
allRenames.put(resField, escaped);
}
}
}
use of org.jetbrains.android.dom.resources.ResourceElement in project android by JetBrains.
the class AndroidResourceUtil method changeValueResource.
/**
* Sets a new value for a resource.
* @param project the project containing the resource
* @param resDir the res/ directory containing the resource
* @param name the name of the resource to be modified
* @param newValue the new resource value
* @param fileName the resource values file name
* @param dirNames list of values directories where the resource should be changed
* @param useGlobalCommand if true, the undo will be registered globally. This allows the command to be undone from anywhere in the IDE
* and not only the XML editor
* @return true if the resource value was changed
*/
public static boolean changeValueResource(@NotNull final Project project, @NotNull VirtualFile resDir, @NotNull final String name, @NotNull final ResourceType resourceType, @NotNull final String newValue, @NotNull String fileName, @NotNull List<String> dirNames, final boolean useGlobalCommand) {
if (dirNames.isEmpty()) {
return false;
}
ArrayList<VirtualFile> resFiles = Lists.newArrayListWithExpectedSize(dirNames.size());
for (String dirName : dirNames) {
final VirtualFile resFile = findResourceFile(resDir, fileName, dirName);
if (resFile != null) {
resFiles.add(resFile);
}
}
if (!ensureFilesWritable(project, resFiles)) {
return false;
}
final Resources[] resourcesElements = new Resources[resFiles.size()];
for (int i = 0; i < resFiles.size(); i++) {
final Resources resources = AndroidUtils.loadDomElement(project, resFiles.get(i), Resources.class);
if (resources == null) {
AndroidUtils.reportError(project, AndroidBundle.message("not.resource.file.error", fileName));
return false;
}
resourcesElements[i] = resources;
}
List<PsiFile> psiFiles = Lists.newArrayListWithExpectedSize(resFiles.size());
PsiManager manager = PsiManager.getInstance(project);
for (VirtualFile file : resFiles) {
PsiFile psiFile = manager.findFile(file);
if (psiFile != null) {
psiFiles.add(psiFile);
}
}
PsiFile[] files = psiFiles.toArray(new PsiFile[psiFiles.size()]);
WriteCommandAction<Boolean> action = new WriteCommandAction<Boolean>(project, "Change " + resourceType.getName() + " Resource", files) {
@Override
protected void run(@NotNull Result<Boolean> result) throws Throwable {
if (useGlobalCommand) {
CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
}
result.setResult(false);
for (Resources resources : resourcesElements) {
for (ResourceElement element : getValueResourcesFromElement(resourceType, resources)) {
String value = element.getName().getStringValue();
if (name.equals(value)) {
element.setStringValue(newValue);
result.setResult(true);
}
}
}
}
};
return action.execute().getResultObject();
}
use of org.jetbrains.android.dom.resources.ResourceElement in project android by JetBrains.
the class AndroidResourceUtil method getValueResourcesFromElement.
@NotNull
public static List<ResourceElement> getValueResourcesFromElement(@NotNull ResourceType resourceType, @NotNull Resources resources) {
final List<ResourceElement> result = new ArrayList<>();
//noinspection EnumSwitchStatementWhichMissesCases
switch(resourceType) {
case STRING:
result.addAll(resources.getStrings());
break;
case PLURALS:
result.addAll(resources.getPluralses());
break;
case DRAWABLE:
result.addAll(resources.getDrawables());
break;
case COLOR:
result.addAll(resources.getColors());
break;
case DIMEN:
result.addAll(resources.getDimens());
break;
case STYLE:
result.addAll(resources.getStyles());
break;
case ARRAY:
result.addAll(resources.getStringArrays());
result.addAll(resources.getIntegerArrays());
result.addAll(resources.getArrays());
break;
case INTEGER:
result.addAll(resources.getIntegers());
break;
case FRACTION:
result.addAll(resources.getFractions());
break;
case BOOL:
result.addAll(resources.getBools());
break;
}
for (Item item : resources.getItems()) {
String type = item.getType().getValue();
if (resourceType.getName().equals(type)) {
result.add(item);
}
}
return result;
}
Aggregations