Search in sources :

Example 1 with ValueResourceElementWrapper

use of org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper in project android by JetBrains.

the class NlIdPropertyItem method setValue.

@Override
public void setValue(Object value) {
    String newId = value != null ? stripIdPrefix(value.toString()) : "";
    String oldId = getValue();
    XmlTag tag = getTag();
    if (ourRefactoringChoice != REFACTOR_NO && oldId != null && !oldId.isEmpty() && !newId.isEmpty() && !oldId.equals(newId) && tag != null && tag.isValid()) {
        // Offer rename refactoring?
        XmlAttribute attribute = tag.getAttribute(SdkConstants.ATTR_ID, SdkConstants.ANDROID_URI);
        if (attribute != null) {
            Module module = getModel().getModule();
            Project project = module.getProject();
            XmlAttributeValue valueElement = attribute.getValueElement();
            if (valueElement != null && valueElement.isValid()) {
                // Exact replace only, no comment/text occurrence changes since it is non-interactive
                ValueResourceElementWrapper wrapper = new ValueResourceElementWrapper(valueElement);
                RenameProcessor processor = new RenameProcessor(project, wrapper, NEW_ID_PREFIX + newId, false, /*comments*/
                false);
                processor.setPreviewUsages(false);
                // Do a quick usage search to see if we need to ask about renaming
                UsageInfo[] usages = processor.findUsages();
                if (usages.length > 0) {
                    int choice = ourRefactoringChoice;
                    if (choice == REFACTOR_ASK) {
                        DialogBuilder builder = createDialogBuilder(project);
                        builder.setTitle("Update Usages?");
                        // UGH!
                        JPanel panel = new JPanel(new BorderLayout());
                        JLabel label = new JLabel("<html>" + "Update usages as well?<br>" + "This will update all XML references and Java R field references.<br>" + "<br>" + "</html>");
                        panel.add(label, BorderLayout.CENTER);
                        JBCheckBox checkBox = new JBCheckBox("Don't ask again during this session");
                        panel.add(checkBox, BorderLayout.SOUTH);
                        builder.setCenterPanel(panel);
                        builder.setDimensionServiceKey("idPropertyDimension");
                        builder.removeAllActions();
                        DialogBuilder.CustomizableAction yesAction = builder.addOkAction();
                        yesAction.setText(Messages.YES_BUTTON);
                        builder.addActionDescriptor(dialogWrapper -> new AbstractAction(Messages.NO_BUTTON) {

                            @Override
                            public void actionPerformed(ActionEvent actionEvent) {
                                dialogWrapper.close(DialogWrapper.NEXT_USER_EXIT_CODE);
                            }
                        });
                        builder.addCancelAction();
                        int exitCode = builder.show();
                        choice = exitCode == DialogWrapper.OK_EXIT_CODE ? REFACTOR_YES : exitCode == DialogWrapper.NEXT_USER_EXIT_CODE ? REFACTOR_NO : ourRefactoringChoice;
                        //noinspection AssignmentToStaticFieldFromInstanceMethod
                        ourRefactoringChoice = checkBox.isSelected() ? choice : REFACTOR_ASK;
                        if (exitCode == DialogWrapper.CANCEL_EXIT_CODE) {
                            return;
                        }
                    }
                    if (choice == REFACTOR_YES) {
                        processor.run();
                        return;
                    }
                }
            }
        }
    }
    super.setValue(!StringUtil.isEmpty(newId) ? NEW_ID_PREFIX + newId : null);
}
Also used : XmlAttribute(com.intellij.psi.xml.XmlAttribute) RenameProcessor(com.intellij.refactoring.rename.RenameProcessor) ActionEvent(java.awt.event.ActionEvent) XmlAttributeValue(com.intellij.psi.xml.XmlAttributeValue) JBCheckBox(com.intellij.ui.components.JBCheckBox) Project(com.intellij.openapi.project.Project) Module(com.intellij.openapi.module.Module) DialogBuilder(com.intellij.openapi.ui.DialogBuilder) UsageInfo(com.intellij.usageView.UsageInfo) XmlTag(com.intellij.psi.xml.XmlTag) ValueResourceElementWrapper(org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper)

Example 2 with ValueResourceElementWrapper

use of org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper in project android by JetBrains.

the class AndroidRenameHandler method performValueResourceRenaming.

private static void performValueResourceRenaming(Project project, Editor editor, DataContext dataContext, XmlTag tag) {
    final XmlAttribute nameAttribute = tag.getAttribute("name");
    if (nameAttribute == null) {
        return;
    }
    final XmlAttributeValue attributeValue = nameAttribute.getValueElement();
    if (attributeValue == null) {
        return;
    }
    RenameDialog.showRenameDialog(dataContext, new RenameDialog(project, new ValueResourceElementWrapper(attributeValue), null, editor));
}
Also used : RenameDialog(com.intellij.refactoring.rename.RenameDialog) ValueResourceElementWrapper(org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper)

Example 3 with ValueResourceElementWrapper

use of org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper in project android by JetBrains.

the class AndroidResourceRenameResourceProcessor method prepareResourceFieldRenaming.

