package org.rubypeople.rdt.internal.debug.ui.launcher;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.ui.AbstractLaunchConfigurationTab;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.rubypeople.rdt.core.ILoadpathEntry;
import org.rubypeople.rdt.core.IRubyProject;
import org.rubypeople.rdt.core.RubyCore;
import org.rubypeople.rdt.internal.core.RubyModelManager;
import org.rubypeople.rdt.internal.debug.ui.RdtDebugUiMessages;
import org.rubypeople.rdt.internal.debug.ui.RdtDebugUiPlugin;
import org.rubypeople.rdt.internal.debug.ui.rubyvms.AddVMDialog;
import org.rubypeople.rdt.internal.debug.ui.rubyvms.IAddVMDialogRequestor;
import org.rubypeople.rdt.internal.debug.ui.rubyvms.RubyVMMessages;
import org.rubypeople.rdt.internal.launching.RubyLaunchConfigurationAttribute;
import org.rubypeople.rdt.internal.launching.RuntimeLoadpathEntry;
import org.rubypeople.rdt.internal.ui.RubyPluginImages;
import org.rubypeople.rdt.launching.IRubyLaunchConfigurationConstants;
import org.rubypeople.rdt.launching.IRuntimeLoadpathEntry;
import org.rubypeople.rdt.launching.IVMInstall;
import org.rubypeople.rdt.launching.IVMInstallType;
import org.rubypeople.rdt.launching.RubyRuntime;
import org.rubypeople.rdt.launching.VMStandin;
public class RubyEnvironmentTab extends AbstractLaunchConfigurationTab implements SelectionListener
{
protected ListViewer loadPathListViewer;
protected List<IVMInstall> installedInterpretersWorkingCopy;
protected Combo interpreterCombo;
protected Button loadPathDefaultButton;
private Button fAddButton;
private Button fRemoveButton;
private Button fUpButton;
private Button fDownButton;
public RubyEnvironmentTab()
{
super();
}
public void createControl(Composite parent)
{
Composite composite = createPageRoot(parent);
TabFolder tabFolder = new TabFolder(composite, SWT.NONE);
GridData gridData = new GridData(GridData.FILL_BOTH);
tabFolder.setLayoutData(gridData);
addLoadPathTab(tabFolder);
addInterpreterTab(tabFolder);
}
protected void addLoadPathTab(TabFolder tabFolder)
{
Composite comp = new Composite(tabFolder, SWT.NONE);
GridLayout topLayout = new GridLayout();
topLayout.numColumns = 2;
topLayout.marginHeight = 0;
topLayout.marginWidth = 0;
comp.setLayout(topLayout);
GridData gd = new GridData(GridData.FILL_BOTH);
comp.setLayoutData(gd);
loadPathListViewer = new ListViewer(comp, SWT.BORDER | SWT.MULTI | SWT.V_SCROLL | SWT.H_SCROLL);
loadPathListViewer.setContentProvider(new LoadPathContentProvider());
loadPathListViewer.setLabelProvider(new LoadPathEntryLabelProvider());
loadPathListViewer.getList().setLayoutData(new GridData(GridData.FILL_BOTH));
Composite pathButtonComp = new Composite(comp, SWT.NONE);
GridLayout pathButtonLayout = new GridLayout();
pathButtonLayout.marginHeight = 0;
pathButtonLayout.marginWidth = 0;
pathButtonComp.setLayout(pathButtonLayout);
gd = new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_FILL);
pathButtonComp.setLayoutData(gd);
fAddButton = createPushButton(pathButtonComp, "Add...");
fAddButton.addSelectionListener(this);
fRemoveButton = createPushButton(pathButtonComp, "Remove");
fRemoveButton.addSelectionListener(this);
fUpButton = createPushButton(pathButtonComp, RubyVMMessages.VMLibraryBlock_4);
fUpButton.addSelectionListener(this);
fDownButton = createPushButton(pathButtonComp, RubyVMMessages.VMLibraryBlock_5);
fDownButton.addSelectionListener(this);
loadPathDefaultButton = new Button(comp, SWT.CHECK);
loadPathDefaultButton
.setText(RdtDebugUiMessages.LaunchConfigurationTab_RubyEnvironment_loadPathDefaultButton_label);
loadPathDefaultButton.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
loadPathDefaultButton.addSelectionListener(getLoadPathDefaultButtonSelectionListener());
loadPathDefaultButton.setEnabled(true);
TabItem loadPathTab = new TabItem(tabFolder, SWT.NONE, 0);
loadPathTab.setText(RdtDebugUiMessages.LaunchConfigurationTab_RubyEnvironment_loadPathTab_label);
loadPathTab.setControl(comp);
loadPathTab.setData(loadPathListViewer);
}
/**
* Creates and returns a button
*
* @param parent
* parent widget
* @param label
* label
* @return Button
*/
protected Button createPushButton(Composite parent, String label)
{
Button button = new Button(parent, SWT.PUSH);
button.setFont(parent.getFont());
button.setText(label);
// fDialog.setButtonLayoutData(button);
return button;
}
protected SelectionListener getLoadPathSelectionListener()
{
return new SelectionAdapter()
{
public void widgetSelected(SelectionEvent e)
{
System.out.println("Loadpath list selection occurred: " + e.getSource());
}
};
}
protected SelectionListener getLoadPathDefaultButtonSelectionListener()
{
return new SelectionAdapter()
{
public void widgetSelected(SelectionEvent e)
{
setUseLoadPathDefaults(((Button) e.getSource()).getSelection());
}
};
}
protected void addInterpreterTab(TabFolder tabFolder)
{
Composite interpreterComposite = new Composite(tabFolder, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginHeight = 0;
layout.marginWidth = 0;
interpreterComposite.setLayout(layout);
interpreterComposite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
createVerticalSpacer(interpreterComposite, 2);
interpreterCombo = new Combo(interpreterComposite, SWT.READ_ONLY);
interpreterCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
initializeInterpreterCombo(interpreterCombo);
interpreterCombo.addModifyListener(getInterpreterComboModifyListener());
Button interpreterAddButton = new Button(interpreterComposite, SWT.PUSH);
interpreterAddButton
.setText(RdtDebugUiMessages.LaunchConfigurationTab_RubyEnvironment_interpreterAddButton_label);
interpreterAddButton.addSelectionListener(new AddInterpreterSelectionAdapter(interpreterCombo, getShell()));
TabItem interpreterTab = new TabItem(tabFolder, SWT.NONE);
interpreterTab.setText(RdtDebugUiMessages.LaunchConfigurationTab_RubyEnvironment_interpreterTab_label);
interpreterTab.setControl(interpreterComposite);
}
private static class AddInterpreterSelectionAdapter extends SelectionAdapter implements IAddVMDialogRequestor
{
private Combo fCombo;
private Shell fShell;
public AddInterpreterSelectionAdapter(Combo combo, Shell shell)
{
fCombo = combo;
fShell = shell;
}
public void widgetSelected(SelectionEvent evt)
{
AddVMDialog dialog = new AddVMDialog(this, fShell, RubyRuntime.getVMInstallTypes(), null);
dialog.setTitle(RubyVMMessages.InstalledJREsBlock_7);
if (dialog.open() != Window.OK)
{
return;
}
}
public boolean isDuplicateName(String name)
{
return false;
}
public void vmAdded(IVMInstall vm)
{
// FIXME Use something like JREsUpdater?
if (vm instanceof VMStandin)
{
VMStandin standin = (VMStandin) vm;
standin.convertToRealVM();
}
fCombo.add(vm.getName());
fCombo.select(fCombo.indexOf(vm.getName()));
}
}
protected ModifyListener getInterpreterComboModifyListener()
{
return new ModifyListener()
{
public void modifyText(ModifyEvent evt)
{
updateLaunchConfigurationDialog();
}
};
}
protected void createVerticalSpacer(Composite comp, int colSpan)
{
Label label = new Label(comp, SWT.NONE);
GridData gd = new GridData();
gd.horizontalSpan = colSpan;
label.setLayoutData(gd);
}
public void setDefaults(ILaunchConfigurationWorkingCopy configuration)
{
IVMInstall defaultInterpreter = RubyRuntime.getDefaultVMInstall();
if (defaultInterpreter != null)
{
configuration.setAttribute(IRubyLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME, defaultInterpreter
.getName());
configuration.setAttribute(IRubyLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, defaultInterpreter
.getVMInstallType().getId());
}
}
public void initializeFrom(ILaunchConfiguration configuration)
{
initializeLoadPath(configuration);
initializeInterpreterSelection(configuration);
}
protected void initializeLoadPath(ILaunchConfiguration configuration)
{
boolean useDefaultLoadPath = true;
try
{
useDefaultLoadPath = configuration.getAttribute(IRubyLaunchConfigurationConstants.ATTR_DEFAULT_LOADPATH,
true);
setUseLoadPathDefaults(useDefaultLoadPath);
if (useDefaultLoadPath)
{
String projectName = configuration
.getAttribute(IRubyLaunchConfigurationConstants.ATTR_PROJECT_NAME, "");
if (projectName.length() != 0)
{
IRubyProject project = RubyModelManager.getRubyModelManager().getRubyModel().getRubyProject(
projectName);
if (project != null)
{
ILoadpathEntry[] entries = project.getRawLoadpath();
entries = filterStandard(entries);
loadPathListViewer.setInput(entries);
}
}
}
else
{
// use custom loadpath
List<String> entries = configuration.getAttribute(IRubyLaunchConfigurationConstants.ATTR_LOADPATH,
Collections.EMPTY_LIST);
ILoadpathEntry[] rtes = new ILoadpathEntry[entries.size()];
int i = 0;
for (String entry : entries)
{
rtes[i] = RubyRuntime.newRuntimeLoadpathEntry(entry).getLoadpathEntry();
i++;
}
loadPathListViewer.setInput(rtes);
}
}
catch (CoreException e)
{
log(e);
}
}
private ILoadpathEntry[] filterStandard(ILoadpathEntry[] entries)
{
List<ILoadpathEntry> copy = new ArrayList<ILoadpathEntry>();
for (ILoadpathEntry loadpathEntry : entries)
{
if ((loadpathEntry.getEntryKind() == ILoadpathEntry.CPE_VARIABLE)
|| (loadpathEntry.getEntryKind() == ILoadpathEntry.CPE_CONTAINER))
continue;
copy.add(loadpathEntry);
}
return copy.toArray(new ILoadpathEntry[copy.size()]);
}
protected void setUseLoadPathDefaults(boolean useDefaults)
{
loadPathListViewer.getList().setEnabled(!useDefaults);
fAddButton.setEnabled(!useDefaults);
fRemoveButton.setEnabled(!useDefaults);
fUpButton.setEnabled(!useDefaults);
fDownButton.setEnabled(!useDefaults);
loadPathDefaultButton.setSelection(useDefaults);
setDirty(true);
updateLaunchConfigurationDialog();
}
protected void initializeInterpreterSelection(ILaunchConfiguration configuration)
{
String interpreterName = null;
try
{
interpreterName = configuration.getAttribute(IRubyLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME,
(String) null);
}
catch (CoreException e)
{
log(e);
}
if (interpreterName != null && !interpreterName.equals(""))
interpreterCombo.select(interpreterCombo.indexOf(interpreterName));
}
protected void initializeInterpreterCombo(Combo interpreterCombo)
{
installedInterpretersWorkingCopy = new ArrayList<IVMInstall>();
List<IVMInstall> standins = new ArrayList<IVMInstall>();
IVMInstallType[] types = RubyRuntime.getVMInstallTypes();
for (int i = 0; i < types.length; i++)
{
IVMInstallType type = types[i];
IVMInstall[] installs = type.getVMInstalls();
for (int j = 0; j < installs.length; j++)
{
IVMInstall install = installs[j];
standins.add(new VMStandin(install));
}
}
installedInterpretersWorkingCopy.addAll(standins);
String[] interpreterNames = new String[installedInterpretersWorkingCopy.size()];
for (int interpreterIndex = 0; interpreterIndex < installedInterpretersWorkingCopy.size(); interpreterIndex++)
{
IVMInstall interpreter = (IVMInstall) installedInterpretersWorkingCopy.get(interpreterIndex);
interpreterNames[interpreterIndex] = interpreter.getName();
}
interpreterCombo.setItems(interpreterNames);
IVMInstall selectedInterpreter = RubyRuntime.getDefaultVMInstall();
if (selectedInterpreter != null)
interpreterCombo.select(interpreterCombo.indexOf(selectedInterpreter.getName()));
}
public void performApply(ILaunchConfigurationWorkingCopy configuration)
{
int selectionIndex = interpreterCombo.getSelectionIndex();
if (selectionIndex >= 0)
{
IVMInstall vm = installedInterpretersWorkingCopy.get(selectionIndex);
configuration.setAttribute(IRubyLaunchConfigurationConstants.ATTR_VM_INSTALL_NAME, vm.getName());
configuration.setAttribute(IRubyLaunchConfigurationConstants.ATTR_VM_INSTALL_TYPE, vm.getVMInstallType()
.getId());
}
setAttribute(IRubyLaunchConfigurationConstants.ATTR_DEFAULT_LOADPATH, configuration, loadPathDefaultButton
.getSelection(), true);
if (!loadPathDefaultButton.getSelection())
{
ILoadpathEntry[] loadPathEntries = (ILoadpathEntry[]) loadPathListViewer.getInput();
List<String> loadPathStrings = new ArrayList<String>();
for (int i = 0; i < loadPathEntries.length; i++)
{
try
{
ILoadpathEntry entry = loadPathEntries[i];
if (entry.getEntryKind() == ILoadpathEntry.CPE_SOURCE)
{
if (entry.getPath().equals(
new Path("/"
+ configuration.getAttribute(
IRubyLaunchConfigurationConstants.ATTR_PROJECT_NAME, ""))))
{
continue;
}
}
IRuntimeLoadpathEntry runtime = new RuntimeLoadpathEntry(entry);
loadPathStrings.add(runtime.getMemento());
}
catch (CoreException e)
{
log(e);
}
}
configuration.setAttribute(IRubyLaunchConfigurationConstants.ATTR_LOADPATH, loadPathStrings);
}
}
protected Composite createPageRoot(Composite parent)
{
Composite composite = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
composite.setLayout(layout);
createVerticalSpacer(composite, 2);
setControl(composite);
return composite;
}
public String getName()
{
return RdtDebugUiMessages.LaunchConfigurationTab_RubyEnvironment_name;
}
public boolean isValid(ILaunchConfiguration launchConfig)
{
try
{
String selectedInterpreter = launchConfig.getAttribute(
RubyLaunchConfigurationAttribute.SELECTED_INTERPRETER, "");
if (selectedInterpreter.length() == 0)
{
setErrorMessage(RdtDebugUiMessages.LaunchConfigurationTab_RubyEnvironment_interpreter_not_selected_error_message);
return false;
}
}
catch (CoreException e)
{
log(e);
}
setErrorMessage(null);
return true;
}
protected void log(Throwable t)
{
RdtDebugUiPlugin.log(t);
}
public Image getImage()
{
return RubyPluginImages.get(RubyPluginImages.IMG_CTOOLS_RUBY);
}
public void widgetDefaultSelected(SelectionEvent e)
{
}
public void widgetSelected(SelectionEvent e)
{
if (e.getSource().equals(fAddButton))
{
// Pop open a directory dialog, add it to the loadpath
DirectoryDialog dialog = new DirectoryDialog(getShell());
String result = dialog.open();
if (result != null)
{
// Add to custom loadpath!
ILoadpathEntry[] loadPathEntries = (ILoadpathEntry[]) loadPathListViewer.getInput();
ILoadpathEntry[] copy = new ILoadpathEntry[loadPathEntries.length + 1];
System.arraycopy(loadPathEntries, 0, copy, 0, loadPathEntries.length);
copy[loadPathEntries.length] = RubyCore.newLibraryEntry(new Path(result));
loadPathListViewer.setInput(copy);
}
}
else if (e.getSource().equals(fRemoveButton))
{
ISelection selection = loadPathListViewer.getSelection();
if (selection instanceof IStructuredSelection)
{
IStructuredSelection structured = (IStructuredSelection) selection;
ILoadpathEntry firstElement = (ILoadpathEntry) structured.getFirstElement();
ILoadpathEntry[] loadPathEntries = (ILoadpathEntry[]) loadPathListViewer.getInput();
ILoadpathEntry[] copy = new ILoadpathEntry[loadPathEntries.length - 1];
int i = 0;
for (ILoadpathEntry entry : loadPathEntries)
{
if (entry.equals(firstElement))
continue;
copy[i++] = entry;
}
loadPathListViewer.setInput(copy);
}
}
// TODO Re-order selected loadpath when up/down clicked
}
}