Bug 542704 - Breakpoint not enabled when adding from Stack Trace

- in JavaExceptionHyperLink.linkActivated(), for an existing
  exception breakpoint, default enablement to true and save
  original enablement value to reset if user cancels property dialog
- add new ATTR_ENABLED_SETTING_ON_CANCEL attribute to JavaBreakpointPage
- in JavaBreakpointPage.performCancel() reset enabled setting back to
  original if ATTR_ENABLED_SETTING_ON_CANCEL is set
- in JavaBreakpointPage.performOK(), reset
  ATTR_ENABLED_SETTING_ON_CANCEL attribute to null
- add new test case to LineTrackerTests

Change-Id: Iea8abc9279776bcefae83b7af6efc355016b91ec
Signed-off-by: Jeff Johnston <jjohnstn@redhat.com>
diff --git a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/LineTrackerTests.java b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/LineTrackerTests.java
index afd3f68..9528825 100644
--- a/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/LineTrackerTests.java
+++ b/org.eclipse.jdt.debug.tests/tests/org/eclipse/jdt/debug/tests/core/LineTrackerTests.java
@@ -21,16 +21,20 @@
 import org.eclipse.debug.core.ILaunch;
 import org.eclipse.debug.core.ILaunchConfiguration;
 import org.eclipse.debug.core.ILaunchManager;
+import org.eclipse.debug.core.model.IBreakpoint;
 import org.eclipse.debug.internal.core.IInternalDebugCoreConstants;
 import org.eclipse.debug.ui.console.IConsole;
 import org.eclipse.debug.ui.console.IConsoleLineTrackerExtension;
 import org.eclipse.jdt.debug.core.IJavaDebugTarget;
+import org.eclipse.jdt.debug.core.IJavaExceptionBreakpoint;
+import org.eclipse.jdt.debug.core.JDIDebugModel;
 import org.eclipse.jdt.debug.testplugin.ConsoleLineTracker;
 import org.eclipse.jdt.debug.tests.AbstractDebugTest;
 import org.eclipse.jdt.internal.debug.ui.IJDIPreferencesConstants;
 import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin;
 import org.eclipse.jdt.internal.debug.ui.console.JavaExceptionHyperLink;
 import org.eclipse.jdt.internal.debug.ui.console.JavaStackTraceHyperlink;
+import org.eclipse.jdt.internal.debug.ui.propertypages.JavaBreakpointPage;
 import org.eclipse.jface.preference.IPreferenceStore;
 import org.eclipse.jface.text.BadLocationException;
 import org.eclipse.jface.text.IRegion;
@@ -182,6 +186,77 @@
 	    }
 	}
 
