blob: 460a8599e9cada5b1639d567af17b6430e1915d2 [file] [log] [blame]
/*
* Copyright (c) 2014-2016 Eike Stepper (Berlin, Germany) and others.
* 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:
* Eike Stepper - initial API and implementation
* Ericsson AB (Julian Enoch) - Bug 434525 - Allow prompted variables to be pre-populated
*/
package org.eclipse.oomph.setup.ui.wizards;
import org.eclipse.oomph.base.Annotation;
import org.eclipse.oomph.base.util.BaseUtil;
import org.eclipse.oomph.internal.setup.SetupPrompter;
import org.eclipse.oomph.internal.ui.AccessUtil;
import org.eclipse.oomph.preferences.util.PreferencesUtil;
import org.eclipse.oomph.setup.AnnotationConstants;
import org.eclipse.oomph.setup.Installation;
import org.eclipse.oomph.setup.SetupTask;
import org.eclipse.oomph.setup.SetupTaskContext;
import org.eclipse.oomph.setup.Trigger;
import org.eclipse.oomph.setup.User;
import org.eclipse.oomph.setup.VariableChoice;
import org.eclipse.oomph.setup.VariableTask;
import org.eclipse.oomph.setup.Workspace;
import org.eclipse.oomph.setup.internal.core.SetupContext;
import org.eclipse.oomph.setup.internal.core.SetupTaskPerformer;
import org.eclipse.oomph.setup.internal.core.util.Authenticator;
import org.eclipse.oomph.setup.internal.core.util.SetupCoreUtil;
import org.eclipse.oomph.setup.ui.PropertyField;
import org.eclipse.oomph.setup.ui.PropertyField.AuthenticatedField;
import org.eclipse.oomph.setup.ui.PropertyField.ValueListener;
import org.eclipse.oomph.setup.ui.SetupUIPlugin;
import org.eclipse.oomph.setup.ui.wizards.SetupWizard.IndexLoader;
import org.eclipse.oomph.setup.util.StringExpander;
import org.eclipse.oomph.ui.ButtonBar;
import org.eclipse.oomph.ui.ErrorDialog;
import org.eclipse.oomph.ui.UICallback;
import org.eclipse.oomph.ui.UIUtil;
import org.eclipse.oomph.util.CollectionUtil;
import org.eclipse.oomph.util.OS;
import org.eclipse.oomph.util.StringUtil;
import org.eclipse.oomph.util.UserCallback;
import org.eclipse.emf.common.util.BasicEList;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.ControlAdapter;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Eike Stepper
*/
public class VariablePage extends SetupWizardPage implements SetupPrompter
{
private static final String SETUP_TASK_ANALYSIS_TITLE = "Setup Task Analysis";
private static final URI INSTALLATION_ID_URI = URI.createURI("#~installation.id");
private static final URI WORKSPACE_ID_URI = URI.createURI("#~workspace.id");
private Composite composite;
private ScrolledComposite scrolledComposite;
private final FieldHolderManager manager = new FieldHolderManager();
private final Set<String> unusedVariables = new HashSet<String>();
private boolean prompted;
private boolean fullPrompt;
private boolean updating;
private Set<SetupTaskPerformer> incompletePerformers = new LinkedHashSet<SetupTaskPerformer>();
private Set<SetupTaskPerformer> allPromptedPerfomers = new LinkedHashSet<SetupTaskPerformer>();
private SetupTaskPerformer performer;
private Control focusControl;
private SetupContext originalContext;
private boolean save = true;
private boolean defaultsSet;
private UserCallback userCallback;
private final Validator validator = new Validator();
private FocusListener focusListener = new FocusAdapter()
{
@Override
public void focusGained(FocusEvent e)
{
focusControl = (Control)e.widget;
}
};
private PerformerCreationJob performerCreationJob;
private long delay;
public VariablePage()
{
super("VariablePage");
setTitle("Variables");
setDescription("Enter values for the required variables.");
}
@Override
protected Control createUI(Composite parent)
{
Composite mainComposite = new Composite(parent, SWT.NONE);
mainComposite.setLayout(UIUtil.createGridLayout(1));
mainComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout outerLayout = (GridLayout)parent.getParent().getLayout();
outerLayout.marginLeft = outerLayout.marginWidth;
outerLayout.marginWidth = 0;
scrolledComposite = new ScrolledComposite(mainComposite, SWT.VERTICAL);
scrolledComposite.setExpandHorizontal(true);
scrolledComposite.setExpandVertical(true);
scrolledComposite.setShowFocusedControl(true);
scrolledComposite.setLayoutData(new GridData(GridData.FILL_BOTH));
GridLayout layout = UIUtil.createGridLayout(3);
layout.horizontalSpacing = 10;
layout.verticalSpacing = 10;
layout.marginRight = outerLayout.marginLeft;
composite = new Composite(scrolledComposite, SWT.NONE);
composite.setLayout(layout);
scrolledComposite.setContent(composite);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
ControlAdapter resizeListener = new ControlAdapter()
{
@Override
public void controlResized(ControlEvent event)
{
Point size = composite.computeSize(scrolledComposite.getClientArea().width, SWT.DEFAULT);
scrolledComposite.setMinSize(size);
}
};
scrolledComposite.addControlListener(resizeListener);
composite.addControlListener(resizeListener);
composite.notifyListeners(SWT.Resize, new Event());
return mainComposite;
}
@Override
protected void createCheckButtons(ButtonBar buttonBar)
{
final Button fullPromptButton = buttonBar.addCheckButton("Show all variables", "", false, "fullPrompt");
fullPrompt = fullPromptButton.getSelection();
fullPromptButton.addSelectionListener(new SelectionAdapter()
{
@Override
public void widgetSelected(SelectionEvent e)
{
fullPrompt = fullPromptButton.getSelection();
validator.schedule(false);
}
});
AccessUtil.setKey(fullPromptButton, "showAll");
}
private synchronized boolean updateFields()
{
unusedVariables.clear();
for (FieldHolder fieldHolder : manager)
{
fieldHolder.clear();
}
Set<SetupTaskPerformer> performers = new LinkedHashSet<SetupTaskPerformer>();
if (incompletePerformers.isEmpty())
{
if (performer != null)
{
performers.add(performer);
}
performers.addAll(allPromptedPerfomers);
}
else
{
performers.addAll(incompletePerformers);
performers.addAll(allPromptedPerfomers);
}
Set<String> usedVariables = new HashSet<String>();
for (FieldHolder fieldHolder : manager)
{
String value = fieldHolder.getValue();
if (!StringUtil.isEmpty(value))
{
usedVariables.addAll(SetupTaskPerformer.getVariables(value));
}
}
for (SetupTaskPerformer setupTaskPerformer : performers)
{
List<VariableTask> variables = setupTaskPerformer.getUnresolvedVariables();
for (VariableTask variable : variables)
{
VariableTask ruleVariable = setupTaskPerformer.getRuleVariable(variable);
if (ruleVariable == null)
{
if (variable.getAnnotation(AnnotationConstants.ANNOTATION_UNDECLARED_VARIABLE) != null)
{
String name = variable.getName();
if (!usedVariables.contains(name))
{
Trigger trigger = getTrigger();
boolean isUsedInActualTriggeredTask = false;
for (SetupTask setupTask : setupTaskPerformer.getTriggeredSetupTasks())
{
if (setupTask.getTriggers().contains(trigger) && setupTaskPerformer.isVariableUsed(name, setupTask, true))
{
isUsedInActualTriggeredTask = true;
break;
}
}
if (!isUsedInActualTriggeredTask)
{
unusedVariables.add(name);
continue;
}
}
}
manager.getFieldHolder(variable, true, false);
}
else
{
FieldHolder fieldHolder = manager.getFieldHolder(ruleVariable, true, false);
fieldHolder.add(variable);
manager.associate(variable, fieldHolder);
}
}
}
boolean setDefault = false;
for (FieldHolder fieldHolder : manager)
{
if (StringUtil.isEmpty(fieldHolder.getValue()))
{
String initialValue = null;
String initialDefaultValue = null;
for (VariableTask variable : fieldHolder.getVariables())
{
if (initialValue == null)
{
String value = variable.getValue();
if (!StringUtil.isEmpty(value))
{
initialValue = value;
// Check the choices for ones that specify "match choice" annotations.
for (VariableChoice choice : variable.getChoices())
{
Annotation annotation = choice.getAnnotation(AnnotationConstants.ANNOTATION_MATCH_CHOICE);
if (annotation != null)
{
String choiceValue = choice.getValue();
if (choiceValue != null)
{
// Expand the choice into a pattern where the variables expand to ".*" and the rest of the value is quoted as literal.
StringBuffer result = new StringBuffer("\\Q");
Matcher matcher = StringExpander.STRING_EXPANSION_PATTERN.matcher(choiceValue);
while (matcher.find())
{
matcher.appendReplacement(result, "\\\\E.*\\\\Q");
}
matcher.appendTail(result);
try
{
// If the pattern matches, use the value of the choice as the initial value.
Pattern pattern = Pattern.compile(result.toString());
if (pattern.matcher(value).matches())
{
initialValue = choiceValue;
setDefault = true;
break;
}
}
catch (Throwable throwable)
{
// Ignore.
}
}
}
}
}
}
if (initialDefaultValue == null)
{
String defaultValue = variable.getDefaultValue();
if (!StringUtil.isEmpty(defaultValue))
{
initialDefaultValue = defaultValue;
}
}
}
if (!StringUtil.isEmpty(initialValue))
{
fieldHolder.setValue(initialValue);
}
else if (!StringUtil.isEmpty(initialDefaultValue))
{
setDefault = true;
fieldHolder.setValue(initialDefaultValue);
}
else
{
String defaultValue = fieldHolder.getDefaultValue();
if (!StringUtil.isEmpty(defaultValue))
{
setDefault = true;
fieldHolder.setValue(defaultValue);
}
}
}
}
try
{
for (FieldHolder fieldHolder : manager)
{
updating = true;
fieldHolder.update();
}
}
finally
{
updating = false;
}
for (FieldHolder fieldHolder : manager)
{
fieldHolder.recordInitialValue();
}
// Determine the URIs of all the variables actually being used.
Set<URI> uris = new HashSet<URI>();
if (performer != null)
{
for (VariableTask variable : performer.getUnresolvedVariables())
{
uris.add(manager.getURI(variable));
VariableTask ruleVariable = performer.getRuleVariable(variable);
if (ruleVariable != null)
{
uris.add(manager.getURI(ruleVariable));
}
}
}
manager.cleanup(uris);
ScrolledComposite parent = (ScrolledComposite)composite.getParent();
Point origin = parent.getOrigin();
parent.setRedraw(false);
List<SetupTaskPerformer> allPerformers = new ArrayList<SetupTaskPerformer>(allPromptedPerfomers);
if (performer != null)
{
allPerformers.add(0, performer);
}
// Determine an appropriate field order.
manager.reorder(allPerformers);
parent.pack();
parent.getParent().layout();
parent.setOrigin(origin);
parent.setRedraw(true);
FieldHolder firstField = null;
FieldHolder firstEmptyField = null;
for (FieldHolder fieldHolder : manager)
{
if (!fieldHolder.isDisposed())
{
if (firstField == null)
{
firstField = fieldHolder;
}
if (firstEmptyField == null && StringUtil.isEmpty(fieldHolder.getValue()))
{
firstEmptyField = fieldHolder;
}
}
}
if (focusControl != null && !focusControl.isDisposed())
{
focusControl.setFocus();
parent.showControl(focusControl);
}
else
{
FieldHolder field = firstEmptyField;
if (field == null)
{
field = firstField;
}
if (field != null)
{
field.setFocus();
parent.showControl(field.getControl());
}
}
for (FieldHolder fieldHolder : manager)
{
if (!fieldHolder.isDisposed())
{
Control control = fieldHolder.getControl();
PropertyField field = fieldHolder.field;
Label label = field.getLabel();
Control helper = field.getHelper();
for (VariableTask variable : fieldHolder.getVariables())
{
String name = variable.getName();
if (name.startsWith("@<id>"))
{
name = name.substring(name.indexOf("name: ") + 6, name.indexOf(')'));
}
AccessUtil.setKey(label, name + ".label");
AccessUtil.setKey(control, name + ".control");
AccessUtil.setKey(helper, name + ".helper");
break;
}
}
}
if (setDefault)
{
defaultsSet = true;
}
if (isPageComplete() ? setDefault : firstEmptyField == null || setDefault)
{
// If the page isn't complete but there are no empty fields, then the last change introduced a new field.
// So we should validate again to be sure there really needs to be more information prompted from the user.
return true;
}
return false;
}
private void validate()
{
try
{
performer = null;
incompletePerformers.clear();
allPromptedPerfomers.clear();
setButtonState(IDialogConstants.NEXT_ID, false);
performerCreationJob = new PerformerCreationJob(SETUP_TASK_ANALYSIS_TITLE)
{
@Override
protected SetupTaskPerformer createPerformer() throws Exception
{
return VariablePage.this.createPerformer(VariablePage.this, fullPrompt);
}
@Override
protected Dialog createDialog()
{
return createDialog(getShell(), SETUP_TASK_ANALYSIS_TITLE, null,
"Analyzing the needed setup tasks has taken more than " + (System.currentTimeMillis() - getStart()) / 1000
+ " seconds. The Next button will be disabled, though animated, until it completes. You may continue to modify the values of the variables.",
MessageDialog.INFORMATION, new String[] { IDialogConstants.OK_LABEL }, 0);
}
@Override
protected void handleDialogResult(int result)
{
if (result == 0)
{
setDelay(Integer.MAX_VALUE);
}
else
{
setDelay(2 * getDelay());
}
}
};
if (delay != 0)
{
performerCreationJob.setDelay(delay);
}
performerCreationJob.create();
delay = performerCreationJob.getDelay();
Throwable throwable = performerCreationJob.getThrowable();
if (throwable != null)
{
if (throwable instanceof OperationCanceledException)
{
performerCreationJob = null;
return;
}
throw throwable;
}
performer = performerCreationJob.getPerformer();
UIUtil.asyncExec(getControl(), new Runnable()
{
public void run()
{
performerCreationJob = null;
if (updateFields())
{
validate();
}
}
});
if (performer == null)
{
setPageComplete(false);
}
else
{
setPageComplete(true);
if (!prompted)
{
prompted = true;
gotoNextPage();
}
}
}
catch (Throwable t)
{
performerCreationJob = null;
SetupUIPlugin.INSTANCE.log(t);
ErrorDialog.open(t);
}
}
private void clearSpecialFieldHolders()
{
clearSpecialFieldHolders(INSTALLATION_ID_URI);
clearSpecialFieldHolders(WORKSPACE_ID_URI);
}
private void clearSpecialFieldHolders(URI uri)
{
FieldHolderRecord fieldHolderRecord = manager.getFieldHolderRecord(uri);
if (fieldHolderRecord != null)
{
FieldHolder fieldHolder = fieldHolderRecord.getFieldHolder();
if (fieldHolder != null && !fieldHolder.isDirty())
{
fieldHolder.clearValue();
}
}
}
@Override
public void enterPage(boolean forward)
{
if (forward)
{
if (userCallback == null)
{
Shell shell = getShell();
userCallback = new UICallback(shell, shell.getText());
}
clearSpecialFieldHolders();
}
performer = getWizard().getPerformer();
if (performer != null && forward)
{
performer.setPrompter(this);
setPageComplete(true);
gotoNextPage();
}
else
{
if (!forward)
{
getWizard().setSetupContext(originalContext);
originalContext = null;
}
IndexLoader indexLoader = getWizard().getIndexLoader();
if (indexLoader != null)
{
indexLoader.awaitIndexLoad();
}
setPageComplete(false);
validate();
if (forward && getPreviousPage() == null)
{
UIUtil.asyncExec(getControl(), new Runnable()
{
public void run()
{
if (isPageComplete() && !defaultsSet)
{
gotoNextPage();
}
}
});
}
}
}
@Override
public void leavePage(boolean forward)
{
if (forward)
{
originalContext = getWizard().getSetupContext();
final List<VariableTask> unresolvedVariables = performer.getUnresolvedVariables();
for (FieldHolder fieldHolder : manager)
{
unresolvedVariables.addAll(fieldHolder.getVariables());
}
final ResourceSet resourceSet = SetupCoreUtil.createResourceSet();
User user = getUser();
final User copiedUser = EcoreUtil.copy(user);
URI userResourceURI = user.eResource().getURI();
Resource userResource = resourceSet.createResource(userResourceURI);
userResource.getContents().add(copiedUser);
Installation installation = performer.getInstallation();
Resource installationResource = installation.eResource();
URI installationResourceURI = installationResource.getURI();
installationResource
.setURI(URI.createFileURI(new File(performer.getProductConfigurationLocation(), "org.eclipse.oomph.setup/installation.setup").toString()));
Workspace workspace = performer.getWorkspace();
Resource workspaceResource = null;
URI workspaceResourceURI = null;
if (workspace != null)
{
workspaceResource = workspace.eResource();
workspaceResourceURI = workspaceResource.getURI();
workspaceResource
.setURI(URI.createFileURI(new File(performer.getWorkspaceLocation(), ".metadata/.plugins/org.eclipse.oomph.setup/workspace.setup").toString()));
}
Installation copiedInstallation = EcoreUtil.copy(installation);
URI copiedInstallationResourceURI = installation.eResource().getURI();
Resource copiedInstallationResource = resourceSet.createResource(copiedInstallationResourceURI);
copiedInstallationResource.getContents().add(copiedInstallation);
Workspace copiedWorkspace = EcoreUtil.copy(workspace);
if (workspace != null)
{
URI copiedWorkspaceResourceURI = workspace.eResource().getURI();
Resource copiedWorkspaceResource = resourceSet.createResource(copiedWorkspaceResourceURI);
copiedWorkspaceResource.getContents().add(copiedWorkspace);
}
performer.recordVariables(copiedInstallation, copiedWorkspace, copiedUser);
unresolvedVariables.clear();
getWizard().setSetupContext(SetupContext.create(copiedInstallation, copiedWorkspace, copiedUser));
setPerformer(performer);
if (save)
{
BaseUtil.saveEObject(copiedUser);
performer.savePasswords();
}
installationResource.setURI(installationResourceURI);
if (workspaceResource != null)
{
workspaceResource.setURI(workspaceResourceURI);
}
}
else
{
originalContext = null;
setPerformer(null);
validator.cancel();
}
}
public synchronized String getValue(VariableTask variable)
{
FieldHolder fieldHolder = manager.getFieldHolder(variable, false, true);
if (fieldHolder != null && (updating || fieldHolder.isDirty()))
{
String value = fieldHolder.getValue();
if (!"".equals(value))
{
return value;
}
}
if (updating && performer != null)
{
Object value = performer.getMap().get(variable.getName());
if (value != null)
{
return value.toString();
}
}
return null;
}
public OS getOS()
{
return getWizard().getOS();
}
public String getVMPath()
{
return getWizard().getVMPath();
}
public synchronized boolean promptVariables(List<? extends SetupTaskContext> contexts)
{
prompted = true;
@SuppressWarnings("unchecked")
List<SetupTaskPerformer> performers = (List<SetupTaskPerformer>)contexts;
allPromptedPerfomers.addAll(performers);
for (SetupTaskPerformer performer : performers)
{
boolean resolvedAll = true;
List<VariableTask> unresolvedVariables = performer.getUnresolvedVariables();
for (VariableTask variable : unresolvedVariables)
{
FieldHolder fieldHolder = manager.getFieldHolder(variable, false, true);
if (fieldHolder != null)
{
String value = fieldHolder.getValue();
if (!"".equals(value))
{
variable.setValue(value);
}
else
{
resolvedAll = false;
}
}
else if (unusedVariables.contains(variable.getName()))
{
variable.setValue(" ");
}
else
{
resolvedAll = false;
}
}
if (!resolvedAll)
{
incompletePerformers.add(performer);
}
}
boolean isComplete = incompletePerformers.isEmpty();
return isComplete;
}
public UserCallback getUserCallback()
{
return userCallback;
}
/**
* @author Ed Merks
*/
private final class FieldHolder implements ValueListener
{
private final Set<VariableTask> variables = new LinkedHashSet<VariableTask>();
private PropertyField field;
private String initialValue;
public FieldHolder(VariableTask variable)
{
field = PropertyField.createField(variable);
field.fill(composite);
field.addValueListener(this);
field.getControl().addFocusListener(focusListener);
variables.add(variable);
}
public boolean isDisposed()
{
return field == null;
}
private Control getControl()
{
if (field == null)
{
return null;
}
Control control = field.getControl();
Control parent = control.getParent();
if (parent == composite)
{
return control;
}
return null;
}
public void setFocus()
{
if (field == null)
{
throw new IllegalStateException("Can't set the value of a disposed field");
}
field.setFocus();
}
public String getValue()
{
return field == null ? initialValue : field.getValue();
}
public String getDefaultValue()
{
return field == null ? null : field.getDefaultValue();
}
public void clearValue()
{
initialValue = "";
if (field != null)
{
field.setValue("", false, false);
}
}
public void setValue(String value)
{
if (field == null)
{
throw new IllegalStateException("Can't set the value of a disposed field");
}
initialValue = null;
field.setValue(value, false);
}
public Set<VariableTask> getVariables()
{
return Collections.unmodifiableSet(variables);
}
public void clear()
{
variables.clear();
if (field instanceof AuthenticatedField)
{
AuthenticatedField authenticatedField = (AuthenticatedField)field;
authenticatedField.clear();
}
}
public void add(VariableTask variable)
{
if (variables.add(variable))
{
String value = field.getValue();
if (!"".equals(value))
{
variable.setValue(value);
}
}
}
public void update()
{
if (field instanceof AuthenticatedField)
{
AuthenticatedField authenticatedField = (AuthenticatedField)field;
String value = field.getValue();
Set<Authenticator> allAuthenticators = new LinkedHashSet<Authenticator>();
for (VariableTask variable : variables)
{
if (!StringUtil.isEmpty(value))
{
variable.setValue(value);
}
Set<? extends Authenticator> authenticators = SetupTaskPerformer.getAuthenticators(variable);
if (authenticators != null)
{
allAuthenticators.addAll(authenticators);
}
}
if (!allAuthenticators.isEmpty())
{
for (Iterator<Authenticator> it = allAuthenticators.iterator(); it.hasNext();)
{
Authenticator authenticator = it.next();
if (authenticator.isFiltered())
{
it.remove();
}
}
authenticatedField.addAll(allAuthenticators);
if (allAuthenticators.isEmpty())
{
dispose(PreferencesUtil.encrypt(" "));
}
}
}
}
public void valueChanged(String oldValue, String newValue) throws Exception
{
synchronized (VariablePage.this)
{
for (VariableTask variable : variables)
{
variable.setValue(newValue);
}
}
validator.schedule(true);
}
public void recordInitialValue()
{
if (initialValue == null && field != null)
{
initialValue = field.getValue();
}
}
public boolean isDirty()
{
return field != null && initialValue != null && !initialValue.equals(field.getValue());
}
public void dispose(String value)
{
if (field != null)
{
field.dispose();
field = null;
}
if (StringUtil.isEmpty(initialValue))
{
initialValue = value;
}
}
public void dispose()
{
if (field != null)
{
field.dispose();
field = null;
}
}
@Override
public String toString()
{
return field == null ? "<disposed>" : field.toString();
}
}
/**
* @author Ed Merks
*/
private static class FieldHolderRecord
{
private FieldHolder fieldHolder;
private final Set<URI> variableURIs = new HashSet<URI>();
public FieldHolderRecord()
{
}
public FieldHolder getFieldHolder()
{
return fieldHolder;
}
public void setFieldHolder(FieldHolder fieldHolder)
{
this.fieldHolder = fieldHolder;
}
public Set<URI> getVariableURIs()
{
return variableURIs;
}
@Override
public String toString()
{
return variableURIs.toString();
}
}
/**
* @author Ed Merks
*/
private class FieldHolderManager implements Iterable<FieldHolder>
{
private final EList<FieldHolderRecord> fields = new BasicEList<FieldHolderRecord>();
public Iterator<FieldHolder> iterator()
{
final Iterator<FieldHolderRecord> iterator = fields.iterator();
return new Iterator<FieldHolder>()
{
public boolean hasNext()
{
return iterator.hasNext();
}
public FieldHolder next()
{
return iterator.next().getFieldHolder();
}
public void remove()
{
throw new UnsupportedOperationException();
}
};
}
public void reorder(List<SetupTaskPerformer> allPerformers)
{
List<Control> controls = new ArrayList<Control>();
Map<FieldHolderRecord, Set<FieldHolderRecord>> ruleUses = new LinkedHashMap<FieldHolderRecord, Set<FieldHolderRecord>>();
LOOP: for (FieldHolderRecord fieldHolderRecord : fields)
{
FieldHolder fieldHolder = fieldHolderRecord.getFieldHolder();
Control control = fieldHolder.getControl();
if (control != null)
{
controls.add(control);
for (VariableTask variable : fieldHolder.getVariables())
{
for (SetupTaskPerformer performer : allPerformers)
{
EAttribute eAttribute = performer.getAttributeRuleVariableData(variable);
if (eAttribute != null)
{
CollectionUtil.addAll(ruleUses, fieldHolderRecord, Collections.<FieldHolderRecord> emptySet());
continue LOOP;
}
}
}
// for (VariableTask variable : fieldHolder.getVariables())
// {
// for (SetupTaskPerformer performer : allPerformers)
// {
// EStructuralFeature.Setting setting = performer.getImpliedVariableData(variable);
// if (setting != null)
// {
// continue LOOP;
// }
// }
// }
for (VariableTask variable : fieldHolder.getVariables())
{
for (SetupTaskPerformer performer : allPerformers)
{
VariableTask dependantVariable = performer.getRuleVariableData(variable);
if (dependantVariable != null)
{
VariableTask ruleVariable = performer.getRuleVariable(dependantVariable);
if (ruleVariable != null)
{
FieldHolderRecord dependantFieldHolderRecord = getFieldHolderRecord(getURI(ruleVariable));
if (dependantFieldHolderRecord != null)
{
CollectionUtil.add(ruleUses, dependantFieldHolderRecord, fieldHolderRecord);
continue LOOP;
}
}
}
}
}
}
}
int fieldsSize = fields.size();
if (fieldsSize > 1)
{
int index = 0;
int maxPosition = fieldsSize - 1;
for (Map.Entry<FieldHolderRecord, Set<FieldHolderRecord>> entry : ruleUses.entrySet())
{
FieldHolderRecord fieldHolderRecord = entry.getKey();
fields.move(index++, fieldHolderRecord);
Set<FieldHolderRecord> fieldHolderRecords = entry.getValue();
for (FieldHolderRecord dependantFieldHolderRecord : fieldHolderRecords)
{
fields.move(Math.min(index++, maxPosition), dependantFieldHolderRecord);
}
}
}
int size = controls.size();
if (size > 1)
{
List<Control> children = Arrays.asList(composite.getChildren());
int controlOffset = 0;
for (Control child : children)
{
if (controls.contains(child))
{
break;
}
++controlOffset;
}
Control target = children.get(PropertyField.NUM_COLUMNS - 1);
int count = 0;
for (FieldHolder fieldHolder : this)
{
Control control = fieldHolder.getControl();
if (control != null)
{
int index = children.indexOf(control) - controlOffset;
Control newTarget = null;
for (int j = PropertyField.NUM_COLUMNS - 1; j >= 0; --j)
{
Control child = children.get(index + j);
if (newTarget == null)
{
newTarget = child;
if (index == count)
{
break;
}
}
child.moveBelow(target);
}
target = newTarget;
count += PropertyField.NUM_COLUMNS;
}
}
}
}
public void cleanup(Set<URI> uris)
{
LOOP: for (FieldHolderRecord fieldHolderRecord : fields)
{
for (URI uri : fieldHolderRecord.getVariableURIs())
{
if (uris.contains(uri))
{
continue LOOP;
}
}
FieldHolder fieldHolder = fieldHolderRecord.getFieldHolder();
if (fieldHolder.getVariables().isEmpty() && !fieldHolder.isDirty())
{
fieldHolder.dispose();
}
}
}
public URI getURI(VariableTask variable)
{
String name = variable.getName();
if (variable.getAnnotation(AnnotationConstants.ANNOTATION_GLOBAL_VARIABLE) != null)
{
return URI.createURI("#" + name);
}
Resource resource = variable.eResource();
URI uri;
if (resource == null)
{
uri = URI.createURI("#");
}
else
{
EObject eObject = resource.getContents().get(0);
if (eObject instanceof Installation || eObject instanceof Workspace)
{
uri = URI.createURI(resource.getURI().lastSegment()).appendFragment(resource.getURIFragment(variable));
}
else
{
uri = EcoreUtil.getURI(variable);
}
}
uri = uri.appendFragment(uri.fragment() + "~" + name);
return uri;
}
private FieldHolderRecord getFieldHolderRecord(URI uri)
{
for (FieldHolderRecord fieldHolderRecord : fields)
{
if (fieldHolderRecord.getVariableURIs().contains(uri))
{
return fieldHolderRecord;
}
}
return null;
}
public void associate(VariableTask variable, FieldHolder fieldHolder)
{
URI uri = getURI(variable);
for (FieldHolderRecord fieldHolderRecord : fields)
{
if (fieldHolderRecord.getFieldHolder() == fieldHolder)
{
fieldHolderRecord.getVariableURIs().add(uri);
break;
}
}
}
public FieldHolder getFieldHolder(VariableTask variable, boolean demandCreate, boolean includeDisposed)
{
URI uri = getURI(variable);
FieldHolderRecord fieldHolderRecord = getFieldHolderRecord(uri);
FieldHolder fieldHolder = null;
if (fieldHolderRecord == null)
{
if (!demandCreate)
{
return null;
}
fieldHolderRecord = new FieldHolderRecord();
fieldHolderRecord.getVariableURIs().add(uri);
fields.add(fieldHolderRecord);
}
else
{
fieldHolder = fieldHolderRecord.getFieldHolder();
if (fieldHolder.isDisposed())
{
if (includeDisposed)
{
return fieldHolder;
}
if (!demandCreate)
{
return null;
}
fieldHolder = null;
}
}
if (fieldHolder == null)
{
fieldHolder = new FieldHolder(variable);
fieldHolderRecord.setFieldHolder(fieldHolder);
}
else if (!updating)
{
fieldHolder.add(variable);
}
return fieldHolder;
}
@Override
public String toString()
{
return fields.toString();
}
}
/**
* A class for delayed validation.
* @author Ed Merks
*/
private class Validator implements Runnable
{
private boolean canceled;
private boolean dispatched;
private boolean redispatch;
private boolean clearSpecialFieldHolders;
public void run()
{
if (!canceled && !getShell().isDisposed())
{
dispatched = false;
if (redispatch || performerCreationJob != null)
{
if (performerCreationJob != null)
{
performerCreationJob.cancel();
}
schedule(clearSpecialFieldHolders);
}
else
{
if (clearSpecialFieldHolders)
{
clearSpecialFieldHolders();
clearSpecialFieldHolders = false;
}
validate();
}
}
}
public void schedule(boolean clearSpecialFieldHolders)
{
canceled = false;
if (clearSpecialFieldHolders)
{
this.clearSpecialFieldHolders = true;
}
if (dispatched)
{
redispatch = true;
}
else
{
dispatched = true;
redispatch = false;
UIUtil.timerExec(350, this);
}
}
public void cancel()
{
canceled = true;
dispatched = false;
redispatch = false;
clearSpecialFieldHolders = false;
if (performerCreationJob != null)
{
performerCreationJob.cancel();
}
}
}
}