package com.intellij.lang.javascript.flex.run; import com.intellij.execution.RunManager; import com.intellij.execution.actions.ConfigurationContext; import com.intellij.execution.actions.RunConfigurationProducer; import com.intellij.execution.configurations.RunConfiguration; import com.intellij.flex.model.bc.OutputType; import com.intellij.flex.model.bc.TargetPlatform; import com.intellij.lang.javascript.flex.FlexModuleType; import com.intellij.lang.javascript.flex.projectStructure.model.FlexBuildConfiguration; import com.intellij.lang.javascript.flex.projectStructure.model.FlexBuildConfigurationManager; import com.intellij.lang.javascript.flex.projectStructure.options.BCUtils; import com.intellij.lang.javascript.psi.JSFile; import com.intellij.lang.javascript.psi.ecmal4.JSClass; import com.intellij.lang.javascript.psi.ecmal4.XmlBackedJSClassFactory; import com.intellij.lang.javascript.psi.impl.JSPsiImplUtils; import com.intellij.openapi.module.Module; import com.intellij.openapi.module.ModuleType; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.xml.XmlFile; import org.jetbrains.annotations.Nullable; import java.util.List; public class FlashRunConfigurationProducer extends RunConfigurationProducer<FlashRunConfiguration> { public FlashRunConfigurationProducer() { super(FlashRunConfigurationType.getInstance()); } protected boolean setupConfigurationFromContext(final FlashRunConfiguration configuration, final ConfigurationContext context, final Ref<PsiElement> sourceElement) { final Module module = context.getModule(); if (module == null || ModuleType.get(module) != FlexModuleType.getInstance()) return false; final JSClass jsClass = getJSClass(context.getPsiLocation()); if (jsClass == null || !isAcceptedMainClass(jsClass, module)) return false; final FlashRunnerParameters params = configuration.getRunnerParameters(); params.setModuleName(module.getName()); final FlexBuildConfiguration bc = getBCToBaseOn(module, jsClass.getQualifiedName()); params.setBCName(bc.getName()); if (bc.getOutputType() == OutputType.Application && jsClass.getQualifiedName().equals(bc.getMainClass())) { params.setOverrideMainClass(false); } else { params.setOverrideMainClass(true); params.setOverriddenMainClass(jsClass.getQualifiedName()); params.setOverriddenOutputFileName(jsClass.getName() + ".swf"); } if (bc.getTargetPlatform() == TargetPlatform.Mobile && bc.getOutputType() == OutputType.Application && params.getMobileRunTarget() == FlashRunnerParameters.AirMobileRunTarget.Emulator) { if (params.getAppDescriptorForEmulator() == FlashRunnerParameters.AppDescriptorForEmulator.Android && !bc.getAndroidPackagingOptions().isEnabled() && bc.getIosPackagingOptions().isEnabled()) { params.setAppDescriptorForEmulator(FlashRunnerParameters.AppDescriptorForEmulator.IOS); } if (params.getAppDescriptorForEmulator() == FlashRunnerParameters.AppDescriptorForEmulator.IOS && bc.getAndroidPackagingOptions().isEnabled() && !bc.getIosPackagingOptions().isEnabled()) { params.setAppDescriptorForEmulator(FlashRunnerParameters.AppDescriptorForEmulator.Android); } } configuration.setGeneratedName(); return true; } public boolean isConfigurationFromContext(final FlashRunConfiguration configuration, final ConfigurationContext context) { final Module module = context.getModule(); if (module == null || ModuleType.get(module) != FlexModuleType.getInstance()) return false; if (!module.getName().equals(configuration.getRunnerParameters().getModuleName())) return false; final JSClass jsClass = getJSClass(context.getPsiLocation()); if (jsClass == null || !isAcceptedMainClass(jsClass, module)) return false; final List<RunConfiguration> existing = RunManager.getInstance(module.getProject()).getConfigurationsList(getConfigurationType()); final RunConfiguration suitable = findSuitableRunConfig(module, jsClass.getQualifiedName(), existing); return suitable == configuration; } private static FlexBuildConfiguration getBCToBaseOn(final Module module, final String fqn) { final FlexBuildConfigurationManager manager = FlexBuildConfigurationManager.getInstance(module); FlexBuildConfiguration appWithSuitableMainClass = null; for (FlexBuildConfiguration bc : manager.getBuildConfigurations()) { if (bc.getOutputType() == OutputType.Application && fqn.equals(bc.getMainClass())) { if (manager.getActiveConfiguration() == bc) { return bc; // the best choice } appWithSuitableMainClass = bc; } } // 2nd good choice - any app with matching main class (though not active at this moment) // if no apps with matching main class - take active bc and override main class return appWithSuitableMainClass != null ? appWithSuitableMainClass : manager.getActiveConfiguration(); } @Nullable private static RunConfiguration findSuitableRunConfig(final Module module, final String fqn, final List<RunConfiguration> existing) { final FlexBuildConfigurationManager manager = FlexBuildConfigurationManager.getInstance(module); RunConfiguration basedOnBC = null; RunConfiguration basedOnMainClass = null; RunConfiguration basedOnMainClassAndActiveBC = null; for (final RunConfiguration runConfig : existing) { final FlashRunnerParameters params = ((FlashRunConfiguration)runConfig).getRunnerParameters(); if (module.getName().equals(params.getModuleName())) { final FlexBuildConfiguration bc = manager.findConfigurationByName(params.getBCName()); if (bc == null) continue; if (params.isOverrideMainClass()) { if (fqn.equals(params.getOverriddenMainClass())) { if (manager.getActiveConfiguration() == bc) { basedOnMainClassAndActiveBC = runConfig; } basedOnMainClass = runConfig; } } else { if (bc.getOutputType() == OutputType.Application && fqn.equals(bc.getMainClass())) { if (manager.getActiveConfiguration() == bc) { return runConfig; // the best choice } basedOnBC = runConfig; } } } } // second good choice - based on app bc with matching main class (though not active at this moment) // third - based on overridden main class and active bc // forth - based on overridden main class and any bc return basedOnBC != null ? basedOnBC : basedOnMainClassAndActiveBC != null ? basedOnMainClassAndActiveBC : basedOnMainClass; } @Nullable private static JSClass getJSClass(final @Nullable PsiElement sourceElement) { PsiElement element = PsiTreeUtil.getNonStrictParentOfType(sourceElement, JSClass.class, JSFile.class, XmlFile.class); if (element instanceof JSFile) { element = JSPsiImplUtils.findClass((JSFile)element); } else if (element instanceof XmlFile) { element = XmlBackedJSClassFactory.getXmlBackedClass((XmlFile)element); } return element instanceof JSClass ? (JSClass)element : null; } public static boolean isAcceptedMainClass(@Nullable final JSClass jsClass, @Nullable final Module module) { return jsClass != null && module != null && BCUtils.isValidMainClass(module, null, jsClass, true); } }