/******************************************************************************* * Copyright (c) 2007, 2010 Intel 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: * Intel Corporation - Initial API and implementation * IBM Corporation * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.managedbuilder.ui.properties; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CoreModel; 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.buildproperties.IBuildPropertyManager; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyType; import org.eclipse.cdt.managedbuilder.buildproperties.IBuildPropertyValue; import org.eclipse.cdt.managedbuilder.core.IConfiguration; import org.eclipse.cdt.managedbuilder.core.IManagedProject; import org.eclipse.cdt.managedbuilder.core.IProjectType; import org.eclipse.cdt.managedbuilder.core.IToolChain; 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.cdt.managedbuilder.ui.wizards.MBSWizardHandler; import org.eclipse.cdt.ui.newui.INewCfgDialog; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; 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.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; /** * @noextend This class is not intended to be subclassed by clients. * @noinstantiate This class is not intended to be instantiated by clients. */ public class NewCfgDialog implements INewCfgDialog { private static final String NULL = "[null]"; //$NON-NLS-1$ private static final String SEPARATOR = " > "; //$NON-NLS-1$ private static final String ART = MBSWizardHandler.ARTIFACT; private static final String NOT = Messages.NewCfgDialog_3; // Widgets private Text configName; private Text configDescription; private Combo cloneConfigSelector; private Combo realConfigSelector; private Button b_cloneFromProject; private Button b_cloneFromExtension; private Button b_importFromOtherProject; private Button b_importPredefined; private Combo importSelector; private Combo importDefSelector; private Label statusLabel; /** Default configurations defined in the toolchain description */ private ICProjectDescription des; private IConfiguration[] cfgds; private IConfiguration[] rcfgs; private IConfiguration parentConfig; private String newName; private String newDescription; private String title; private Map<String, IConfiguration> imported; private Map<String, IConfiguration> importedDef; protected Shell parentShell; private class LocalDialog extends Dialog { LocalDialog(Shell parentShell) { super(parentShell); setShellStyle(getShellStyle()|SWT.RESIZE); } /* (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) { newName = configName.getText().trim(); newDescription = configDescription.getText().trim(); if (b_cloneFromProject.getSelection()) parentConfig = cfgds[cloneConfigSelector.getSelectionIndex()]; else if (b_cloneFromExtension.getSelection()) // real cfg parentConfig = rcfgs[realConfigSelector.getSelectionIndex()]; else if (b_importFromOtherProject.getSelection()) parentConfig = getConfigFromName(importSelector.getText(), imported); else if (b_importPredefined.getSelection()) parentConfig = getConfigFromName(importDefSelector.getText(), importedDef); if (parentConfig != null) newConfiguration(); } 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); } setButtons(); } @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); // bug 187634: Add a label to warn user that configuration name will be used directly // as a directory name in the filesystem. Label warningLabel = new Label(group1, SWT.BEGINNING | SWT.WRAP); warningLabel.setFont(parent.getFont()); warningLabel.setText(Messages.NewConfiguration_label_warning); gd = new GridData(SWT.FILL, SWT.BEGINNING, true, false, 3, 1); gd.widthHint = 300; warningLabel.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(newName); 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() { public void modifyText(ModifyEvent e) { setButtons(); } }); // 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(newDescription); configDescription.setFocus(); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); gd.horizontalSpan = 2; gd.widthHint = IDialogConstants.ENTRY_FIELD_WIDTH; configDescription.setLayoutData(gd); final Group group = new Group(composite, SWT.NONE); group.setFont(composite.getFont()); group.setText(Messages.NewConfiguration_label_group); GridLayout layout = new GridLayout(2, false); group.setLayout(layout); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 3; group.setLayoutData(gd); b_cloneFromProject = new Button(group, SWT.RADIO); b_cloneFromProject.setText(Messages.NewCfgDialog_0); gd = new GridData(GridData.BEGINNING); b_cloneFromProject.setLayoutData(gd); b_cloneFromProject.setSelection(true); b_cloneFromProject.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); cloneConfigSelector = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); cloneConfigSelector.setFont(group.getFont()); cloneConfigSelector.setItems(getConfigNamesAndDescriptions(cfgds, false)); int index = cloneConfigSelector.indexOf(newName); cloneConfigSelector.select(index < 0 ? 0 : index); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); cloneConfigSelector.setLayoutData(gd); cloneConfigSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); b_cloneFromExtension = new Button(group, SWT.RADIO); b_cloneFromExtension.setText(Messages.NewCfgDialog_1); gd = new GridData(GridData.BEGINNING); b_cloneFromExtension.setLayoutData(gd); b_cloneFromExtension.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); String[] extCfgs = getConfigNamesAndDescriptions(rcfgs, true); realConfigSelector = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); realConfigSelector.setFont(group.getFont()); realConfigSelector.setItems(extCfgs); index = realConfigSelector.indexOf(newName); realConfigSelector.select(index < 0 ? 0 : index); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); realConfigSelector.setLayoutData(gd); realConfigSelector.setEnabled(false); realConfigSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); if(extCfgs.length == 0) b_cloneFromExtension.setEnabled(false); /* import */ b_importFromOtherProject = new Button(group, SWT.RADIO); b_importFromOtherProject.setText(Messages.NewCfgDialog_4); gd = new GridData(GridData.BEGINNING); b_importFromOtherProject.setLayoutData(gd); b_importFromOtherProject.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); importSelector = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); importSelector.setFont(group.getFont()); importSelector.setItems(getImportItems()); importSelector.select(0); importSelector.setVisibleItemCount(Math.min(10, importSelector.getItemCount())); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); importSelector.setLayoutData(gd); importSelector.setEnabled(false); importSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); /* import predefined */ b_importPredefined = new Button(group, SWT.RADIO); b_importPredefined.setText(Messages.NewCfgDialog_5); gd = new GridData(GridData.BEGINNING); b_importPredefined.setLayoutData(gd); b_importPredefined.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); importDefSelector = new Combo(group, SWT.DROP_DOWN | SWT.READ_ONLY | SWT.BORDER); importDefSelector.setFont(group.getFont()); importDefSelector.setItems(getImportDefItems()); importDefSelector.select(0); importDefSelector.setVisibleItemCount(Math.min(10, importDefSelector.getItemCount())); gd = new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL); importDefSelector.setLayoutData(gd); importDefSelector.setEnabled(false); importDefSelector.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { setButtons(); } }); 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; } /* (non-Javadoc) * Update the status message and button state based on the input selected * by the user * */ private void setButtons() { 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 (cfgds.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)) { s = Messages.NewConfiguration_error_invalidName; } 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); } if (b_importFromOtherProject.getSelection() && importSelector.getSelectionIndex() == 0) if (b != null) b.setEnabled(false); if (b_importPredefined.getSelection() && importDefSelector.getSelectionIndex() == 0) if (b != null) b.setEnabled(false); cloneConfigSelector.setEnabled(b_cloneFromProject.getSelection()); realConfigSelector.setEnabled(b_cloneFromExtension.getSelection()); importSelector.setEnabled(b_importFromOtherProject.getSelection()); importDefSelector.setEnabled(b_importPredefined.getSelection()); } } public int open() { if (parentShell == null) return 1; LocalDialog dlg = new LocalDialog(parentShell); return dlg.open(); } /** */ public NewCfgDialog() { newName = new String(); newDescription = new String(); } public void setShell(Shell shell) { parentShell = shell; } public void setProject(ICProjectDescription prj) { des = prj; ICConfigurationDescription[] descs = des.getConfigurations(); cfgds = new IConfiguration[descs.length]; ArrayList<IConfiguration> lst = new ArrayList<IConfiguration>(); for (int i = 0; i < descs.length; ++i) { cfgds[i] = ManagedBuildManager.getConfigurationForDescription(descs[i]); IConfiguration cfg = cfgds[i]; for(; cfg != null && !cfg.isExtensionElement(); cfg = cfg.getParent()) {} if (cfg != null) { IProjectType pType = cfg.getProjectType(); if(pType != null){ IConfiguration[] cfs = pType.getConfigurations(); for (IConfiguration c : cfs) { if (c != null && !lst.contains(c)) lst.add(c); } } } } rcfgs = lst.toArray(new IConfiguration[lst.size()]); } public void setTitle(String _title) { title = _title; } private String [] getConfigNamesAndDescriptions(IConfiguration[] arr, boolean check) { String [] names = new String[arr.length]; for (int i = 0; i < arr.length; ++i) names[i] = getNameAndDescription(arr[i]); if (check) { boolean doubles = false; for (int i=0; i<names.length; i++) { for (int j=0; j<names.length; j++) { if (i != j && names[i].equals(names[j])) { doubles = true; break; } } } if (doubles) { for (int i=0; i<names.length; i++) { IToolChain tc = arr[i].getToolChain(); String s = (tc == null) ? NULL : tc.getName(); names[i] = names[i] + " : " + s; //$NON-NLS-1$ } } } return names; } private String getNameAndDescription(IConfiguration cfg) { String name = cfg.getName(); if (name == null) name = NULL; if ( (cfg.getDescription() == null) || cfg.getDescription().equals("")) //$NON-NLS-1$ return name; else return name + "( " + cfg.getDescription() +" )"; //$NON-NLS-1$ //$NON-NLS-2$ } protected boolean isDuplicateName(String newName) { for (int i = 0; i < cfgds.length; i++) { if (cfgds[i].getName().equals(newName)) return true; } return false; } protected boolean isSimilarName(String newName) { for (int i = 0; i < cfgds.length; i++) { if (cfgds[i].getName().equalsIgnoreCase(newName)) return true; } return false; } /* (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; } /** * Create a new configuration, using the values currently set in * the dialog. */ private void newConfiguration() { String id = ManagedBuildManager.calculateChildId(parentConfig.getId(), null); IManagedProject imp = ManagedBuildManager.getBuildInfo(des.getProject()).getManagedProject(); if (imp == null || !(imp instanceof ManagedProject)) return; ManagedProject mp = (ManagedProject) imp; try { ICConfigurationDescription cfgDes = null; Configuration config = new Configuration(mp, (Configuration)parentConfig, id, false, true); if (b_cloneFromProject.getSelection()) { ICConfigurationDescription base = ManagedBuildManager.getDescriptionForConfiguration(parentConfig); cfgDes = des.createConfiguration(id, newName, base); cfgDes.setDescription(newDescription); } else if (b_importFromOtherProject.getSelection()) { IResource owner = parentConfig.getOwner(); if (owner!=null) { // need writable cfg description for cloning ICProjectDescription prjDesOther = CCorePlugin.getDefault().getProjectDescription(owner.getProject(), true); ICConfigurationDescription base = prjDesOther.getConfigurationByName(parentConfig.getName()); if (base != null) { cfgDes = des.createConfiguration(id, newName, base); cfgDes.setDescription(newDescription); } } } if (cfgDes == null) { // when "Default" or "Predefined" selected or import from other project failed CConfigurationData data = config.getConfigurationData(); cfgDes = des.createConfiguration(ManagedBuildManager.CFG_DATA_PROVIDER_ID, data); } if (cfgDes != null) { config.setConfigurationDescription(cfgDes); config.setName(newName); config.setDescription(newDescription); String target = config.getArtifactName(); if (target == null || target.length() == 0) config.setArtifactName(mp.getDefaultArtifactName()); // Export artifact info as needed by project references config.exportArtifactInfo(); } if (cfgDes == null) { throw new CoreException(new Status(IStatus.ERROR, "org.eclipse.cdt.managedbuilder.ui", -1, //$NON-NLS-1$ Messages.NewCfgDialog_2, null)); } } catch (CoreException e) { ManagedBuilderUIPlugin.log(e); } } private String[] getImportItems() { imported = new HashMap<String, IConfiguration>(); if (des != null) { IProject[] ps = des.getProject().getWorkspace().getRoot().getProjects(); for (IProject p : ps) { ICProjectDescription prjd = CoreModel.getDefault().getProjectDescription(p, false); if (prjd == null) continue; ICConfigurationDescription[] cfgs = prjd.getConfigurations(); if (cfgs == null || cfgs.length == 0) continue; for (ICConfigurationDescription d : cfgs) { IConfiguration cfg = ManagedBuildManager.getConfigurationForDescription(d); if (cfg != null) imported.put(p.getName() + SEPARATOR + d.getName(), cfg); } } } ArrayList<String> lst = new ArrayList<String>(imported.keySet()); Collections.sort(lst); lst.add(0, NOT); return lst.toArray(new String[lst.size()]); } private String[] getImportDefItems() { importedDef = new HashMap<String, IConfiguration>(); IBuildPropertyManager bpm = ManagedBuildManager.getBuildPropertyManager(); IBuildPropertyType bpt = bpm.getPropertyType(ART); for (IBuildPropertyValue v : bpt.getSupportedValues()) { String id = v.getId(); IToolChain[] tcs = ManagedBuildManager.getExtensionsToolChains(ART, id, false); if (tcs == null || tcs.length == 0) continue; for (IToolChain tc : tcs) { if (tc.isSystemObject() || tc.isAbstract() || ! tc.isSupported()) continue; // prefix: "X" shown if toolchain is not supported by platform. String pre = ManagedBuildManager.isPlatformOk(tc) ? " " : "X "; //$NON-NLS-1$ //$NON-NLS-2$ for (IConfiguration c : ManagedBuildManager.getExtensionConfigurations(tc, ART, id)) { if (c.isSystemObject() || ! c.isSupported()) continue; importedDef.put(pre + v.getName() + SEPARATOR + tc.getName() + SEPARATOR + c.getName(), c); } } } ArrayList<String> lst = new ArrayList<String>(importedDef.keySet()); Collections.sort(lst); lst.add(0, NOT); return lst.toArray(new String[lst.size()]); } private IConfiguration getConfigFromName(String s, Map<String, IConfiguration> imp) { if (imp == null) return null; return imp.get(s); } }