/******************************************************************************* * Copyright (c) 2003, 2016 IBM Corporation 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: * IBM Rational Software - Initial API and implementation *******************************************************************************/ package org.eclipse.cdt.managedbuilder.ui.properties; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.ManagedBuildManager; import org.eclipse.cdt.managedbuilder.internal.core.Configuration; import org.eclipse.cdt.managedbuilder.internal.core.ManagedProject; import org.eclipse.cdt.managedbuilder.internal.ui.Messages; import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.preference.JFacePreferences; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.osgi.util.NLS; 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.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.Control; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; /** * Build-system specific version * for "add new configuration" dialog * in "Manage configurations" feature * * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ public class NewBuildConfigurationDialog extends Dialog { // Widgets private Button btnClone; private Button btnCopy; private Text configName; private Text configDescription; private Combo copyConfigSelector; private Combo cloneConfigSelector; private Label statusLabel; // Bookkeeping private boolean clone; /** Default configurations defined in the toolchain description */ private IConfiguration[] defaultCfgds; /** Configurations defined in the target */ private IConfiguration[] definedCfgds; private IConfiguration parentConfig; private ICProjectDescription des; private String newName; private String newDescription; final private String title; /** * @param parentShell * @param managedTarget * @param nameList A list of names (Strings) that have been added by the user but have not yet been added to the target * @param title The title of the dialog */ protected NewBuildConfigurationDialog(Shell parentShell, ICProjectDescription prjd, ICConfigurationDescription[] _cfgds, IConfiguration[] _defs, String title) { super(parentShell); this.title = title; des = prjd; setShellStyle(getShellStyle()|SWT.RESIZE); newName = ""; //$NON-NLS-1$ newDescription = ""; //$NON-NLS-1$ parentConfig = null; // The default behaviour is to clone the settings clone = true; // Populate the list of default and defined configurations definedCfgds = new IConfiguration[_cfgds.length]; for (int i=0; i<_cfgds.length; i++) definedCfgds[i] = ManagedBuildManager.getConfigurationForDescription(_cfgds[i]); defaultCfgds = _defs; } /* (non-Javadoc) * Method declared on Dialog. Cache the name and base config selections. * We don't have to worry that the index or name is wrong because we * enable the OK button IFF those conditions are met. */ @Override protected void buttonPressed(int buttonId) { if (buttonId == IDialogConstants.OK_ID) { String description = ""; //$NON-NLS-1$ String nameAndDescription = ""; //$NON-NLS-1$ String baseConfigNameAndDescription = ""; //$NON-NLS-1$ newName = configName.getText().trim(); newDescription = configDescription.getText().trim(); if (clone) { baseConfigNameAndDescription = cloneConfigSelector.getItem(cloneConfigSelector.getSelectionIndex()); for (int i = 0; i < definedCfgds.length; i++) { description = definedCfgds[i].getDescription(); if( (description == null) || (description.isEmpty()) ){ nameAndDescription = definedCfgds[i].getName(); } else { nameAndDescription = definedCfgds[i].getName() + "( " + description + " )"; //$NON-NLS-1$ //$NON-NLS-2$ } if (nameAndDescription.equals(baseConfigNameAndDescription)) { parentConfig = definedCfgds[i]; break; } } } else { // Get the parent config out of the default config list baseConfigNameAndDescription = copyConfigSelector.getItem(copyConfigSelector.getSelectionIndex()); for (int i = 0; i < defaultCfgds.length; i++) { description = defaultCfgds[i].getDescription(); if( (description == null) || (description.isEmpty()) ) { nameAndDescription = defaultCfgds[i].getName(); } else { nameAndDescription = defaultCfgds[i].getName() + "( " + description + " )"; //$NON-NLS-1$ //$NON-NLS-2$ } if (nameAndDescription.equals(baseConfigNameAndDescription)) { parentConfig = defaultCfgds[i]; break; } } } } else { newName = null; newDescription = null; parentConfig = null; } super.buttonPressed(buttonId); } /* (non-Javadoc) * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) */ @Override protected void configureShell(Shell shell) { super.configureShell(shell); if (title != null) shell.setText(title); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite) */ @Override protected void createButtonsForButtonBar(Composite parent) { super.createButtonsForButtonBar(parent); configName.setFocus(); if (configName != null) { configName.setText(newName); } validateState(); } @Override protected Control createDialogArea(Composite parent) { Composite composite = new Composite(parent, SWT.NULL); composite.setFont(parent.getFont()); composite.setLayout(new GridLayout(3, false)); composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); // Create a group for the name & description final Group group1 = new Group(composite, SWT.NONE); group1.setFont(composite.getFont()); GridLayout layout1 = new GridLayout(3, false); group1.setLayout(layout1); GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 3; group1.setLayoutData(gd); // Add a label and a text widget for Configuration's name final Label nameLabel = new Label(group1, SWT.LEFT); nameLabel.setFont(parent.getFont()); nameLabel.setText(Messages.NewConfiguration_label_name); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 1; gd.grabExcessHorizontalSpace = false; nameLabel.setLayoutData(gd); configName = new Text(group1, SWT.SINGLE | SWT.BORDER); configName.setFont(group1.getFont()); configName.setText(getNewName()); configName.setFocus(); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 2; gd.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; configName.setLayoutData(gd); configName.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { validateState(); } }); // Add a label and a text widget for Configuration's description final Label descriptionLabel = new Label(group1, SWT.LEFT); descriptionLabel.setFont(parent.getFont()); descriptionLabel.setText(Messages.NewConfiguration_label_description); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 1; gd.grabExcessHorizontalSpace = false; descriptionLabel.setLayoutData(gd); configDescription = new Text(group1, SWT.SINGLE | SWT.BORDER); configDescription.setFont(group1.getFont()); configDescription.setText(getNewDescription()); configDescription.setFocus(); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 2; gd.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; configDescription.setLayoutData(gd); // Create a group for the radio buttons final Group group = new Group(composite, SWT.NONE); group.setFont(composite.getFont()); group.setText(Messages.NewConfiguration_label_group); GridLayout layout = new GridLayout(3, false); group.setLayout(layout); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 3; group.setLayoutData(gd); SelectionListener radioListener = new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent event) { clone = btnClone.getSelection(); updateComboState(); } }; // Add a radio button and combo box to copy from default config btnCopy = new Button(group, SWT.RADIO); btnCopy.setFont(group.getFont()); btnCopy.setText(Messages.NewConfiguration_label_copy); setButtonLayoutData(btnCopy); btnCopy.addSelectionListener(radioListener); copyConfigSelector = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); copyConfigSelector.setFont(group.getFont()); int index = copyConfigSelector.indexOf(newName); copyConfigSelector.select(index < 0 ? 0 : index); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 2; gd.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; copyConfigSelector.setLayoutData(gd); copyConfigSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { validateState(); } }); copyConfigSelector.setEnabled(false); // Create a radio button and combo for clonable configs btnClone = new Button(group, SWT.RADIO); btnClone.setFont(group.getFont()); btnClone.setText(Messages.NewConfiguration_label_clone); setButtonLayoutData(btnClone); btnClone.addSelectionListener(radioListener); btnClone.setSelection(true); cloneConfigSelector = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); cloneConfigSelector.setFont(group.getFont()); cloneConfigSelector.setItems(getDefinedConfigNamesAndDescriptions()); index = cloneConfigSelector.indexOf(newName); cloneConfigSelector.select(index < 0 ? 0 : index); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 2; gd.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; cloneConfigSelector.setLayoutData(gd); cloneConfigSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { validateState(); } }); updateComboState(); updateDefaultConfigs(); statusLabel = new Label(composite, SWT.CENTER); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 3; statusLabel.setLayoutData(gd); statusLabel.setFont(composite.getFont()); statusLabel.setForeground(JFaceResources.getColorRegistry().get(JFacePreferences.ERROR_COLOR)); return composite; } /** * updates the list of default configurations */ private void updateDefaultConfigs(){ // IConfiguration cfgs[] = managedProject.getProjectType().getConfigurations(); if(defaultCfgds.length != 0){ String namesAndDescriptions[] = new String[defaultCfgds.length]; for (int i = 0; i < defaultCfgds.length; ++i) { if ( (defaultCfgds[i].getDescription() == null) || defaultCfgds[i].getDescription().isEmpty()) namesAndDescriptions[i] = defaultCfgds[i].getName(); else namesAndDescriptions[i] = defaultCfgds[i].getName() + "( " + defaultCfgds[i].getDescription() + " )"; //$NON-NLS-1$ //$NON-NLS-2$ } int selectionIndex = copyConfigSelector.getSelectionIndex(); String oldSelection = null; if(selectionIndex != -1) oldSelection = copyConfigSelector.getItem(selectionIndex); copyConfigSelector.setItems(namesAndDescriptions); if(oldSelection != null) selectionIndex = copyConfigSelector.indexOf(oldSelection); if(selectionIndex == -1) selectionIndex = 0; copyConfigSelector.select(selectionIndex); } else{ copyConfigSelector.removeAll(); } validateState(); } /* * Returns the array of configuration names defined for this managed project. * This list will be used to populate the list of configurations to * clone. */ private String [] getDefinedConfigNamesAndDescriptions() { String [] namesAndDescriptions = new String[definedCfgds.length]; for (int i = 0; i < definedCfgds.length; ++i) { if ( (definedCfgds[i].getDescription() == null) || definedCfgds[i].getDescription().isEmpty()) namesAndDescriptions[i] = definedCfgds[i].getName(); else namesAndDescriptions[i] = definedCfgds[i].getName() + "( " + definedCfgds[i].getDescription() +" )"; //$NON-NLS-1$ //$NON-NLS-2$ } return namesAndDescriptions; } /** * @return <code>String</code> containing the name chosen by the user for the * new configuration. */ public String getNewName() { return newName; } protected boolean isDuplicateName(String newName) { for (int i = 0; i < definedCfgds.length; i++) { if (definedCfgds[i].getName().equals(newName)) return true; } return false; } protected boolean isSimilarName(String newName) { for (int i = 0; i < definedCfgds.length; i++) { if (definedCfgds[i].getName().equalsIgnoreCase(newName)) return true; } return false; } /* (non-Javadoc) * Radio button selection event handler calls this helper method to * enable or disable the radio buttons. */ protected void updateComboState() { cloneConfigSelector.setEnabled(clone); copyConfigSelector.setEnabled(!clone); // btnShowAll.setVisible(!clone); validateState(); } /* (non-Javadoc) * Checks the argument for leading whitespaces and invalid directory name characters. * @param name * @return <I>true</i> is the name is a valid directory name with no whitespaces */ private boolean validateName(String name) { // Names must be at least one character in length if (name.trim().length() == 0) return false; // Iterate over the name checking for bad characters char[] chars = name.toCharArray(); // No whitespaces at the start of a name if (Character.isWhitespace(chars[0])) { return false; } for (int index = 0; index < chars.length; ++index) { // Config name must be a valid dir name too, so we ban "\ / : * ? " < >" in the names if (!Character.isLetterOrDigit(chars[index])) { switch (chars[index]) { case '/': case '\\': case ':': case '*': case '?': case '\"': case '<': case '>': return false; default: break; } } } return true; } /* (non-Javadoc) * Update the status message and button state based on the input selected * by the user * */ private void validateState() { String s = null; String currentName = configName.getText(); // Trim trailing whitespace while (currentName.length() > 0 && Character.isWhitespace(currentName.charAt(currentName.length()-1))) { currentName = currentName.substring(0, currentName.length()-1); } // Make sure that the name is at least one character in length if (currentName.length() == 0) { // No error message, but cannot select OK s = ""; //$NON-NLS-1$ } else if(clone ? definedCfgds.length == 0 : defaultCfgds.length == 0) { s = ""; //$NON-NLS-1$ // Make sure the name is not a duplicate } else if (isDuplicateName(currentName)) { s = NLS.bind(Messages.NewConfiguration_error_duplicateName, currentName); } else if (isSimilarName(currentName)) { s = NLS.bind(Messages.NewConfiguration_error_caseName, currentName); } else if (!validateName(currentName)) { // TODO Create a decent I18N string to describe this problem s = NLS.bind(Messages.NewConfiguration_error_invalidName, currentName); } if (statusLabel == null) return; Button b = getButton(IDialogConstants.OK_ID); if (s != null) { statusLabel.setText(s); statusLabel.setVisible(true); if (b != null) b.setEnabled(false); } else { statusLabel.setVisible(false); if (b != null) b.setEnabled(true); } return; } public String getNewDescription() { return newDescription; } /** * Create a new configuration, using the values currently set in * the dialog. * * Always returns null - in fact, return value * is kept for compatibility only. */ public ICConfigurationDescription newConfiguration() { Configuration cfg = (Configuration)parentConfig; String id = ManagedBuildManager.calculateChildId(cfg.getId(), null); ManagedProject mp = (ManagedProject)ManagedBuildManager.getBuildInfo(des.getProject()).getManagedProject(); Configuration config = new Configuration(mp, cfg, id, true, false); config.setName(getNewName()); config.setDescription(getNewDescription()); String target = config.getArtifactName(); if (target == null || target.length() == 0) config.setArtifactName(mp.getDefaultArtifactName()); CConfigurationData data = config.getConfigurationData(); try { des.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, data); } catch (CoreException e) { System.out.println(Messages.NewBuildConfigurationDialog_0); System.out.println(Messages.NewBuildConfigurationDialog_1 + e.getLocalizedMessage()); } return null; } }