From 7f8cebfdf922e75e88f5b254d4020e7822950afc Mon Sep 17 00:00:00 2001 From: Tobias Schwarz Date: Tue, 14 May 2013 14:22:34 +0200 Subject: Target Explorer: fix validation --- .../services/interfaces/ISimulatorService.java | 10 ++++ .../locator/services/AbstractSimulatorService.java | 22 +++++++ .../controls/InfoSectionPeerNameControl.java | 2 +- .../editor/sections/GeneralInformationSection.java | 69 +++++++++++++++++++++- .../org/eclipse/tcf/te/tcf/ui/nls/Messages.java | 2 + .../eclipse/tcf/te/tcf/ui/nls/Messages.properties | 4 +- .../ui/wizards/pages/AbstractConfigWizardPage.java | 8 +++ .../tcf/ui/wizards/pages/NewTargetWizardPage.java | 68 ++++++++++++++++++++- 8 files changed, 179 insertions(+), 6 deletions(-) (limited to 'target_explorer') diff --git a/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/ISimulatorService.java b/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/ISimulatorService.java index b10388c12..f5e85ee0e 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/ISimulatorService.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.runtime.services/src/org/eclipse/tcf/te/runtime/services/interfaces/ISimulatorService.java @@ -84,4 +84,14 @@ public interface ISimulatorService extends IService { * @return true if the configuration is valid. */ public boolean isValidConfig(Object context, String config); + + /** + * Validate a simulator context + * . + * @param context The context. Must not be null. + * @param config The configuration to validate. + * + * @return true if the context is valid. + */ + public boolean isValidContext(Object context, String config); } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/AbstractSimulatorService.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/AbstractSimulatorService.java index 8f3ab6c64..acffb7f09 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/AbstractSimulatorService.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.locator/src/org/eclipse/tcf/te/tcf/locator/services/AbstractSimulatorService.java @@ -10,12 +10,34 @@ */ package org.eclipse.tcf.te.tcf.locator.services; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.eclipse.tcf.protocol.Protocol; import org.eclipse.tcf.te.runtime.services.AbstractService; import org.eclipse.tcf.te.runtime.services.interfaces.ISimulatorService; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; /** * Abstract simulator service implementation. */ public abstract class AbstractSimulatorService extends AbstractService implements ISimulatorService { + /* (non-Javadoc) + * @see org.eclipse.tcf.te.runtime.services.interfaces.ISimulatorService#isValidContext(java.lang.Object, java.lang.String) + */ + @Override + public boolean isValidContext(final Object context, String config) { + if (context instanceof IPeerModel) { + final AtomicBoolean complete = new AtomicBoolean(false); + Runnable runnable = new Runnable() { + @Override + public void run() { + complete.set(((IPeerModel)context).isComplete()); + } + }; + Protocol.invokeAndWait(runnable); + return complete.get(); + } + return false; + } } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/controls/InfoSectionPeerNameControl.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/controls/InfoSectionPeerNameControl.java index c83a9cf44..39b60aade 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/controls/InfoSectionPeerNameControl.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/controls/InfoSectionPeerNameControl.java @@ -20,7 +20,7 @@ import org.eclipse.tcf.te.ui.jface.interfaces.IValidatingContainer; */ public class InfoSectionPeerNameControl extends PeerNameControl { // Reference to the parent general information section - private final GeneralInformationSection infoSection; + protected final GeneralInformationSection infoSection; /** * Constructor. diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/sections/GeneralInformationSection.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/sections/GeneralInformationSection.java index 15b930352..9f41d1561 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/sections/GeneralInformationSection.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/editor/sections/GeneralInformationSection.java @@ -10,6 +10,7 @@ package org.eclipse.tcf.te.tcf.ui.editor.sections; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; @@ -17,6 +18,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.jface.fieldassist.FieldDecorationRegistry; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; @@ -38,6 +40,7 @@ import org.eclipse.tcf.te.runtime.utils.StatusHelper; import org.eclipse.tcf.te.tcf.core.peers.Peer; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModelProperties; +import org.eclipse.tcf.te.tcf.locator.model.Model; import org.eclipse.tcf.te.tcf.locator.nodes.PeerRedirector; import org.eclipse.tcf.te.tcf.ui.activator.UIPlugin; import org.eclipse.tcf.te.tcf.ui.editor.controls.InfoSectionPeerNameControl; @@ -68,6 +71,10 @@ public class GeneralInformationSection extends AbstractSection { // Reference to the properties container representing the working copy for the section /* default */ final IPropertiesContainer wc = new PropertiesContainer(); + // The list of existing configuration names. Used to generate a unique name + // and validate the wizard + /* default */ final java.util.List usedNames = new ArrayList(); + /** * Constructor. * @@ -121,7 +128,31 @@ public class GeneralInformationSection extends AbstractSection { section.setClient(client); // Create the peer name control - nameControl = new InfoSectionPeerNameControl(this); + nameControl = new InfoSectionPeerNameControl(this) { + @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 + valid = !infoSection.usedNames.contains(name.trim().toUpperCase()); + if (!valid) { + setMessage(Messages.GeneralInformationSection_error_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; + } + }; nameControl.setFormToolkit(toolkit); nameControl.setParentControlIsInnerPanel(true); nameControl.setupPanel(client); @@ -276,8 +307,11 @@ public class GeneralInformationSection extends AbstractSection { setIsUpdating(false); } + initializeUsedNameList(); + // Re-evaluate the dirty state dataChanged(null); + // Adjust the control enablement updateEnablement(); } @@ -299,13 +333,14 @@ public class GeneralInformationSection extends AbstractSection { // Extract the widget data into the working copy if (nameControl != null) { String name = nameControl.getEditFieldControlText(); - if (name != null && !"".equals(name.trim())) { //$NON-NLS-1$ + boolean used = name != null && usedNames.contains(name.trim().toUpperCase()); + if (!used && name != null && !"".equals(name.trim()) ) { //$NON-NLS-1$ wc.setProperty(IPeer.ATTR_NAME, name); } else { // Build up the message template String template = NLS.bind(Messages.OverviewEditorPage_error_save, wc.getStringProperty(IPeer.ATTR_NAME), Messages.PossibleCause); // Handle the status - Status status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), NLS.bind(Messages.GeneralInformationSection_error_emptyName, nameControl.getMessage())); + Status status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), used ? Messages.GeneralInformationSection_error_nameInUse : Messages.GeneralInformationSection_error_emptyName); StatusHandlerUtil.handleStatus(status, od, template, null, IContextHelpIds.MESSAGE_SAVE_FAILED, GeneralInformationSection.this, null); } } @@ -453,4 +488,32 @@ public class GeneralInformationSection extends AbstractSection { SWTControlUtil.setEnabled(nameControl.getEditFieldControl(), isStatic.get() && !isRemote.get()); } } + + /** + * Initialize the used name list. + */ + protected void initializeUsedNameList() { + usedNames.clear(); + + Runnable runnable = new Runnable() { + @Override + public void run() { + // Get all peer model objects + IPeerModel[] peers = Model.getModel().getPeers(); + // Loop them and find the ones which are of our handled types + for (IPeerModel peerModel : peers) { + if (peerModel.isStatic() && !peerModel.equals(od)) { + String name = peerModel.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); + } } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.java index ad7e95ef6..7ee73acc8 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.java @@ -56,6 +56,7 @@ public class Messages extends NLS { public static String GeneralInformationSection_title; public static String GeneralInformationSection_description; + public static String GeneralInformationSection_error_nameInUse; public static String GeneralInformationSection_state; public static String GeneralInformationSection_state__1; @@ -92,6 +93,7 @@ public class Messages extends NLS { public static String NewTargetWizardPage_description; public static String NewTargetWizardPage_section_transportType; public static String NewTargetWizardPage_section_attributes; + public static String NewTargetWizardPage_error_nameInUse; public static String RemotePeerDiscoveryRootNode_label; diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.properties index 86609176f..b5a670b8f 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.properties +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/nls/Messages.properties @@ -24,7 +24,8 @@ GeneralInformationSection_state_2=Not Reachable. Connection attempt timed out. GeneralInformationSection_state_3=Not Reachable. Connection attempt failed. GeneralInformationSection_state_4=Waiting to become Ready. GeneralInformationSection_error_delete=Failed to remove old target: {0}.\n\n{1} -GeneralInformationSection_error_emptyName=The target name cannot be empty. {0} +GeneralInformationSection_error_emptyName=The target name cannot be empty. +GeneralInformationSection_error_nameInUse=The target name is already used. Please choose a unique name. LabelProviderDelegate_state_0=Reachable LabelProviderDelegate_state_1=Communicating @@ -51,6 +52,7 @@ NewTargetWizardPage_title=New Target NewTargetWizardPage_description=Specify the attributes of the target to connect to. NewTargetWizardPage_section_transportType=Specify the transport type and properties: NewTargetWizardPage_section_attributes=Specify additional target attributes: +NewTargetWizardPage_error_nameInUse=This target name is already used. Please choose a unique name. RemotePeerDiscoveryRootNode_label=Neighborhood diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/AbstractConfigWizardPage.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/AbstractConfigWizardPage.java index 679aaa7f4..31580cfbc 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/AbstractConfigWizardPage.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/AbstractConfigWizardPage.java @@ -108,6 +108,14 @@ public abstract class AbstractConfigWizardPage extends AbstractFormsWizardPage i } } + 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; } } diff --git a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/NewTargetWizardPage.java b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/NewTargetWizardPage.java index ee0fa4d35..ba5ad613b 100644 --- a/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/NewTargetWizardPage.java +++ b/target_explorer/plugins/org.eclipse.tcf.te.tcf.ui/src/org/eclipse/tcf/te/tcf/ui/wizards/pages/NewTargetWizardPage.java @@ -9,6 +9,7 @@ *******************************************************************************/ package org.eclipse.tcf.te.tcf.ui.wizards.pages; +import java.util.ArrayList; import java.util.Map; import java.util.UUID; @@ -16,15 +17,19 @@ import org.eclipse.core.runtime.Assert; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogPage; import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IMessageProvider; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; 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.runtime.properties.PropertiesContainer; import org.eclipse.tcf.te.tcf.core.interfaces.ITransportTypes; +import org.eclipse.tcf.te.tcf.locator.interfaces.nodes.IPeerModel; +import org.eclipse.tcf.te.tcf.locator.model.Model; import org.eclipse.tcf.te.tcf.ui.controls.CustomTransportPanel; import org.eclipse.tcf.te.tcf.ui.controls.PeerAttributesTablePart; import org.eclipse.tcf.te.tcf.ui.controls.PeerNameControl; @@ -59,6 +64,10 @@ public class NewTargetWizardPage extends AbstractValidatingWizardPage implements // The UUID of the new peer to create private final UUID uuid = UUID.randomUUID(); + // The list of existing configuration names. Used to generate a unique name + // and validate the wizard + /* default */ final java.util.List usedNames = new ArrayList(); + /** * Local transport type control implementation. */ @@ -211,7 +220,33 @@ public class NewTargetWizardPage extends AbstractValidatingWizardPage implements client.setBackground(parent.getBackground()); // Add the controls - peerNameControl = new PeerNameControl(this); + peerNameControl = new PeerNameControl(this) { + @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 NewTargetWizardPage) { + valid = !((NewTargetWizardPage)getParentPage()).usedNames.contains(name.trim().toUpperCase()); + if (!valid) { + setMessage(Messages.NewTargetWizardPage_error_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; + } + }; peerNameControl.setFormToolkit(toolkit); peerNameControl.setParentControlIsInnerPanel(true); peerNameControl.setupPanel(client); @@ -262,6 +297,9 @@ public class NewTargetWizardPage extends AbstractValidatingWizardPage implements // restore the widget values from the history restoreWidgetValues(); + + // Initialize the used configuration name list + initializeUsedNameList(); } /** @@ -405,4 +443,32 @@ public class NewTargetWizardPage extends AbstractValidatingWizardPage implements if (transportTypePanelControl != null) transportTypePanelControl.restoreWidgetValues(settings, null); } } + + /** + * Initialize the used name list. + */ + protected void initializeUsedNameList() { + usedNames.clear(); + + Runnable runnable = new Runnable() { + @Override + public void run() { + // Get all peer model objects + IPeerModel[] peers = Model.getModel().getPeers(); + // Loop them and find the ones which are of our handled types + for (IPeerModel peerModel : peers) { + if (peerModel.isStatic()) { + String name = peerModel.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); + } } -- cgit v1.2.3