Bug 364815: [preferences] UI for new preferences regarding annotation
based null analysis
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/OptionsConfigurationBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/OptionsConfigurationBlock.java
index 8503003..29b2e49 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/OptionsConfigurationBlock.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/OptionsConfigurationBlock.java
@@ -241,6 +241,8 @@
 
 		public static final int TEXT_CONTROL= 4;
 
+		public static final int LINK= 5;
+
 		/**
 		 * Tells the type of UI control corresponding to this node. One of
 		 * <ul>
@@ -525,6 +527,10 @@
 			return addChild(parentNode, label, key, PreferenceTreeNode.EXPANDABLE_COMPOSITE, showAllChildren);
 		}
 
+		public PreferenceTreeNode addLink(Composite parentComposite, String label, Key key, SelectionListener linkListener, int indent, int widthHint, PreferenceTreeNode parentNode) {
+			fConfigBlock.addLink(parentComposite, label, key, linkListener, indent, widthHint);
+			return addChild(parentNode, label, key, PreferenceTreeNode.LINK, false);
+		}
 		private boolean match(PreferenceTreeNode node, StringMatcher labelMatcher, StringMatcher valueMatcher) {
 			if (node.getKey() == null) {
 				return false;
@@ -636,6 +642,8 @@
 				control= fConfigBlock.getTextControl(node.getKey());
 			} else if (controlType == PreferenceTreeNode.EXPANDABLE_COMPOSITE) {
 				control= fConfigBlock.getExpandableComposite(node.getKey());
+			} else if (controlType == PreferenceTreeNode.LINK) {
+				control= fConfigBlock.getLink(node.getKey());
 			}
 
 			if (control != null) {
@@ -687,6 +695,7 @@
 	protected final ArrayList<Button> fCheckBoxes;
 	protected final ArrayList<Combo> fComboBoxes;
 	protected final ArrayList<Text> fTextBoxes;
+	protected final ArrayList<Link> fLinks;
 	protected final HashMap<Control, Label> fLabels;
 	protected final ArrayList<ExpandableComposite> fExpandableComposites;
 
@@ -747,6 +756,7 @@
 		fCheckBoxes= new ArrayList<Button>();
 		fComboBoxes= new ArrayList<Combo>();
 		fTextBoxes= new ArrayList<Text>(2);
+		fLinks= new ArrayList<Link>(2);
 		fLabels= new HashMap<Control, Label>();
 		fExpandableComposites= new ArrayList<ExpandableComposite>();
 
@@ -799,6 +809,7 @@
 
 
 	protected void settingsUpdated() {
+		// hook for subclasses
 	}
 
 
@@ -1051,6 +1062,26 @@
 		return textBox;
 	}
 
+	public Link addLink(Composite parent, String label, Key key, SelectionListener linkListener, int indent, int widthHint) {
+		GridData gd= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
+		gd.horizontalSpan= 3;
+		gd.horizontalIndent= indent;
+		gd.widthHint= widthHint;
+
+		Link link= new Link(parent, SWT.NONE);
+		link.setFont(JFaceResources.getDialogFont());
+		link.setText(label);
+		link.setData(key);
+		link.setLayoutData(gd);
+		link.addSelectionListener(linkListener);
+
+		makeScrollableCompositeAware(link);
+
+		fLinks.add(link);
+
+		return link;
+	}
+
 	protected ScrolledPageContent getParentScrolledComposite(Control control) {
 		Control parent= control.getParent();
 		while (!(parent instanceof ScrolledPageContent) && parent != null) {
@@ -1131,9 +1162,8 @@
 
 	protected SelectionListener getSelectionListener() {
 		if (fSelectionListener == null) {
-			fSelectionListener= new SelectionListener() {
-				public void widgetDefaultSelected(SelectionEvent e) {}
-
+			fSelectionListener= new SelectionAdapter() {
+				@Override
 				public void widgetSelected(SelectionEvent e) {
 					controlChanged(e.widget);
 				}
@@ -1442,6 +1472,7 @@
 	}
 
 	public void dispose() {
+		// hook for subclasses
 	}
 
 	/**
@@ -1541,6 +1572,17 @@
 		return null;
 	}
 
+	protected Link getLink(Key key) {
+		for (int i= fLinks.size() - 1; i >= 0; i--) {
+			Link curr= fLinks.get(i);
+			Key data= (Key)curr.getData();
+			if (key.equals(data)) {
+				return curr;
+			}
+		}
+		return null;
+	}
+	
 	protected Control findControl(Key key) {
 		Combo comboBox= getComboBox(key);
 		if (comboBox != null) {
@@ -1554,6 +1596,10 @@
 		if (text != null) {
 			return text;
 		}
+		Link link= getLink(key);
+		if (link != null) {
+			return link;
+		}
 		return null;
 	}
 
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
index 35daf8e..3253527 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.java
@@ -372,7 +372,12 @@
 	public static String ProblemSeveritiesConfigurationBlock_needsbuild_title;
 	public static String ProblemSeveritiesConfigurationBlock_needsfullbuild_message;
 	public static String ProblemSeveritiesConfigurationBlock_needsprojectbuild_message;
-	public static String ProblemSeveritiesConfigurationBlock_nonnull_is_default;
+	public static String ProblemSeveritiesConfigurationBlock_nonnull_annotation_label;
+	public static String ProblemSeveritiesConfigurationBlock_nonnull_is_default_project;
+	public static String ProblemSeveritiesConfigurationBlock_nonnull_is_default_workspace;
+	public static String ProblemSeveritiesConfigurationBlock_nonnullbydefault_annotation_label;
+	public static String ProblemSeveritiesConfigurationBlock_null_annotation_description_link;
+	public static String ProblemSeveritiesConfigurationBlock_nullable_annotation_label;
 	public static String ProblemSeveritiesConfigurationBlock_common_description;
 	public static String ProblemSeveritiesConfigurationBlock_pb_unavoidable_generic_type_problems;
 	public static String ProblemSeveritiesConfigurationBlock_pb_unsafe_type_op_label;
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
index d39c1ce..d3087ba 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/PreferencesMessages.properties
@@ -392,7 +392,12 @@
 ProblemSeveritiesConfigurationBlock_needsbuild_title=Error/Warning Settings Changed
 ProblemSeveritiesConfigurationBlock_needsfullbuild_message=The Error/Warning settings have changed. A full rebuild is required for changes to take effect. Do the full build now?
 ProblemSeveritiesConfigurationBlock_needsprojectbuild_message=The Error/Warning settings have changed. A rebuild of the project is required for changes to take effect. Build the project now?
-ProblemSeveritiesConfigurationBlock_nonnull_is_default=Use non-null as default
+ProblemSeveritiesConfigurationBlock_nonnull_annotation_label='NonNull' annotation:
+ProblemSeveritiesConfigurationBlock_nonnull_is_default_project=Use non-null as project-wide default
+ProblemSeveritiesConfigurationBlock_nonnull_is_default_workspace=Use non-null as workspace-wide default
+ProblemSeveritiesConfigurationBlock_nonnullbydefault_annotation_label='NonNullByDefault' annotation:
+ProblemSeveritiesConfigurationBlock_null_annotation_description_link='@Nullable' elements can be null. '@NonNull' elements must never be null. '@NonNullByDefault' sets 'non-null' as default for all elements in a package, type, or method. Enter custom annotation names or <a>Restore Default Annotations</a>.
+ProblemSeveritiesConfigurationBlock_nullable_annotation_label='Nullable' annotation:
 
 ProblemSeveritiesConfigurationBlock_common_description=&Select the severity level for the following optional Java compiler problems:
 ProblemSeveritiesConfigurationBlock_pb_unavoidable_generic_type_problems=Ignore unavoidable generic type problems
diff --git a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java
index c875f93..5e041cd 100644
--- a/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java
+++ b/org.eclipse.jdt.ui/ui/org/eclipse/jdt/internal/ui/preferences/ProblemSeveritiesConfigurationBlock.java
@@ -11,12 +11,18 @@
  *******************************************************************************/
 package org.eclipse.jdt.internal.ui.preferences;
 
