package org.fandev.module.ui.roots;
import com.intellij.ide.util.BrowseFilesListener;
import com.intellij.openapi.fileChooser.FileChooser;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ui.configuration.ModuleConfigurationState;
import com.intellij.openapi.roots.ui.configuration.ModuleElementsEditor;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.ui.FieldPanel;
import org.fandev.icons.Icons;
import org.fandev.lang.fan.FanBundle;
import org.fandev.module.FanModuleSettings;
import org.fandev.module.pod.PodFileParser;
import org.fandev.module.pod.PodModel;
import org.fandev.module.wizard.ui.CheckBoxFieldPanel;
import org.fandev.module.wizard.ui.FanFieldPanel;
import org.fandev.utils.FanUtil;
import org.fandev.utils.PodUtil;
import org.fandev.utils.VirtualFileUtil;
import org.jetbrains.annotations.Nls;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* @author Dror Bereznitsky
* @date Jan 31, 2009 11:34:31 PM
*/
public class PodEditor extends ModuleElementsEditor {
private JPanel buildScriptPathPanel;
private JTextField podName;
private JTextField version;
private JTextField podDescription;
private JTextField srcDirs;
private JTextField resDirs;
private JTextField outDir;
private JCheckBox docApi;
private JCheckBox docSrc;
private JTextField indexes;
private JTextField metas;
private JTextField dependencies;
private boolean podModified = false;
private PodModel pod;
protected PodEditor(final ModuleConfigurationState state) {
super(state);
// This is sad, Why can't I find something with a reference to the podModel?!?
pod = PodFileParser.parse(getModuleSettings().getBuildScript(), getModuleSettings().getModule());
// and later on, I have to rewrite the damned build file!
}
protected JComponent createComponentImpl() {
buildScriptPathPanel = new JPanel();
buildScriptPathPanel.setLayout(new BoxLayout(buildScriptPathPanel,BoxLayout.PAGE_AXIS));
// podName
podName = new JTextField(pod.getName());
version = new JTextField(pod.getVersion());
podDescription = new JTextField(pod.getDescription());
srcDirs = new JTextField(FanUtil.listPairToFirstString(pod.getSrcDirs()));
resDirs = new JTextField(FanUtil.listPairToFirstString(pod.getResDirs()));
dependencies = new JTextField(FanUtil.listToString(pod.getDependencies()));
outDir = new JTextField(pod.getOutDir());
docApi = new JCheckBox("", pod.getDocApi());
docSrc = new JCheckBox("", pod.getDocSrc());
indexes = new JTextField(FanUtil.listPairToString(pod.getIndexes()));
metas = new JTextField(FanUtil.listPairToString(pod.getMetas()));
final VirtualFile moduleFile = getModel().getModule().getModuleFile().getParent();
// callbacks for srcDirs, resDirs. I expect that the user wants to select
// multiple directories, but that's b0rked in BrowseFilesListener. Fixed in
// the actionperformed listener
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());
podModified = true;
}
};
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());
podModified = true;
}
};
// 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(resDirs,
FanBundle.message("pod.outDir"),
FanBundle.message("pod.outDir"),
resDirsChooser) {
@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());
podModified = true;
}
};
// 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(pod.getOutDir());
dependenciesChooser.setRoot(VirtualFileUtil.refreshAndFindFileByLocalPath(
VirtualFileUtil.buildUrl(getState().getRootModel().getSdk().getHomePath(), "lib/fan")));
dependenciesChooser.addRoot(v);
}
final BrowseFilesListener dependenciesBrowseListener = new BrowseFilesListener(dependencies,
FanBundle.message("pod.dependencies"),
FanBundle.message("pod.dependencies"),
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());
}
};
podName.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
podModified = true;
}
});
version.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
podModified = true;
}
});
podDescription.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
podModified = true;
}
});
docApi.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
podModified = true;
}
});
docSrc.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent e) {
podModified = true;
}
});
final ActionListener indexesListener = new ActionListener() {
public void actionPerformed(final ActionEvent e) {
podModified = true;
}
};
indexes.addActionListener(indexesListener);
final ActionListener metasListener = new ActionListener() {
public void actionPerformed(final ActionEvent e) {
podModified = true;
}
};
metas.addActionListener(metasListener);
final FieldPanel podNamePanel = new FieldPanel(podName, FanBundle.message("pod.name"), null, null, null);
final FieldPanel descriptionPanel = new FieldPanel(podDescription, FanBundle.message("pod.description"), null, null, null);
final FieldPanel versionPanel = new FieldPanel(version, FanBundle.message("pod.version"), null, null, null);
final FieldPanel srcDirsPanel = new FieldPanel(srcDirs, FanBundle.message("src.dirs.path"), null, srcDirsBrowseListener, null);
final FieldPanel resDirsPanel = new FieldPanel(resDirs, FanBundle.message("res.dirs.path"), null, resDirsBrowseListener, null);
final FieldPanel dependenciesPanel = new FieldPanel(dependencies, FanBundle.message("pod.dependencies"), null, dependenciesBrowseListener, null);
final FieldPanel outDirPanel = new FieldPanel(outDir, FanBundle.message("pod.outDir"), null, outDirBrowseListener, null);
final CheckBoxFieldPanel docApiPanel = new CheckBoxFieldPanel(docApi, FanBundle.message("pod.docApi"));
final CheckBoxFieldPanel docSrcPanel = new CheckBoxFieldPanel(docSrc, FanBundle.message("pod.docSrc"));
final FanFieldPanel indexesPanel = new FanFieldPanel(indexes, FanBundle.message("pod.indexes"), FanBundle.message("pod.indexes"), indexesListener, null);
final FanFieldPanel metasPanel = new FanFieldPanel(metas, FanBundle.message("pod.metas"), FanBundle.message("pod.metas"), metasListener, null);
buildScriptPathPanel.add(podNamePanel);
buildScriptPathPanel.add(descriptionPanel);
buildScriptPathPanel.add(versionPanel);
buildScriptPathPanel.add(srcDirsPanel);
buildScriptPathPanel.add(resDirsPanel);
buildScriptPathPanel.add(dependenciesPanel);
buildScriptPathPanel.add(outDirPanel);
buildScriptPathPanel.add(docApiPanel);
buildScriptPathPanel.add(docSrcPanel);
buildScriptPathPanel.add(indexesPanel);
buildScriptPathPanel.add(metasPanel);
return buildScriptPathPanel;
}
public void saveData() {
pod.setName(podName.getText());
pod.setDescription(podDescription.getText());
pod.setVersion(version.getText());
pod.setDocApi(docApi.isSelected());
pod.setDocSrc(docSrc.isSelected());
pod.setSrcDirs(FanUtil.firstStringToListPair(srcDirs.getText()));
pod.setResDirs(FanUtil.firstStringToListPair(resDirs.getText()));
pod.setDependencies(FanUtil.stringToList(dependencies.getText()));
pod.setOutDir(outDir.getText());
pod.setIndexes(FanUtil.stringToListPair(indexes.getText()));
pod.setMetas(FanUtil.stringToListPair(metas.getText()));
// Save out a new build.fan?!?
final Module m = getModel().getModule();
FanUtil.generateBuildScript(m.getModuleFile().getParent().getPath(), m.getProject(), pod);
podModified = false;
}
@Override
public boolean isModified() {
return podModified;
}
@Nls
public String getDisplayName() {
return "Build Script Editor";
}
public Icon getIcon() {
return Icons.FAN_16;
}
public String getHelpTopic() {
return null;
}
public static PodEditor createPodEditor(final ModuleConfigurationState state) {
return new PodEditor(state);
}
private FanModuleSettings getModuleSettings() {
return FanModuleSettings.getInstance(getModel().getModule());
}
}