Package org.mevenide.idea.psi.util

Source Code of org.mevenide.idea.psi.util.PsiUnnamedPropertyChangeListener$RowAppenderRunnable

package org.mevenide.idea.psi.util;

import com.intellij.psi.PsiElement;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.IncorrectOperationException;
import java.util.*;
import javax.swing.event.EventListenerList;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mevenide.idea.Res;
import org.mevenide.idea.util.IDEUtils;
import org.mevenide.idea.util.event.*;

/**
* @author Arik
*/
public class PsiUnnamedPropertyChangeListener extends PsiPropertyChangeListener
        implements BeanRowsObservable {
    /**
     * Logging.
     */
    private static final Log LOG = LogFactory.getLog(PsiUnnamedPropertyChangeListener.class);

    /**
     * Resources
     */
    private static final Res RES = Res.getInstance(PsiUnnamedPropertyChangeListener.class);

    /**
     * Synchronization lock.
     */
    private final Object LOCK = new Object();

    /**
     * The path to the tag containing all row tags.
     */
    private final XmlTagPath containerPath;

    /**
     * Cache for lazily created tag paths, as property names are not known in advance.
     */
    private final Map<String, XmlTagPath> pathsCache = Collections.synchronizedMap(new HashMap<String, XmlTagPath>(
            10));

    /**
     * Property change listeners container.
     */
    private final EventListenerList listenerList = new EventListenerList();

    /**
     * The name to use for properties without a name.
     */
    private String unknownPropertyName;

    public PsiUnnamedPropertyChangeListener(final XmlFile pFile,
                                            final String pContainerPath) {
        this(new XmlTagPath(pFile, pContainerPath));
    }

    public PsiUnnamedPropertyChangeListener(final XmlTagPath pContainerPath) {
        if (pContainerPath == null)
            throw new IllegalArgumentException(RES.get("null.arg", "pContainerPath"));
        containerPath = pContainerPath;
    }

    public String getUnknownPropertyName() {
        return unknownPropertyName;
    }

    public void setUnknownPropertyName(final String pUnknownPropertyName) {
        unknownPropertyName = pUnknownPropertyName;
    }

    public final String[] getPropertyNames() {
        final XmlTag[] tags = getPropertyTags();
        final String[] names = new String[tags.length];
        for (int i = 0; i < tags.length; i++)
            names[i] = tags[i].getName();

        return names;
    }

    public final void renameProperty(final String pPropertyName,
                                     final String pNewPropertyName) {
        final XmlTagPath tagPath = getPropertyTagPath(pPropertyName, false);
        XmlTag tag = tagPath == null ? null : tagPath.getTag();
        if (tag == null)
            return;

        //
        //rename the tag
        //
        final TagRenamerRunnable runnable = new TagRenamerRunnable(tag, pNewPropertyName);
        IDEUtils.runCommand(containerPath.getProject(), runnable);
        tag = runnable.getTag();
        if (tag == null)
            return;

        //
        //create new path based on new property name
        //
        final String[] pathTokens = tagPath.getPathTokens(false);
        pathTokens[pathTokens.length - 1] = pNewPropertyName;

        //
        //remove the old path
        //
        pathsCache.remove(pPropertyName);
        notifyRemoval(pPropertyName);

        //
        //put in the cache the new path
        //
        final String path = StringUtils.join(pathTokens, '/');
        final XmlTagPath newTagPath = new XmlTagPath(containerPath, path);
        pathsCache.put(pNewPropertyName, newTagPath);

        notifyAddition(pNewPropertyName);
    }

    public final XmlTag[] getPropertyTags() {
        final XmlTag containerTag = containerPath.getTag();
        if (containerTag == null)
            return new XmlTag[0];

        return containerTag.getSubTags();
    }

    protected String getPropertyForElement(final PsiElement pElement) {
        final XmlTag[] tags = getPropertyTags();
        for (XmlTag tag : tags) {
            if (PsiTreeUtil.isAncestor(tag, pElement, false))
                return tag.getName();
        }

        return null;
    }

    protected String getPropertyForPath(final String[] pPath) {
        final XmlTag[] tags = getPropertyTags();
        for (XmlTag tag : tags) {
            final String[] path = PsiUtils.getPathTokens(tag);

            int i = 0;
            boolean equal = true;
            while (i < path.length && i < pPath.length && equal) {
                equal = path[i].equals(pPath[i]);
                i++;
            }

            if (equal && pPath.length >= path.length)
                return tag.getName();
        }

        return null;
    }

    public final XmlTagPath getPropertyTagPath(final String pProperty) {
        return getPropertyTagPath(pProperty, true);
    }

    public final XmlTagPath getPropertyTagPath(final String pProperty,
                                               final boolean pCreateIfNotFound) {
        XmlTagPath path = pathsCache.get(pProperty);
        if (path == null && pCreateIfNotFound) {
            path = new XmlTagPath(containerPath, pProperty);
            pathsCache.put(pProperty, path);
        }

        return path;
    }

    public void addBeanRowsListener(BeanRowsListener pListener) {
        synchronized (LOCK) {
            listenerList.add(BeanRowsListener.class, pListener);
        }
    }

    public void removeBeanRowsListener(BeanRowsListener pListener) {
        synchronized (LOCK) {
            listenerList.remove(BeanRowsListener.class, pListener);
        }
    }

    public int getRowCount() {
        final XmlTag containerTag = containerPath.getTag();
        if (containerTag == null)
            return 0;

        return containerTag.getSubTags().length;
    }

    public int appendRow() {
        final RowAppenderRunnable addTagCmd = new RowAppenderRunnable();

        IDEUtils.runCommand(containerPath.getProject(), addTagCmd);
        return addTagCmd.getResult();
    }

    public void deleteRows(final int... pRowIndices) {
        final Runnable deleteTagsCmd = new RowDeleterRunnable(pRowIndices);

        IDEUtils.runCommand(containerPath.getProject(), deleteTagsCmd);
    }

    @Override
    protected void notifyAddition(final String pPropertyName) {
        final String[] propertyNames = getPropertyNames();
        final int row = ArrayUtils.indexOf(propertyNames, pPropertyName);
        fireRowAddedEvent(row);
    }

    @Override
    protected void notifyChange(final String pPropertyName) {
        String[] propertyNames = getPropertyNames();
        int row = ArrayUtils.indexOf(propertyNames, pPropertyName);
        fireRowChangedEvent(row, pPropertyName, getValue(pPropertyName));
    }

    @Override
    protected void notifyRemoval(final String pPropertyName) {
        fireRowsChangedEvent();
    }

    private BeanRowsListener[] getListeners() {
        return listenerList.getListeners(BeanRowsListener.class);
    }

    private void fireRowAddedEvent(final int pRow) {
        BeanRowEvent event = null;
        for (BeanRowsListener listener : getListeners()) {
            if (event == null)
                event = new BeanRowAddedEvent(this, pRow);
            listener.rowAdded(event);
        }
    }

    private void fireRowRemovedEvent(final int pRow) {
        BeanRowEvent event = null;
        for (BeanRowsListener listener : getListeners()) {
            if (event == null)
                event = new BeanRowRemovedEvent(this, pRow);
            listener.rowRemoved(event);
        }
    }

    private void fireRowChangedEvent(final int pRow,
                                     final String pProperty,
                                     final Object pValue) {
        BeanRowEvent event = null;
        for (BeanRowsListener listener : getListeners()) {
            if (event == null)
                event = new BeanRowChangedEvent(this, pRow, pProperty, pValue);
            listener.rowChanged(event);
        }
    }

    private void fireRowsChangedEvent() {
        BeanRowEvent event = null;
        for (BeanRowsListener listener : getListeners()) {
            if (event == null)
                event = new BeanRowsChangedEvent(this);
            listener.rowsChanged(event);
        }
    }

    private class RowAppenderRunnable implements Runnable {
        private int result = -1;

        public void run() {
            result = -1;
            try {
                final XmlTag containerTag = containerPath.ensureTag();
                final String namespace = containerTag.getNamespace();
                final XmlTag rowTag = (XmlTag) containerTag.add(
                        containerTag.createChildTag(unknownPropertyName,
                                                    namespace,
                                                    null,
                                                    false));

                final XmlTag[] childTags = containerTag.getSubTags();
                for (int i = 0; i < childTags.length; i++) {
                    XmlTag tag = childTags[i];
                    if (tag.equals(rowTag)) {
                        result = i;
                        break;
                    }
                }
            }
            catch (IncorrectOperationException e) {
                LOG.error(e.getMessage(), e);
            }
        }

        public final int getResult() {
            return result;
        }
    }

    private class RowDeleterRunnable implements Runnable {
        private final int[] rowIndices;

        public RowDeleterRunnable(final int... pRowIndices) {
            rowIndices = pRowIndices;
        }

        public void run() {
            try {
                final XmlTag containerTag = containerPath.getTag();
                if (containerTag == null)
                    return;

                final XmlTag[] childTags = containerTag.getSubTags();
                final Set<XmlTag> tags = new HashSet<XmlTag>(rowIndices.length);
                for (int rowIndice : rowIndices)
                    tags.add(childTags[rowIndice]);

                for (XmlTag xmlTag : tags)
                    xmlTag.delete();
            }
            catch (IncorrectOperationException e) {
                LOG.error(e.getMessage(), e);
            }
        }
    }

    private class TagRenamerRunnable implements Runnable {
        private final String newName;
        private XmlTag tag;

        public TagRenamerRunnable(final XmlTag pTag, final String pNewName) {
            tag = pTag;
            newName = pNewName;
        }

        public void run() {
            try {
                tag = (XmlTag) tag.setName(newName);
            }
            catch (IncorrectOperationException e) {
                LOG.error(e.getMessage(), e);
                tag = null;
            }
        }

        public XmlTag getTag() {
            return tag;
        }
    }
}
TOP

Related Classes of org.mevenide.idea.psi.util.PsiUnnamedPropertyChangeListener$RowAppenderRunnable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.