blob: e1cb4f6a05d78727b312cdcdd2012066ec2f57aa [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 University of Illinois All rights reserved. This program
* and the accompanying materials are made available under the terms of the
* Eclipse Public License v1.0 which accompanies this distribution, and is
* available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Albert L. Rossi - design and implementation
******************************************************************************/
package org.eclipse.ptp.rm.jaxb.ui.launch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.ui.ILaunchConfigurationDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.ptp.core.elements.IPQueue;
import org.eclipse.ptp.launch.ui.extensions.RMLaunchValidation;
import org.eclipse.ptp.rm.jaxb.core.IJAXBResourceManager;
import org.eclipse.ptp.rm.jaxb.core.data.TabControllerType;
import org.eclipse.ptp.rm.jaxb.core.runnable.ScriptHandler;
import org.eclipse.ptp.rm.jaxb.core.utils.CoreExceptionUtils;
import org.eclipse.ptp.rm.jaxb.core.variables.LCVariableMap;
import org.eclipse.ptp.rm.jaxb.ui.ICellEditorUpdateModel;
import org.eclipse.ptp.rm.jaxb.ui.IUpdateModel;
import org.eclipse.ptp.rm.jaxb.ui.JAXBUIPlugin;
import org.eclipse.ptp.rm.jaxb.ui.dialogs.ScrollingEditableMessageDialog;
import org.eclipse.ptp.rm.jaxb.ui.handlers.ValueUpdateHandler;
import org.eclipse.ptp.rm.jaxb.ui.messages.Messages;
import org.eclipse.ptp.rm.jaxb.ui.model.ViewerUpdateModel;
import org.eclipse.ptp.rm.jaxb.ui.util.LaunchTabBuilder;
import org.eclipse.ptp.rm.jaxb.ui.util.WidgetActionUtils;
import org.eclipse.ptp.rm.jaxb.ui.util.WidgetBuilderUtils;
import org.eclipse.ptp.rmsystem.IResourceManager;
import org.eclipse.swt.SWT;
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.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Shell;
/**
* Launch Tab which builds its control from the JAXB data elements. The number,
* type and disposition of widgets connected to Properties or Attributes is
* almost entirely configurable via the XML.<br>
* <br>
* Aside from being registered with the update handler, the widgets specific to
* this tab are also maintained in a local map so that their values (and only
* theirs) will appear in the environment when performApply() is called. A list
* of viewers is also kept so that refresh can be called on them when the tab is
* (re-)initialized or the defaults are reset. <br>
* <br>
* If different widgets on different tabs reference the same Property or
* Attribute, its value will change everywhere. However, if the
* <code>shared</code> property is set to true, then the local map is populated
* by values produced from all tabs and defaults are likewise reset on all
* widgets in the update handler. This shared option is motivated by a scenario
* in which the attributes are partitioned (empty intersection) between the
* various tabs, but all of them are necessary to the definition of the job
* submission. The default (not shared) implies that the tabs have intersecting
* subsets of the whole attribute set, any one of which is sufficient to
* configure a launch.
*
* @author arossi
*
*/
public class JAXBDynamicLaunchConfigurationTab extends AbstractJAXBLaunchConfigurationTab implements SelectionListener {
private final TabControllerType controller;
private final ValueUpdateHandler updateHandler;
private final List<Viewer> viewers;
private final Map<Object, IUpdateModel> localWidgets;
private final boolean shared;
private ILaunchConfiguration listenerConfiguration;
/**
* @param rm
* the resource manager
* @param dialog
* the ancestor main launch dialog
* @param controller
* the JAXB data element from which this tab's control will be
* built
* @param parentTab
* the parent controller tab
*/
public JAXBDynamicLaunchConfigurationTab(IJAXBResourceManager rm, ILaunchConfigurationDialog dialog,
TabControllerType controller, JAXBControllerLaunchConfigurationTab parentTab) {
super(parentTab, dialog);
this.controller = controller;
shared = controller.isSharedEnvironment();
String title = controller.getTitle();
if (title != null) {
this.title = title;
}
updateHandler = parentTab.getUpdateHandler();
localWidgets = new HashMap<Object, IUpdateModel>();
viewers = new ArrayList<Viewer>();
}
/*
* Value validation is handled up front, so this just return true.
* (non-Javadoc)
*
* @see
* org.eclipse.ptp.launch.ui.extensions.IRMLaunchConfigurationDynamicTab
* #canSave(org.eclipse.swt.widgets.Control,
* org.eclipse.ptp.rmsystem.IResourceManager,
* org.eclipse.ptp.core.elements.IPQueue)
*/
public RMLaunchValidation canSave(Control control, IResourceManager rm, IPQueue queue) {
return new RMLaunchValidation(true, null);
}
/*
* Maintains the top-level control element on which to rehang the rest of
* the controls when rebuilt. (non-Javadoc)
*
* @see
* org.eclipse.ptp.launch.ui.extensions.IRMLaunchConfigurationDynamicTab
* #createControl(org.eclipse.swt.widgets.Composite,
* org.eclipse.ptp.rmsystem.IResourceManager,
* org.eclipse.ptp.core.elements.IPQueue)
*/
public void createControl(Composite parent, IResourceManager rm, IPQueue queue) throws CoreException {
control = WidgetBuilderUtils.createComposite(parent, 1);
LaunchTabBuilder builder = new LaunchTabBuilder(this);
try {
builder.build(control);
} catch (Throwable t) {
CoreExceptionUtils.newException(Messages.CreateControlConfigurableError, t);
}
createViewScriptGroup(control);
parentTab.resize(this.control);
}
/**
* The top-level control.
*/
public Control getControl() {
return control;
}
/**
* Used by the LaunchTabBuilder.
*
* @return the JAXB data element used to build the control
*/
public TabControllerType getController() {
return controller;
}
@Override
public Image getImage() {
return null;
}
/**
* Used by the LaunchTabBuilder.
*
* @return the map of widgets specific to this tab.
*/
public Map<Object, IUpdateModel> getLocalWidgets() {
return localWidgets;
}
/**
* Used by the LaunchTabBuilder
*
* @return the main controller tab
*/
public JAXBControllerLaunchConfigurationTab getParent() {
return parentTab;
}
/**
* @return title of tab.
*/
@Override
public String getText() {
return title;
}
/*
* 1. resets the configuation. 2. clears viewers and repopulate that list.
* 3. repopulates the handler with local widgets. 4. initializes the (new)
* widgets from the original global map. 5. initializes the checked state on
* any checkbox viewers and then refreshes them. (non-Javadoc)
*
* @see
* org.eclipse.ptp.launch.ui.extensions.IRMLaunchConfigurationDynamicTab
* #initializeFrom(org.eclipse.swt.widgets.Control,
* org.eclipse.ptp.rmsystem.IResourceManager,
* org.eclipse.ptp.core.elements.IPQueue,
* org.eclipse.debug.core.ILaunchConfiguration)
*/
public RMLaunchValidation initializeFrom(Control control, IResourceManager rm, IPQueue queue, ILaunchConfiguration configuration) {
try {
ValueUpdateHandler handler = getParent().getUpdateHandler();
listenerConfiguration = configuration;
viewers.clear();
for (Map.Entry<Object, IUpdateModel> e : localWidgets.entrySet()) {
Object key = e.getKey();
if (key instanceof Viewer) {
Viewer viewer = (Viewer) key;
viewers.add(viewer);
}
handler.addUpdateModelEntry(key, e.getValue());
}
LCVariableMap lcMap = parentTab.getLCMap();
lcMap.updateGlobal(configuration);
for (IUpdateModel m : localWidgets.values()) {
m.initialize(lcMap);
}
for (IUpdateModel m : localWidgets.values()) {
if (m instanceof ViewerUpdateModel) {
((ViewerUpdateModel) m).initializeChecked();
}
}
for (Viewer v : viewers) {
v.refresh();
}
} catch (Throwable t) {
JAXBUIPlugin.log(t);
return new RMLaunchValidation(false, t.getMessage());
}
return new RMLaunchValidation(true, null);
}
/*
* Value validation is now handled up front, so this just returns true.
* (non-Javadoc)
*
* @see
* org.eclipse.ptp.launch.ui.extensions.IRMLaunchConfigurationDynamicTab
* #isValid(org.eclipse.debug.core.ILaunchConfiguration,
* org.eclipse.ptp.rmsystem.IResourceManager,
* org.eclipse.ptp.core.elements.IPQueue)
*/
public RMLaunchValidation isValid(ILaunchConfiguration launchConfig, IResourceManager rm, IPQueue queue) {
return new RMLaunchValidation(true, null);
}
/*
* Defaults are taken care of by the load method on the LCVariableMap
* (non-Javadoc)
*
* @see
* org.eclipse.ptp.launch.ui.extensions.IRMLaunchConfigurationDynamicTab
* #setDefaults(org.eclipse.debug.core.ILaunchConfigurationWorkingCopy,
* org.eclipse.ptp.rmsystem.IResourceManager,
* org.eclipse.ptp.core.elements.IPQueue)
*/
public RMLaunchValidation setDefaults(ILaunchConfigurationWorkingCopy configuration, IResourceManager rm, IPQueue queue) {
return new RMLaunchValidation(true, null);
}
/*
* Tab acts a listener for viewScript button. (non-Javadoc)
*
* @see
* org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse
* .swt.events.SelectionEvent)
*/
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
/*
* Tab acts a listener for viewScript button. If the resource manager does
* not use a script, this call returns immediately; else it calls
* #realizeLocalScript(ILaunchConfiguration), then displays the result in a
* read-only dialog. (non-Javadoc)
*
* @see
* org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt
* .events.SelectionEvent)
*/
public void widgetSelected(SelectionEvent e) {
Shell shell = Display.getDefault().getActiveShell();
try {
if (!parentTab.hasScript()) {
MessageDialog.openWarning(shell, Messages.ScriptNotSupportedWarning_title, Messages.ScriptNotSupportedWarning
+ LINE_SEP);
return;
}
String text = realizeLocalScript(listenerConfiguration);
new ScrollingEditableMessageDialog(shell, Messages.DisplayScript, text, true).open();
} catch (Throwable t) {
WidgetActionUtils.errorMessage(shell, t, Messages.DisplayScriptError, Messages.DisplayScriptErrorTitle, false);
}
}
/*
* Writes values of local widgets or cell editors (if the viewer row is
* selected) to the local map. (non-Javadoc)
*
* @see
* org.eclipse.ptp.rm.jaxb.ui.launch.AbstractJAXBLaunchConfigurationTab#
* doRefreshLocal()
*/
@Override
protected void doRefreshLocal() {
for (IUpdateModel m : getModels()) {
if (m instanceof ICellEditorUpdateModel) {
if (((ICellEditorUpdateModel) m).isChecked()) {
localMap.put(m.getName(), m.getValueFromControl());
}
} else {
localMap.put(m.getName(), m.getValueFromControl());
if (m instanceof ViewerUpdateModel) {
((ViewerUpdateModel) m).putCheckedSettings(localMap);
}
}
}
}
/*
* Adds the View Script and Restore Defaults buttons to the bottom of the
* control pane.
*/
private void createViewScriptGroup(final Composite control) {
GridLayout layout = WidgetBuilderUtils.createGridLayout(2, true);
GridData gd = WidgetBuilderUtils.createGridData(SWT.NONE, 2);
Group grp = WidgetBuilderUtils.createGroup(control, SWT.NONE, layout, gd);
if (parentTab.hasScript()) {
WidgetBuilderUtils.createPushButton(grp, Messages.ViewScript, this);
}
WidgetBuilderUtils.createPushButton(grp, Messages.DefaultValues, new SelectionListener() {
public void widgetDefaultSelected(SelectionEvent e) {
widgetSelected(e);
}
public void widgetSelected(SelectionEvent e) {
resetDefaults();
}
});
}
/*
* Determines whether the set of widgets is local or global.
*
* @return the set of widgets to be accessed for values.
*/
private Collection<IUpdateModel> getModels() {
Collection<IUpdateModel> models = null;
if (shared) {
models = updateHandler.getControlToModelMap().values();
} else {
models = localWidgets.values();
}
return models;
}
/*
* After refreshing the local map, it swaps in the map to be the active
* environment, adds any environment variables from the Environment Tab,
* then schedules a script handler job. Swaps the previous map back into the
* active environement when the handler returns.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private synchronized String realizeLocalScript(ILaunchConfiguration config) throws Throwable {
String value = ZEROSTR;
refreshLocal(config);
LCVariableMap lcMap = parentTab.getLCMap();
Map<String, Object> current = lcMap.swapVariables(localMap);
Map env = config.getAttribute(ILaunchManager.ATTR_ENVIRONMENT_VARIABLES, (Map) null);
ScriptHandler job = new ScriptHandler(null, parentTab.getScript(), lcMap, env);
job.schedule();
try {
job.join();
} catch (InterruptedException ignored) {
}
value = job.getScriptValue();
lcMap.swapVariables(current);
return value;
}
/*
* First resets default values from the LCVariableMap on widgets and
* selected rows in the viewers, then has the viewers rewrite their
* templated strings. The update handler is called to refresh all the
* widgets from the map, and then the viewers are refreshed.
*/
private synchronized void resetDefaults() {
Collection<IUpdateModel> models = getModels();
for (IUpdateModel m : models) {
if (m instanceof ICellEditorUpdateModel) {
if (((ICellEditorUpdateModel) m).isChecked()) {
m.restoreDefault();
}
} else {
m.restoreDefault();
}
}
for (IUpdateModel m : models) {
if (m instanceof ViewerUpdateModel) {
((ViewerUpdateModel) m).storeValue();
}
}
updateHandler.handleUpdate(null, null);
for (Viewer v : viewers) {
v.refresh();
}
}
}