Bug 235857 Enablement of the Save button on the Secure Storage preference page
diff --git a/bundles/org.eclipse.equinox.security.tests/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.security.tests/META-INF/MANIFEST.MF
index 94d71bb..0eab06b 100644
--- a/bundles/org.eclipse.equinox.security.tests/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.security.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: Equinox security tests
 Bundle-SymbolicName: org.eclipse.equinox.security.tests;singleton:=true
-Bundle-Version: 1.0.0.qualifier
+Bundle-Version: 1.0.100.qualifier
 Bundle-Activator: org.eclipse.equinox.internal.security.tests.SecurityTestsActivator
 Bundle-RequiredExecutionEnvironment: J2SE-1.4
 Bundle-Vendor: Eclipse.org
diff --git a/bundles/org.eclipse.equinox.security.tests/src/org/eclipse/equinox/internal/security/tests/storage/SecurePreferencesTest.java b/bundles/org.eclipse.equinox.security.tests/src/org/eclipse/equinox/internal/security/tests/storage/SecurePreferencesTest.java
index 6e368d1..48f969d 100644
--- a/bundles/org.eclipse.equinox.security.tests/src/org/eclipse/equinox/internal/security/tests/storage/SecurePreferencesTest.java
+++ b/bundles/org.eclipse.equinox.security.tests/src/org/eclipse/equinox/internal/security/tests/storage/SecurePreferencesTest.java
@@ -17,8 +17,7 @@
 import junit.framework.Test;
 import junit.framework.TestSuite;
 import org.eclipse.core.runtime.FileLocator;
-import org.eclipse.equinox.internal.security.storage.SecurePreferencesRoot;
-import org.eclipse.equinox.internal.security.storage.SecurePreferencesWrapper;
+import org.eclipse.equinox.internal.security.storage.friends.InternalExchangeUtils;
 import org.eclipse.equinox.internal.security.tests.SecurityTestsActivator;
 import org.eclipse.equinox.security.storage.ISecurePreferences;
 import org.eclipse.equinox.security.storage.StorageException;
