/******************************************************************************* * Copyright (c) 2013, 2015 Wind River Systems, Inc. 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: * Wind River Systems - initial API and implementation *******************************************************************************/ package org.eclipse.tcf.te.tcf.ui.wizards.pages; import java.util.ArrayList; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.dialogs.IDialogPage; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.swt.SWT; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.tcf.protocol.IPeer; import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerNode; import org.eclipse.tcf.te.tcf.locator.model.ModelManager; import org.eclipse.tcf.te.tcf.ui.controls.PeerNameControl; import org.eclipse.tcf.te.tcf.ui.nls.Messages; import org.eclipse.tcf.te.ui.controls.validator.RegexValidator; import org.eclipse.tcf.te.ui.controls.validator.Validator; import org.eclipse.tcf.te.ui.forms.CustomFormToolkit; import org.eclipse.tcf.te.ui.forms.parts.AbstractSection; import org.eclipse.tcf.te.ui.interfaces.data.IDataExchangeNode; import org.eclipse.tcf.te.ui.wizards.pages.AbstractFormsWizardPage; import org.eclipse.ui.forms.IManagedForm; /** * Abstract new configuration wizard page implementation. */ public abstract class AbstractConfigWizardPage extends AbstractFormsWizardPage implements IDataExchangeNode { private ConfigNameControl configName = null; private AbstractSection selectorSection = null; private AbstractSection detailsSection = null; private AbstractSection[] additionalSections = null; // The list of existing configuration names. Used to generate a unique name // and validate the wizard /* default */ final java.util.List<String> usedNames = new ArrayList<String>(); /** * Internal configuration name control implementation. */ protected static class ConfigNameControl extends PeerNameControl { /** * Constructor. * @param parentPage The parent dialog page this control is embedded in. * Might be <code>null</code> if the control is not associated with a page. */ public ConfigNameControl(IDialogPage parentPage) { super(parentPage); setEditFieldLabel(Messages.AbstractConfigWizardPage_configName_label); } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.controls.BaseEditBrowseTextControl#doCreateEditFieldValidator() */ @Override protected Validator doCreateEditFieldValidator() { return new RegexValidator(Validator.ATTR_MANDATORY, "[0-9a-zA-Z. _()-]+"); //$NON-NLS-1$ } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.controls.BaseEditBrowseTextControl#configureEditFieldValidator(org.eclipse.tcf.te.ui.controls.validator.Validator) */ @Override protected void configureEditFieldValidator(Validator validator) { if (validator instanceof RegexValidator) { validator.setMessageText(RegexValidator.INFO_MISSING_VALUE, Messages.AbstractConfigWizardPage_configName_infoMissingValue); } } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.controls.BaseEditBrowseTextControl#isValid() */ @Override public boolean isValid() { boolean valid = true; String name = getEditFieldControlTextForValidation(); if (!"".equals(name)) { //$NON-NLS-1$ // Name is not empty -> check against the list of used names if (getParentPage() instanceof AbstractConfigWizardPage) { valid = !((AbstractConfigWizardPage)getParentPage()).usedNames.contains(name.trim().toUpperCase()); if (!valid) { setMessage(Messages.AbstractConfigWizardPage_configName_nameInUse, IMessageProvider.ERROR); } } } if (!valid && getControlDecoration() != null) { // Setup and show the control decoration if necessary if (isEnabled()) { // Update the control decorator updateControlDecoration(getMessage(), getMessageType()); } } return valid ? super.isValid() : false; } } /** * Constructor. * * @param pageName The page name. Must not be <code>null</code>. */ public AbstractConfigWizardPage(String pageName) { super(pageName); } /** * Constructor. * * @param pageName The page name. Must not be <code>null</code>. * @param title The wizard page title or <code>null</code>. * @param titleImage The wizard page title image or <code>null</code>. */ public AbstractConfigWizardPage(String pageName, String title, ImageDescriptor titleImage) { super(pageName, title, titleImage); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.DialogPage#dispose() */ @Override public void dispose() { if (configName != null) { configName.dispose(); configName = null; } if (selectorSection != null) { selectorSection.dispose(); selectorSection = null; } if (detailsSection != null) { detailsSection.dispose(); detailsSection = null; } if (additionalSections != null) { for (AbstractSection additionalSection : additionalSections) { additionalSection.dispose(); } additionalSections = null; } super.dispose(); } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.wizards.pages.AbstractFormsWizardPage#doCreateFormContent(org.eclipse.swt.widgets.Composite, org.eclipse.tcf.te.ui.forms.CustomFormToolkit) */ @Override protected void doCreateFormContent(Composite parent, CustomFormToolkit toolkit) { Assert.isNotNull(parent); Assert.isNotNull(toolkit); // Add the controls configName = new ConfigNameControl(this); configName.setupPanel(parent); Label label = new Label(parent, SWT.HORIZONTAL | SWT.SEPARATOR); label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); selectorSection = doCreateSelectorSection(getManagedForm(), parent); if (selectorSection != null) { selectorSection.getSection().setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); } detailsSection = doCreateDetailsSection(getManagedForm(), parent); if (detailsSection != null) { detailsSection.getSection().setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); } additionalSections = doCreateAdditionalSections(getManagedForm(), parent); for (AbstractSection additionalSection : additionalSections) { additionalSection.getSection().setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); } // restore the widget values from the history restoreWidgetValues(); // Initialize the used configuration name list initializeUsedNameList(); } public String getConfigName() { if (configName != null) { return configName.getEditFieldControlText(); } return null; } /** * Creates the selector section. * * @param form The managed form instance. Must not be <code>null</code>. * @param parent The parent composite. Must not be <code>null</code>. * * @return The selector section instance or <code>null</code>. */ protected abstract AbstractSection doCreateSelectorSection(IManagedForm form, Composite parent); /** * Returns the selector section instance. * * @return The selector section instance or <code>null</code> if not yet created. */ protected final AbstractSection getSelectorSection() { return selectorSection; } /** * Creates the details section. * * @param form The managed form instance. Must not be <code>null</code>. * @param parent The parent composite. Must not be <code>null</code>. * * @return The details section instance or <code>null</code>. */ protected abstract AbstractSection doCreateDetailsSection(IManagedForm form, Composite parent); /** * Creates the additional sections. * * @param form The managed form instance. Must not be <code>null</code>. * @param parent The parent composite. Must not be <code>null</code>. * * @return The additional sections or an empty array. */ protected AbstractSection[] doCreateAdditionalSections(IManagedForm form, Composite parent) { return new AbstractSection[0]; } /** * Returns the additional sections instances. * * @return The additional sections instances or <code>null</code> if not yet created. */ protected final AbstractSection[] getAdditionalSection() { return additionalSections; } /** * Returns the details section instance. * * @return The details section instance or <code>null</code> if not yet created. */ protected final AbstractSection getDetailsSection() { return detailsSection; } /** * Returns the peer type. * * @return The peer type. Never <code>null</code>. */ protected abstract String getPeerType(); /** * Return the pattern that matches a configuration name with * the default name. The pattern is used to decide if the user * modified the configuration name or not. * * @param The default configuration name template. Must not be <code>null</code>. * @return The default configuration name pattern. Never <code>null</code>. */ protected abstract String getConfigNamePattern(); protected abstract String getNewConfigName(); /** * Initialize the used name list. */ protected void initializeUsedNameList() { usedNames.clear(); Runnable runnable = new Runnable() { @Override public void run() { // Get all peer model objects IPeerNode[] peers = ModelManager.getPeerModel().getPeerNodes(); // Loop them and find the ones which are of our handled types for (IPeerNode peerNode : peers) { String name = peerNode.getPeer().getName(); Assert.isNotNull(name); if (!"".equals(name) && !usedNames.contains(name)) { //$NON-NLS-1$ usedNames.add(name.trim().toUpperCase()); } } } }; Assert.isTrue(!Protocol.isDispatchThread()); Protocol.invokeAndWait(runnable); } /** * Auto-generate a configuration name. * * @param customID The custom ID to bind with the default configuration name template, or <code>null</code>. */ public void autoGenerateConfigurationName(String customID) { customID = customID != null ? customID.replaceAll("[^0-9a-zA-Z. _()-]", "_") : ""; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ // If the user modified the configuration name, we have to leave it alone. String pattern = getConfigNamePattern(); Assert.isNotNull(pattern); String currentName = configName != null ? configName.getEditFieldControlText().trim() : null; if (currentName != null && !"".equals(currentName.trim()) && !currentName.matches(pattern)) { //$NON-NLS-1$ return; } // Generate a new proposal String origProposedName = customID; String proposedName = origProposedName; if (usedNames.contains(proposedName.trim().toUpperCase()) && proposedName.matches(".* \\([0-9]*\\)")) { //$NON-NLS-1$ int index = proposedName.lastIndexOf(' '); if (index > 0) { origProposedName = proposedName.substring(0, index); proposedName = origProposedName; } } if (usedNames.contains(proposedName.trim().toUpperCase()) && proposedName.matches(pattern)) { proposedName = getNewConfigName(); } // Unify the proposed name to avoid duplicated configuration names int count = 0; while (usedNames.contains(proposedName.trim().toUpperCase())) { count++; proposedName = origProposedName.trim() + " (" + count + ")"; //$NON-NLS-1$ //$NON-NLS-2$ } // Set the configuration name if (configName != null) { configName.setEditFieldControlText(proposedName.trim()); } } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.wizards.pages.AbstractValidatingWizardPage#doValidate() */ @Override protected ValidationResult doValidate() { ValidationResult result = new ValidationResult(); boolean valid = true; if (configName != null) { valid &= configName.isValid(); result.setResult(configName); } if (selectorSection != null) { valid &= selectorSection.isValid(); result.setResult(selectorSection); } if (detailsSection != null) { valid &= detailsSection.isValid(); result.setResult(detailsSection); } if (additionalSections != null) { for (AbstractSection additionalSection : additionalSections) { valid &= additionalSection.isValid(); result.setResult(additionalSection); } } result.setValid(valid); return result; } /** * Updates the given attributes properties container with the current control content. * * @param peerAttributes The peer attributes. Must not be <code>null</code>. */ protected void updatePeerAttributes(IPropertiesContainer peerAttributes) { Assert.isNotNull(peerAttributes); // If the page has been never shown, we are done here if (getControl() == null) { return; } String value = configName != null ? configName.getEditFieldControlText() : null; if (value != null && !"".equals(value)) { //$NON-NLS-1$ peerAttributes.setProperty(IPeer.ATTR_NAME, value); } if (selectorSection != null) { updateAttribute(selectorSection, peerAttributes); } if (detailsSection != null) { updateAttribute(detailsSection, peerAttributes); } if (additionalSections != null) { for (AbstractSection additionalSection : additionalSections) { updateAttribute(additionalSection, peerAttributes); } } } /** * Update the given attributes properties container with the section * attributes. * * @param section The section. Must not be <code>null</code>. * @param peerAttributes The peer attributes. Must not be <code>null</code>. */ protected void updateAttribute(AbstractSection section, IPropertiesContainer peerAttributes) { Assert.isNotNull(section); Assert.isNotNull(peerAttributes); if (section instanceof IDataExchangeNode) { ((IDataExchangeNode)section).extractData(peerAttributes); } } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.interfaces.data.IDataExchangeNode#extractData(org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer) */ @Override public void extractData(IPropertiesContainer data) { Assert.isNotNull(data); // Update with the current control content updatePeerAttributes(data); } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.interfaces.data.IDataExchangeNode#setupData(org.eclipse.tcf.te.runtime.interfaces.properties.IPropertiesContainer) */ @Override public void setupData(IPropertiesContainer data) { if (selectorSection instanceof IDataExchangeNode) { ((IDataExchangeNode)selectorSection).setupData(data); } if (detailsSection instanceof IDataExchangeNode) { ((IDataExchangeNode)detailsSection).setupData(data); } if (additionalSections != null) { for (AbstractSection additionalSection : additionalSections) { ((IDataExchangeNode)additionalSection).setupData(data); } } if (data.containsKey(IPeer.ATTR_NAME)) { String name = data.getStringProperty(IPeer.ATTR_NAME); name = name.replaceAll("[^0-9a-zA-Z. _()-]", "_"); //$NON-NLS-1$ //$NON-NLS-2$ autoGenerateConfigurationName(name); } } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.wizards.pages.AbstractWizardPage#saveWidgetValues() */ @Override public void saveWidgetValues() { super.saveWidgetValues(); IDialogSettings settings = getDialogSettings(); if (settings != null) { if (selectorSection != null) { selectorSection.saveWidgetValues(settings); } if (detailsSection != null) { detailsSection.saveWidgetValues(settings); } if (additionalSections != null) { for (AbstractSection additionalSection : additionalSections) { additionalSection.saveWidgetValues(settings); } } } } /* (non-Javadoc) * @see org.eclipse.tcf.te.ui.wizards.pages.AbstractWizardPage#restoreWidgetValues() */ @Override public void restoreWidgetValues() { super.restoreWidgetValues(); IDialogSettings settings = getDialogSettings(); if (settings != null) { if (selectorSection != null) { selectorSection.restoreWidgetValues(settings); } if (detailsSection != null) { detailsSection.restoreWidgetValues(settings); } if (additionalSections != null) { for (AbstractSection additionalSection : additionalSections) { additionalSection.restoreWidgetValues(settings); } } } } }