blob: ec1a380cbb5e7b4089bc7701190c6617754412ed [file] [log] [blame]
package org.jetbrains.plugins.groovy.mvc.projectView;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.NonNls;
/**
* @author Dmitry Krasilschikov
*/
public class NodeId {
private final String myFileUrl;
private final PsiElement myElement;
/**
* Indicates in which sub tree element is located (controllers/models/migrations/.. /particular userfolder)
* It is nesessary for supporting user folders more correctly and prevent dublicating NodeIds
*/
private final String myLocationRootMark;
private int hash; // Default cached hash code equals to 0
@NonNls public static final String CONTROLLERS_SUBTREE = "CONTROLLERS_SUBTREE";
@NonNls public static final String CONTROLLER_IN_CONTROLLERS_SUBTREE = "CONTROLLER_IN_" + CONTROLLERS_SUBTREE;
@NonNls public static final String ACTION_IN_CONTROLLERS_SUBTREE = "ACTION_IN_" + CONTROLLERS_SUBTREE;
@NonNls public static final String DOMAINS_SUBTREE = "DOMAINS_SUBTREE";
@NonNls public static final String DOMAIN_CLASS_IN_DOMAINS_SUBTREE = "DOMAIN_CLASS_IN_" + DOMAINS_SUBTREE;
@NonNls public static final String VIEWS_SUBTREE = "VIEWS_SUBTREE";
@NonNls public static final String TESTS_TREE = "TESTS";
@NonNls public static final String TEST_CLASS_IN_TESTS_SUBTREE = "TEST_IN" + TESTS_TREE;
public NodeId(@NotNull final String fileUrl, @Nullable final String locationRootMark) {
this(fileUrl, null, locationRootMark);
}
public NodeId(@NotNull final PsiElement element, @Nullable final String locationRootMark) {
this(null, element, locationRootMark);
}
/**
* Unique id for Rails Project view nodes.
* By common sense and for correct support of rename operation.
* NodeId with equal PsiElements and locationRootMarks should be equal. Thus there is
* no sence to use psiElement with cached fileUrl
* On the other hand some elements may not have reperesentaion in Psi
* (e.g. files with unregistered extension), thus we should work with them via file url.
* @param fileUrl
* @param element
* @param locationRootMark
*/
private NodeId(@Nullable final String fileUrl,
@Nullable final PsiElement element,
@Nullable final String locationRootMark) {
myFileUrl = fileUrl;
myElement = element;
myLocationRootMark = locationRootMark;
}
@Nullable
public String getFileUrl() {
return myFileUrl;
}
@Nullable
public String getLocationRootMark() {
return myLocationRootMark;
}
@Nullable
public PsiElement getPsiElement() {
return myElement;
}
public String toString() {
// For Debug purposes
final StringBuilder buff = new StringBuilder();
buff.append("[url = ");
buff.append(getFileUrl());
buff.append(", psiElement = ");
buff.append(getPsiElement());
buff.append(", location mark = (");
buff.append(getLocationRootMark());
buff.append(")]");
return buff.toString();
}
@SuppressWarnings({"EqualsWhichDoesntCheckParameterClass"})
@Override
public boolean equals(final Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) {
return false;
}
final NodeId nodeId = (NodeId)o;
// url
if (myFileUrl != null
? !myFileUrl.equals(nodeId.myFileUrl)
: nodeId.myFileUrl != null) {
return false;
}
// location
if (myLocationRootMark != null
? !myLocationRootMark.equals(nodeId.myLocationRootMark)
: nodeId.myLocationRootMark != null) {
return false;
}
// pointer on null/not null
if (myElement != nodeId.myElement) {
return false;
}
return true;
}
@Override
public int hashCode() {
if (hash == 0) {
hash = (myFileUrl != null) ? myFileUrl.hashCode() : 1;
hash = 31 * hash + (myLocationRootMark != null ? myLocationRootMark.hashCode() : 0);
// pointer delegates hashCode() to its element
/**
* This hack allows as to ignore strange behavior of equals() and hashcode()
* in LazySmartPsielementPointer which some times can't compare
* properly pointers pointing on the same psi element instance
*/
if (myElement != null) {
hash = 31 * hash + myElement.hashCode();
} else {
hash = 31 * hash;
}
}
return hash;
}
}