@@ -84,8 +83,7 @@
 	 * preference data.
 	 */
 	private boolean isModified(ISecurePreferences node) {
-		SecurePreferencesRoot rootData = ((SecurePreferencesWrapper) node).getContainer().getRootData();
-		return rootData.isModified();
+		return InternalExchangeUtils.isModified(node);
 	}
 
 	private void check(ISecurePreferences preferences) throws StorageException {
diff --git a/bundles/org.eclipse.equinox.security.ui/META-INF/MANIFEST.MF b/bundles/org.eclipse.equinox.security.ui/META-INF/MANIFEST.MF
index 6b27b10..52fb16e 100644
--- a/bundles/org.eclipse.equinox.security.ui/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.equinox.security.ui/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.equinox.security.ui;singleton:=true
-Bundle-Version: 1.0.0.qualifier
+Bundle-Version: 1.0.100.qualifier
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Import-Package: javax.crypto.spec,
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/TabContents.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/TabContents.java
index d138168..509ab66 100644
--- a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/TabContents.java
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/TabContents.java
@@ -35,6 +35,7 @@
 	private Shell shell;
 	protected NodesView nodesView = null;
 	protected ValuesView valuesView = null;
+	protected Button buttonSave = null;
 
 	public void setSelection(ISecurePreferences selectedNode) {
 		valuesView.setInput(selectedNode);
@@ -75,18 +76,21 @@
 		buttonBar.setLayout(buttonBarLayout);
 		buttonBar.setLayoutData(new GridData(GridData.END, GridData.BEGINNING, false, false));
 
-		Button buttonSave = new Button(buttonBar, SWT.PUSH);
+		buttonSave = new Button(buttonBar, SWT.PUSH);
 		buttonSave.setText(SecUIMessages.saveButton);
 		setButtonSize(buttonSave);
 		buttonSave.addSelectionListener(new SelectionAdapter() {
 
 			public void widgetSelected(SelectionEvent e) {
 				ISecurePreferences root = SecurePreferencesFactory.getDefault();
+				if (root == null)
+					return;
 				try {
 					root.flush();
 				} catch (IOException exception) {
 					Activator.log(IStatus.ERROR, exception.getMessage(), null, exception);
 				}
+				validateSave(); // save could fail so re-check
 			}
 		});
 
@@ -124,6 +128,19 @@
 
 		GridLayoutFactory.fillDefaults().margins(LayoutConstants.getSpacing()).generateLayout(page);
 		InternalExchangeUtils.addDeleteListener(this);
+		validateSave();
+	}
+
+	public void modified() {
+		validateSave();
+	}
+
+	public void validateSave() {
+		ISecurePreferences root = SecurePreferencesFactory.getDefault();
+		if (root == null)
+			return;
+		boolean modified = (root == null) ? false : InternalExchangeUtils.isModified(root);
+		buttonSave.setEnabled(modified);
 	}
 
 	public void onDeleted() {
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ISecurePreferencesSelection.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ISecurePreferencesSelection.java
index 9784db1..e3d7380 100644
--- a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ISecurePreferencesSelection.java
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ISecurePreferencesSelection.java
@@ -13,6 +13,16 @@
 import org.eclipse.equinox.security.storage.ISecurePreferences;
 
 public interface ISecurePreferencesSelection {
+	/**
+	 * Called by child elements to inform container that current selection has been
+	 * modified
+	 * @param selectedNode newly selected element
+	 */
 	public void setSelection(ISecurePreferences selectedNode);
 
+	/**
+	 * Called by child elements to inform container that information has been
+	 * modified.
+	 */
+	public void modified();
 }
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/NodesView.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/NodesView.java
index 593ac79..4a80c45 100644
--- a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/NodesView.java
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/NodesView.java
@@ -188,6 +188,7 @@
 						return;
 					String name = nodeDialog.getNodeName();
 					ISecurePreferences child = node.node(name);
+					parentView.modified();
 
 					// expand and select new node
 					ISecurePreferences parentNode = child.parent();
@@ -216,6 +217,7 @@
 					if (parentNode == null)
 						return; // can't remove root node
 					node.removeNode();
+					parentView.modified();
 
 					// refresh parent node and select it
 					nodeTreeViewer.refresh(parentNode, false);
diff --git a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ValuesView.java b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ValuesView.java
index e2c38bf..5e2d3a3 100644
--- a/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ValuesView.java
+++ b/bundles/org.eclipse.equinox.security.ui/src/org/eclipse/equinox/internal/security/ui/storage/view/ValuesView.java
@@ -249,6 +249,7 @@
 				boolean encrypt = newValueDialog.encrypt();
 				try {
 					selectedNode.put(key, value, encrypt);
+					parentView.modified();
 				} catch (StorageException e) {
 					Activator.log(IStatus.ERROR, SecUIMessages.failedEncrypt, null, e);
 				}
@@ -279,6 +280,7 @@
 				if (dialog.open() != SWT.YES)
 					return;
 				selectedNode.remove(key);
+				parentView.modified();
 				tableViewer.refresh();
 			}
 		};
@@ -364,6 +366,7 @@
 		}
 		try {
 			selectedNode.put(key, value, encrypted);
+			parentView.modified();
 		} catch (StorageException e) {
 			MessageBox dialog = new MessageBox(shell, SWT.ICON_WARNING | SWT.OK);
 			dialog.setMessage(SecUIMessages.failedEncrypt);
diff --git a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/friends/InternalExchangeUtils.java b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/friends/InternalExchangeUtils.java
index 5ee5a61..fe95443 100644
--- a/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/friends/InternalExchangeUtils.java
+++ b/bundles/org.eclipse.equinox.security/src/org/eclipse/equinox/internal/security/storage/friends/InternalExchangeUtils.java
@@ -135,6 +135,11 @@
 		return password;
 	}
 
+	static public boolean isModified(ISecurePreferences node) {
+		SecurePreferencesRoot rootData = ((SecurePreferencesWrapper) node).getContainer().getRootData();
+		return rootData.isModified();
+	}
+
 	/**
 	 * This is a bit of a strange code that tries to determine if we are running in a JUnit
 	 */