package org.fandev.module.wizard.ui; import com.intellij.ide.util.BrowseFilesListener; import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.ui.FieldPanel; import javax.swing.*; import org.fandev.module.pod.PodModel; import org.fandev.lang.fan.FanBundle; import org.fandev.module.wizard.FanModuleBuilder; import org.fandev.utils.FanUtil; import org.fandev.utils.PodUtil; import org.fandev.utils.VirtualFileUtil; import java.awt.*; import java.awt.event.ActionListener; import java.awt.event.ActionEvent; /** * @author Dror Bereznitsky * @date Jan 26, 2009 2:09:05 PM */ //TODO have proper binding between view and model public class FanPodCreatePanel extends JComponent { private final JLabel messageLabel; private final JTextField podName; private final JTextField version; private final JTextField podDescription; private final JCheckBox docApi; private final JCheckBox docSrc; private final JTextField indexes; private final JTextField outDir; private final JTextField metas; private final JTextField dependencies; private final JTextField srcDirs; private final JTextField resDirs; private PodModel podModel; public FanPodCreatePanel(final FanModuleBuilder builder) { podModel = builder.getModulePod(); VirtualFile moduleFile = null; if (builder.getModuleFileDirectory() != null) { moduleFile = VirtualFileUtil.refreshAndFindFileByLocalPath(builder.getModuleFileDirectory()); } setBorder(BorderFactory.createEtchedBorder()); setLayout(new BorderLayout()); final JPanel myMainPanel = new JPanel(); myMainPanel.setLayout(new BoxLayout(myMainPanel,BoxLayout.PAGE_AXIS)); messageLabel = new JLabel(); podName = new JTextField(podModel.getName()); version = new JTextField(podModel.getVersion()); podDescription = new JTextField(podModel.getDescription()); srcDirs = new JTextField(FanUtil.listPairToFirstString(podModel.getSrcDirs())); resDirs = new JTextField(FanUtil.listPairToFirstString(podModel.getResDirs())); dependencies = new JTextField(FanUtil.listToString(podModel.getDependencies())); outDir = new JTextField(podModel.getOutDir()); docApi = new JCheckBox("", podModel.getDocApi()); docSrc = new JCheckBox("", podModel.getDocSrc()); indexes = new JTextField(FanUtil.listPairToString(podModel.getIndexes())); metas = new JTextField(FanUtil.listPairToString(podModel.getMetas())); // actionListeners by the dozen podName.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { podModel.setName(podName.getText()); } }); version.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { podModel.setVersion(version.getText()); } }); podDescription.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { podModel.setDescription(podDescription.getText()); } }); docApi.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { podModel.setDocApi(docApi.isSelected()); } }); docSrc.addActionListener(new ActionListener() { public void actionPerformed(final ActionEvent e) { podModel.setDocSrc(docSrc.isSelected()); } }); final ActionListener indexesListener = new ActionListener() { public void actionPerformed(final ActionEvent e) { podModel.setIndexes(FanUtil.stringToListPair(indexes.getText())); } }; indexes.addActionListener(indexesListener); final ActionListener metasListener = new ActionListener() { public void actionPerformed(final ActionEvent e) { podModel.setMetas(FanUtil.stringToListPair(metas.getText())); } }; metas.addActionListener(metasListener); // We have the same-style file browsers here as in PodEditor, for the same reason. // BrowseFileListener is broken insofar as it does not handle multiple file selections. final FileChooserDescriptor srcDirsChooser = new FileChooserDescriptor(false, true, false, false, false, true) { public boolean isFileSelectable(final VirtualFile file) { return file.isDirectory(); } }; if (moduleFile != null) { srcDirsChooser.setRoot(moduleFile); } final BrowseFilesListener srcDirsBrowseListener = new BrowseFilesListener(srcDirs, FanBundle.message("src.dirs.path"), FanBundle.message("src.dirs.path.description"), srcDirsChooser) { @Override public void actionPerformed(final ActionEvent e) { final VirtualFile fileToSelect = getFileToSelect(); final VirtualFile[] files = (fileToSelect != null) ? FileChooser.chooseFiles(srcDirs, srcDirsChooser, fileToSelect) : FileChooser.chooseFiles(srcDirs, srcDirsChooser); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < files.length; i++) { if (i != 0) { sb.append(", "); } final String file = files[i].getName(); sb.append(file); if (!file.endsWith("/")) { sb.append('/'); } } srcDirs.setText(sb.toString()); } }; final FileChooserDescriptor resDirsChooser = new FileChooserDescriptor(false, true, false, false, false, true) { public boolean isFileSelectable(final VirtualFile file) { return file.isDirectory(); } }; if (moduleFile != null) { resDirsChooser.setRoot(moduleFile); } final BrowseFilesListener resDirsBrowseListener = new BrowseFilesListener(resDirs, FanBundle.message("res.dirs.path"), FanBundle.message("res.dirs.path.description"), resDirsChooser) { @Override public void actionPerformed(final ActionEvent e) { final VirtualFile fileToSelect = getFileToSelect(); final VirtualFile[] files = (fileToSelect != null) ? FileChooser.chooseFiles(resDirs, resDirsChooser, fileToSelect) : FileChooser.chooseFiles(resDirs, resDirsChooser); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < files.length; i++) { if (i != 0) { sb.append(", "); } final String file = files[i].getName(); sb.append(file); if (!file.endsWith("/")) { sb.append('/'); } } resDirs.setText(sb.toString()); } }; // We did not need to have the same ornate callback, but: I wanted to make // sure that we placed the directory's relative name, and that it furthermore // has a trailing "/". final FileChooserDescriptor outDirChooser = new FileChooserDescriptor(false, true, false, false, false, false) { public boolean isFileSelectable(final VirtualFile file) { return file.isDirectory(); } }; if (moduleFile != null) { outDirChooser.setRoot(moduleFile); } final BrowseFilesListener outDirBrowseListener = new BrowseFilesListener(outDir, FanBundle.message("out.dir.path"), FanBundle.message("out.dir.path.description"), outDirChooser) { @Override public void actionPerformed(final ActionEvent e) { final VirtualFile fileToSelect = getFileToSelect(); final VirtualFile[] files = (fileToSelect != null) ? FileChooser.chooseFiles(outDir, outDirChooser, fileToSelect) : FileChooser.chooseFiles(outDir, outDirChooser); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < files.length; i++) { if (i != 0) { sb.append(", "); } final String file = files[i].getName(); sb.append(file); if (!file.endsWith("/")) { sb.append('/'); } } outDir.setText(sb.toString()); } }; // Dependencies callback is wild because we open up every pod file chosen, // pull out its version ID, and ensure that only the name of the file (without // extension) is posted to th textfield. final FileChooserDescriptor dependenciesChooser = new FileChooserDescriptor(true, false, false, false, false, true) { public boolean isFileSelectable(final VirtualFile file) { return file.getExtension().equals("pod"); } }; if (moduleFile != null) { // we want a list of pod files, both from our "outDir" and from the sdk's lib/fan // directory. Now, here we're stuck: since I allow a string to contain outDir(), // it COULD be a Fan expression. Why not; build.fan is source code, not metadata! // I'll just pretend it has a legit directory. If I am wrong, LOL, too bad! final VirtualFile v = moduleFile.findChild(podModel.getOutDir()); dependenciesChooser.setRoot(VirtualFileUtil.refreshAndFindFileByLocalPath( VirtualFileUtil.buildUrl(builder.getSdk().getHomePath(), "lib/fan"))); dependenciesChooser.addRoot(v); } final BrowseFilesListener dependenciesBrowseListener = new BrowseFilesListener(dependencies, FanBundle.message("out.dir.path"), FanBundle.message("out.dir.path.description"), dependenciesChooser) { @Override public void actionPerformed(final ActionEvent e) { final VirtualFile fileToSelect = getFileToSelect(); final VirtualFile[] files = (fileToSelect != null) ? FileChooser.chooseFiles(dependencies, dependenciesChooser, fileToSelect) : FileChooser.chooseFiles(dependencies, dependenciesChooser); final StringBuilder sb = new StringBuilder(); for (int i = 0; i < files.length; i++ ) { final String file = files[i].getNameWithoutExtension(); final String version = PodUtil.getPodVersion(files[i]); if (i != 0) { sb.append(", "); } sb.append(file); sb.append(' '); sb.append(version); } dependencies.setText(sb.toString()); } }; final FieldPanel podNameFieldPanel = new FieldPanel(podName, FanBundle.message("pod.name"), null, null, null); final FieldPanel versionFieldPanel = new FieldPanel(version, FanBundle.message("pod.version"), null, null, null); final FieldPanel podDescriptionFieldPanel = new FieldPanel(podDescription, FanBundle.message("pod.description"), null, null, null); final FieldPanel srcDirsFieldPanel = new FieldPanel(srcDirs, FanBundle.message("pod.srcDirs"), null, srcDirsBrowseListener, null); final FieldPanel resDirsFieldPanel = new FieldPanel(resDirs, FanBundle.message("pod.resDirs"), null, resDirsBrowseListener, null); final FieldPanel outDirFieldPanel = new FieldPanel(outDir, FanBundle.message("pod.outDir"), null, outDirBrowseListener, null); final FieldPanel dependenciesFieldPanel = new FieldPanel(dependencies, FanBundle.message("pod.dependencies"), null, dependenciesBrowseListener, null); final CheckBoxFieldPanel docApiFieldPanel = new CheckBoxFieldPanel(docApi, FanBundle.message("pod.docApi")); final CheckBoxFieldPanel docSrcFieldPanel = new CheckBoxFieldPanel(docSrc, FanBundle.message("pod.docSrc")); final FanFieldPanel indexesFieldPanel = new FanFieldPanel(indexes, FanBundle.message("pod.indexes"), FanBundle.message("pod.indexes"), indexesListener, null); final FanFieldPanel metasFieldPanel = new FanFieldPanel(metas, FanBundle.message("pod.metas"), FanBundle.message("pod.metas"), metasListener, null); myMainPanel.add(messageLabel); myMainPanel.add(podNameFieldPanel); myMainPanel.add(versionFieldPanel); myMainPanel.add(podDescriptionFieldPanel); myMainPanel.add(dependenciesFieldPanel); myMainPanel.add(srcDirsFieldPanel); myMainPanel.add(resDirsFieldPanel); myMainPanel.add(outDirFieldPanel); myMainPanel.add(docApiFieldPanel); myMainPanel.add(docSrcFieldPanel); myMainPanel.add(indexesFieldPanel); myMainPanel.add(metasFieldPanel); add(myMainPanel, BorderLayout.PAGE_START); } void setMessage(final String message) { messageLabel.setText(message); } void setModel(final PodModel podModel) { this.podModel = podModel; podName.setText(podModel.getName()); version.setText(podModel.getVersion()); podDescription.setText(podModel.getDescription()); dependencies.setText(FanUtil.listToString(podModel.getDependencies())); docApi.setSelected(podModel.getDocApi()); docSrc.setSelected(podModel.getDocSrc()); indexes.setText(FanUtil.listPairToString(podModel.getIndexes())); metas.setText(FanUtil.listPairToString(podModel.getMetas())); srcDirs.setText(FanUtil.listPairToFirstString(podModel.getSrcDirs())); resDirs.setText(FanUtil.listPairToFirstString(podModel.getResDirs())); outDir.setText(podModel.getOutDir()); } void updateModel() { podModel.setName(podName.getText()); podModel.setVersion(version.getText()); podModel.setDescription(podDescription.getText()); podModel.setDependencies(FanUtil.stringToList(dependencies.getText())); podModel.setDocApi(docApi.isSelected()); podModel.setDocSrc(docSrc.isSelected()); podModel.setIndexes(FanUtil.stringToListPair(indexes.getText())); podModel.setMetas(FanUtil.stringToListPair(metas.getText())); podModel.setSrcDirs(FanUtil.firstStringToListPair(srcDirs.getText())); podModel.setResDirs(FanUtil.firstStringToListPair(resDirs.getText())); podModel.setOutDir(outDir.getText()); } }