package jetbrains.mps.ide.dialogs.project.creation;
/*Generated by MPS */
import com.intellij.openapi.ui.DialogWrapper;
import org.apache.log4j.Logger;
import org.apache.log4j.LogManager;
import javax.swing.JPanel;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import javax.swing.JTextField;
import jetbrains.mps.smodel.Language;
import jetbrains.mps.smodel.Generator;
import jetbrains.mps.project.MPSProject;
import jetbrains.mps.vfs.FileSystem;
import java.awt.HeadlessException;
import java.awt.GridLayout;
import java.awt.Dimension;
import org.jetbrains.annotations.Nullable;
import javax.swing.JComponent;
import javax.swing.JLabel;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import jetbrains.mps.ide.ui.filechoosers.treefilechooser.TreeFileChooser;
import jetbrains.mps.vfs.IFile;
import java.io.File;
import jetbrains.mps.baseLanguage.closures.runtime.Wrappers;
import jetbrains.mps.ide.newSolutionDialog.NewModuleUtil;
import jetbrains.mps.baseLanguage.closures.runtime._FunctionTypes;
import jetbrains.mps.project.structure.modules.GeneratorDescriptor;
import org.apache.log4j.Level;
import com.intellij.openapi.util.Disposer;
import jetbrains.mps.project.structure.modules.LanguageDescriptor;
import jetbrains.mps.smodel.ModuleRepositoryFacade;
public class NewGeneratorDialog extends DialogWrapper {
private static final Logger LOG = LogManager.getLogger(NewGeneratorDialog.class);
private final JPanel myContenetPane;
private TextFieldWithBrowseButton myTemplateModelsDir;
private JTextField myGeneratorName;
private final Language mySourceLanguage;
private Generator myResult;
private final MPSProject myProject;
private final FileSystem myProjectFS;
public NewGeneratorDialog(MPSProject project, Language sourceLanguage) throws HeadlessException {
super(project.getProject());
myProject = project;
setTitle("New Generator");
mySourceLanguage = sourceLanguage;
// I don't know what's proper mechanism to obtain FS for the project. Could use one from sourceLanguage's descriptor file
// but would prefer not to access module's descriptor file at all.
myProjectFS = FileSystem.getInstance();
myContenetPane = new JPanel(new GridLayout(4, 1));
myContenetPane.setPreferredSize(new Dimension(600, 100));
initContentPane();
init();
}
@Nullable
@Override
protected JComponent createCenterPanel() {
return myContenetPane;
}
private void initContentPane() {
myContenetPane.add(new JLabel("Generator name"));
myGeneratorName = new JTextField();
myContenetPane.add(myGeneratorName);
myContenetPane.add(new JLabel("Templates root"));
myTemplateModelsDir = new TextFieldWithBrowseButton();
myTemplateModelsDir.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String oldPath = myTemplateModelsDir.getText();
TreeFileChooser chooser = new TreeFileChooser();
chooser.setMode(TreeFileChooser.MODE_DIRECTORIES);
if (oldPath != null && oldPath.length() != 0) {
chooser.setInitialFile(myProjectFS.getFile(oldPath));
}
IFile result = chooser.showDialog();
if (result != null) {
myTemplateModelsDir.setText(result.toPath().toString());
}
}
});
myContenetPane.add(myTemplateModelsDir);
updateTemplateModelsDir();
}
private void updateTemplateModelsDir() {
IFile moduleDir = mySourceLanguage.getModuleSourceDir();
assert moduleDir != null;
String path = moduleDir.toPath().toString();
String modelsDir = path + File.separatorChar + "generator" + File.separatorChar + "template";
myTemplateModelsDir.setText(modelsDir);
}
private boolean isValidName(String name) {
for (char c : name.toCharArray()) {
if (!(Character.isLetterOrDigit(c)) && c != '_') {
return false;
}
}
return true;
}
public Generator getResult() {
return myResult;
}
@Override
protected void doOKAction() {
if (myTemplateModelsDir.getText().length() == 0) {
setErrorText("No template models root");
return;
}
final IFile templateModelsPath = myProjectFS.getFile(myTemplateModelsDir.getText());
if (templateModelsPath.toPath().isRelative()) {
setErrorText("Path should be absolute");
return;
}
final String name = myGeneratorName.getText();
if (!(isValidName(name))) {
setErrorText("Only letters, digits and '_' can be used in a generator's alias.");
return;
}
dispose();
final Wrappers._T<Generator> newGenerator = new Wrappers._T<Generator>(null);
NewModuleUtil.runModuleCreation(myProject, new _FunctionTypes._void_P0_E0() {
public void invoke() {
try {
// see MPS-18743
myProject.getRepository().saveAll();
// XXX why saveAll is not part of NewModuleUtil.runModuleCreation?
templateModelsPath.mkdirs();
// FIXME I know it's ugly to assume templateModelsPath always points to a descendant of generator module location, just don't want to deal with UI update
// right now, nor to introduce a hack to guess whether it's relative to mySourceLanguage.getModuleSourceDir() and how many separators are there.
final GeneratorDescriptor generatorDescriptor = NewModuleUtil.createGeneratorDescriptor(Generator.generateGeneratorUID(mySourceLanguage), templateModelsPath.getParent(), templateModelsPath);
generatorDescriptor.setAlias(name);
newGenerator.value = createNewGenerator(mySourceLanguage, generatorDescriptor);
NewModuleUtil.createTemplateModelIfNoneYet(newGenerator.value);
} catch (Exception e) {
// XXX again, why it's not common for any runModuleCreation?
if (LOG.isEnabledFor(Level.ERROR)) {
LOG.error("Failed to create new generator module", e);
}
newGenerator.value = null;
}
}
});
myResult = newGenerator.value;
super.doOKAction();
}
@Override
protected void dispose() {
super.dispose();
Disposer.dispose(myTemplateModelsDir);
}
/*package*/ Generator createNewGenerator(final Language language, GeneratorDescriptor generatorDescriptor) {
final LanguageDescriptor languageDescriptor = language.getModuleDescriptor();
generatorDescriptor.setSourceLanguage(language.getModuleReference());
languageDescriptor.getGenerators().add(generatorDescriptor);
language.setModuleDescriptor(languageDescriptor);
language.save();
return new ModuleRepositoryFacade(myProject).getModule(generatorDescriptor.getModuleReference(), Generator.class);
}
}