[430228] The ignoring of HTML Tag Attribute Names from validation should be allowed for any version of HTML document

Tag Attribute names can be ignored from the validation for any version of HTML documents (not only for HTML5)
Tag Attribute names filter is made to be case-insensitive
QuickFix for 'unknown' attribute names is made to work only for any version of HTML documents
QuickFix is made to restore original preference values when user presses 'Cancel' button on preference page

Signed-off-by: vrubezhny <vrubezhny@exadel.com>
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java
index 4b3b8e2..eb618b3 100644
--- a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2004, 2013 IBM Corporation and others.
+ * Copyright (c) 2004, 2014 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -177,7 +177,7 @@
 					if (isHTML5(target))
 						continue;
 				}		
-				// Check for user-defined exclusions for HTML5 attribute names
+				// Check for user-defined exclusions
 				if (!shouldValidateAttributeName(target, attrName)) 
 					continue;
 
@@ -364,8 +364,6 @@
 	}
 	
 	private boolean shouldValidateAttributeName(Element target, String attrName) {
-		if (!isHTML5(target)) return true;
-
 		Object adapter = (target instanceof IAdaptable ? ((IAdaptable)target).getAdapter(IResource.class) : null);
 		IProject project = (adapter instanceof IResource ? ((IResource)adapter).getProject() : null);
 		
@@ -377,7 +375,7 @@
 				strMatcher = new StringMatcher(excluded);
 				fIgnorePatterns.put(excluded, strMatcher);
 			}
-			if (strMatcher.match(attrName))
+			if (strMatcher.match(attrName.toLowerCase()))
 				return false;
 		}
 
diff --git a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/HTMLAttributeValidationQuickFixProcessor.java b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/HTMLAttributeValidationQuickFixProcessor.java
index e3028f3..6b0c458 100644
--- a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/HTMLAttributeValidationQuickFixProcessor.java
+++ b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/HTMLAttributeValidationQuickFixProcessor.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 IBM Corporation and others.
+ * Copyright (c) 2013, 2014 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -45,6 +45,7 @@
 import org.eclipse.wst.sse.ui.internal.reconcile.TemporaryAnnotation;
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMAttr;
 import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode;
+import org.w3c.dom.Element;
 import org.w3c.dom.NamedNodeMap;
 
 public class HTMLAttributeValidationQuickFixProcessor implements IQuickAssistProcessor {
@@ -132,6 +133,8 @@
 						continue;
 
 					IDOMNode node = (IDOMNode) ContentAssistUtils.getNodeAt(viewer, offset);
+					if (!(node instanceof Element))
+						continue;
 
 					Object adapter = (node instanceof IAdaptable ? ((IAdaptable)node).getAdapter(IResource.class) : null);
 					IProject project = (adapter instanceof IResource ? ((IResource)adapter).getProject() : null);
@@ -144,6 +147,10 @@
 							fLookupOrder = new IScopeContext[] {projectScope, new InstanceScope(), new DefaultScope()};
 					}
 					
+					boolean ignore = fPreferenceService.getBoolean(
+							getPreferenceNodeQualifier(), HTMLCorePreferenceNames.IGNORE_ATTRIBUTE_NAMES, 
+							HTMLCorePreferenceNames.IGNORE_ATTRIBUTE_NAMES_DEFAULT, fLookupOrder);
+
 					String ignoreList = fPreferenceService.getString(
 							getPreferenceNodeQualifier(), HTMLCorePreferenceNames.ATTRIBUTE_NAMES_TO_IGNORE, 
 							HTMLCorePreferenceNames.ATTRIBUTE_NAMES_TO_IGNORE_DEFAULT, fLookupOrder);
@@ -161,9 +168,10 @@
 					String name = getAttributeName(node, offset);
 					if (name == null) continue;
 					
-					if (!result.contains(name.toLowerCase())) {
+					// If ignore == false. then show a quick fix anyway (due to allow to turn 'ignore' option on)
+					if (!ignore || shouldShowQuickFix(result, name.toLowerCase())) {
 						IgnoreAttributeNameCompletionProposal p = new IgnoreAttributeNameCompletionProposal(
-								name, offset, NLS.bind(HTMLUIMessages.DoNotValidateAttribute, name), 
+								name.toLowerCase(), offset, NLS.bind(HTMLUIMessages.DoNotValidateAttribute, name), 
 								HTMLUIMessages.DoNotValidateAttributeAddInfo, node);
 						if (!proposals.contains(p))
 							proposals.add(p);  
@@ -175,16 +183,15 @@
 						
 						// Do not continue creating proposals for the rest of patterns if 
 						// a more common pattern is already created
-						if (result.contains(namePattern.toString().toLowerCase())) 
+						if (ignore && result.contains(namePattern.toString().toLowerCase()))
 							break;
 						
-						if (!result.contains(namePattern.toString().toLowerCase())) {
-							IgnoreAttributeNameCompletionProposal p = new IgnoreAttributeNameCompletionProposal(
-									namePattern.toString(), offset, NLS.bind(HTMLUIMessages.DoNotValidateAllAttributes, namePattern.toString()), 
-									HTMLUIMessages.DoNotValidateAllAttributesAddInfo, node); 
-							if (!proposals.contains(p))
-								proposals.add(p);  
-						}
+						IgnoreAttributeNameCompletionProposal p = new IgnoreAttributeNameCompletionProposal(
+								namePattern.toString().toLowerCase(), offset, NLS.bind(HTMLUIMessages.DoNotValidateAllAttributes, namePattern.toString()), 
+								HTMLUIMessages.DoNotValidateAllAttributesAddInfo, node); 
+						if (!proposals.contains(p))
+							proposals.add(p);  
+
 						dashIndex = name.indexOf('-', dashIndex + 1);
 					}
 				}
