/* * Copyright 2003-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.mps.ide.ui.dialogs.properties; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.ui.AnActionButton; import com.intellij.ui.AnActionButtonRunnable; import com.intellij.ui.IdeBorderFactory; import com.intellij.ui.SpeedSearchComparator; import com.intellij.ui.ToolbarDecorator; import com.intellij.ui.components.JBCheckBox; import com.intellij.ui.components.JBLabel; import com.intellij.ui.table.JBTable; import com.intellij.uiDesigner.core.GridConstraints; import com.intellij.uiDesigner.core.GridLayoutManager; import jetbrains.mps.extapi.persistence.FileDataSource; import jetbrains.mps.extapi.persistence.FolderDataSource; import jetbrains.mps.findUsages.CompositeFinder; import jetbrains.mps.icons.MPSIcons; import jetbrains.mps.icons.MPSIcons.General; import jetbrains.mps.ide.findusages.model.IResultProvider; import jetbrains.mps.ide.findusages.model.SearchQuery; import jetbrains.mps.ide.findusages.model.holders.GenericHolder; import jetbrains.mps.ide.findusages.model.holders.LanguageHolder; import jetbrains.mps.ide.findusages.model.holders.ModelsHolder; import jetbrains.mps.ide.findusages.model.holders.ModuleRefHolder; import jetbrains.mps.ide.findusages.model.scopes.ModelsScope; import jetbrains.mps.ide.findusages.view.FindUtils; import jetbrains.mps.ide.icons.IdeIcons; import jetbrains.mps.ide.project.ProjectHelper; import jetbrains.mps.ide.ui.dialogs.properties.choosers.CommonChoosers; import jetbrains.mps.ide.ui.dialogs.properties.creators.ModelChooser; import jetbrains.mps.ide.ui.dialogs.properties.input.ModuleCollector; import jetbrains.mps.ide.ui.dialogs.properties.renders.DependencyCellState; import jetbrains.mps.ide.ui.dialogs.properties.renders.LanguageTableCellRenderer; import jetbrains.mps.ide.ui.dialogs.properties.renders.ModelTableCellRender; import jetbrains.mps.ide.ui.dialogs.properties.tables.models.ModelImportedModelsTableModel; import jetbrains.mps.ide.ui.dialogs.properties.tables.models.UsedLangsTableModel; import jetbrains.mps.ide.ui.dialogs.properties.tables.models.UsedLangsTableModel.ValidImportCondition; import jetbrains.mps.ide.ui.dialogs.properties.tabs.BaseTab; import jetbrains.mps.ide.ui.finders.LanguageUsagesFinder; import jetbrains.mps.ide.ui.finders.ModelUsagesFinder; import jetbrains.mps.project.DevKit; import jetbrains.mps.project.ModuleInstanceCondition; import jetbrains.mps.project.Project; import jetbrains.mps.project.VisibleModuleCondition; import jetbrains.mps.project.dependency.VisibilityUtil; import jetbrains.mps.smodel.DefaultSModelDescriptor; import jetbrains.mps.smodel.Language; import jetbrains.mps.smodel.MPSModuleRepository; import jetbrains.mps.smodel.ModelAccessHelper; import jetbrains.mps.smodel.ModelDependencyScanner; import jetbrains.mps.smodel.language.LanguageRegistry; import jetbrains.mps.util.CollectionUtil; import jetbrains.mps.util.Computable; import jetbrains.mps.util.ComputeRunnable; import jetbrains.mps.util.ConditionalIterable; import jetbrains.mps.util.FileUtil; import jetbrains.mps.util.IterableUtil; import jetbrains.mps.util.NotCondition; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.mps.openapi.language.SLanguage; import org.jetbrains.mps.openapi.model.EditableSModel; import org.jetbrains.mps.openapi.model.SModel; import org.jetbrains.mps.openapi.model.SModelReference; import org.jetbrains.mps.openapi.module.SModule; import org.jetbrains.mps.openapi.module.SModuleReference; import org.jetbrains.mps.openapi.module.SRepository; import org.jetbrains.mps.openapi.module.SearchScope; import org.jetbrains.mps.openapi.persistence.DataSource; import org.jetbrains.mps.util.Condition; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JTextField; import javax.swing.ListSelectionModel; import javax.swing.table.TableCellRenderer; import java.awt.Dimension; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; public class ModelPropertiesConfigurable extends MPSPropertiesConfigurable { private ModelProperties myModelProperties; private SModel myModelDescriptor; private boolean myInPlugin = false; public ModelPropertiesConfigurable(SModel modelDescriptor, Project project) { this(modelDescriptor, project, false); } public ModelPropertiesConfigurable(final SModel modelDescriptor, Project project, boolean inPlugin) { super(project); myModelDescriptor = modelDescriptor; // readAction here is a hack, rather action shall do read. Alas, there are few places to get fixed, can't do it right now. myModelProperties = new ModelAccessHelper(project.getModelAccess()).runReadAction(new Computable<ModelProperties>() { @Override public ModelProperties compute() { return new ModelProperties(modelDescriptor); } }); myInPlugin = inPlugin; registerTabs(/*new ModelCommonTab(),*/ new ModelDependenciesComponent(), new ModelUsedLanguagesTab(), new InfoTab()); } @Nls @Override public String getDisplayName() { return String.format(PropertiesBundle.message("model.title"), myModelDescriptor.getModelName()); } @Override protected void save() { myModelProperties.saveChanges(); } public class ModelCommonTab extends CommonTab { private ModelDependenciesComponent myModelDependenciesComponent; @Override protected String getConfigItemName() { return myModelDescriptor.getModelName(); } @Override protected String getConfigItemPath() { if (myModelDescriptor instanceof EditableSModel) { DataSource source = myModelDescriptor.getSource(); if (source instanceof FileDataSource) { return FileUtil.getCanonicalPath(((FileDataSource) source).getFile().getPath()); } } return ""; } @Override protected JComponent getBottomComponent() { myModelDependenciesComponent = new ModelDependenciesComponent(); return myModelDependenciesComponent.getImportedModelsComponent(); } @Override public void init() { super.init(); myTextFieldName.setEditable(false); } @Override public boolean isModified() { return super.isModified() || myModelDependenciesComponent.isModified(); } @Override public void apply() { myModelDependenciesComponent.apply(); } } /*package*/ Set<SModelReference> getActualCrossModelReferences() { return new ModelAccessHelper(myProject.getRepository()).runReadAction(new Computable<Set<SModelReference>>() { @Override public Set<SModelReference> compute() { final ModelDependencyScanner modelScanner = new ModelDependencyScanner(); modelScanner.crossModelReferences(true).usedLanguages(false).usedConcepts(false).walk(myModelDescriptor); return modelScanner.getCrossModelReferences(); } }); } protected class ModelDependenciesComponent extends BaseTab { private ModelImportedModelsTableModel myImportedModels; private JPanel myImportedModelsComponent; private FindActionButton myFindActionButton; public JPanel getImportedModelsComponent() { return myImportedModelsComponent; } public ModelDependenciesComponent() { super(PropertiesBundle.message("mps.properties.dependencies.title"), General.Dependencies, PropertiesBundle.message("mps.properties.dependencies.tip")); myImportedModels = new ModelImportedModelsTableModel(myModelProperties); myImportedModels.init(); } protected boolean confirmRemove(final Object value) { if (value instanceof SModelReference) { final SModelReference modelReference = (SModelReference) value; if (getActualCrossModelReferences().contains(modelReference)) { ViewUsagesDeleteDialog viewUsagesDeleteDialog = new ViewUsagesDeleteDialog( ProjectHelper.toIdeaProject(myProject), "Delete imported model", "This model is used in model. Do you really what to delete it?", "Model state will become inconsistent") { @Override public void doViewAction() { myFindActionButton.actionPerformed(null); } }; viewUsagesDeleteDialog.show(); return viewUsagesDeleteDialog.isOK(); } } return true; } @Override public void init() { myImportedModelsComponent = new JPanel(); myImportedModelsComponent.setLayout(new GridLayoutManager(2, 1, MPSPropertiesConfigurable.INSETS, -1, -1)); final JBTable importedModelsTable = new JBTable(); importedModelsTable.setShowHorizontalLines(false); importedModelsTable.setShowVerticalLines(false); importedModelsTable.setAutoCreateRowSorter(false); importedModelsTable.setAutoscrolls(true); importedModelsTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); importedModelsTable.setModel(myImportedModels); ModelTableCellRender cellRender = new ModelTableCellRender(myProject.getRepository()); cellRender.addCellState(new Condition<SModel>() { @Override public boolean met(SModel m) { return m == null; } }, DependencyCellState.NOT_AVAILABLE); cellRender.addCellState(new Condition<SModel>() { @Override public boolean met(SModel m) { return !VisibilityUtil.isVisible(myModelDescriptor.getModule(), m); } }, DependencyCellState.NOT_IN_SCOPE); final Set<SModelReference> actualCrossModelRefs = getActualCrossModelReferences(); cellRender.addCellState(new Condition<SModel>() { @Override public boolean met(SModel m) { return !actualCrossModelRefs.contains(m.getReference()); } }, DependencyCellState.UNUSED); importedModelsTable.setDefaultRenderer(SModelReference.class, cellRender); ToolbarDecorator decorator = ToolbarDecorator.createDecorator(importedModelsTable); decorator.setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton anActionButton) { List<SModelReference> list = new ModelChooser(myProject).compute(); for (SModelReference reference : list) { if (!myModelDescriptor.getReference().equals(reference)) { myImportedModels.addItem(reference); } } } }).setRemoveAction(new RemoveEntryAction(importedModelsTable) { @Override protected boolean confirmRemove(int row) { return ModelDependenciesComponent.this.confirmRemove(importedModelsTable.getValueAt(row, 0)); } }).addExtraAction(myFindActionButton = new FindActionButton(importedModelsTable) { @Override public void actionPerformed(AnActionEvent e) { final SearchScope scope = new ModelsScope(myModelDescriptor); final List<SModelReference> modelReferences = new ArrayList<SModelReference>(); for (int i : myTable.getSelectedRows()) { modelReferences.add(myImportedModels.getValueAt(i)); } final SearchQuery query = new SearchQuery(new ModelsHolder(modelReferences), scope); final IResultProvider provider = FindUtils.makeProvider(new CompositeFinder(new ModelUsagesFinder())); showUsageImpl(query, provider); forceCancelCloseDialog(); } }).addExtraAction(new AnActionButton() { { getTemplatePresentation().setIcon(MPSIcons.General.ModelChecker); getTemplatePresentation().setText("Remove unused model imports"); } @Override public boolean isEnabled() { return super.isEnabled() && anyModelNotUsed(); } private boolean anyModelNotUsed() { return myImportedModels.getItemsStream().anyMatch(mr -> !actualCrossModelRefs.contains(mr)); } @Override public void actionPerformed(AnActionEvent e) { boolean anyRemoved = false; for(int row = myImportedModels.getRowCount()-1; row >= 0; row--) { if (!actualCrossModelRefs.contains(myImportedModels.getValueAt(row))) { myImportedModels.removeRow(row); anyRemoved = true; } } if (anyRemoved) { myImportedModels.fireTableDataChanged(); importedModelsTable.clearSelection(); } } }); decorator.setPreferredSize(new Dimension(500, 150)); JPanel table = decorator.createPanel(); table.setBorder(IdeBorderFactory.createBorder()); myImportedModelsComponent.add(table, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); new TableColumnSearch(importedModelsTable, 0).setComparator(new SpeedSearchComparator(false, true)); setTabComponent(myImportedModelsComponent); } @Override public boolean isModified() { return myImportedModels.isModified(); } @Override public void apply() { myImportedModels.apply(); } } public class ModelUsedLanguagesTab extends UsedLanguagesTab { private IsLanguageInUse myInUseCondition; @Override protected UsedLangsTableModel getUsedLangsTableModel() { UsedLangsTableModel rv = new UsedLangsTableModel(myProject.getRepository()); rv.init(myModelProperties.getUsedLanguages(), myModelProperties.getUsedDevKits()); return rv; } @Override public void apply() { myModelProperties.getUsedLanguages().clear(); myModelProperties.getUsedDevKits().clear(); myUsedLangsTableModel.fillResult(myModelProperties.getUsedLanguages(), myModelProperties.getUsedDevKits()); } @Override protected TableCellRenderer getTableCellRender() { SRepository contextRepo = myProject.getRepository(); Set<SLanguage> inUse = new ModelAccessHelper(myProject.getModelAccess()).runReadAction(new ComputeUsedLanguages(myModelDescriptor)); myInUseCondition = new IsLanguageInUse(inUse, myModelProperties.getUsedLanguages()); LanguageTableCellRenderer usedInModel = new LanguageTableCellRenderer(contextRepo); usedInModel.addCellState(NotCondition.negate(new ValidImportCondition(contextRepo)), DependencyCellState.NOT_AVAILABLE); usedInModel.addCellState(NotCondition.negate(myInUseCondition), DependencyCellState.UNUSED); return usedInModel; } protected void findUsages(final Object value) { final SearchScope scope = new ModelsScope(myModelDescriptor); final UsedLangsTableModel.Import entry = (UsedLangsTableModel.Import) value; final SearchQuery query = new SearchQuery(entry.myLanguage != null ? new LanguageHolder(entry.myLanguage) : new ModuleRefHolder(entry.myDevKit), scope); final IResultProvider provider = FindUtils.makeProvider(new LanguageUsagesFinder()); // FIXME FindAction below uses slightly different code to perform search, merge. Unwrap devkit here, do not rely on LanguageUsageFinder to do that? showUsageImpl(query, provider); forceCancelCloseDialog(); } @Override protected ToolbarDecorator createToolbar(JBTable usedLangsTable) { ToolbarDecorator decorator = super.createToolbar(usedLangsTable); decorator.setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton anActionButton) { Iterable<SModule> modules = new ConditionalIterable<SModule>(getProjectModules(), new ModuleInstanceCondition(Language.class, DevKit.class)); modules = new ConditionalIterable<SModule>(modules, new VisibleModuleCondition()); ComputeRunnable<List<SModuleReference>> c = new ComputeRunnable<List<SModuleReference>>(new ModuleCollector(modules)); myProject.getModelAccess().runReadAction(c); List<SModuleReference> list = CommonChoosers.showModuleSetChooser(myProject, "Choose Language or DevKit", c.getResult()); for (SModuleReference reference : list) { myUsedLangsTableModel.addItem(reference); } myUsedLangsTableModel.fireTableDataChanged(); } }).setRemoveAction(new RemoveEntryAction(usedLangsTable) { @Override protected boolean confirmRemove(int row) { final UsedLangsTableModel.Import entry = myUsedLangsTableModel.getValueAt(row); boolean inActualUse = new ModelAccessHelper(myProject.getModelAccess()).runReadAction(new Computable<Boolean>() { @Override public Boolean compute() { return myInUseCondition.met(entry); } }); if (inActualUse) { ViewUsagesDeleteDialog viewUsagesDeleteDialog = new ViewUsagesDeleteDialog( ProjectHelper.toIdeaProject(myProject), "Delete used language", "This language is used by model. Do you really what to delete it?", "Model state will become inconsistent") { @Override public void doViewAction() { findUsages(entry); } }; viewUsagesDeleteDialog.show(); return viewUsagesDeleteDialog.isOK(); } return true; } }); decorator.addExtraAction(new FindActionButton(usedLangsTable) { @Override public void actionPerformed(AnActionEvent e) { final SearchScope scope = new ModelsScope(myModelDescriptor); final List<SLanguage> languages = getSelectedLanguages(); final SearchQuery query = new SearchQuery(new GenericHolder<Collection<SLanguage>>(languages, "Languages"), scope); final IResultProvider provider = FindUtils.makeProvider(new CompositeFinder(new LanguageUsagesFinder())); showUsageImpl(query, provider); forceCancelCloseDialog(); } }); decorator.addExtraAction(new AnActionButton() { { getTemplatePresentation().setIcon(MPSIcons.General.ModelChecker); getTemplatePresentation().setText("Remove unused languages"); } @Override public void actionPerformed(AnActionEvent e) { myProject.getModelAccess().runReadAction(new Runnable() { @Override public void run() { boolean anyRemoved = false; for (int row = myUsedLangsTable.getRowCount() - 1; row >= 0; row--) { if (!myInUseCondition.met(myUsedLangsTableModel.getValueAt(row))) { myUsedLangsTableModel.removeRow(row); anyRemoved = true; } } if (anyRemoved) { myUsedLangsTableModel.fireTableDataChanged(); myUsedLangsTable.clearSelection(); } } }); } }); return decorator; } } private class InfoTab extends BaseTab { private final boolean myIsDefSModelDescr; private JBCheckBox myDoNotGenerateCheckBox; private JBCheckBox myGenerateIntoModelFolderCheckBox; private UsedLangsTableModel myEngagedLanguagesModel; public InfoTab() { super(PropertiesBundle.message("model.info.title"), IdeIcons.DEFAULT_ICON, PropertiesBundle.message("model.info.tip")); myIsDefSModelDescr = myInPlugin && myModelDescriptor instanceof DefaultSModelDescriptor; } @Override public void init() { int rowsCount = myIsDefSModelDescr ? 6 : 5; int rowIndex = 0; final JPanel panel = new JPanel(); panel.setLayout(new GridLayoutManager(rowsCount, 1, INSETS, -1, -1)); myDoNotGenerateCheckBox = new JBCheckBox(PropertiesBundle.message("model.info.checkboxDNG"), myModelProperties.isDoNotGenerate()); panel.add(myDoNotGenerateCheckBox, new GridConstraints(rowIndex++, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW | GridConstraints.SIZEPOLICY_CAN_SHRINK, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); if (myIsDefSModelDescr) { myGenerateIntoModelFolderCheckBox = new JBCheckBox(PropertiesBundle.message("model.info.checkboxGIMF"), myModelProperties.isGenerateIntoModelFolder()); panel.add(myGenerateIntoModelFolderCheckBox, new GridConstraints(rowIndex++, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_GROW | GridConstraints.SIZEPOLICY_CAN_SHRINK, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); } panel.add(new JBLabel(PropertiesBundle.message("mps.properties.common.filepathlabel")), new GridConstraints(rowIndex++, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false)); String filePath = "(not editable model)"; if (myModelDescriptor instanceof EditableSModel) { DataSource source = myModelDescriptor.getSource(); if (source instanceof FileDataSource) { filePath = FileUtil.getCanonicalPath(((FileDataSource) source).getFile().getPath()); } else if (source instanceof FolderDataSource) { filePath = FileUtil.getCanonicalPath(((FolderDataSource) source).getFolder().getPath()); } } JTextField textField = new JTextField(); textField.setEditable(false); textField.setText(filePath); panel.add(textField, new GridConstraints(rowIndex++, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null)); final JBTable languagesTable = new JBTable(); languagesTable.setShowHorizontalLines(false); languagesTable.setShowVerticalLines(false); languagesTable.setAutoCreateRowSorter(false); languagesTable.setAutoscrolls(true); languagesTable.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); myEngagedLanguagesModel = new UsedLangsTableModel(myProject.getRepository(), PropertiesBundle.message("model.info.engaged.title")); ArrayList<SLanguage> engagedLanguages = new ArrayList<SLanguage>(); engagedLanguages.addAll(myModelProperties.getLanguagesEngagedOnGeneration()); myEngagedLanguagesModel.init(engagedLanguages, Collections.<SModuleReference>emptyList()); languagesTable.setModel(myEngagedLanguagesModel); LanguageTableCellRenderer cellRenderer = new LanguageTableCellRenderer(myProject.getRepository()); Set<SLanguage> languagesInUse = new ModelAccessHelper(myProject.getModelAccess()).runReadAction(new ComputeUsedLanguages(myModelDescriptor)); IsLanguageInUse inUseCondition = new IsLanguageInUse(languagesInUse, Collections.<SLanguage>emptySet()); cellRenderer.addCellState(inUseCondition, DependencyCellState.SUPERFLUOUS_ENGAGED); cellRenderer.registerIn(languagesTable); ToolbarDecorator decorator = ToolbarDecorator.createDecorator(languagesTable); decorator.setAddAction(new AnActionButtonRunnable() { @Override public void run(AnActionButton anActionButton) { Collection<SLanguage> languages = new ModelAccessHelper(myProject.getRepository()).runReadAction(() -> LanguageRegistry.getInstance(myProject.getRepository()).getAllLanguages()); List<SLanguage> list = CommonChoosers.showLanguageSetChooser(myProject, PropertiesBundle.message("model.into.engaged.add.title"), languages); for (SLanguage l : list) { myEngagedLanguagesModel.addItem(l); } myEngagedLanguagesModel.fireTableDataChanged(); } }).setRemoveAction(new RemoveEntryAction(languagesTable)); decorator.setPreferredSize(new Dimension(500, 150)); JPanel table = decorator.createPanel(); table.setBorder(IdeBorderFactory.createBorder()); panel.add(table, new GridConstraints(rowIndex, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false)); new TableColumnSearch(languagesTable, 0).setComparator(new SpeedSearchComparator(false, true)); setTabComponent(panel); } @Override public boolean isModified() { return myDoNotGenerateCheckBox.isSelected() != myModelProperties.isDoNotGenerate() || (myIsDefSModelDescr ? (myGenerateIntoModelFolderCheckBox.isSelected() != myModelProperties.isGenerateIntoModelFolder()) : false) || myEngagedLanguagesModel.isModified(); } @Override public void apply() { myModelProperties.setDoNotGenerate(myDoNotGenerateCheckBox.isSelected()); if (myIsDefSModelDescr) { myModelProperties.setGenerateIntoModelFolder(myGenerateIntoModelFolderCheckBox.isSelected()); } ArrayList<SLanguage> engagedLanguages = new ArrayList<SLanguage>(); myEngagedLanguagesModel.fillResult(engagedLanguages, new ArrayList<SModuleReference>()/*ignored, shall be empty*/); myModelProperties.getLanguagesEngagedOnGeneration().clear(); myModelProperties.getLanguagesEngagedOnGeneration().addAll(engagedLanguages); } } /** * Answers whether given module is among specified */ private static class IsLanguageInUse implements Condition<UsedLangsTableModel.Import> { private final Collection<SLanguage> myActualUse; private final Collection<SLanguage> myExplicitUse; /** * @param actualInUse set of modules to check against * @param explicitInUse set of modules to treat as known and that should not be considered when (and if) we build derived * dependencies of a module in question. */ public IsLanguageInUse(@NotNull Collection<SLanguage> actualInUse, @NotNull Collection<SLanguage> explicitInUse) { myActualUse = actualInUse; myExplicitUse = explicitInUse; } @Override public boolean met(UsedLangsTableModel.Import entry) { if (entry == null) { return false; } if (entry.myLanguage != null) { return myActualUse.contains(entry.myLanguage); } if (entry.myDevKit != null) { // FIXME we shall do with DevKit as SModule smth anyway (i.e. to match SLanguage), that's why MPSModuleRepository here final SModule module = entry.myDevKit.resolve(MPSModuleRepository.getInstance()); if (!(module instanceof DevKit)) { return false; } HashSet<SLanguage> burstDeps = new HashSet<SLanguage>(); final DevKit devKit = (DevKit) module; burstDeps.addAll(IterableUtil.asCollection(devKit.getAllExportedLanguageIds())); // if module is already there (e.g. explicitly imported), do not consider devkit with it as used/necessary burstDeps.removeAll(myExplicitUse); return CollectionUtil.intersects(burstDeps, myActualUse); } return false; } } private static class ComputeUsedLanguages implements Computable<Set<SLanguage>> { private final SModel myModel; public ComputeUsedLanguages(@NotNull SModel model) { myModel = model; } @Override public Set<SLanguage> compute() { final ModelDependencyScanner ms = new ModelDependencyScanner().usedLanguages(true).crossModelReferences(false); ms.walk(myModel); return ms.getUsedLanguages(); } } }