378032: BooleanAttributeEditor should initialize attribute to false

Change-Id: I29c92306b8055e6d9867f77ef222f1d301020443
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=378032
diff --git a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/AttributeEditorTest.java b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/AttributeEditorTest.java
index 17e46b9..73a3981 100644
--- a/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/AttributeEditorTest.java
+++ b/org.eclipse.mylyn.tasks.tests/src/org/eclipse/mylyn/tasks/tests/ui/AttributeEditorTest.java
@@ -11,6 +11,8 @@
 
 package org.eclipse.mylyn.tasks.tests.ui;
 
+import java.util.concurrent.atomic.AtomicBoolean;
+
 import junit.framework.TestCase;
 
 import org.eclipse.core.runtime.CoreException;
@@ -23,12 +25,15 @@
 import org.eclipse.mylyn.tasks.core.data.TaskAttributeMapper;
 import org.eclipse.mylyn.tasks.core.data.TaskData;
 import org.eclipse.mylyn.tasks.core.data.TaskDataModel;
+import org.eclipse.mylyn.tasks.core.data.TaskDataModelEvent;
+import org.eclipse.mylyn.tasks.core.data.TaskDataModelListener;
 import org.eclipse.mylyn.tasks.tests.connector.MockRepositoryConnector;
 import org.eclipse.mylyn.tasks.tests.connector.MockTask;
 import org.eclipse.mylyn.tasks.ui.editors.AbstractAttributeEditor;
 import org.eclipse.swt.SWT;
 import org.eclipse.swt.graphics.Color;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Display;
 import org.eclipse.swt.widgets.Label;
 import org.eclipse.swt.widgets.Shell;
 import org.eclipse.ui.forms.widgets.FormToolkit;
@@ -212,12 +217,43 @@
 	}
 
 	public void testBooleanAttribute() throws Exception {
+		FormToolkit toolkit = new FormToolkit(Display.getDefault());
 		TaskAttribute attribute = new TaskAttribute(taskData.getRoot(), "a.required.boolean");
 		attribute.getMetaData().setType(TaskAttribute.TYPE_BOOLEAN);
 		attribute.getMetaData().setRequired(true);
+		final AtomicBoolean firedAttributeChanged = new AtomicBoolean();
+		manager.addModelListener(new TaskDataModelListener() {
+			@Override
+			public void attributeChanged(TaskDataModelEvent event) {
+				firedAttributeChanged.set(true);
+			}
+		});
 
 		MockBooleanAttributeEditor editor = new MockBooleanAttributeEditor(manager, attribute);
 		assertFalse(editor.needsValue());
+		assertFalse(editor.getValue());
+		assertFalse(attribute.hasValue());
+		editor.createControl(WorkbenchUtil.getShell(), toolkit);
+		assertFalse(attribute.hasValue());
+		processAllEvents();
+		assertTrue(attribute.hasValue());
+		assertEquals(Boolean.toString(false), attribute.getValue());
+		assertFalse(firedAttributeChanged.get());
+
+		attribute.setValue(Boolean.toString(true));
+		editor = new MockBooleanAttributeEditor(manager, attribute);
+		editor.createControl(WorkbenchUtil.getShell(), toolkit);
+		processAllEvents();
+		assertEquals(Boolean.toString(true), attribute.getValue());
+		assertFalse(firedAttributeChanged.get());
+	}
+
+	/**
+	 * wait for the async call in BooleanAttributeEditor to run
+	 */
+	private void processAllEvents() {
+		while (Display.getDefault().readAndDispatch()) {
+		}
 	}
 
 	private TaskDataModel createManager() throws Exception {
diff --git a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/BooleanAttributeEditor.java b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/BooleanAttributeEditor.java
index 4e2df2f..4b7d060 100644
--- a/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/BooleanAttributeEditor.java
+++ b/org.eclipse.mylyn.tasks.ui/src/org/eclipse/mylyn/internal/tasks/ui/editors/BooleanAttributeEditor.java
@@ -19,6 +19,7 @@
 import org.eclipse.swt.events.SelectionEvent;
 import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.PlatformUI;
 import org.eclipse.ui.forms.widgets.FormToolkit;
 
 /**
@@ -56,6 +57,17 @@
 		button.setToolTipText(getDescription());
 		refresh();
 		setControl(button);
+		if (!getTaskAttribute().hasValue()) {
+			// set initial value to false to match what the editor shows 
+			// use asyncExec to ensure this happens after decorating, otherwise this appears as an incoming change
+			PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
+				public void run() {
+					if (!getTaskAttribute().hasValue()) {
+						getAttributeMapper().setBooleanValue(getTaskAttribute(), false);
+					}
+				}
+			});
+		}
 	}
 
 	@Override