com.intellij.codeInsight.daemon.impl.analysis.AddSchemaPrefixIntention.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.codeInsight.daemon.impl.analysis.AddSchemaPrefixIntention.java

Source

/*
 * Copyright 2000-2013 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.codeInsight.daemon.impl.analysis;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.intellij.codeInsight.intention.PsiElementBaseIntentionAction;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.InputValidator;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiReference;
import com.intellij.psi.XmlRecursiveElementVisitor;
import com.intellij.psi.impl.source.resolve.reference.impl.providers.TypeOrElementOrAttributeReference;
import com.intellij.psi.impl.source.xml.SchemaPrefixReference;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlAttributeValue;
import com.intellij.psi.xml.XmlElement;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.IncorrectOperationException;
import consulo.annotations.RequiredDispatchThread;

/**
 * @author Konstantin Bulenkov
 */
public class AddSchemaPrefixIntention extends PsiElementBaseIntentionAction {
    public static final String NAME = "Insert Namespace Prefix";

    public AddSchemaPrefixIntention() {
        setText(NAME);
    }

    @Nonnull
    @Override
    public String getFamilyName() {
        return NAME;
    }

    @Override
    public boolean startInWriteAction() {
        return false;
    }

    @Override
    public void invoke(@Nonnull Project project, Editor editor, @Nonnull PsiElement element)
            throws IncorrectOperationException {
        final XmlAttribute xmlns = getXmlnsDeclaration(element);
        if (xmlns == null) {
            return;
        }
        final String namespace = xmlns.getValue();
        final XmlTag tag = xmlns.getParent();

        if (tag != null) {
            final Set<String> ns = tag.getLocalNamespaceDeclarations().keySet();
            final String nsPrefix = Messages.showInputDialog(project, "Namespace Prefix:", NAME,
                    Messages.getInformationIcon(), "", new InputValidator() {
                        @RequiredDispatchThread
                        @Override
                        public boolean checkInput(String inputString) {
                            return !ns.contains(inputString);
                        }

                        @RequiredDispatchThread
                        @Override
                        public boolean canClose(String inputString) {
                            return checkInput(inputString);
                        }
                    });
            if (nsPrefix == null) {
                return;
            }
            final List<XmlTag> tags = new ArrayList<XmlTag>();
            final List<XmlAttributeValue> values = new ArrayList<XmlAttributeValue>();
            new WriteCommandAction(project, NAME, tag.getContainingFile()) {
                @Override
                protected void run(Result result) throws Throwable {
                    tag.accept(new XmlRecursiveElementVisitor() {
                        @Override
                        public void visitXmlTag(XmlTag tag) {
                            if (tag.getNamespace().equals(namespace) && tag.getNamespacePrefix().length() == 0) {
                                tags.add(tag);
                            }
                            super.visitXmlTag(tag);
                        }

                        @Override
                        public void visitXmlAttributeValue(XmlAttributeValue value) {
                            PsiReference ref = null;
                            boolean skip = false;
                            for (PsiReference reference : value.getReferences()) {
                                if (reference instanceof TypeOrElementOrAttributeReference) {
                                    ref = reference;
                                } else if (reference instanceof SchemaPrefixReference) {
                                    skip = true;
                                    break;
                                }
                            }
                            if (!skip && ref != null) {
                                final PsiElement xmlElement = ref.resolve();
                                if (xmlElement instanceof XmlElement) {
                                    final XmlTag tag = PsiTreeUtil.getParentOfType(xmlElement, XmlTag.class, false);
                                    if (tag != null) {
                                        if (tag.getNamespace().equals(namespace)) {
                                            if (ref.getRangeInElement().getLength() == value.getValue().length()) { //no ns prefix
                                                values.add(value);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    });
                    for (XmlAttributeValue value : values) {
                        ((XmlAttribute) value.getParent()).setValue(nsPrefix + ":" + value.getValue());
                    }
                    for (XmlTag xmlTag : tags) {
                        xmlTag.setName(nsPrefix + ":" + xmlTag.getLocalName());
                    }
                    xmlns.setName("xmlns:" + nsPrefix);
                }
            }.execute();
        }
    }

    @Override
    public boolean isAvailable(@Nonnull Project project, Editor editor, @Nonnull PsiElement element) {
        return getXmlnsDeclaration(element) != null;
    }

    @Nullable
    private static XmlAttribute getXmlnsDeclaration(PsiElement element) {
        final PsiElement parent = element.getParent();
        if (parent instanceof XmlTag) {
            XmlTag tag = (XmlTag) parent;
            if (tag.getNamespacePrefix().length() == 0) {
                while (tag != null) {
                    final XmlAttribute attr = tag.getAttribute("xmlns");
                    if (attr != null) {
                        return attr;
                    }
                    tag = tag.getParentTag();
                }
            }
        } else if (parent instanceof XmlAttribute && ((XmlAttribute) parent).getName().equals("xmlns")) {
            return (XmlAttribute) parent;
        }
        return null;
    }
}