package com.intellij.flex.uiDesigner;
import com.intellij.ide.impl.ProjectUtil;
import com.intellij.javascript.flex.FlexAnnotationNames;
import com.intellij.javascript.flex.mxml.schema.ClassBackedElementDescriptor;
import com.intellij.javascript.flex.resolve.ActionScriptClassResolver;
import com.intellij.lang.javascript.flex.AnnotationBackedDescriptor;
import com.intellij.lang.javascript.flex.XmlBackedJSClassImpl;
import com.intellij.lang.javascript.psi.ecmal4.JSClass;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.project.Project;
import com.intellij.pom.Navigatable;
import com.intellij.psi.meta.PsiPresentableMetaData;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import gnu.trove.THashMap;
import gnu.trove.THashSet;
import java.io.DataInput;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
public class ResolveExternalInlineStyleSourceAction implements Runnable {
private static final Logger LOG = Logger.getInstance("#com.intellij.flex.uiDesigner.ResolveExternalInlineStyleSourceAction");
private final String parentFqn;
private final String elementFqn;
private final String targetStyleName;
private final Map<String, String> properties;
private final GlobalSearchScope scope;
private final Project project;
private final static Set<String> ignoredRootTags = new THashSet<>(5);
static {
ignoredRootTags.add("Metadata");
ignoredRootTags.add("states");
ignoredRootTags.add(XmlBackedJSClassImpl.SCRIPT_TAG_NAME);
ignoredRootTags.add("Library");
ignoredRootTags.add("Private");
}
public ResolveExternalInlineStyleSourceAction(DataInput input, Module module) throws IOException {
parentFqn = input.readUTF();
elementFqn = input.readUTF();
targetStyleName = input.readUTF();
scope = module.getModuleWithDependenciesAndLibrariesScope(false);
project = module.getProject();
int size = input.readShort();
properties = new THashMap<>(size);
assert size > 0;
for (int i = 0; i < size; i++) {
String name = input.readUTF();
if (name.length() == 0) {
continue;
}
properties.put(name, input.readUTF());
}
assert properties.size() > 0;
}
public ResolveExternalInlineStyleSourceAction(String parentFqn,
String elementFqn,
String targetStyleName,
Map<String, String> properties,
Module module) {
this.parentFqn = parentFqn;
this.elementFqn = elementFqn;
this.targetStyleName = targetStyleName;
this.properties = properties;
scope = module.getModuleWithDependenciesAndLibrariesScope(false);
project = module.getProject();
}
@Override
public void run() {
Navigatable target = find();
if (target == null) {
LOG.error("Can't find target property " + targetStyleName + " of " + elementFqn + " in " + parentFqn);
}
else {
target.navigate(true);
ProjectUtil.focusProjectWindow(project, true);
}
}
public Navigatable find() {
JSClass classElement = ((JSClass)ActionScriptClassResolver.findClassByQNameStatic(parentFqn, scope));
assert classElement != null;
XmlTag rootTag = ((XmlFile)classElement.getNavigationElement().getContainingFile()).getRootTag();
assert rootTag != null && rootTag.getDescriptor() != null && rootTag.getDescriptor() instanceof ClassBackedElementDescriptor;
return find(rootTag, true);
}
private Navigatable find(XmlTag parent, boolean firstLevel) {
for (XmlTag xmlTag : parent.getSubTags()) {
String localName = xmlTag.getLocalName();
if (firstLevel && ignoredRootTags.contains(localName)) {
continue;
}
XmlElementDescriptor xmlTagDescriptor = xmlTag.getDescriptor();
if (xmlTagDescriptor instanceof ClassBackedElementDescriptor) {
Navigatable result;
if (xmlTagDescriptor.getQualifiedName().equals(elementFqn)) {
result = findTargetIfStyleDeclarationOwner(xmlTag);
if (result != null) {
return result;
}
}
result = find(xmlTag, false);
if (result != null) {
return result;
}
}
}
return null;
}
private Navigatable findTargetIfStyleDeclarationOwner(XmlTag parent) {
int foundCount = 0;
Navigatable target = null;
for (XmlAttribute attribute : parent.getAttributes()) {
XmlAttributeDescriptor descriptor = attribute.getDescriptor();
// 8
if (descriptor instanceof AnnotationBackedDescriptor) {
String ourValue = properties.get(descriptor.getName());
if (ourValue != null) {
if (attribute.getDisplayValue().equals(ourValue)) {
foundCount++;
if (descriptor.getName().equals(targetStyleName)) {
target = (Navigatable)attribute;
}
if (foundCount == properties.size()) {
return target;
}
}
}
}
}
for (XmlTag tag : parent.getSubTags()) {
XmlElementDescriptor descriptor = tag.getDescriptor();
if (descriptor instanceof AnnotationBackedDescriptor &&
((PsiPresentableMetaData)descriptor).getTypeName().equals(FlexAnnotationNames.STYLE)) {
String ourValue = properties.get(descriptor.getName());
if (ourValue != null) {
if (tag.getSubTags().length == 0 && tag.getValue().getTrimmedText().equals(ourValue)) {
foundCount++;
if (descriptor.getName().equals(targetStyleName)) {
target = (Navigatable)tag;
}
if (foundCount == properties.size()) {
return target;
}
}
}
}
}
return null;
}
}