+import java.util.Hashtable;
+
 import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.graphics.Font;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Link;
 
 import org.eclipse.core.resources.IProject;
 
@@ -134,6 +140,9 @@
 	private static final Key PREF_PB_UNUSED_OBJECT_ALLOCATION= getJDTCoreKey(JavaCore.COMPILER_PB_UNUSED_OBJECT_ALLOCATION);
 	private static final Key PREF_PB_MISSING_STATIC_ON_METHOD= getJDTCoreKey(JavaCore.COMPILER_PB_MISSING_STATIC_ON_METHOD);
 	private static final Key PREF_PB_POTENTIALLY_MISSING_STATIC_ON_METHOD= getJDTCoreKey(JavaCore.COMPILER_PB_POTENTIALLY_MISSING_STATIC_ON_METHOD);
+	
+	// special key
+	private static final Key NULL_ANNOTATIONS_LINK= OptionsConfigurationBlock.getLocalKey("ProblemSeveritiesConfigurationBlock_null_annotations_link"); //$NON-NLS-1$
 
 	// values
 	private static final String ERROR= JavaCore.ERROR;
@@ -219,7 +228,7 @@
 
 		Composite commonComposite= createStyleTabContent(mainComp);
 		GridData gridData= new GridData(SWT.FILL, SWT.FILL, true, true);
-		gridData.heightHint= fPixelConverter.convertHeightInCharsToPixels(20);
+		gridData.heightHint= fPixelConverter.convertHeightInCharsToPixels(30);
 		commonComposite.setLayoutData(gridData);
 
 		validateSettings(null, null, null);
@@ -450,9 +459,6 @@
 		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_pb_unused_private_label;
 		fFilteredPrefTree.addComboBox(inner, label, PREF_PB_UNUSED_PRIVATE, errorWarningIgnore, errorWarningIgnoreLabels, defaultIndent, section);
 
