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); } }