@@ -218,6 +225,20 @@
 		return null;
 	}
 	
+	private boolean shouldShowQuickFix(Set lcIgnoredPatterns, String attrName) {
+		// Check the attribute name absence in ignore list
+		String [] lcPatterns = (String[])lcIgnoredPatterns.toArray(new String[0]);
+		for (int i = 0; i < lcPatterns.length; i++) {
+			StringMatcher strMatcher = new StringMatcher(lcPatterns[i]);
+			if (strMatcher.match(attrName.toLowerCase())) {
+				return false; // The attribute name is already ignored, no need to show a quickfix
+			}
+		}
+
+		// The attribute name is not ignored yet, need to show a quickfix
+		return true;
+	}
+	
 	private String getPreferenceNodeQualifier() {
 		return HTMLCorePlugin.getDefault().getBundle().getSymbolicName();
 	}
diff --git a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/IgnoreAttributeNameCompletionProposal.java b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/IgnoreAttributeNameCompletionProposal.java
index 14c9f80..f43e9fe 100644
--- a/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/IgnoreAttributeNameCompletionProposal.java
+++ b/bundles/org.eclipse.wst.html.ui/src/org/eclipse/wst/html/ui/internal/text/correction/IgnoreAttributeNameCompletionProposal.java
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2013 IBM Corporation and others.
+ * Copyright (c) 2013, 2014 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
  * which accompanies this distribution, and is available at
@@ -10,6 +10,9 @@
  *******************************************************************************/
 package org.eclipse.wst.html.ui.internal.text.correction;
 
+import java.util.HashSet;
+import java.util.Set;
+
 import org.eclipse.core.resources.IProject;
 import org.eclipse.core.resources.IResource;
 import org.eclipse.core.resources.ProjectScope;
@@ -23,6 +26,7 @@
 import org.eclipse.jface.text.IDocument;
 import org.eclipse.jface.text.contentassist.ICompletionProposal;
 import org.eclipse.jface.text.contentassist.IContextInformation;
+import org.eclipse.jface.window.Window;
 import org.eclipse.swt.graphics.Image;
 import org.eclipse.swt.graphics.Point;
 import org.eclipse.swt.widgets.Shell;
@@ -92,10 +96,12 @@
 		
 		StringBuffer ignoreList = new StringBuffer(originalAttributeNames);
 	
-		if (ignoreList.length() > 0)
-			ignoreList.append(',');
-		
-		ignoreList.append(fPattern);
+		if (!containsPattern(originalAttributeNames, fPattern)) { 
+			if (ignoreList.length() > 0)
+				ignoreList.append(',');
+			
+			ignoreList.append(fPattern.toLowerCase());
+		}
 
 		fLookupOrder[0].getNode(getPreferenceNodeQualifier())
 			.putBoolean(HTMLCorePreferenceNames.IGNORE_ATTRIBUTE_NAMES, true); 
@@ -103,26 +109,50 @@
 		fLookupOrder[0].getNode(getPreferenceNodeQualifier())
 			.put(HTMLCorePreferenceNames.ATTRIBUTE_NAMES_TO_IGNORE, ignoreList.toString()); 
 
-		for(int i = 0; i < fLookupOrder.length; i++) {
-			try {
-				fLookupOrder[i].getNode(getPreferenceNodeQualifier()).flush();
-			} catch (BackingStoreException e) {
-				Logger.logException(e);
-			}
-		}
-
 		PreferenceDialog dialog = hasProjectSettings ? 
 				PreferencesUtil.createPropertyDialogOn(getShell(), project, HTMLValidationPreferencePage.PROPERTY_PAGE_ID, null, null) :
 					PreferencesUtil.createPreferenceDialogOn(getShell(), HTMLValidationPreferencePage.PREFERENCE_PAGE_ID, null, null);
+
+		int result = Window.CANCEL;
 		if (dialog != null) {
 			Object page = dialog.getSelectedPage();
 			if (page instanceof HTMLValidationPreferencePage) {
 				((HTMLValidationPreferencePage)page).overrideOriginValues(originalEnableIgnore, originalAttributeNames);
 			}
-			dialog.open();
+			result = dialog.open();
+		}
+
+		if (Window.CANCEL == result) {
+			fLookupOrder[0].getNode(getPreferenceNodeQualifier())
+			.putBoolean(HTMLCorePreferenceNames.IGNORE_ATTRIBUTE_NAMES, originalEnableIgnore); 
+
+			fLookupOrder[0].getNode(getPreferenceNodeQualifier())
+				.put(HTMLCorePreferenceNames.ATTRIBUTE_NAMES_TO_IGNORE, originalAttributeNames); 
+		
+			for(int i = 0; i < fLookupOrder.length; i++) {
+				try {
+					fLookupOrder[i].getNode(getPreferenceNodeQualifier()).flush();
+				} catch (BackingStoreException e) {
+					Logger.logException(e);
+				}
+			}
 		}
 	}
 	
+	private boolean containsPattern(String ignoreList, String pattern) {
+		Set result = new HashSet();
+		if (ignoreList.trim().length() > 0) {
+			String[] names = ignoreList.split(","); //$NON-NLS-1$
+			for (int i = 0; names != null && i < names.length; i++) {
+				String name = names[i] == null ? null : names[i].trim();
+				if (name != null && name.length() > 0) 
+					result.add(name.toLowerCase());
+			}
+		}
+		return result.contains(pattern.toLowerCase());
+	}
+
+	
 	/*
 	 * @see ICompletionProposal#getDisplayString()
 	 */