org.netbeans.modules.android.grammars.resources.ResourcesGrammar.java Source code

Java tutorial

Introduction

Here is the source code for org.netbeans.modules.android.grammars.resources.ResourcesGrammar.java

Source

/*
 * 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 org.netbeans.modules.android.grammars.resources;

import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.netbeans.modules.android.grammars.AbstractResultNode;
import org.netbeans.modules.android.grammars.SimpleAttr;
import org.netbeans.modules.android.grammars.SimpleElement;
import org.netbeans.modules.android.grammars.SimpleEntityReference;
import org.netbeans.modules.xml.api.model.GrammarQuery;
import org.netbeans.modules.xml.api.model.GrammarResult;
import org.netbeans.modules.xml.api.model.HintContext;
import org.openide.util.Enumerations;
import org.w3c.dom.Attr;
import org.w3c.dom.DOMException;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

/**
 * Query implementation for resource XML files -- strings, attributes, colors and similar.
 *
 * @author Radim Kubacki
 */
public class ResourcesGrammar implements GrammarQuery {

    private static final Logger LOG = Logger.getLogger(ResourcesGrammar.class.getName());

    private final ResourcesModel model;

    public ResourcesGrammar() {
        model = new ResourcesModel();
    }

    /**
     * Allow to get names of <b>parsed general entities</b>.
     * @return list of <code>CompletionResult</code>s (ENTITY_REFERENCE_NODEs)
     */
    @Override
    public Enumeration<GrammarResult> queryEntities(String prefix) {
        List<GrammarResult> list = new ArrayList<GrammarResult>();

        // XXX(radim): add well-know build-in entity names, can we do better?

        if ("lt".startsWith(prefix)) {
            list.add(new SimpleEntityReference("lt"));
        }
        if ("gt".startsWith(prefix)) {
            list.add(new SimpleEntityReference("gt"));
        }
        if ("apos".startsWith(prefix)) {
            list.add(new SimpleEntityReference("apos"));
        }
        if ("quot".startsWith(prefix)) {
            list.add(new SimpleEntityReference("quot"));
        }
        if ("amp".startsWith(prefix)) {
            list.add(new SimpleEntityReference("amp"));
        }

        LOG.log(Level.FINE, "queryEntities({0}) -> {1}", new Object[] { prefix, list });
        return Collections.enumeration(list);
    }

    @Override
    public Enumeration<GrammarResult> queryAttributes(HintContext ctx) {

        Element ownerElement = null;
        // Support both versions of GrammarQuery contract
        if (ctx.getNodeType() == Node.ATTRIBUTE_NODE) {
            ownerElement = ((Attr) ctx).getOwnerElement();
        } else if (ctx.getNodeType() == Node.ELEMENT_NODE) {
            ownerElement = (Element) ctx;
        }
        if (ownerElement == null) {
            return Enumerations.empty();
        }
        ResElementDescriptor resElem = findElement(ownerElement);
        LOG.log(Level.FINE, "queryAttributes(tag={0} element={1} prefix={2})",
                new Object[] { ownerElement, resElem, ctx.getCurrentPrefix() });
        List<GrammarResult> list = new ArrayList<GrammarResult>();
        String prefix = ctx.getCurrentPrefix();
        // TODO(radim): filter existing attrs
        //    NamedNodeMap existingAttributes = ownerElement.getAttributes();
        if (resElem != null) {
            for (ResAttrDescriptor resElemAttr : resElem.getAttrs()) {
                if (resElemAttr.getName().startsWith(prefix)) {
                    list.add(new SimpleAttr(resElemAttr.getName(), resElemAttr.getDescription()));
                }
            }
        }

        LOG.log(Level.FINE, "queryAttributes({0}) -> {1}", new Object[] { prefix, list });
        return Collections.enumeration(list);
    }

