/* * Copyright 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"). * You may not use this file except in compliance with the License. * A copy of the License is located at * * http://aws.amazon.com/apache2.0 * * or in the "license" file accompanying this file. This file is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the License for the specific language governing * permissions and limitations under the License. */ package com.amazonaws.eclipse.cloudformation.ui; import static com.amazonaws.eclipse.cloudformation.validators.TemplateParameterValidators.newMaxLengthValidator; import static com.amazonaws.eclipse.cloudformation.validators.TemplateParameterValidators.newMaxValueValidator; import static com.amazonaws.eclipse.cloudformation.validators.TemplateParameterValidators.newMinLengthValidator; import static com.amazonaws.eclipse.cloudformation.validators.TemplateParameterValidators.newMinValueValidator; import static com.amazonaws.eclipse.cloudformation.validators.TemplateParameterValidators.newPatternValidator; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.eclipse.core.databinding.DataBindingContext; import org.eclipse.core.databinding.observable.Observables; import org.eclipse.core.databinding.validation.IValidator; import org.eclipse.jface.databinding.swt.ISWTObservableValue; import org.eclipse.jface.databinding.swt.SWTObservables; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.jface.fieldassist.FieldDecoration; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import com.amazonaws.eclipse.cloudformation.CloudFormationPlugin; import com.amazonaws.eclipse.cloudformation.model.ParametersDataModel; import com.amazonaws.eclipse.databinding.ChainValidator; import com.amazonaws.eclipse.databinding.DecorationChangeListener; import com.amazonaws.eclipse.databinding.NotEmptyValidator; import com.amazonaws.services.cloudformation.model.TemplateParameter; /** * A composite dynamically built from a set of AWS CloudFormation template parameters. */ public class ParametersComposite extends Composite { private static final String ALLOWED_VALUES = "AllowedValues"; private static final String MAX_LENGTH = "MaxLength"; private static final String MIN_LENGTH = "MinLength"; private static final String MAX_VALUE = "MaxValue"; private static final String MIN_VALUE = "MinValue"; private static final String CONSTRAINT_DESCRIPTION = "ConstraintDescription"; private static final String ALLOWED_PATTERN = "AllowedPattern"; private final ParametersDataModel dataModel; private final DataBindingContext bindingContext; private final Map<?, ?> parameterMap; public ParametersComposite(Composite parent, ParametersDataModel dataModel, DataBindingContext bindingContext) { super(parent, SWT.NONE); this.dataModel = dataModel; this.parameterMap = (Map<?, ?>) dataModel.getTemplate().get("Parameters"); this.bindingContext = bindingContext; setLayout(new GridLayout(2, false)); setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); createControls(); } private void createControls() { if (dataModel.getTemplateParameters() == null || dataModel.getTemplateParameters().isEmpty()) { Label label = new Label(this, SWT.NONE); label.setText("Selected template has no parameters"); label.setLayoutData(new GridData(SWT.LEFT, SWT.TOP, true, false, 2, 1)); } for (TemplateParameter param : dataModel.getTemplateParameters()) { createParameterSection(param); } } @SuppressWarnings({ "rawtypes", "unchecked" }) private void createParameterSection(TemplateParameter param) { // Unfortunately, we have to manually adjust for field decorations FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault().getFieldDecoration( FieldDecorationRegistry.DEC_ERROR); int fieldDecorationWidth = fieldDecoration.getImage().getBounds().width; Control paramControl = null; ISWTObservableValue observeParameter = null; ChainValidator<String> validationStatusProvider = null; if ( parameterMap.containsKey(param.getParameterKey()) ) { Label label = new Label(this, SWT.None); label.setText(param.getParameterKey()); Map paramMap = (Map) parameterMap.get(param.getParameterKey()); // Update the default value in the model. if (dataModel.getParameterValues().get(param.getParameterKey()) == null) { dataModel.getParameterValues().put(param.getParameterKey(), param.getDefaultValue()); } // If the template enumerates allowed values, present them as a // combo drop down if ( paramMap.containsKey(ALLOWED_VALUES) ) { Combo combo = new Combo(this, SWT.DROP_DOWN | SWT.READ_ONLY); Collection<String> allowedValues = (Collection<String>) paramMap.get(ALLOWED_VALUES); GridDataFactory.fillDefaults().grab(true, false).indent(fieldDecorationWidth, 0).applyTo(combo); combo.setItems(allowedValues.toArray(new String[allowedValues.size()])); observeParameter = SWTObservables.observeSelection(combo); paramControl = combo; } else { // Otherwise, just use a text field with validation constraints Text text = new Text(this, SWT.BORDER); GridDataFactory.fillDefaults().grab(true, false).indent(fieldDecorationWidth, 0).applyTo(text); observeParameter = SWTObservables.observeText(text, SWT.Modify); paramControl = text; // Add validators for the constraints listed in the template List<IValidator> validators = new ArrayList<IValidator>(); if ( paramMap.containsKey(ALLOWED_PATTERN) ) { String pattern = (String) paramMap.get(ALLOWED_PATTERN); Pattern p = Pattern.compile(pattern); validators.add(newPatternValidator(p, param.getParameterKey() + ": " + (String) paramMap.get(CONSTRAINT_DESCRIPTION))); } if ( paramMap.containsKey(MIN_LENGTH) ) { validators.add(newMinLengthValidator(parseValueToInteger(paramMap.get(MIN_LENGTH)), param .getParameterKey())); } if ( paramMap.containsKey(MAX_LENGTH) ) { validators.add(newMaxLengthValidator(parseValueToInteger(paramMap.get(MAX_LENGTH)), param .getParameterKey())); } if ( paramMap.containsKey(MIN_VALUE) ) { validators.add(newMinValueValidator(parseValueToInteger(paramMap.get(MIN_VALUE)), param .getParameterKey())); } if ( paramMap.containsKey(MAX_VALUE) ) { validators.add(newMaxValueValidator(parseValueToInteger(paramMap.get(MAX_VALUE)), param .getParameterKey())); } if ( !validators.isEmpty() ) { validationStatusProvider = new ChainValidator<String>(observeParameter, validators.toArray(new IValidator[validators.size()])); } } } else { CloudFormationPlugin.getDefault().logError("No parameter map object found for " + param.getParameterKey(), null); return; } if (param.getDescription() != null) { Label description = new Label(this, SWT.WRAP); GridDataFactory.fillDefaults().grab(true, false).span(2, 1).indent(0, -8).applyTo(description); description.setText(param.getDescription()); description.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY)); } bindingContext.bindValue(observeParameter, Observables.observeMapEntry( dataModel.getParameterValues(), param.getParameterKey(), String.class)); if ( validationStatusProvider != null ) { bindingContext.addValidationStatusProvider(validationStatusProvider); ControlDecoration decoration = new ControlDecoration(paramControl, SWT.TOP | SWT.LEFT); decoration.setDescriptionText("Invalid value"); decoration.setImage(fieldDecoration.getImage()); new DecorationChangeListener(decoration, validationStatusProvider.getValidationStatus()); } } private int parseValueToInteger(Object value) { if (value instanceof Integer) { return ((Integer) value).intValue(); } else { return Integer.parseInt((String) value); } } }