package com.siberika.idea.pascal.sdk;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.Result;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.fileChooser.FileChooserDescriptor;
import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.projectRoots.AdditionalDataConfigurable;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.ui.TextBrowseFolderListener;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileEvent;
import com.intellij.openapi.vfs.VirtualFileListener;
import com.intellij.psi.search.FileTypeIndex;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.ui.JBColor;
import com.intellij.ui.TabbedPaneWrapper;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.util.FileContentUtil;
import com.intellij.util.indexing.FileBasedIndex;
import com.siberika.idea.pascal.DCUFileType;
import com.siberika.idea.pascal.PPUFileType;
import com.siberika.idea.pascal.PascalBundle;
import com.siberika.idea.pascal.jps.sdk.PascalSdkData;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.border.LineBorder;
import java.awt.*;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* Author: George Bakhtadze
* Date: 18/01/2013
*/
public class PascalSdkConfigUI implements AdditionalDataConfigurable {
private final Disposable myDisposable = Disposer.newDisposable();
private TextFieldWithBrowseButton compilerCommandEdit;
private Sdk sdk;
private JTextField compilerOptionsEdit;
private TextFieldWithBrowseButton decompilerCommandEdit;
private TextFieldWithBrowseButton gdbCommandEdit;
private JTextField gdbOptionsEdit;
private JCheckBox gdbResolveNames;
private JCheckBox gdbRedirectConsole;
private JCheckBox gdbRetrieveChilds;
private JCheckBox gdbUseGdbInit;
private final Map<String, JComponent> keyComponentMap = new HashMap<String, JComponent>();
public JComponent createComponent() {
TabbedPaneWrapper myTabbedPane = new TabbedPaneWrapper(myDisposable);
myTabbedPane.addTab(PascalBundle.message("ui.sdkSettings.tab.general"), createGeneralOptionsPanel());
myTabbedPane.addTab(PascalBundle.message("ui.sdkSettings.tab.debugger"), createDebuggerOptionsPanel());
if (!(sdk.getSdkType() instanceof FPCSdkType)) {
myTabbedPane.getTabComponentAt(1).setVisible(false);
}
keyComponentMap.clear();
keyComponentMap.put(PascalSdkData.Keys.COMPILER_COMMAND.getKey(), compilerCommandEdit);
keyComponentMap.put(PascalSdkData.Keys.COMPILER_OPTIONS.getKey(), compilerOptionsEdit);
keyComponentMap.put(PascalSdkData.Keys.DECOMPILER_COMMAND.getKey(), decompilerCommandEdit);
keyComponentMap.put(PascalSdkData.Keys.DEBUGGER_COMMAND.getKey(), gdbCommandEdit);
keyComponentMap.put(PascalSdkData.Keys.DEBUGGER_OPTIONS.getKey(), gdbOptionsEdit);
keyComponentMap.put(PascalSdkData.Keys.DEBUGGER_REDIRECT_CONSOLE.getKey(), gdbRedirectConsole);
keyComponentMap.put(PascalSdkData.Keys.DEBUGGER_RETRIEVE_CHILDS.getKey(), gdbRetrieveChilds);
keyComponentMap.put(PascalSdkData.Keys.DEBUGGER_RESOLVE_NAMES.getKey(), gdbResolveNames);
keyComponentMap.put(PascalSdkData.Keys.DEBUGGER_USE_GDBINIT.getKey(), gdbUseGdbInit);
return myTabbedPane.getComponent();
}
private JPanel createGeneralOptionsPanel() {
JPanel panel = new JPanel();
panel.setBorder(new LineBorder(JBColor.border()));
panel.setLayout(new GridLayoutManager(4, 2, new Insets(0, 0, 0, 0), -1, -1));
addLabel(panel, PascalBundle.message("ui.sdkSettings.compiler.command"), 0);
compilerCommandEdit = addFileFieldWithBrowse(panel, 0);
addLabel(panel, PascalBundle.message("ui.sdkSettings.compiler.options"), 1);
compilerOptionsEdit = new JTextField();
panel.add(compilerOptionsEdit, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
addLabel(panel, PascalBundle.message("ui.sdkSettings.decompiler.command"), 2);
decompilerCommandEdit = addFileFieldWithBrowse(panel, 2);
JLabel statusLabel = new JLabel();
panel.add(statusLabel, new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL,
GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 1, false));
if (BasePascalSdkType.getAdditionalData(sdk).getBoolean(PascalSdkData.Keys.DELPHI_IS_STARTER)) {
statusLabel.setText(PascalBundle.message("ui.sdkSettings.delphi.starter.warning"));
}
return panel;
}
private JPanel createDebuggerOptionsPanel() {
JPanel panel = new JPanel();
panel.setBorder(new LineBorder(JBColor.border()));
panel.setLayout(new GridLayoutManager(6, 2, new Insets(0, 0, 0, 0), -1, -1));
addLabel(panel, PascalBundle.message("ui.sdkSettings.gdb.command"), 0);
gdbCommandEdit = addFileFieldWithBrowse(panel, 0);
panel.add(gdbCommandEdit, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
addLabel(panel, PascalBundle.message("ui.sdkSettings.gdb.options"), 1);
gdbOptionsEdit = new JTextField();
panel.add(gdbOptionsEdit, new GridConstraints(1, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
addLabel(panel, PascalBundle.message("ui.sdkSettings.gdb.redirect.console"), 2);
gdbRedirectConsole = new JCheckBox();
panel.add(gdbRedirectConsole, new GridConstraints(2, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
addLabel(panel, PascalBundle.message("ui.sdkSettings.gdb.retrieve.childs"), 3);
gdbRetrieveChilds = new JCheckBox();
panel.add(gdbRetrieveChilds, new GridConstraints(3, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
addLabel(panel, PascalBundle.message("ui.sdkSettings.gdb.resolve.names"), 4);
gdbResolveNames = new JCheckBox();
panel.add(gdbResolveNames, new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
addLabel(panel, PascalBundle.message("ui.sdkSettings.gdb.use.gdbinit"), 5);
gdbUseGdbInit = new JCheckBox();
panel.add(gdbUseGdbInit, new GridConstraints(5, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
return panel;
}
private void addLabel(JPanel panel, String caption, int row) {
final JLabel label1 = new JLabel(caption);
panel.add(label1, new GridConstraints(row, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE,
GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 1, false));
}
private TextFieldWithBrowseButton addFileFieldWithBrowse(JPanel panel, int row) {
FileChooserDescriptor fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFileDescriptor();
fileChooserDescriptor.setTitle(PascalBundle.message("title.choose.file"));
TextFieldWithBrowseButton field = new TextFieldWithBrowseButton();
field.addBrowseFolderListener(new TextBrowseFolderListener(fileChooserDescriptor));
panel.add(field, new GridConstraints(row, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
null, null, null, 0, false));
return field;
}
public boolean isModified() {
for (Map.Entry<String, JComponent> entry : keyComponentMap.entrySet()) {
if (!getValue(entry.getValue()).equals(BasePascalSdkType.getAdditionalData(sdk).getValue(entry.getKey()))) {
return true;
}
}
return false;
}
public void apply() throws ConfigurationException {
for (Map.Entry<String, JComponent> entry : keyComponentMap.entrySet()) {
BasePascalSdkType.getAdditionalData(sdk).setValue(entry.getKey(), getValue(keyComponentMap.get(entry.getKey())));
}
if ((decompilerCommandEdit != null) &&
!getValue(keyComponentMap.get(PascalSdkData.Keys.DECOMPILER_COMMAND.getKey())).equals(
BasePascalSdkType.getAdditionalData(sdk).getValue(PascalSdkData.Keys.DECOMPILER_COMMAND.getKey()))
) {
BasePascalSdkType.getAdditionalData(sdk).setValue(PascalSdkData.Keys.DECOMPILER_CACHE.getKey(), null);
invalidateCompiledCache();
}
}
private Object getValue(JComponent control) {
if (control instanceof TextFieldWithBrowseButton) {
return ((TextFieldWithBrowseButton) control).getText();
} else if (control instanceof JTextField) {
return ((JTextField) control).getText();
} else if (control instanceof JCheckBox) {
return ((JCheckBox) control).isSelected() ? PascalSdkData.SDK_DATA_TRUE : "0";
} else {
throw new IllegalStateException("getValue: Invalid control: " + ((control != null) ? control.getClass() : "null"));
}
}
private void invalidateCompiledCache() {
ApplicationManager.getApplication().invokeLater(new Runnable() {
@Override
public void run() {
Project[] projects = ProjectManager.getInstance().getOpenProjects();
final FileDocumentManager documentManager = FileDocumentManager.getInstance();
for (final Project project : projects) {
final Module[] modules = ModuleManager.getInstance(project).getModules();
new WriteCommandAction(project) {
@Override
protected void run(@NotNull Result result) throws Throwable {
for (Module module : modules) {
Collection<VirtualFile> files = FileBasedIndex.getInstance().getContainingFiles(FileTypeIndex.NAME, PPUFileType.INSTANCE, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module));
files.addAll(FileBasedIndex.getInstance().getContainingFiles(FileTypeIndex.NAME, DCUFileType.INSTANCE, GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(module)));
for (VirtualFile virtualFile : files) {
((VirtualFileListener) documentManager).contentsChanged(new VirtualFileEvent(null, virtualFile, virtualFile.getName(), virtualFile.getParent()));
}
FileContentUtil.reparseFiles(files);
}
}
}.execute();
}
}
});
}
public void reset() {
for (Map.Entry<String, JComponent> entry : keyComponentMap.entrySet()) {
setValue(keyComponentMap.get(entry.getKey()), BasePascalSdkType.getAdditionalData(sdk).getValue(entry.getKey()));
}
}
private void setValue(JComponent control, Object value) {
if (control instanceof TextFieldWithBrowseButton) {
((TextFieldWithBrowseButton) control).setText((String) value);
} else if (control instanceof JTextField) {
((JTextField) control).setText((String) value);
} else if (control instanceof JCheckBox) {
((JCheckBox) control).setSelected(PascalSdkData.SDK_DATA_TRUE.equals(value));
} else {
throw new IllegalStateException("setValue: Invalid control: " + ((control != null) ? control.getClass() : "null"));
}
}
public void disposeUIResources() {
}
@Override
public void setSdk(Sdk sdk) {
this.sdk = sdk;
}
}