+	public void testJavaExceptionHyperLink() throws Exception {
+		ConsoleLineTracker.setDelegate(this);
+		fTarget = null;
+		IPreferenceStore jdiUIPreferences = JDIDebugUIPlugin.getDefault().getPreferenceStore();
+		boolean suspendOnException = jdiUIPreferences.getBoolean(IJDIPreferencesConstants.PREF_SUSPEND_ON_UNCAUGHT_EXCEPTIONS);
+		jdiUIPreferences.setValue(IJDIPreferencesConstants.PREF_SUSPEND_ON_UNCAUGHT_EXCEPTIONS, false);
+		try {
+			fTarget = launchAndTerminate("ThrowsNPE");
+
+			synchronized (fLock) {
+				if (!fStopped) {
+					fLock.wait(30000);
+				}
+			}
+			assertTrue("Never received 'start' notification", fStarted);
+			assertTrue("Never received 'stopped' notification", fStopped);
+			assertTrue("Console should be an IOCosnole", fConsole instanceof IOConsole);
+			IOConsole console = (IOConsole) fConsole;
+			IHyperlink[] hyperlinks = console.getHyperlinks();
+
+			// should be 1 exception hyperlink
+			int total = 0;
+			for (int i = 0; i < hyperlinks.length; i++) {
+				IHyperlink hyperlink = hyperlinks[i];
+				if (hyperlink instanceof JavaExceptionHyperLink) {
+					total++;
+					// should be followed by a stack trace hyperlink
+					assertTrue("Stack trace hyperlink missing", hyperlinks[i + 1] instanceof JavaStackTraceHyperlink);
+				}
+			}
+			assertEquals("Wrong number of exception hyperlinks", 1, total);
+			IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(JDIDebugModel.getPluginIdentifier());
+			IJavaExceptionBreakpoint foundBreakpoint = null;
+			for (int i = 0; i < breakpoints.length; i++) {
+				IBreakpoint breakpoint = breakpoints[i];
+				if (breakpoint instanceof IJavaExceptionBreakpoint) {
+					IJavaExceptionBreakpoint exceptionBreakpoint = (IJavaExceptionBreakpoint) breakpoint;
+					if ("java.lang.NullPointerException".equals(exceptionBreakpoint.getTypeName())) {
+						foundBreakpoint = exceptionBreakpoint;
+						break;
+					}
+				}
+			}
+			assertTrue("NPE breakpoint should not exist yet", foundBreakpoint == null);
+			IJavaExceptionBreakpoint ex = createExceptionBreakpoint("java.lang.NullPointerException", true, false);
+			ex.setEnabled(false);
+			JavaExceptionHyperLink exLink = (JavaExceptionHyperLink) hyperlinks[0];
+			exLink.linkActivated();
+			breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(JDIDebugModel.getPluginIdentifier());
+			foundBreakpoint = null;
+			for (int i = 0; i < breakpoints.length; i++) {
+				IBreakpoint breakpoint = breakpoints[i];
+				if (breakpoint instanceof IJavaExceptionBreakpoint) {
+					IJavaExceptionBreakpoint exceptionBreakpoint = (IJavaExceptionBreakpoint) breakpoint;
+					if ("java.lang.NullPointerException".equals(exceptionBreakpoint.getTypeName())) {
+						foundBreakpoint = exceptionBreakpoint;
+						break;
+					}
+				}
+			}
+			assertTrue("NPE breakpoint not found", foundBreakpoint != null);
+			assertTrue("NPE breakpoint not enabled", foundBreakpoint.isEnabled());
+			assertTrue("NPE breakpoint cancel enablement value not false", foundBreakpoint.getMarker().getAttribute(JavaBreakpointPage.ATTR_ENABLED_SETTING_ON_CANCEL, "").equals("false"));
+		} finally {
+			ConsoleLineTracker.setDelegate(null);
+			jdiUIPreferences.setValue(IJDIPreferencesConstants.PREF_SUSPEND_ON_UNCAUGHT_EXCEPTIONS, suspendOnException);
+			terminateAndRemove(fTarget);
+		}
+
+	}
+
 	/**
 	 * @see org.eclipse.debug.ui.console.IConsoleLineTracker#dispose()
 	 */
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaExceptionHyperLink.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaExceptionHyperLink.java
index 1c67f33..77f6cd6 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaExceptionHyperLink.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/console/JavaExceptionHyperLink.java
@@ -68,6 +68,9 @@
 				if (breakpoint instanceof IJavaExceptionBreakpoint) {
 					IJavaExceptionBreakpoint exceptionBreakpoint = (IJavaExceptionBreakpoint) breakpoint;
 					if (fExceptionName.equals(exceptionBreakpoint.getTypeName())) {
+						// reset enabled setting to true but save original value to reset if user cancels dialog
+						exceptionBreakpoint.getMarker().setAttribute(JavaBreakpointPage.ATTR_ENABLED_SETTING_ON_CANCEL, Boolean.toString(exceptionBreakpoint.isEnabled()));
+						exceptionBreakpoint.setEnabled(true);
 						showProperties(exceptionBreakpoint);
 						return;
 					}
diff --git a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/JavaBreakpointPage.java b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/JavaBreakpointPage.java
index 7516044..cfbaa40 100644
--- a/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/JavaBreakpointPage.java
+++ b/org.eclipse.jdt.debug.ui/ui/org/eclipse/jdt/internal/debug/ui/propertypages/JavaBreakpointPage.java
@@ -81,6 +81,11 @@
 	public static final String ATTR_DELETE_ON_CANCEL = JDIDebugUIPlugin.getUniqueIdentifier() + ".ATTR_DELETE_ON_CANCEL";  //$NON-NLS-1$
 
 	/**
+	 * Attribute used to indicate resetting the enable attribute if cancel is pressed.
+	 */
+	public static final String ATTR_ENABLED_SETTING_ON_CANCEL = JDIDebugUIPlugin.getUniqueIdentifier() + ".ATTR_ENABLED_SETTING_ON_CANCEL"; //$NON-NLS-1$
+
+	/**
 	 * Constant for the empty string
 	 */
 	protected static final String EMPTY_STRING = ""; //$NON-NLS-1$
@@ -102,6 +107,7 @@
 					breakpoint.getMarker().setAttribute(ATTR_DELETE_ON_CANCEL, (String)null);
 					breakpoint.setRegistered(true);
 				}
+				breakpoint.getMarker().setAttribute(ATTR_ENABLED_SETTING_ON_CANCEL, (String) null);
 				doStore();
 			}
 		};
@@ -415,6 +421,12 @@
 	@Override
 	public boolean performCancel() {
 		try {
+			String enableSetting = getBreakpoint().getMarker().getAttribute(ATTR_ENABLED_SETTING_ON_CANCEL, null);
+			if (enableSetting != null) {
+				// if this is an old breakpoint we must reset enablement setting
+				boolean enabled = Boolean.parseBoolean(enableSetting);
+				getBreakpoint().setEnabled(enabled);
+			}
 			if (getBreakpoint().getMarker().getAttribute(ATTR_DELETE_ON_CANCEL) != null) {
 			    // if this breakpoint is being created, delete on cancel
 				getBreakpoint().delete();