Search in sources :

Example 6 with ResourceElement

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;
}
Also used : ResourceElement(org.jetbrains.android.dom.resources.ResourceElement) DomElement(com.intellij.util.xml.DomElement) LocalResourceManager(org.jetbrains.android.resourceManagers.LocalResourceManager) XmlAttributeValue(com.intellij.psi.xml.XmlAttributeValue) XmlTag(com.intellij.psi.xml.XmlTag) Nullable(org.jetbrains.annotations.Nullable)

Example 7 with ResourceElement

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;
}
Also used : VirtualFile(com.intellij.openapi.vfs.VirtualFile) WriteCommandAction(com.intellij.openapi.command.WriteCommandAction) XmlAttribute(com.intellij.psi.xml.XmlAttribute) LayoutViewElement(org.jetbrains.android.dom.layout.LayoutViewElement) StyleItem(org.jetbrains.android.dom.resources.StyleItem) Result(com.intellij.openapi.application.Result) UndoConfirmationPolicy(com.intellij.openapi.command.UndoConfirmationPolicy) ResourceValue(org.jetbrains.android.dom.resources.ResourceValue) Style(org.jetbrains.android.dom.resources.Style) PsiFile(com.intellij.psi.PsiFile) HashSet(com.intellij.util.containers.HashSet) ResourceElement(org.jetbrains.android.dom.resources.ResourceElement) Project(com.intellij.openapi.project.Project) XmlTag(com.intellij.psi.xml.XmlTag) Nullable(org.jetbrains.annotations.Nullable)

Example 8 with ResourceElement

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);
        }
    }
}
Also used : ResourceElement(org.jetbrains.android.dom.resources.ResourceElement) ResourceType(com.android.resources.ResourceType) ResourceManager(org.jetbrains.android.resourceManagers.ResourceManager) LocalResourceManager(org.jetbrains.android.resourceManagers.LocalResourceManager) XmlAttributeValue(com.intellij.psi.xml.XmlAttributeValue) Predicate(com.google.common.base.Predicate) Project(com.intellij.openapi.project.Project) DomElement(com.intellij.util.xml.DomElement) XmlElement(com.intellij.psi.xml.XmlElement) Style(org.jetbrains.android.dom.resources.Style) XmlTag(com.intellij.psi.xml.XmlTag) LazyValueResourceElementWrapper(org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper) ValueResourceElementWrapper(org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper)

Example 9 with ResourceElement

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();
}
Also used : VirtualFile(com.intellij.openapi.vfs.VirtualFile) WriteCommandAction(com.intellij.openapi.command.WriteCommandAction) ResourceElement(org.jetbrains.android.dom.resources.ResourceElement) NotNull(org.jetbrains.annotations.NotNull) Result(com.intellij.openapi.application.Result) Resources(org.jetbrains.android.dom.resources.Resources)

Example 10 with ResourceElement

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;
}
Also used : ResourceElement(org.jetbrains.android.dom.resources.ResourceElement) Item(org.jetbrains.android.dom.resources.Item) NotNull(org.jetbrains.annotations.NotNull)

Aggregations

ResourceElement (org.jetbrains.android.dom.resources.ResourceElement)16 XmlTag (com.intellij.psi.xml.XmlTag)7 NotNull (org.jetbrains.annotations.NotNull)7 Result (com.intellij.openapi.application.Result)6 WriteCommandAction (com.intellij.openapi.command.WriteCommandAction)6 DomElement (com.intellij.util.xml.DomElement)6 Nullable (org.jetbrains.annotations.Nullable)6 VirtualFile (com.intellij.openapi.vfs.VirtualFile)5 Resources (org.jetbrains.android.dom.resources.Resources)4 Style (org.jetbrains.android.dom.resources.Style)4 XmlAttributeValue (com.intellij.psi.xml.XmlAttributeValue)3 ResourceType (com.android.resources.ResourceType)2 ConfiguredThemeEditorStyle (com.android.tools.idea.editors.theme.datamodels.ConfiguredThemeEditorStyle)2 Project (com.intellij.openapi.project.Project)2 PsiFile (com.intellij.psi.PsiFile)2 XmlAttribute (com.intellij.psi.xml.XmlAttribute)2 Processor (com.intellij.util.Processor)2 Item (org.jetbrains.android.dom.resources.Item)2 StyleItem (org.jetbrains.android.dom.resources.StyleItem)2 LocalResourceManager (org.jetbrains.android.resourceManagers.LocalResourceManager)2