/*
* 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();
}
}
}