All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.intellij.xml.DefaultXmlNamespaceHelper Maven / Gradle / Ivy

Go to download

A packaging of the IntelliJ Community Edition xml-psi-impl library. This is release number 1 of trunk branch 142.

The newest version!
/*
 * 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.xml;

import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.ScrollType;
import com.intellij.openapi.module.ModuleUtilCore;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.XmlElementFactory;
import com.intellij.psi.xml.*;
import com.intellij.util.IncorrectOperationException;
import com.intellij.xml.index.XmlNamespaceIndex;
import com.intellij.xml.index.XmlTagNamesIndex;
import com.intellij.xml.util.XmlUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.*;

/**
 * @author yole
 */
public class DefaultXmlNamespaceHelper extends XmlNamespaceHelper {
  private static final Logger LOG = Logger.getInstance(DefaultXmlNamespaceHelper.class);

  @Override
  protected boolean isAvailable(PsiFile file) {
    return true;
  }

  @Override
  public void insertNamespaceDeclaration(@NotNull final XmlFile file,
                                         @Nullable final Editor editor,
                                         @NotNull final Set possibleNamespaces,
                                         @Nullable String nsPrefix,
                                         @Nullable final Runner runAfter) throws IncorrectOperationException {

    final String namespace = possibleNamespaces.iterator().next();

    final Project project = file.getProject();
    final XmlTag rootTag = file.getRootTag();
    assert rootTag != null;
    XmlAttribute anchor = getAnchor(rootTag);

    final List providers = XmlSchemaProvider.getAvailableProviders(file);
    String prefix = getPrefix(file, nsPrefix, namespace, providers);

    final XmlElementFactory elementFactory = XmlElementFactory.getInstance(project);
    String location = getLocation(file, namespace, providers);
    String xsiPrefix = null;
    if (location != null) {
      xsiPrefix = rootTag.getPrefixByNamespace(XmlUtil.XML_SCHEMA_INSTANCE_URI);
      if (xsiPrefix == null) {
        xsiPrefix = "xsi";
        rootTag.add(elementFactory.createXmlAttribute("xmlns:xsi", XmlUtil.XML_SCHEMA_INSTANCE_URI));
      }
    }

    @NonNls final String qname = "xmlns" + (prefix.length() > 0 ? ":"+ prefix :"");
    final XmlAttribute attribute = elementFactory.createXmlAttribute(qname, namespace);
    if (anchor == null) {
      rootTag.add(attribute);
    } else {
      rootTag.addAfter(attribute, anchor);
    }

    if (location != null) {
      XmlAttribute locationAttribute = rootTag.getAttribute(XmlUtil.SCHEMA_LOCATION_ATT, XmlUtil.XML_SCHEMA_INSTANCE_URI);
      final String pair = namespace + " " + location;
      if (locationAttribute == null) {
        locationAttribute = elementFactory.createXmlAttribute(xsiPrefix + ":" + XmlUtil.SCHEMA_LOCATION_ATT, pair);
        rootTag.add(locationAttribute);
      }
      else {
        final String value = locationAttribute.getValue();
        if (!StringUtil.notNullize(value).contains(namespace)) {
          if (value == null || StringUtil.isEmptyOrSpaces(value)) {
            locationAttribute.setValue(pair);
          }
          else {
            locationAttribute.setValue(value.trim() + " " + pair);
          }
        }
      }
    }
    XmlUtil.reformatTagStart(rootTag);

    if (editor != null && namespace.length() == 0) {
      final XmlAttribute xmlAttribute = rootTag.getAttribute(qname);
      if (xmlAttribute != null) {
        final XmlAttributeValue value = xmlAttribute.getValueElement();
        assert value != null;
        final int startOffset = value.getTextOffset();
        editor.getCaretModel().moveToOffset(startOffset);
        editor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
      }
    }
    if (runAfter != null) {
      runAfter.run(prefix);
    }
  }