private static void prepareResourceFieldRenaming(PsiField field, String newName, Map<PsiElement, String> allRenames) {
    new RenameJavaVariableProcessor().prepareRenaming(field, newName, allRenames);
    List<PsiElement> resources = AndroidResourceUtil.findResourcesByField(field);
    PsiElement res = resources.get(0);
    final String newResName;
    if (res instanceof PsiFile) {
        // Resource comes from XML file, don't need to suggest change underscores to dots
        newResName = newName;
    } else if (res instanceof XmlAttributeValue) {
        newResName = getResourceName(field.getProject(), newName, ((XmlAttributeValue) res).getValue());
    } else {
        // AndroidResourceUtil.findResourcesByField supposed to return a list of PsiElements that are
        // either PsiFile or XmlAttributeValue. Previous version of this code doesn't handle other
        // possibilities at all and would crash with ClassCastException, having an explicit error message
        // seems to be a slightly better option.
        Logger.getInstance(AndroidResourceRenameResourceProcessor.class).error(String.format("%s: res is neither PsiFile nor XmlAttributeValue", AndroidResourceRenameResourceProcessor.class.getSimpleName()));
        newResName = newName;
    }
    for (PsiElement resource : resources) {
        if (resource instanceof PsiFile) {
            PsiFile file = (PsiFile) resource;
            String extension = FileUtilRt.getExtension(file.getName());
            allRenames.put(resource, newResName + '.' + extension);
        } else if (resource instanceof XmlAttributeValue) {
            XmlAttributeValue value = (XmlAttributeValue) resource;
            final String s = AndroidResourceUtil.isIdDeclaration(value) ? NEW_ID_PREFIX + newResName : newResName;
            allRenames.put(new ValueResourceElementWrapper(value), s);
            // we have to rename not just R.styleable.Foo but the also R.styleable.Foo_* attributes
            if (value.getParent() instanceof XmlAttribute) {
                XmlAttribute parent = (XmlAttribute) value.getParent();
                XmlTag tag = parent.getParent();
                if (tag.getName().equals(TAG_DECLARE_STYLEABLE)) {
                    AndroidFacet facet = AndroidFacet.getInstance(tag);
                    String oldName = tag.getAttributeValue(ATTR_NAME);
                    if (facet != null && oldName != null) {
                        for (XmlTag attr : tag.getSubTags()) {
                            if (attr.getName().equals(TAG_ATTR)) {
                                String name = attr.getAttributeValue(ATTR_NAME);
                                if (name != null) {
                                    String oldAttributeName = oldName + '_' + name;
                                    PsiField[] fields = AndroidResourceUtil.findResourceFields(facet, STYLEABLE.getName(), oldAttributeName, true);
                                    if (fields.length > 0) {
                                        String newAttributeName = newName + '_' + name;
                                        for (PsiField f : fields) {
                                            allRenames.put(f, newAttributeName);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
Also used : RenameJavaVariableProcessor(com.intellij.refactoring.rename.RenameJavaVariableProcessor) XmlAttribute(com.intellij.psi.xml.XmlAttribute) XmlAttributeValue(com.intellij.psi.xml.XmlAttributeValue) AndroidFacet(org.jetbrains.android.facet.AndroidFacet) LazyValueResourceElementWrapper(org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper) ValueResourceElementWrapper(org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper) XmlTag(com.intellij.psi.xml.XmlTag)

Example 4 with ValueResourceElementWrapper

use of org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper in project android by JetBrains.

the class ThemeEditorStyle method getNamePsiElement.

/**
   * Returns a PsiElement of the name attribute for this theme
   * made from a RANDOM sourceXml
   */
@Nullable
public PsiElement getNamePsiElement() {
    Collection<ResourceItem> resources = getStyleResourceItems();
    if (resources.isEmpty()) {
        return null;
    }
    // Any sourceXml will do to get the name attribute from
    final XmlTag sourceXml = LocalResourceRepository.getItemTag(myManager.getProject(), resources.iterator().next());
    assert sourceXml != null;
    final XmlAttribute nameAttribute = sourceXml.getAttribute("name");
    if (nameAttribute == null) {
        return null;
    }
    XmlAttributeValue attributeValue = nameAttribute.getValueElement();
    if (attributeValue == null) {
        return null;
    }
    return new ValueResourceElementWrapper(attributeValue);
}
Also used : XmlAttribute(com.intellij.psi.xml.XmlAttribute) XmlAttributeValue(com.intellij.psi.xml.XmlAttributeValue) ResourceItem(com.android.ide.common.res2.ResourceItem) XmlTag(com.intellij.psi.xml.XmlTag) ValueResourceElementWrapper(org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper) Nullable(org.jetbrains.annotations.Nullable)

Example 5 with ValueResourceElementWrapper

use of org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper 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)

Aggregations

ValueResourceElementWrapper (org.jetbrains.android.dom.wrappers.ValueResourceElementWrapper)6 XmlAttributeValue (com.intellij.psi.xml.XmlAttributeValue)5 XmlAttribute (com.intellij.psi.xml.XmlAttribute)4 XmlTag (com.intellij.psi.xml.XmlTag)4 LazyValueResourceElementWrapper (org.jetbrains.android.dom.wrappers.LazyValueResourceElementWrapper)3 Project (com.intellij.openapi.project.Project)2 LocalResourceManager (org.jetbrains.android.resourceManagers.LocalResourceManager)2 ResourceItem (com.android.ide.common.res2.ResourceItem)1 ResourceType (com.android.resources.ResourceType)1 Predicate (com.google.common.base.Predicate)1 Module (com.intellij.openapi.module.Module)1 DialogBuilder (com.intellij.openapi.ui.DialogBuilder)1 XmlElement (com.intellij.psi.xml.XmlElement)1 RenameDialog (com.intellij.refactoring.rename.RenameDialog)1 RenameJavaVariableProcessor (com.intellij.refactoring.rename.RenameJavaVariableProcessor)1 RenameProcessor (com.intellij.refactoring.rename.RenameProcessor)1 JBCheckBox (com.intellij.ui.components.JBCheckBox)1 UsageInfo (com.intellij.usageView.UsageInfo)1 DomElement (com.intellij.util.xml.DomElement)1 ActionEvent (java.awt.event.ActionEvent)1