package com.intellij.javascript.flex.css;
import com.intellij.codeInsight.documentation.DocumentationManager;
import com.intellij.codeInspection.LocalQuickFix;
import com.intellij.javascript.flex.FlexAnnotationNames;
import com.intellij.javascript.flex.mxml.schema.CodeContext;
import com.intellij.lang.Language;
import com.intellij.lang.css.CSSLanguage;
import com.intellij.lang.css.CssDialect;
import com.intellij.lang.css.CssDialectMappings;
import com.intellij.lang.documentation.DocumentationProvider;
import com.intellij.lang.injection.InjectedLanguageManager;
import com.intellij.lang.javascript.JavaScriptSupportLoader;
import com.intellij.lang.javascript.flex.FlexModuleType;
import com.intellij.lang.javascript.flex.FlexUtils;
import com.intellij.lang.javascript.flex.XmlBackedJSClassImpl;
import com.intellij.lang.javascript.psi.ecmal4.JSAttribute;
import com.intellij.lang.javascript.psi.ecmal4.JSAttributeNameValuePair;
import com.intellij.lang.javascript.psi.ecmal4.JSClass;
import com.intellij.lang.javascript.psi.ecmal4.JSQualifiedNamedElement;
import com.intellij.lang.javascript.psi.ecmal4.impl.ActionScriptClassImpl;
import com.intellij.lang.javascript.psi.resolve.ActionScriptResolveUtil;
import com.intellij.lang.javascript.psi.resolve.JSResolveUtil;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleType;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiReference;
import com.intellij.psi.css.*;
import com.intellij.psi.css.descriptor.CssFunctionDescriptor;
import com.intellij.psi.css.descriptor.CssFunctionDescriptorStub;
import com.intellij.psi.css.descriptor.CssPseudoSelectorDescriptor;
import com.intellij.psi.css.descriptor.CssPseudoSelectorDescriptorStub;
import com.intellij.psi.css.descriptor.value.CssNullValue;
import com.intellij.psi.css.descriptor.value.CssValueDescriptor;
import com.intellij.psi.css.descriptor.value.CssValueValidator;
import com.intellij.psi.css.impl.CssTermTypes;
import com.intellij.psi.css.impl.descriptor.value.CssGroupValue;
import com.intellij.psi.css.impl.descriptor.value.CssStringValue;
import com.intellij.psi.css.impl.util.scheme.CssElementDescriptorFactory2;
import com.intellij.psi.css.impl.util.scheme.CssElementDescriptorProviderImpl;
import com.intellij.psi.css.resolve.HtmlCssClassOrIdReference;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlTag;
import com.intellij.ui.JBColor;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.indexing.FileBasedIndex;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.util.HtmlUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.awt.*;
import java.util.*;
import java.util.List;
import static com.intellij.openapi.module.ModuleUtilCore.findModuleForFile;
import static com.intellij.openapi.module.ModuleUtilCore.findModuleForPsiElement;
import static com.intellij.psi.util.PsiUtilCore.toPsiElementArray;
/**
* @author Eugene.Kudelevsky
*/
public class FlexCssElementDescriptorProvider extends CssElementDescriptorProvider {
private final FlexCssValueValidator FLEX_CSS_VALUE_VALIDATOR = new FlexCssValueValidator(this);
private final Map<String, CssFunctionDescriptor> myFunctionDescriptors = ContainerUtil.newHashMap();
public FlexCssElementDescriptorProvider(@NotNull CssElementDescriptorFactory2 descriptorFactory) {
CssStringValue singleStringValue = descriptorFactory.createStringValueDescriptor(null, 1, 1, null);
CssGroupValue embedFunctionValue = descriptorFactory.createGroupValue(CssGroupValue.Type.OR, 1, 1, null, null);
CssValueDescriptor commaSeparator = descriptorFactory.createTextValueDescriptor(",", 1, 1, null);
CssGroupValue attributes = descriptorFactory.createGroupValue(CssGroupValue.Type.AND, 1, 1, embedFunctionValue, commaSeparator);
attributes.addChild(createAttributeValueDescriptor("source", true, descriptorFactory, attributes));
attributes.addChild(createAttributeValueDescriptor("mimeType", false, descriptorFactory, attributes));
attributes.addChild(createBooleanAttributeValueDescriptor("smoothing", false, descriptorFactory, attributes));
attributes.addChild(createBooleanAttributeValueDescriptor("compression", false, descriptorFactory, attributes));
attributes.addChild(createAttributeValueDescriptor("quality", false, descriptorFactory, attributes));
attributes.addChild(createAttributeValueDescriptor("scaleGridTop", false, descriptorFactory, attributes));
attributes.addChild(createAttributeValueDescriptor("scaleGridBottom", false, descriptorFactory, attributes));
attributes.addChild(createAttributeValueDescriptor("scaleGridLeft", false, descriptorFactory, attributes));
attributes.addChild(createAttributeValueDescriptor("scaleGridRight", false, descriptorFactory, attributes));
attributes.addChild(createAttributeValueDescriptor("symbol", false, descriptorFactory, attributes));
embedFunctionValue.addChild(descriptorFactory.createStringValueDescriptor(null, 1, 1, embedFunctionValue));
embedFunctionValue.addChild(attributes);
myFunctionDescriptors.put("Embed", new CssFunctionDescriptorStub("Embed", embedFunctionValue));
myFunctionDescriptors.put("ClassReference", new CssFunctionDescriptorStub("ClassReference", singleStringValue));
myFunctionDescriptors.put("PropertyReference", new CssFunctionDescriptorStub("PropertyReference", singleStringValue));
}
private static CssGroupValue createAttributeValueDescriptor(@NotNull String attributeName, boolean required,
@NotNull CssElementDescriptorFactory2 descriptorFactory,
@NotNull CssGroupValue parent) {
CssGroupValue attributeValue = descriptorFactory.createGroupValue(CssGroupValue.Type.ALL, required ? 1 : 0, 1, parent, null);
attributeValue.addChild(descriptorFactory.createNameValueDescriptor(attributeName, attributeName, 1, 1, attributeValue));
attributeValue.addChild(descriptorFactory.createTextValueDescriptor("=", 1, 1, attributeValue));
attributeValue.addChild(descriptorFactory.createStringValueDescriptor(null, 1, 1, attributeValue));
return attributeValue;
}
private static CssGroupValue createBooleanAttributeValueDescriptor(@NotNull String attributeName, boolean required,
@NotNull CssElementDescriptorFactory2 descriptorFactory,
@NotNull CssGroupValue parent) {
CssGroupValue attributeValue = descriptorFactory.createGroupValue(CssGroupValue.Type.ALL, required ? 1 : 0, 1, parent, null);
attributeValue.addChild(descriptorFactory.createNameValueDescriptor(attributeName, attributeName, 1, 1, attributeValue));
attributeValue.addChild(descriptorFactory.createTextValueDescriptor("=", 1, 1, attributeValue));
CssGroupValue booleanValue = descriptorFactory.createGroupValue(CssGroupValue.Type.OR, 1, 1, attributeValue, null);
booleanValue.addChild(descriptorFactory.createStringValueDescriptor("true", 1, 1, booleanValue));
booleanValue.addChild(descriptorFactory.createStringValueDescriptor("false", 1, 1, booleanValue));
attributeValue.addChild(booleanValue);
return attributeValue;
}
public boolean isMyContext(@Nullable PsiElement context) {
if (context == null || !context.isValid()) return false;
PsiFile file = context.getContainingFile();
if (file == null) return false;
if (HtmlUtil.hasHtml(file)) return false;
final VirtualFile vFile = file.getOriginalFile().getVirtualFile();
if (vFile != null) {
final FileType type = vFile.getFileType();
if (type instanceof LanguageFileType) {
Language lang = ((LanguageFileType)type).getLanguage();
if (lang.isKindOf(CSSLanguage.INSTANCE) && !lang.is(CSSLanguage.INSTANCE)) return false;
}
}
Module module = findModuleForPsiElement(file);
if (module == null) {
file = InjectedLanguageManager.getInstance(file.getProject()).getTopLevelFile(context);
if (file != null) {
module = findModuleForPsiElement(file);
}
}
if (module == null || ModuleType.get(module) != FlexModuleType.getInstance()) {
return false;
}
if (vFile != null) {
CssDialect dialect = CssDialectMappings.getInstance(context.getProject()).getMapping(vFile);
return dialect == null || dialect == FlexCSSDialect.getInstance();
}
return true;
}
@NotNull
@Override
public CssValueValidator getValueValidator() {
return FLEX_CSS_VALUE_VALIDATOR;
}
@Override
public boolean shouldAskOtherProviders(PsiElement context) {
return false;
}
@Nullable
private static String findJsClassOrFile(@NotNull JSClass root, Set<JSClass> visited, Set<String> possibleQNames) {
if (!visited.add(root)) return null;
String qName = root.getQualifiedName();
if (qName != null && possibleQNames.contains(qName)) {
return qName;
}
Set<String> includes = ContainerUtil.newLinkedHashSet();
FlexCssUtil.collectAllIncludes(root, includes);
String fileName = null;
for (String include : includes) {
if (possibleQNames.contains(include)) {
fileName = include;
}
}
if (fileName != null) {
return fileName;
}
for (JSClass jsSuper : root.getSupers()) {
String result = findJsClassOrFile(jsSuper, visited, possibleQNames);
if (result != null) return result;
}
return null;
}
private static List<FlexStyleIndexInfo> filter(Collection<? extends Collection<FlexStyleIndexInfo>> collections,
List<CssSimpleSelector> selectors,
@NotNull GlobalSearchScope scope,
@Nullable Module module) {
Set<String> allNames = ContainerUtil.newLinkedHashSet();
for (Collection<FlexStyleIndexInfo> collection : collections) {
for (FlexStyleIndexInfo info : collection) {
allNames.add(info.getClassOrFileName());
}
}
Set<String> namesFromSelectors = null;
if (selectors.size() > 0 && !containsGlobalSelectors(selectors)) {
namesFromSelectors = ContainerUtil.newLinkedHashSet();
for (CssSimpleSelector selector : selectors) {
if (module != null) {
final JSClass jsClass = getClassFromMxmlDescriptor(selector, module);
if (jsClass != null) {
String classOrFileName = findJsClassOrFile(jsClass, ContainerUtil.newLinkedHashSet(), allNames);
if (classOrFileName != null) {
namesFromSelectors.add(classOrFileName);
}
continue;
}
}
final String selectorName = selector.getElementName();
Collection<JSQualifiedNamedElement> elements = JSResolveUtil.findElementsByName(selectorName, scope.getProject(), scope);
for (PsiElement element : elements) {
if (element instanceof JSClass) {
String classOrFileName = findJsClassOrFile((JSClass)element, ContainerUtil.newLinkedHashSet(), allNames);
if (classOrFileName != null) {
namesFromSelectors.add(classOrFileName);
}
}
}
}
}
List<FlexStyleIndexInfo> result = new ArrayList<>();
for (Collection<FlexStyleIndexInfo> collection : collections) {
for (FlexStyleIndexInfo info : collection) {
if (namesFromSelectors == null || namesFromSelectors.contains(info.getClassOrFileName())) {
result.add(info);
}
}
}
return result;
}
public PsiElement getDocumentationElementForSelector(@NotNull String selectorName, @Nullable PsiElement context) {
if (context != null) {
Collection<JSQualifiedNamedElement> classes = getClasses(selectorName, context);
if (classes != null) {
for (JSQualifiedNamedElement c : classes) {
if (c instanceof JSClass) {
return c;
}
}
}
}
return null;
}
@NotNull
@Override
public Collection<? extends CssPseudoSelectorDescriptor> findPseudoSelectorDescriptors(@NotNull String name, @Nullable PsiElement context) {
return Collections.singletonList(new CssPseudoSelectorDescriptorStub(name));
}
@NotNull
@Override
public Collection<? extends CssValueDescriptor> getNamedValueDescriptors(@NotNull String name, @Nullable CssValueDescriptor parent) {
return Collections.singletonList(new CssNullValue(parent));
}
@NotNull
@Override
public Collection<? extends CssPropertyDescriptor> findPropertyDescriptors(@NotNull String propertyName, PsiElement context) {
if (context != null) {
Module module = findModuleForPsiElement(context);
GlobalSearchScope scope = FlexCssUtil.getResolveScope(context);
List<Set<FlexStyleIndexInfo>> lists = FileBasedIndex.getInstance().getValues(FlexStyleIndex.INDEX_ID, propertyName, scope);
List<CssSimpleSelector> selectors = findSimpleSelectorsAbove(context);
List<FlexStyleIndexInfo> infos = filter(lists, selectors, scope, module);
if (infos.size() > 0) {
return Collections.singletonList(new FlexCssPropertyDescriptor(infos));
}
}
return Collections.emptyList();
}
@NotNull
@Override
public Collection<? extends CssFunctionDescriptor> findFunctionDescriptors(@NotNull String functionName, @Nullable PsiElement context) {
return ContainerUtil.createMaybeSingletonList(myFunctionDescriptors.get(functionName));
}
public boolean isPossibleSelector(@NotNull String selector, @NotNull PsiElement context) {
if (selector.equals("global")) return true;
GlobalSearchScope scope = FlexCssUtil.getResolveScope(context);
Collection<JSQualifiedNamedElement> classes = JSResolveUtil.findElementsByName(selector, context.getProject(), scope);
for (JSQualifiedNamedElement c : classes) {
if (c instanceof JSClass) {
return true;
}
}
return false;
}
public boolean isPossiblePseudoSelector(@NotNull String selectorName, @Nullable PsiElement context) {
return false;
}
private static boolean isInClassicForm(String propertyName) {
return propertyName.indexOf('-') >= 0;
}
private static void fillPropertyDescriptorsDynamically(@NotNull final JSClass jsClass, Set<JSClass> visited, final Set<CssPropertyDescriptor> result) {
if (!visited.add(jsClass)) return;
FlexUtils.processMetaAttributesForClass(jsClass, new ActionScriptResolveUtil.MetaDataProcessor() {
public boolean process(@NotNull JSAttribute jsAttribute) {
if (FlexAnnotationNames.STYLE.equals(jsAttribute.getName())) {
JSAttributeNameValuePair pair = jsAttribute.getValueByName("name");
String styleName = pair != null ? pair.getSimpleValue() : null;
String qualifiedName = jsClass.getQualifiedName();
if (styleName != null && qualifiedName != null) {
result.add(new FlexCssPropertyDescriptor(ContainerUtil.newLinkedHashSet(
FlexStyleIndexInfo.create(qualifiedName, styleName, jsAttribute, true))));
}
}
return true;
}
public boolean handleOtherElement(PsiElement el, PsiElement context, @Nullable Ref<PsiElement> continuePassElement) {
return true;
}
});
for (JSClass jsSuper : jsClass.getSupers()) {
if (jsSuper != null) {
fillPropertyDescriptorsDynamically(jsSuper, visited, result);
}
}
}
@NotNull
private static Collection<? extends CssPropertyDescriptor> getPropertyDescriptorsDynamically(@NotNull List<CssSimpleSelector> selectors,
@NotNull Module module) {
FileBasedIndex fileBasedIndex = FileBasedIndex.getInstance();
GlobalSearchScope scope = module.getModuleWithDependenciesAndLibrariesScope(false);
Set<JSClass> visited = ContainerUtil.newLinkedHashSet();
Set<CssPropertyDescriptor> result = ContainerUtil.newLinkedHashSet();
Project project = module.getProject();
for (CssSimpleSelector selector : selectors) {
final JSClass jsClass = getClassFromMxmlDescriptor(selector, module);
if (jsClass != null) {
fillPropertyDescriptorsDynamically(jsClass, visited, result);
continue;
}
final String shortClassName = selector.getElementName();
Collection<JSQualifiedNamedElement> candidates = JSResolveUtil.findElementsByName(shortClassName, project, scope);
for (JSQualifiedNamedElement candidate : candidates) {
if (candidate instanceof JSClass) {
fillPropertyDescriptorsDynamically((JSClass)candidate, visited, result);
}
}
}
for (Iterator<CssPropertyDescriptor> iterator = result.iterator(); iterator.hasNext();) {
CssPropertyDescriptor propertyDescriptor = iterator.next();
List<Set<FlexStyleIndexInfo>> values = fileBasedIndex.getValues(FlexStyleIndex.INDEX_ID, propertyDescriptor.getPropertyName(), scope);
if (values.size() == 0) {
iterator.remove();
}
}
return result;
}
private static boolean containsGlobalSelectors(@NotNull List<CssSimpleSelector> selectors) {
for (CssSimpleSelector selector : selectors) {
final String elementName = selector.getElementName();
if (elementName.isEmpty() || "global".equals(elementName) || "*".equals(elementName)) {
return true;
}
}
return false;
}
@NotNull
public Collection<? extends CssPropertyDescriptor> getAllPropertyDescriptors(@Nullable PsiElement context) {
if(context == null || DumbService.getInstance(context.getProject()).isDumb()) {
return Collections.emptyList();
}
Module module = findModuleForPsiElement(context);
List<CssSimpleSelector> simpleSelectors = findSimpleSelectorsAbove(context);
if (simpleSelectors.size() > 0 && !containsGlobalSelectors(simpleSelectors)) {
if (module != null) {
return getPropertyDescriptorsDynamically(simpleSelectors, module);
}
}
FileBasedIndex index = FileBasedIndex.getInstance();
Collection<String> keys = ContainerUtil.sorted(index.getAllKeys(FlexStyleIndex.INDEX_ID, context.getProject()));
List<FlexCssPropertyDescriptor> result = new ArrayList<>();
GlobalSearchScope scope = FlexCssUtil.getResolveScope(context);
for (String key : keys) {
if (!isInClassicForm(key)) {
for (Set<FlexStyleIndexInfo> infos : index.getValues(FlexStyleIndex.INDEX_ID, key, scope)) {
result.add(new FlexCssPropertyDescriptor(infos));
}
}
}
return result;
}
@NotNull
public String[] getSimpleSelectors(@NotNull PsiElement context) {
Module module = findModuleForPsiElement(context);
if (module == null) {
return ArrayUtil.EMPTY_STRING_ARRAY;
}
CodeContext codeContext = CodeContext.getContext(JavaScriptSupportLoader.MXML_URI, module);
XmlElementDescriptor[] descriptors = codeContext.getDescriptorsWithAllowedDeclaration();
String[] selectors = new String[descriptors.length + 1];
selectors[0] = "global";
int i = 1;
for (XmlElementDescriptor descriptor : descriptors) {
selectors[i++] = descriptor.getName();
}
return selectors;
}
@Nullable
private static Collection<JSQualifiedNamedElement> getClasses(String className, PsiElement context) {
if (context == null) return null;
Module module = findModuleForPsiElement(context);
GlobalSearchScope scope = module != null ? module.getModuleWithDependenciesAndLibrariesScope(false) : context.getResolveScope();
return JSResolveUtil.findElementsByName(className, context.getProject(), scope);
}
@Nullable
public static XmlElementDescriptor getTypeSelectorDescriptor(@NotNull CssSimpleSelector selector, @NotNull Module module) {
CssStylesheet stylesheet = ((StylesheetFile)selector.getContainingFile()).getStylesheet();
CssNamespace namespace = stylesheet != null ? stylesheet.getNamespace(selector.getNamespaceName()) : null;
if (namespace != null && namespace.getUri() != null) {
return CodeContext.getContext(namespace.getUri(), module).getElementDescriptor(selector.getElementName(), (XmlTag)null);
}
else {
return null;
}
}
@Nullable
private static JSClass getClassFromMxmlDescriptor(@NotNull CssSimpleSelector selector, @NotNull Module module) {
final XmlElementDescriptor xmlElementDescriptor = getTypeSelectorDescriptor(selector, module);
if (xmlElementDescriptor == null) {
return null;
}
final PsiElement declaration = xmlElementDescriptor.getDeclaration();
return declaration instanceof JSClass ? (JSClass)declaration : null;
}
@NotNull
public PsiElement[] getDeclarationsForSimpleSelector(@NotNull CssSimpleSelector selector) {
// flex 4
Module module = findModuleForPsiElement(selector);
// only for project files, due to unknown code context otherwise
if (module != null) {
final JSClass jsClass = getClassFromMxmlDescriptor(selector, module);
if (jsClass != null) {
return new PsiElement[]{jsClass};
}
}
// flex 3 or file not in project files
return getDeclarationsForSimpleSelector(selector.getElementName(), selector);
}
@NotNull
private static PsiElement getReferencedElement(@NotNull PsiElement element) {
if (element instanceof ActionScriptClassImpl) {
return element.getNavigationElement();
}
else if (element instanceof XmlBackedJSClassImpl) {
PsiElement parent = element.getParent();
if (parent != null) {
PsiFile file = parent.getContainingFile();
if (file != null) {
return file;
}
}
}
return element;
}
@NotNull
private static PsiElement[] getDeclarationsForSimpleSelector(@NotNull String className, @Nullable PsiElement context) {
Collection<JSQualifiedNamedElement> elements = getClasses(className, context);
if (elements != null && elements.size() > 0) {
List<PsiElement> result = new ArrayList<>();
Set<String> qNames = ContainerUtil.newLinkedHashSet();
for (JSQualifiedNamedElement c : elements) {
if (c instanceof JSClass) {
// do not add classes with same qualified names
String qName = c.getQualifiedName();
if (qNames.add(qName)) {
result.add(getReferencedElement(c));
}
}
}
return toPsiElementArray(result);
}
return PsiElement.EMPTY_ARRAY;
}
@Override
public boolean providesClassicCss() {
return false;
}
public String generateDocForSelector(@NotNull String selectorName, @Nullable PsiElement context) {
PsiElement[] declarations = getDeclarationsForSimpleSelector(selectorName, context);
JSClass[] classes = new JSClass[declarations.length];
for (int i = 0; i < declarations.length; i++) {
PsiElement declaration = declarations[i];
assert declaration instanceof JSClass;
classes[i] = (JSClass)declaration;
}
Arrays.sort(classes, (c1, c2) -> Comparing.compare(c1.getQualifiedName(), c2.getQualifiedName()));
StringBuilder builder = new StringBuilder();
for (int i = 0, n = classes.length; i < n; i++) {
JSClass jsClass = classes[i];
PsiFile file = jsClass.getContainingFile();
if (file != null) {
DocumentationProvider provider = DocumentationManager.getProviderFromElement(jsClass);
String docForDeclaration = provider.generateDoc(jsClass, jsClass);
if (docForDeclaration != null) {
builder.append(docForDeclaration);
if (i != n - 1) {
builder.append("<br><br>\n\n");
}
}
}
}
return builder.toString();
}
@NotNull
private static List<CssSimpleSelector> findSimpleSelectorsAbove(@NotNull PsiElement context) {
List<CssSimpleSelector> result = ContainerUtil.newArrayList();
CssRuleset ruleset = PsiTreeUtil.getParentOfType(context, CssRuleset.class);
if (ruleset != null) {
for (CssSelector selector : ruleset.getSelectors()) {
CssSimpleSelector simpleSelector = null;
for (PsiElement child : selector.getChildren()) {
if (child instanceof CssSimpleSelector) {
simpleSelector = (CssSimpleSelector)child;
}
}
if (simpleSelector != null) {
result.add(simpleSelector);
}
}
}
return result;
}
@NotNull
public PsiReference getStyleReference(PsiElement element, int start, int end, boolean caseSensitive) {
return new HtmlCssClassOrIdReference(element, start, end, caseSensitive, false);
}
@Override
public Color getColorByValue(@NotNull String value) {
try {
int rgb = Integer.parseInt(value);
return new JBColor(rgb, rgb);
}
catch (NumberFormatException e) {
return null;
}
}
@Override
public boolean isColorTerm(@NotNull CssTerm term) {
return term.getTermType() == CssTermTypes.NUMBER;
}
@NotNull
@Override
public LocalQuickFix[] getQuickFixesForUnknownProperty(@NotNull String propertyName, @NotNull PsiElement context, boolean isOnTheFly) {
if (!isOnTheFly) {
return LocalQuickFix.EMPTY_ARRAY;
}
final VirtualFile vFile = checkForQuickFixAndGetVFile(context);
if (vFile == null) {
return LocalQuickFix.EMPTY_ARRAY;
}
final CssDialect dialect = CssDialectMappings.getInstance(context.getProject()).getMapping(vFile);
if (dialect == CssDialect.CLASSIC) {
final Collection<? extends CssPropertyDescriptor> flexDescriptor = findPropertyDescriptors(propertyName, context);
if (!flexDescriptor.isEmpty()) {
return new LocalQuickFix[]{new SwitchToCssDialectQuickFix(FlexCSSDialect.getInstance())};
}
}
else {
final CssElementDescriptorProviderImpl classicCssDescriptorProvider =
CssElementDescriptorProvider.EP_NAME.findExtension(CssElementDescriptorProviderImpl.class);
if (classicCssDescriptorProvider != null) {
Collection<? extends CssPropertyDescriptor> classicDescriptors = classicCssDescriptorProvider.findPropertyDescriptors(propertyName,
context);
if (!classicDescriptors.isEmpty()) {
return new LocalQuickFix[]{new SwitchToCssDialectQuickFix(CssDialect.CLASSIC)};
}
}
}
return LocalQuickFix.EMPTY_ARRAY;
}
@NotNull
@Override
public LocalQuickFix[] getQuickFixesForUnknownSimpleSelector(@NotNull String selectorName,
@NotNull PsiElement context,
boolean isOnTheFly) {
if (!isOnTheFly) {
return LocalQuickFix.EMPTY_ARRAY;
}
final VirtualFile vFile = checkForQuickFixAndGetVFile(context);
if (vFile == null) {
return LocalQuickFix.EMPTY_ARRAY;
}
final CssDialect dialect = CssDialectMappings.getInstance(context.getProject()).getMapping(vFile);
if (dialect == CssDialect.CLASSIC) {
if (isPossibleSelector(selectorName, context)) {
return new LocalQuickFix[]{new SwitchToCssDialectQuickFix(FlexCSSDialect.getInstance())};
}
}
else {
final CssElementDescriptorProviderImpl classicCssDescriptorProvider =
CssElementDescriptorProvider.EP_NAME.findExtension(CssElementDescriptorProviderImpl.class);
if (classicCssDescriptorProvider != null && classicCssDescriptorProvider.isPossibleSelector(selectorName, context)) {
return new LocalQuickFix[]{new SwitchToCssDialectQuickFix(CssDialect.CLASSIC)};
}
}
return LocalQuickFix.EMPTY_ARRAY;
}
@Override
public boolean isColorTermsSupported() {
return false;
}
@Nullable
private static VirtualFile checkForQuickFixAndGetVFile(@NotNull PsiElement context) {
final PsiFile file = InjectedLanguageManager.getInstance(context.getProject()).getTopLevelFile(context);
if (file == null) {
return null;
}
final VirtualFile vFile = file.getOriginalFile().getVirtualFile();
if (vFile == null || !(vFile.getFileType() == CssFileType.INSTANCE)) {
return null;
}
final Module module = findModuleForFile(vFile, context.getProject());
if (module == null || ModuleType.get(module) != FlexModuleType.getInstance()) {
return null;
}
return vFile;
}
}