    private ResElementDescriptor findElement(Node n) {
        List<String> parentTags = Lists.newArrayList();
        String parentTagName = null;
        Node parent = n;
        while (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
            parentTagName = ((Element) parent).getTagName();
            parentTags.add(parentTagName);
            parent = parent.getParentNode();
        }
        ResElementDescriptor resElem = model.getRootElement();
        if (!parentTags.isEmpty()) {
            boolean isFirst = true;
            while (!parentTags.isEmpty()) {
                final String tag = parentTags.remove(parentTags.size() - 1);
                if (!isFirst) {
                    resElem = Iterables.find(resElem.getChildren(), new Predicate<ResElementDescriptor>() {
                        @Override
                        public boolean apply(ResElementDescriptor input) {
                            return input.getName().equals(tag);
                        }
                    }, null);
                } else {
                    isFirst = false;
                    if (!resElem.getName().equals(tag)) {
                        // something wrong with the hierarchy
                        resElem = null;
                    }
                }
                if (resElem == null) {
                    break;
                }
            }
        }
        LOG.log(Level.FINE, "find element({0}) > {1}", new Object[] { n, resElem });
        return resElem;
    }

    @Override
    public Enumeration<GrammarResult> queryElements(HintContext ctx) {
        LOG.log(Level.FINE, "queryElements({0})", ctx.getCurrentPrefix());

        ResElementDescriptor resElem = findElement(((Node) ctx).getParentNode());
        String prefix = ctx.getCurrentPrefix();

        List<GrammarResult> list = new ArrayList<GrammarResult>();
        if (resElem != null) {
            for (ResElementDescriptor resElemTag : resElem.getChildren()) {
                if (resElemTag.getName().startsWith(prefix)) {
                    list.add(new SimpleElement(resElemTag.getName(), resElemTag.getDescription()));
                }
            }
        }

        LOG.log(Level.FINE, "queryElements({0}) -> {1}", new Object[] { prefix, list });
        return Collections.enumeration(list);
    }

    @Override
    public Enumeration<GrammarResult> queryNotations(String prefix) {
        LOG.log(Level.FINE, "queryNotatios({0})", prefix);
        return Enumerations.empty();
    }

    @Override
    public Enumeration<GrammarResult> queryValues(HintContext ctx) {
        LOG.log(Level.FINE, "queryValues({0})", ctx.getCurrentPrefix());
        //    Attr ownerAttr;
        //    if (ctx.getNodeType() == Node.ATTRIBUTE_NODE) {
        //        ownerAttr = (Attr)ctx;
        //    } else {
        //        LOG.fine("...unknown node type");
        //        return Enumerations.empty();
        //    }
        //    String attrName = ownerAttr.getName();
        //    if (attrName.startsWith("android:")) {
        //      attrName = attrName.substring("android:".length());
        //    }
        List<GrammarResult> choices = new ArrayList<GrammarResult>();
        //    for (String value : model.getAttributeValues(attrName)) {
        //      if (value.startsWith(ctx.getCurrentPrefix())) {
        //        choices.add(new MyText(value));
        //      }
        //    }
        return Collections.enumeration(choices);
    }

    // return defaults, no way to query them
    @Override
    public GrammarResult queryDefault(final HintContext ctx) {
        LOG.log(Level.FINE, "queryDefault({0})", ctx.getCurrentPrefix());
        return null;
    }

    // it is not yet implemented
    @Override
    public boolean isAllowed(Enumeration<GrammarResult> en) {
        return true;
    }

    // customizers section ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    @Override
    public java.awt.Component getCustomizer(HintContext ctx) {
        return null;
    }

    @Override
    public boolean hasCustomizer(HintContext ctx) {
        return false;
    }

    @Override
    public org.openide.nodes.Node.Property[] getProperties(HintContext ctx) {
        return null;
    }

    @Override
    public String toString() {
        return "ResourceGrammar [" + super.toString() + "]";
    }

    // TODO(radim) pull out to share with AndroidGrammar
    private static class MyText extends AbstractResultNode implements Text {

        private String data;

        MyText(String data) {
            this.data = data;
        }

        @Override
        public short getNodeType() {
            return Node.TEXT_NODE;
        }

        @Override
        public String getNodeValue() {
            return data;
        }

        @Override
        public String getData() throws DOMException {
            return data;
        }

        @Override
        public int getLength() {
            return data == null ? -1 : data.length();
        }

        @Override
        public String toString() {
            return data;
        }

        @Override
        public String getDisplayName() {
            return data; // #113804
        }
    }
}