-		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_pb_redundant_null_check;
-		fFilteredPrefTree.addComboBox(inner, label, PREF_PB_REDUNDANT_NULL_CHECK, errorWarningIgnore, errorWarningIgnoreLabels, defaultIndent, section);
-
 		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_pb_unnecessary_else_label;
 		fFilteredPrefTree.addComboBox(inner, label, PREF_PB_UNNECESSARY_ELSE, errorWarningIgnore, errorWarningIgnoreLabels, defaultIndent, section);
 
@@ -549,24 +555,42 @@
 		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_pb_potential_null_reference;
 		fFilteredPrefTree.addComboBox(inner, label, PREF_PB_POTENTIAL_NULL_REFERENCE, errorWarningIgnore, errorWarningIgnoreLabels, defaultIndent, section);
 		
+		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_pb_redundant_null_check;
+		fFilteredPrefTree.addComboBox(inner, label, PREF_PB_REDUNDANT_NULL_CHECK, errorWarningIgnore, errorWarningIgnoreLabels, defaultIndent, section);
+
 		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_include_assert_in_null_analysis;
 		fFilteredPrefTree.addCheckBox(inner, label, PREF_PB_INCLUDE_ASSERTS_IN_NULL_ANALYSIS, enabledDisabled, defaultIndent, section);		
 		
 		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_enable_annotation_null_analysis;
-		node= fFilteredPrefTree.addCheckBox(inner, label, PREF_ANNOTATION_NULL_ANALYSIS, enabledDisabled, defaultIndent, section, false);
+		node= fFilteredPrefTree.addCheckBox(inner, label, PREF_ANNOTATION_NULL_ANALYSIS, enabledDisabled, defaultIndent, section);
 		
-		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_nonnull_is_default;
-		fFilteredPrefTree.addCheckBox(inner, label, PREF_NONNULL_IS_DEFAULT, enabledDisabled, extraIndent, node);
+		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_null_annotation_description_link;
+		SelectionListener linkListener= new SelectionAdapter() {
+			@Override
+			public void widgetSelected(SelectionEvent e) {
+				Hashtable<String, String> defaultOptions= JavaCore.getDefaultOptions();
+				setValue(PREF_NULLABLE_ANNOTATION_NAME, defaultOptions.get(JavaCore.COMPILER_NULLABLE_ANNOTATION_NAME));
+				setValue(PREF_NONNULL_ANNOTATION_NAME, defaultOptions.get(JavaCore.COMPILER_NONNULL_ANNOTATION_NAME));
+				setValue(PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME, defaultOptions.get(JavaCore.COMPILER_NONNULL_BY_DEFAULT_ANNOTATION_NAME));
+				updateControls();
+			}
+		};
+		fFilteredPrefTree.addLink(inner, label, NULL_ANNOTATIONS_LINK, linkListener, extraIndent, fPixelConverter.convertWidthInCharsToPixels(60), node);
 		
-		label= "'Nullable' annotation:";
+		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_nullable_annotation_label;
 		fFilteredPrefTree.addTextField(inner, label, PREF_NULLABLE_ANNOTATION_NAME, extraIndent, 0, node);
 		
-		label= "'NonNull' annotation:";
+		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_nonnull_annotation_label;
 		fFilteredPrefTree.addTextField(inner, label, PREF_NONNULL_ANNOTATION_NAME, extraIndent, 0, node);
 		
-		label= "'NonNullByDefault' annotation:";
+		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_nonnullbydefault_annotation_label;
 		fFilteredPrefTree.addTextField(inner, label, PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME, extraIndent, 0, node);
 		
+		label= fProject == null
+				? PreferencesMessages.ProblemSeveritiesConfigurationBlock_nonnull_is_default_workspace
+				: PreferencesMessages.ProblemSeveritiesConfigurationBlock_nonnull_is_default_project;
+		fFilteredPrefTree.addCheckBox(inner, label, PREF_NONNULL_IS_DEFAULT, enabledDisabled, extraIndent, node);
+		
 		label= PreferencesMessages.ProblemSeveritiesConfigurationBlock_pb_null_spec_violation;
 		fFilteredPrefTree.addComboBox(inner, label, PREF_PB_NULL_SPECIFICATION_VIOLATION, errorWarning, errorWarningLabels, extraIndent, node);
 		
@@ -660,6 +684,8 @@
 		
 		boolean enableAnnotationNullAnalysis= checkValue(PREF_ANNOTATION_NULL_ANALYSIS, ENABLED);
 		getCheckBox(PREF_NONNULL_IS_DEFAULT).setEnabled(enableAnnotationNullAnalysis);
+		Link link= getLink(NULL_ANNOTATIONS_LINK);
+		link.setEnabled(enableAnnotationNullAnalysis);
 		setTextFieldEnabled(PREF_NULLABLE_ANNOTATION_NAME, enableAnnotationNullAnalysis);
 		setTextFieldEnabled(PREF_NONNULL_ANNOTATION_NAME, enableAnnotationNullAnalysis);
 		setTextFieldEnabled(PREF_NONNULL_BY_DEFAULT_ANNOTATION_NAME, enableAnnotationNullAnalysis);