  private static String getPrefix(XmlFile file, String nsPrefix, String namespace, List providers) {
    String prefix = nsPrefix;
    if (prefix == null) {
      for (XmlSchemaProvider provider : providers) {
        prefix = provider.getDefaultPrefix(namespace, file);
        if (prefix != null) {
          break;
        }
      }
    }
    if (prefix == null) {
      prefix = "";
    }
    return prefix;
  }

  private static XmlAttribute getAnchor(XmlTag rootTag) {
    final XmlAttribute[] attributes = rootTag.getAttributes();
    XmlAttribute anchor = null;
    for (XmlAttribute attribute : attributes) {
      final XmlAttributeDescriptor descriptor = attribute.getDescriptor();
      if (attribute.isNamespaceDeclaration() || (descriptor != null && descriptor.isRequired())) {
        anchor = attribute;
      } else {
        break;
      }
    }
    return anchor;
  }

  private static String getLocation(XmlFile file, String namespace, List providers) {
    String location = null;
    if (namespace.length() > 0) {
      for (XmlSchemaProvider provider : providers) {
        Set locations = provider.getLocations(namespace, file);
        if (locations != null && !locations.isEmpty()) {
          location = locations.iterator().next();
        }
      }
    }
    return location;
  }

  @Override
  @NotNull
  public Set guessUnboundNamespaces(@NotNull final PsiElement element, @NotNull XmlFile file) {
    if (!(element instanceof XmlTag)) {
      return Collections.emptySet();
    }
    final XmlTag tag = (XmlTag)element;
    final String name = tag.getLocalName();
    final Set byTagName = getNamespacesByTagName(name, file);
    if (!byTagName.isEmpty()) {
      Set filtered = new HashSet(byTagName);
      filtered.removeAll(Arrays.asList(tag.knownNamespaces()));
      return filtered;
    }
    final Set set = guessNamespace(file, name);
    set.removeAll(Arrays.asList(tag.knownNamespaces()));

    final XmlTag parentTag = tag.getParentTag();
    ns: for (Iterator i = set.iterator(); i.hasNext();) {
      final String s = i.next();
      final Collection namespaces = XmlUtil.findNSFilesByURI(s, element.getProject(), ModuleUtilCore.findModuleForPsiElement(file));
      for (XmlFile namespace : namespaces) {
        final XmlDocument document = namespace.getDocument();
        assert document != null;
        final XmlNSDescriptor nsDescriptor = (XmlNSDescriptor)document.getMetaData();
        assert nsDescriptor != null;
        if (parentTag != null) {
          continue ns;
        }
        final XmlElementDescriptor[] descriptors = nsDescriptor.getRootElementsDescriptors(document);
        for (XmlElementDescriptor descriptor : descriptors) {
          if (descriptor == null) {
            LOG.error(nsDescriptor + " returned null element for getRootElementsDescriptors() array");
            continue;
          }
          if (descriptor.getName().equals(name)) {
            continue ns;
          }
        }
      }
      i.remove();
    }
    return set;
  }

  private static Set guessNamespace(final PsiFile file, String tagName) {
    final Project project = file.getProject();
    final Collection files = XmlTagNamesIndex.getFilesByTagName(tagName, project);
    final Set possibleUris = new LinkedHashSet(files.size());
    for (VirtualFile virtualFile : files) {
      final String namespace = XmlNamespaceIndex.getNamespace(virtualFile, project, file);
      if (namespace != null) {
        possibleUris.add(namespace);
      }
    }
    return possibleUris;
  }

  @Override
  @NotNull
  public Set getNamespacesByTagName(@NotNull final String tagName, @NotNull final XmlFile context) {
    final List providers = XmlSchemaProvider.getAvailableProviders(context);

    HashSet set = new HashSet();
    for (XmlSchemaProvider provider : providers) {
      set.addAll(provider.getAvailableNamespaces(context, tagName));
    }
    return set;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy