blob: 2cec8cacd6ceb963363eb113905a3803327ee61b [file] [log] [blame]
/*
* Copyright 2000-2014 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 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 org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
* @author Konstantin Bulenkov
*/
public class AddSchemaPrefixIntention extends PsiElementBaseIntentionAction {
public static final String NAME = "Insert Namespace Prefix";
public AddSchemaPrefixIntention() {
setText(NAME);
}
@NotNull
@Override
public String getFamilyName() {
return NAME;
}
@Override
public void invoke(@NotNull Project project, Editor editor, @NotNull 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() {
@Override
public boolean checkInput(String inputString) {
return !ns.contains(inputString);
}
@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(@NotNull Result result) throws Throwable {
tag.accept(new XmlRecursiveElementVisitor() {
@Override
public void visitXmlTag(XmlTag tag) {
if (tag.getNamespace().equals(namespace) && tag.getNamespacePrefix().isEmpty()) {
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(@NotNull Project project, Editor editor, @NotNull 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().isEmpty()) {
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;
}
}