Skip to main content
summaryrefslogtreecommitdiffstats
path: root/codan
diff options
context:
space:
mode:
authorAlena Laskavaia2010-05-24 11:05:39 -0400
committerAlena Laskavaia2010-05-24 11:05:39 -0400
commitc2919ed4f940f0e23aa90739bc9b7de13063ab24 (patch)
treef5cd1b898382c7e7c8c8e744166999e9066d126a /codan
parentfc70a0f70db7dff1e8bb335052e3bf0501cbfcd5 (diff)
downloadorg.eclipse.cdt-c2919ed4f940f0e23aa90739bc9b7de13063ab24.tar.gz
org.eclipse.cdt-c2919ed4f940f0e23aa90739bc9b7de13063ab24.tar.xz
org.eclipse.cdt-c2919ed4f940f0e23aa90739bc9b7de13063ab24.zip
Added scope preference for checkers
Diffstat (limited to 'codan')
-rw-r--r--codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java3
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java11
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java63
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/AbstractProblemPreference.java36
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/BasicProblemPreference.java21
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/FileScopeProblemPreference.java264
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/IProblemPreferenceDescriptor.java6
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/ListProblemPreference.java10
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/MapProblemPreference.java9
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CharOperation.java2703
-rw-r--r--codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java6
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java34
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemDialog.java32
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/ExclusionInclusionEntryDialog.java274
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/messages.properties50
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/CodanPreferencePage.java2
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/FileScopePreferencePage.java302
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/BasicElementLabels.java147
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/CustomizeProblemComposite.java (renamed from codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemComposite.java)22
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/FileScopeComposite.java100
-rw-r--r--codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/ParametersComposite.java (renamed from codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/ParametersComposite.java)33
21 files changed, 4069 insertions, 59 deletions
diff --git a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java
index bc2491583d..152887e0a8 100644
--- a/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java
+++ b/codan/org.eclipse.cdt.codan.core.cxx/src/org/eclipse/cdt/codan/core/cxx/model/AbstractIndexAstChecker.java
@@ -63,6 +63,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
}
public synchronized boolean processResource(IResource resource) {
+ if (!shouldProduceProblems(resource)) return false;
if (resource instanceof IFile) {
IFile file = (IFile) resource;
try {
@@ -102,7 +103,7 @@ public abstract class AbstractIndexAstChecker extends AbstractCheckerWithProblem
else
loc = getRuntime().getProblemLocationFactory()
.createProblemLocation(astFile, line);
- getProblemReporter().reportProblem(id, loc, args);
+ reportProblem(id, loc, args);
}
@Override
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java
index 469bab1f7c..ccdfe9297a 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractChecker.java
@@ -65,9 +65,9 @@ public abstract class AbstractChecker implements IChecker {
* - file in scope
* @return problem instance
*/
- public IProblem getProblemById(String id, IFile file) {
- IProblem problem = CheckersRegistry.getInstance().getResourceProfile(
- file).findProblem(id);
+ public IProblem getProblemById(String id, IResource file) {
+ IProblem problem = CheckersRegistry.getInstance()
+ .getResourceProfile(file).findProblem(id);
if (problem == null)
throw new IllegalArgumentException("Id is not registered"); //$NON-NLS-1$
return problem;
@@ -144,4 +144,9 @@ public abstract class AbstractChecker implements IChecker {
public boolean runInEditor() {
return this instanceof IRunnableInEditorChecker;
}
+
+ public void reportProblem(String problemId, IProblemLocation loc,
+ Object... args) {
+ getProblemReporter().reportProblem(problemId, loc, args);
+ }
}
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java
index da6836e0d0..1600da6007 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/model/AbstractCheckerWithProblemPreferences.java
@@ -10,11 +10,17 @@
*******************************************************************************/
package org.eclipse.cdt.codan.core.model;
+import java.util.Collection;
+import java.util.Iterator;
+
import org.eclipse.cdt.codan.core.param.BasicProblemPreference;
+import org.eclipse.cdt.codan.core.param.FileScopeProblemPreference;
import org.eclipse.cdt.codan.core.param.IProblemPreference;
import org.eclipse.cdt.codan.core.param.IProblemPreferenceDescriptor.PreferenceType;
import org.eclipse.cdt.codan.core.param.ListProblemPreference;
import org.eclipse.cdt.codan.core.param.MapProblemPreference;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
/**
* AbstarctChecker that has extra methods to simplify adding problem
@@ -28,7 +34,55 @@ public abstract class AbstractCheckerWithProblemPreferences extends
* Checker that actually has parameter must override this
*/
public void initPreferences(IProblemWorkingCopy problem) {
- // do nothing
+ // by default add file scope preference
+ addPreference(problem, new FileScopeProblemPreference(), null);
+ }
+
+ /**
+ * @param problem
+ * @return
+ */
+ public FileScopeProblemPreference getScopePreference(IProblem problem) {
+ FileScopeProblemPreference scope = (FileScopeProblemPreference) getTopLevelPreferenceMap(
+ problem).getChildDescriptor(FileScopeProblemPreference.KEY);
+ return scope;
+ }
+
+ /**
+ * User can scope out some resources for this checker. Checker can use this
+ * call to test if it should run on this resource at all or not. Test should
+ * be done within processResource method not in enabledInContext.
+ *
+ * @param res
+ * @return
+ */
+ public boolean shouldProduceProblems(IResource res) {
+ Collection<IProblem> refProblems = getRuntime().getChechersRegistry()
+ .getRefProblems(this);
+ for (Iterator<IProblem> iterator = refProblems.iterator(); iterator
+ .hasNext();) {
+ IProblem checkerProblem = iterator.next();
+ if (shouldProduceProblem(
+ getProblemById(checkerProblem.getId(), res),
+ res.getLocation()))
+ return true;
+ }
+ return false;
+ }
+
+ public boolean shouldProduceProblem(IProblem problem, IPath resource) {
+ FileScopeProblemPreference scope = getScopePreference(problem);
+ if (scope == null)
+ return true;
+ return scope.isInScope(resource);
+ }
+
+ @Override
+ public void reportProblem(String problemId, IProblemLocation loc,
+ Object... args) {
+ if (shouldProduceProblem(getProblemById(problemId, loc.getFile()), loc
+ .getFile().getLocation()))
+ super.reportProblem(problemId, loc, args);
}
/**
@@ -102,13 +156,14 @@ public abstract class AbstractCheckerWithProblemPreferences extends
* @param problem
* @return
*/
- protected MapProblemPreference getTopLevelPreferenceMap(
- IProblemWorkingCopy problem) {
+ protected MapProblemPreference getTopLevelPreferenceMap(IProblem problem) {
MapProblemPreference map = (MapProblemPreference) problem
.getPreference();
if (map == null) {
map = new MapProblemPreference("params", ""); //$NON-NLS-1$ //$NON-NLS-2$
- problem.setPreference(map);
+ if (problem instanceof IProblemWorkingCopy) {
+ ((IProblemWorkingCopy) problem).setPreference(map);
+ }
}
return map;
}
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/AbstractProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/AbstractProblemPreference.java
index a6a1e7ac9d..a5b6520b02 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/AbstractProblemPreference.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/AbstractProblemPreference.java
@@ -11,6 +11,7 @@
package org.eclipse.cdt.codan.core.param;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
@@ -150,6 +151,39 @@ public abstract class AbstractProblemPreference implements IProblemPreference {
/**
* @param tokenizer
* @return
+ * @throws IOException
*/
- public abstract void importValue(StreamTokenizer tokenizer);
+ public abstract void importValue(StreamTokenizer tokenizer)
+ throws IOException;
+
+ public void importValue(String str) {
+ StreamTokenizer tokenizer = getImportTokenizer(str);
+ try {
+ importValue(tokenizer);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException(str, e);
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ protected String escape(String x) {
+ x = x.replaceAll("[\"\\\\]", "\\\\$0"); //$NON-NLS-1$//$NON-NLS-2$
+ return "\"" + x + "\""; //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ /**
+ * @param str
+ * @return
+ */
+ protected String unescape(String str) {
+ StreamTokenizer tokenizer = getImportTokenizer(str);
+ try {
+ tokenizer.nextToken();
+ } catch (IOException e) {
+ return null;
+ }
+ String sval = tokenizer.sval;
+ return sval;
+ }
}
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/BasicProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/BasicProblemPreference.java
index f1e40f10e2..a6a0a7f14f 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/BasicProblemPreference.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/BasicProblemPreference.java
@@ -81,11 +81,6 @@ public class BasicProblemPreference extends AbstractProblemPreference {
return x;
}
- protected String escape(String x) {
- x = x.replaceAll("[\"\\\\]", "\\\\$0"); //$NON-NLS-1$//$NON-NLS-2$
- return "\"" + x + "\""; //$NON-NLS-1$//$NON-NLS-2$
- }
-
/*
* (non-Javadoc)
*
@@ -93,6 +88,7 @@ public class BasicProblemPreference extends AbstractProblemPreference {
* org.eclipse.cdt.codan.core.param.IProblemPreferenceValue#importValue(
* java.lang.String)
*/
+ @Override
public void importValue(String str) {
if (str.startsWith("\"")) //$NON-NLS-1$
str = unescape(str);
@@ -115,21 +111,6 @@ public class BasicProblemPreference extends AbstractProblemPreference {
}
}
- /**
- * @param str
- * @return
- */
- protected String unescape(String str) {
- StreamTokenizer tokenizer = getImportTokenizer(str);
- try {
- tokenizer.nextToken();
- } catch (IOException e) {
- return null;
- }
- String sval = tokenizer.sval;
- return sval;
- }
-
@Override
public String toString() {
return "(" + type + ")" + key + ((value == null) ? "" : "=" + value); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$//$NON-NLS-4$
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/FileScopeProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/FileScopeProblemPreference.java
new file mode 100644
index 0000000000..a75ebee4af
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/FileScopeProblemPreference.java
@@ -0,0 +1,264 @@
+/*******************************************************************************
+ * Copyright (c) 2009,2010 QNX Software Systems
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * QNX Software Systems (Alena Laskavaia) - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.codan.core.param;
+
+import java.io.IOException;
+import java.io.StreamTokenizer;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.eclipse.cdt.codan.internal.core.CharOperation;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspace;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * TODO: add description
+ */
+public class FileScopeProblemPreference extends AbstractProblemPreference {
+ public static final String KEY = "fileScope"; //$NON-NLS-1$
+ public static final String EXCLUSION = "exclusion"; //$NON-NLS-1$
+ public static final String INCLUSION = "inclusion"; //$NON-NLS-1$
+ private IResource resource;
+ private IPath[] inclusion = new IPath[0];
+ private IPath[] exclusion = new IPath[0];
+
+ public FileScopeProblemPreference() {
+ setKey(KEY);
+ setLabel("File Exclusion and Inclusion");
+ setType(PreferenceType.TYPE_CUSTOM);
+ }
+
+ /**
+ * @param key
+ * @return
+ */
+ public IPath[] getAttribute(String key) {
+ if (key == EXCLUSION)
+ return exclusion;
+ if (key == INCLUSION)
+ return inclusion;
+ return null;
+ }
+
+ public void setAttribute(String key, IPath[] value) {
+ if (key == EXCLUSION)
+ exclusion = value.clone();
+ if (key == INCLUSION)
+ inclusion = value.clone();
+ }
+
+ /**
+ * @return
+ */
+ public IProject getProject() {
+ if (resource != null)
+ return resource.getProject();
+ return null;
+ }
+
+ /**
+ * @return
+ */
+ public IPath getPath() {
+ if (resource != null)
+ return resource.getFullPath();
+ IWorkspace workspace = ResourcesPlugin.getWorkspace();
+ IWorkspaceRoot root = workspace.getRoot();
+ return root.getFullPath();
+ }
+
+ /**
+ * @param resource
+ * the resource to set
+ */
+ public void setResource(IResource resource) {
+ this.resource = resource;
+ }
+
+ /**
+ * @return the resource
+ */
+ public IResource getResource() {
+ return resource;
+ }
+
+ public String exportValue() {
+ return exportPathList(INCLUSION, inclusion) + "," //$NON-NLS-1$
+ + exportPathList(EXCLUSION, exclusion);
+ }
+
+ /**
+ * @param inclusion2
+ * @param inclusion3
+ * @return
+ */
+ private String exportPathList(String key, IPath[] arr) {
+ String res = key + "=>("; //$NON-NLS-1$
+ for (int i = 0; i < arr.length; i++) {
+ if (i != 0)
+ res += ","; //$NON-NLS-1$
+ res += escape(arr[i].toPortableString());
+ }
+ return res + ")"; //$NON-NLS-1$
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.cdt.codan.core.param.AbstractProblemPreference#importValue
+ * (java.io.StreamTokenizer)
+ */
+ @Override
+ public void importValue(StreamTokenizer tokenizer) throws IOException {
+ List<IPath> inc = importPathList(tokenizer, INCLUSION);
+ inclusion = inc.toArray(new IPath[inc.size()]);
+ checkChar(tokenizer, ',');
+ List<IPath> exc = importPathList(tokenizer, EXCLUSION);
+ exclusion = exc.toArray(new IPath[exc.size()]);
+ }
+
+ /**
+ * @param tokenizer
+ * @param c
+ * @throws IOException
+ */
+ private void checkChar(StreamTokenizer tokenizer, char c)
+ throws IOException {
+ tokenizer.nextToken();
+ if (tokenizer.ttype != c)
+ throw new IllegalArgumentException("Expected " + c); //$NON-NLS-1$
+ }
+
+ /**
+ * @param tokenizer
+ * @param inclusion2
+ * @throws IOException
+ * @throws IllegalAccessException
+ */
+ private void checkKeyword(StreamTokenizer tokenizer, String keyword)
+ throws IOException {
+ tokenizer.nextToken();
+ if (tokenizer.sval == null || !tokenizer.sval.equals(keyword))
+ throw new IllegalArgumentException("Expected " + keyword); //$NON-NLS-1$
+ }
+
+ protected List<IPath> importPathList(StreamTokenizer tokenizer,
+ String keyword) throws IOException {
+ checkKeyword(tokenizer, keyword);
+ checkChar(tokenizer, '=');
+ checkChar(tokenizer, '>');
+ ArrayList<IPath> list = new ArrayList<IPath>();
+ int token;
+ int index = 0;
+ try {
+ checkChar(tokenizer, '(');
+ token = tokenizer.nextToken();
+ if (token != ')')
+ tokenizer.pushBack();
+ else
+ return Collections.emptyList();
+ while (true) {
+ token = tokenizer.nextToken();
+ if (tokenizer.sval == null)
+ throw new IllegalArgumentException();
+ list.add(new Path(tokenizer.sval));
+ token = tokenizer.nextToken();
+ if (token == ')')
+ break;
+ tokenizer.pushBack();
+ checkChar(tokenizer, ',');
+ index++;
+ }
+ } catch (IOException e) {
+ throw new IllegalArgumentException(e);
+ }
+ return list;
+ }
+
+ @Override
+ public Object getValue() {
+ return this;
+ }
+
+ @Override
+ public void setValue(Object value) {
+ if (this == value)
+ return;
+ FileScopeProblemPreference scope = (FileScopeProblemPreference) value;
+ setAttribute(INCLUSION, scope.getAttribute(INCLUSION));
+ setAttribute(EXCLUSION, scope.getAttribute(EXCLUSION));
+ this.resource = scope.getResource();
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.cdt.codan.core.param.AbstractProblemPreference#clone()
+ */
+ @Override
+ public Object clone() {
+ FileScopeProblemPreference scope = (FileScopeProblemPreference) super
+ .clone();
+ scope.setValue(this);
+ return scope;
+ }
+
+ /**
+ * @param file
+ * @return
+ */
+ public boolean isInScope(IPath file) {
+ //System.err.println("test " + file + " " + exportValue());
+ if (inclusion.length > 0) {
+ if (!matchesFilter(file, inclusion))
+ return false;
+ }
+ if (exclusion.length > 0) {
+ if (matchesFilter(file, exclusion))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @param resourcePath
+ * @param inclusion2
+ * @return
+ */
+ private boolean matchesFilter(IPath resourcePath, IPath[] paths) {
+ char[] path = resourcePath.toString().toCharArray();
+ for (int i = 0, length = paths.length; i < length; i++) {
+ char[] pattern = paths[i].toString().toCharArray();
+ if (CharOperation.pathMatch(pattern, path, true, '/')) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static boolean isExcludedPath(IPath resourcePath, IPath[] paths) {
+ char[] path = resourcePath.toString().toCharArray();
+ for (int i = 0, length = paths.length; i < length; i++) {
+ char[] pattern = paths[i].toString().toCharArray();
+ if (CharOperation.pathMatch(pattern, path, true, '/')) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/IProblemPreferenceDescriptor.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/IProblemPreferenceDescriptor.java
index a0b8700474..53f1440ec4 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/IProblemPreferenceDescriptor.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/IProblemPreferenceDescriptor.java
@@ -36,7 +36,8 @@ public interface IProblemPreferenceDescriptor extends Cloneable {
TYPE_BOOLEAN("boolean"), //$NON-NLS-1$
TYPE_FILE("file"), //$NON-NLS-1$
TYPE_LIST("list"), //$NON-NLS-1$
- TYPE_MAP("map"); //$NON-NLS-1$
+ TYPE_MAP("map"), //$NON-NLS-1$
+ TYPE_CUSTOM("custom"); //$NON-NLS-1$
private String literal;
private PreferenceType(String literal) {
@@ -75,8 +76,7 @@ public interface IProblemPreferenceDescriptor extends Cloneable {
return TYPE_LIST;
if (value instanceof Map)
return TYPE_MAP;
- throw new IllegalArgumentException(
- "Cannot determine type for " + value.getClass()); //$NON-NLS-1$
+ return TYPE_CUSTOM;
}
}
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/ListProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/ListProblemPreference.java
index 48d1c15414..e9ccf74a61 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/ListProblemPreference.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/ListProblemPreference.java
@@ -157,11 +157,16 @@ public class ListProblemPreference extends AbstractProblemPreference implements
list.remove(index);
}
- @SuppressWarnings("unchecked")
@Override
public Object clone() {
ListProblemPreference list1 = (ListProblemPreference) super.clone();
- list1.list = (ArrayList<Object>) list.clone();
+ list1.list = new ArrayList<Object>();
+ list1.setChildDescriptor((IProblemPreference) getChildDescriptor()
+ .clone());
+ for (Iterator<Object> iterator = list.iterator(); iterator.hasNext();) {
+ Object value = iterator.next();
+ list1.addChildValue(value);
+ }
return list1;
}
@@ -177,6 +182,7 @@ public class ListProblemPreference extends AbstractProblemPreference implements
return buf.toString() + ")"; //$NON-NLS-1$
}
+ @Override
public void importValue(String str) {
StreamTokenizer tokenizer = getImportTokenizer(str);
try {
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/MapProblemPreference.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/MapProblemPreference.java
index 26469db51a..acf474e6f1 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/MapProblemPreference.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/core/param/MapProblemPreference.java
@@ -98,11 +98,15 @@ public class MapProblemPreference extends AbstractProblemPreference implements
hash.remove(key);
}
- @SuppressWarnings("unchecked")
@Override
public Object clone() {
MapProblemPreference map = (MapProblemPreference) super.clone();
- map.hash = (LinkedHashMap<String, IProblemPreference>) hash.clone();
+ map.hash = new LinkedHashMap<String, IProblemPreference>();
+ for (Iterator<String> iterator = hash.keySet().iterator(); iterator
+ .hasNext();) {
+ String key = iterator.next();
+ map.hash.put(key, (IProblemPreference) hash.get(key).clone());
+ }
return map;
}
@@ -119,6 +123,7 @@ public class MapProblemPreference extends AbstractProblemPreference implements
return buf.toString() + "}"; //$NON-NLS-1$
}
+ @Override
public void importValue(String str) {
StreamTokenizer tokenizer = getImportTokenizer(str);
try {
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CharOperation.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CharOperation.java
new file mode 100644
index 0000000000..8134610d0f
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/CharOperation.java
@@ -0,0 +1,2703 @@
+package org.eclipse.cdt.codan.internal.core;
+
+/**
+ * This class is a collection of helper methods to manipulate char arrays.
+ *
+ * @since 2.1
+ */
+public final class CharOperation {
+ /**
+ * Constant for an empty char array
+ */
+ public static final char[] NO_CHAR = new char[0];
+ /**
+ * Constant for an empty char array with two dimensions.
+ */
+ public static final char[][] NO_CHAR_CHAR = new char[0][];
+
+ /**
+ * Answers a new array with appending the suffix character at the end of the
+ * array.
+ * <br>
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * array = { 'a', 'b' }
+ * suffix = 'c'
+ * => result = { 'a', 'b' , 'c' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = null
+ * suffix = 'c'
+ * => result = { 'c' }
+ * </pre></li>
+ * </ol>
+ *
+ * @param array
+ * the array that is concanated with the suffix character
+ * @param suffix
+ * the suffix character
+ * @return the new array
+ */
+ public static final char[] append(char[] array, char suffix) {
+ if (array == null)
+ return new char[] { suffix };
+ int length = array.length;
+ System.arraycopy(array, 0, array = new char[length + 1], 0, length);
+ array[length] = suffix;
+ return array;
+ }
+
+ /**
+ * Append the given subarray to the target array starting at the given index
+ * in the target array.
+ * The start of the subarray is inclusive, the end is exclusive.
+ * Answers a new target array if it needs to grow, otherwise answers the
+ * same target array.
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * target = { 'a', 'b', '0' }
+ * index = 2
+ * array = { 'c', 'd' }
+ * start = 0
+ * end = 1
+ * => result = { 'a', 'b' , 'c' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * target = { 'a', 'b' }
+ * index = 2
+ * array = { 'c', 'd' }
+ * start = 0
+ * end = 1
+ * => result = { 'a', 'b' , 'c', '0', '0' , '0' } (new array)
+ * </pre></li>
+ * <li><pre>
+ * target = { 'a', 'b', 'c' }
+ * index = 1
+ * array = { 'c', 'd', 'e', 'f' }
+ * start = 1
+ * end = 4
+ * => result = { 'a', 'd' , 'e', 'f', '0', '0', '0', '0' } (new array)
+ * </pre></li>
+ * </ol>
+ *
+ * @param target
+ * the given target
+ * @param index
+ * the given index
+ * @param array
+ * the given array
+ * @param start
+ * the given start index
+ * @param end
+ * the given end index
+ *
+ * @return the new array
+ * @throws NullPointerException
+ * if the target array is null
+ */
+ public static final char[] append(char[] target, int index, char[] array,
+ int start, int end) {
+ int targetLength = target.length;
+ int subLength = end - start;
+ int newTargetLength = subLength + index;
+ if (newTargetLength > targetLength) {
+ System.arraycopy(target, 0, target = new char[newTargetLength * 2],
+ 0, index);
+ }
+ System.arraycopy(array, start, target, index, subLength);
+ return target;
+ }
+
+ /**
+ * Answers the concatenation of the two arrays. It answers null if the two
+ * arrays are null.
+ * If the first array is null, then the second array is returned.
+ * If the second array is null, then the first array is returned.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = null
+ * => result = null
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { ' a' } }
+ * second = null
+ * => result = { { ' a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = null
+ * second = { { ' a' } }
+ * => result = { { ' a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { ' b' } }
+ * second = { { ' a' } }
+ * => result = { { ' b' }, { ' a' } }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array to concatenate
+ * @param second
+ * the second array to concatenate
+ * @return the concatenation of the two arrays, or null if the two arrays
+ * are null.
+ */
+ public static final char[][] arrayConcat(char[][] first, char[][] second) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+ int length1 = first.length;
+ int length2 = second.length;
+ char[][] result = new char[length1 + length2][];
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ return result;
+ }
+
+ /**
+ * Answers a new array adding the second array at the end of first array.
+ * It answers null if the first and second are null.
+ * If the first array is null, then a new array char[][] is created with
+ * second.
+ * If the second array is null, then the first array is returned.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = { 'a' }
+ * => result = { { ' a' } }
+ * </pre>
+ * <li><pre>
+ * first = { { ' a' } }
+ * second = null
+ * => result = { { ' a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { ' a' } }
+ * second = { ' b' }
+ * => result = { { ' a' } , { ' b' } }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array to concatenate
+ * @param second
+ * the array to add at the end of the first array
+ * @return a new array adding the second array at the end of first array, or
+ * null if the two arrays are null.
+ */
+ public static final char[][] arrayConcat(char[][] first, char[] second) {
+ if (second == null)
+ return first;
+ if (first == null)
+ return new char[][] { second };
+ int length = first.length;
+ char[][] result = new char[length + 1][];
+ System.arraycopy(first, 0, result, 0, length);
+ result[length] = second;
+ return result;
+ }
+
+ /**
+ * Compares the contents of the two arrays array and prefix. Returns
+ * <ul>
+ * <li>zero if the array starts with the prefix contents</li>
+ * <li>the difference between the first two characters that are not equal
+ * </li>
+ * <li>one if array length is lower than the prefix length and that the
+ * prefix starts with the
+ * array contents.</li>
+ * </ul>
+ * <p>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = null
+ * prefix = null
+ * => result = NullPointerException
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a', 'b', 'c', 'd', 'e' }
+ * prefix = { 'a', 'b', 'c'}
+ * => result = 0
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a', 'b', 'c', 'd', 'e' }
+ * prefix = { 'a', 'B', 'c'}
+ * => result = 32
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'd', 'b', 'c', 'd', 'e' }
+ * prefix = { 'a', 'b', 'c'}
+ * => result = 3
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a', 'b', 'c', 'd', 'e' }
+ * prefix = { 'd', 'b', 'c'}
+ * => result = -3
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a', 'a', 'c', 'd', 'e' }
+ * prefix = { 'a', 'e', 'c'}
+ * => result = -4
+ * </pre>
+ * </li>
+ * </ol>
+ * </p>
+ *
+ * @param array
+ * the given array
+ * @param prefix
+ * the given prefix
+ * @return the result of the comparison
+ * @exception NullPointerException
+ * if either array or prefix is null
+ */
+ public static final int compareWith(char[] array, char[] prefix) {
+ int arrayLength = array.length;
+ int prefixLength = prefix.length;
+ int min = Math.min(arrayLength, prefixLength);
+ int i = 0;
+ while (min-- != 0) {
+ char c1 = array[i];
+ char c2 = prefix[i++];
+ if (c1 != c2)
+ return c1 - c2;
+ }
+ if (prefixLength == i)
+ return 0;
+ return 1;
+ }
+
+ /**
+ * Answers the concatenation of the two arrays. It answers null if the two
+ * arrays are null.
+ * If the first array is null, then the second array is returned.
+ * If the second array is null, then the first array is returned.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = { 'a' }
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = null
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = { ' b' }
+ * => result = { ' a' , ' b' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array to concatenate
+ * @param second
+ * the second array to concatenate
+ * @return the concatenation of the two arrays, or null if the two arrays
+ * are null.
+ */
+ public static final char[] concat(char[] first, char[] second) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+ int length1 = first.length;
+ int length2 = second.length;
+ char[] result = new char[length1 + length2];
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ return result;
+ }
+
+ /**
+ * Answers the concatenation of the three arrays. It answers null if the
+ * three arrays are null.
+ * If first is null, it answers the concatenation of second and third.
+ * If second is null, it answers the concatenation of first and third.
+ * If third is null, it answers the concatenation of first and second.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = { 'a' }
+ * third = { 'b' }
+ * => result = { ' a', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * second = null
+ * third = { 'b' }
+ * => result = { ' a', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * second = { 'b' }
+ * third = null
+ * => result = { ' a', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = null
+ * second = null
+ * third = null
+ * => result = null
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * second = { 'b' }
+ * third = { 'c' }
+ * => result = { 'a', 'b', 'c' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array to concatenate
+ * @param second
+ * the second array to concatenate
+ * @param third
+ * the third array to concatenate
+ *
+ * @return the concatenation of the three arrays, or null if the three
+ * arrays are null.
+ */
+ public static final char[] concat(char[] first, char[] second, char[] third) {
+ if (first == null)
+ return concat(second, third);
+ if (second == null)
+ return concat(first, third);
+ if (third == null)
+ return concat(first, second);
+ int length1 = first.length;
+ int length2 = second.length;
+ int length3 = third.length;
+ char[] result = new char[length1 + length2 + length3];
+ System.arraycopy(first, 0, result, 0, length1);
+ System.arraycopy(second, 0, result, length1, length2);
+ System.arraycopy(third, 0, result, length1 + length2, length3);
+ return result;
+ }
+
+ /**
+ * Answers the concatenation of the two arrays inserting the separator
+ * character between the two arrays.
+ * It answers null if the two arrays are null.
+ * If the first array is null, then the second array is returned.
+ * If the second array is null, then the first array is returned.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = { 'a' }
+ * separator = '/'
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = null
+ * separator = '/'
+ * => result = { ' a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { ' a' }
+ * second = { ' b' }
+ * separator = '/'
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array to concatenate
+ * @param second
+ * the second array to concatenate
+ * @param separator
+ * the character to insert
+ * @return the concatenation of the two arrays inserting the separator
+ * character
+ * between the two arrays , or null if the two arrays are null.
+ */
+ public static final char[] concat(char[] first, char[] second,
+ char separator) {
+ if (first == null)
+ return second;
+ if (second == null)
+ return first;
+ int length1 = first.length;
+ if (length1 == 0)
+ return second;
+ int length2 = second.length;
+ if (length2 == 0)
+ return first;
+ char[] result = new char[length1 + length2 + 1];
+ System.arraycopy(first, 0, result, 0, length1);
+ result[length1] = separator;
+ System.arraycopy(second, 0, result, length1 + 1, length2);
+ return result;
+ }
+
+ /**
+ * Answers the concatenation of the three arrays inserting the sep1
+ * character between the
+ * two arrays and sep2 between the last two.
+ * It answers null if the three arrays are null.
+ * If the first array is null, then it answers the concatenation of second
+ * and third inserting
+ * the sep2 character between them.
+ * If the second array is null, then it answers the concatenation of first
+ * and third inserting
+ * the sep1 character between them.
+ * If the third array is null, then it answers the concatenation of first
+ * and second inserting
+ * the sep1 character between them.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * sep1 = '/'
+ * second = { 'a' }
+ * sep2 = ':'
+ * third = { 'b' }
+ * => result = { ' a' , ':', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = null
+ * sep2 = ':'
+ * third = { 'b' }
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = { 'b' }
+ * sep2 = ':'
+ * third = null
+ * => result = { ' a' , '/', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * sep1 = '/'
+ * second = { 'b' }
+ * sep2 = ':'
+ * third = { 'c' }
+ * => result = { ' a' , '/', 'b' , ':', 'c' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array to concatenate
+ * @param sep1
+ * the character to insert
+ * @param second
+ * the second array to concatenate
+ * @param sep2
+ * the character to insert
+ * @param third
+ * the second array to concatenate
+ * @return the concatenation of the three arrays inserting the sep1
+ * character between the
+ * two arrays and sep2 between the last two.
+ */
+ public static final char[] concat(char[] first, char sep1, char[] second,
+ char sep2, char[] third) {
+ if (first == null)
+ return concat(second, third, sep2);
+ if (second == null)
+ return concat(first, third, sep1);
+ if (third == null)
+ return concat(first, second, sep1);
+ int length1 = first.length;
+ int length2 = second.length;
+ int length3 = third.length;
+ char[] result = new char[length1 + length2 + length3 + 2];
+ System.arraycopy(first, 0, result, 0, length1);
+ result[length1] = sep1;
+ System.arraycopy(second, 0, result, length1 + 1, length2);
+ result[length1 + length2 + 1] = sep2;
+ System.arraycopy(third, 0, result, length1 + length2 + 2, length3);
+ return result;
+ }
+
+ /**
+ * Answers a new array with prepending the prefix character and appending
+ * the suffix
+ * character at the end of the array. If array is null, it answers a new
+ * array containing the
+ * prefix and the suffix characters.
+ * <br>
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * prefix = 'a'
+ * array = { 'b' }
+ * suffix = 'c'
+ * => result = { 'a', 'b' , 'c' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * prefix = 'a'
+ * array = null
+ * suffix = 'c'
+ * => result = { 'a', 'c' }
+ * </pre></li>
+ * </ol>
+ *
+ * @param prefix
+ * the prefix character
+ * @param array
+ * the array that is concanated with the prefix and suffix
+ * characters
+ * @param suffix
+ * the suffix character
+ * @return the new array
+ */
+ public static final char[] concat(char prefix, char[] array, char suffix) {
+ if (array == null)
+ return new char[] { prefix, suffix };
+ int length = array.length;
+ char[] result = new char[length + 2];
+ result[0] = prefix;
+ System.arraycopy(array, 0, result, 1, length);
+ result[length + 1] = suffix;
+ return result;
+ }
+
+ /**
+ * Answers the concatenation of the given array parts using the given
+ * separator between each
+ * part and appending the given name at the end.
+ * <br>
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * name = { 'c' }
+ * array = { { 'a' }, { 'b' } }
+ * separator = '.'
+ * => result = { 'a', '.', 'b' , '.', 'c' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * name = null
+ * array = { { 'a' }, { 'b' } }
+ * separator = '.'
+ * => result = { 'a', '.', 'b' }
+ * </pre></li>
+ * <li><pre>
+ * name = { ' c' }
+ * array = null
+ * separator = '.'
+ * => result = { 'c' }
+ * </pre></li>
+ * </ol>
+ *
+ * @param name
+ * the given name
+ * @param array
+ * the given array
+ * @param separator
+ * the given separator
+ * @return the concatenation of the given array parts using the given
+ * separator between each
+ * part and appending the given name at the end
+ */
+ public static final char[] concatWith(char[] name, char[][] array,
+ char separator) {
+ int nameLength = name == null ? 0 : name.length;
+ if (nameLength == 0)
+ return concatWith(array, separator);
+ if (array == null)
+ return name;
+ final int length = array.length;
+ if (length == 0)
+ return name;
+ int size = nameLength;
+ int index = length;
+ while (--index >= 0)
+ if (array[index].length > 0)
+ size += array[index].length + 1;
+ char[] result = new char[size];
+ index = size;
+ for (int i = length - 1; i >= 0; i--) {
+ int subLength = array[i].length;
+ if (subLength > 0) {
+ index -= subLength;
+ System.arraycopy(array[i], 0, result, index, subLength);
+ result[--index] = separator;
+ }
+ }
+ System.arraycopy(name, 0, result, 0, nameLength);
+ return result;
+ }
+
+ /**
+ * Answers the concatenation of the given array parts using the given
+ * separator between each
+ * part and appending the given name at the end.
+ * <br>
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * name = { 'c' }
+ * array = { { 'a' }, { 'b' } }
+ * separator = '.'
+ * => result = { 'a', '.', 'b' , '.', 'c' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * name = null
+ * array = { { 'a' }, { 'b' } }
+ * separator = '.'
+ * => result = { 'a', '.', 'b' }
+ * </pre></li>
+ * <li><pre>
+ * name = { ' c' }
+ * array = null
+ * separator = '.'
+ * => result = { 'c' }
+ * </pre></li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @param name
+ * the given name
+ * @param separator
+ * the given separator
+ * @return the concatenation of the given array parts using the given
+ * separator between each
+ * part and appending the given name at the end
+ */
+ public static final char[] concatWith(char[][] array, char[] name,
+ char separator) {
+ int nameLength = name == null ? 0 : name.length;
+ if (nameLength == 0)
+ return concatWith(array, separator);
+ if (array == null)
+ return name;
+ final int length = array.length;
+ if (length == 0)
+ return name;
+ int size = nameLength;
+ int index = length;
+ while (--index >= 0)
+ if (array[index].length > 0)
+ size += array[index].length + 1;
+ char[] result = new char[size];
+ index = 0;
+ for (int i = 0; i < length; i++) {
+ int subLength = array[i].length;
+ if (subLength > 0) {
+ System.arraycopy(array[i], 0, result, index, subLength);
+ index += subLength;
+ result[index++] = separator;
+ }
+ }
+ System.arraycopy(name, 0, result, index, nameLength);
+ return result;
+ }
+
+ /**
+ * Answers the concatenation of the given array parts using the given
+ * separator between each part.
+ * <br>
+ * <br>
+ * For example:<br>
+ * <ol>
+ * <li><pre>
+ * array = { { 'a' }, { 'b' } }
+ * separator = '.'
+ * => result = { 'a', '.', 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = null
+ * separator = '.'
+ * => result = { }
+ * </pre></li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @param separator
+ * the given separator
+ * @return the concatenation of the given array parts using the given
+ * separator between each part
+ */
+ public static final char[] concatWith(char[][] array, char separator) {
+ if (array == null)
+ return CharOperation.NO_CHAR;
+ int length = array.length;
+ if (length == 0)
+ return CharOperation.NO_CHAR;
+ int size = length - 1;
+ int index = length;
+ while (--index >= 0) {
+ if (array[index].length == 0)
+ size--;
+ else
+ size += array[index].length;
+ }
+ if (size <= 0)
+ return CharOperation.NO_CHAR;
+ char[] result = new char[size];
+ index = length;
+ while (--index >= 0) {
+ length = array[index].length;
+ if (length > 0) {
+ System.arraycopy(array[index], 0, result, (size -= length),
+ length);
+ if (--size >= 0)
+ result[size] = separator;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Answers true if the array contains an occurrence of character, false
+ * otherwise.
+ *
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * character = 'c'
+ * array = { { ' a' }, { ' b' } }
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * character = 'a'
+ * array = { { ' a' }, { ' b' } }
+ * result => true
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param character
+ * the character to search
+ * @param array
+ * the array in which the search is done
+ * @return true if the array contains an occurrence of character, false
+ * otherwise.
+ * @exception NullPointerException
+ * if array is null.
+ */
+ public static final boolean contains(char character, char[][] array) {
+ for (int i = array.length; --i >= 0;) {
+ char[] subarray = array[i];
+ for (int j = subarray.length; --j >= 0;)
+ if (subarray[j] == character)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Answers true if the array contains an occurrence of character, false
+ * otherwise.
+ *
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * character = 'c'
+ * array = { ' b' }
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * character = 'a'
+ * array = { ' a' , ' b' }
+ * result => true
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param character
+ * the character to search
+ * @param array
+ * the array in which the search is done
+ * @return true if the array contains an occurrence of character, false
+ * otherwise.
+ * @exception NullPointerException
+ * if array is null.
+ */
+ public static final boolean contains(char character, char[] array) {
+ for (int i = array.length; --i >= 0;)
+ if (array[i] == character)
+ return true;
+ return false;
+ }
+
+ /**
+ * Answers a deep copy of the toCopy array.
+ *
+ * @param toCopy
+ * the array to copy
+ * @return a deep copy of the toCopy array.
+ */
+ public static final char[][] deepCopy(char[][] toCopy) {
+ int toCopyLength = toCopy.length;
+ char[][] result = new char[toCopyLength][];
+ for (int i = 0; i < toCopyLength; i++) {
+ char[] toElement = toCopy[i];
+ int toElementLength = toElement.length;
+ char[] resultElement = new char[toElementLength];
+ System.arraycopy(toElement, 0, resultElement, 0, toElementLength);
+ result[i] = resultElement;
+ }
+ return result;
+ }
+
+ /**
+ * Return true if array ends with the sequence of characters contained in
+ * toBeFound,
+ * otherwise false.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { 'a', 'b', 'c', 'd' }
+ * toBeFound = { 'b', 'c' }
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a', 'b', 'c' }
+ * toBeFound = { 'b', 'c' }
+ * result => true
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array
+ * the array to check
+ * @param toBeFound
+ * the array to find
+ * @return true if array ends with the sequence of characters contained in
+ * toBeFound,
+ * otherwise false.
+ * @exception NullPointerException
+ * if array is null or toBeFound is null
+ */
+ public static final boolean endsWith(char[] array, char[] toBeFound) {
+ int i = toBeFound.length;
+ int j = array.length - i;
+ if (j < 0)
+ return false;
+ while (--i >= 0)
+ if (toBeFound[i] != array[i + j])
+ return false;
+ return true;
+ }
+
+ /**
+ * Answers true if the two arrays are identical character by character,
+ * otherwise false.
+ * The equality is case sensitive.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = null
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { } }
+ * second = null
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { 'a' } }
+ * second = { { 'a' } }
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { 'A' } }
+ * second = { { 'a' } }
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array
+ * @param second
+ * the second array
+ * @return true if the two arrays are identical character by character,
+ * otherwise false
+ */
+ public static final boolean equals(char[][] first, char[][] second) {
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+ for (int i = first.length; --i >= 0;)
+ if (!equals(first[i], second[i]))
+ return false;
+ return true;
+ }
+
+ /**
+ * If isCaseSensite is true, answers true if the two arrays are identical
+ * character
+ * by character, otherwise false.
+ * If it is false, answers true if the two arrays are identical character by
+ * character without checking the case, otherwise false.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = null
+ * isCaseSensitive = true
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { } }
+ * second = null
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { 'A' } }
+ * second = { { 'a' } }
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { { 'A' } }
+ * second = { { 'a' } }
+ * isCaseSensitive = false
+ * result => true
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array
+ * @param second
+ * the second array
+ * @param isCaseSensitive
+ * check whether or not the equality should be case sensitive
+ * @return true if the two arrays are identical character by character
+ * according to the value
+ * of isCaseSensitive, otherwise false
+ */
+ public static final boolean equals(char[][] first, char[][] second,
+ boolean isCaseSensitive) {
+ if (isCaseSensitive) {
+ return equals(first, second);
+ }
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+ for (int i = first.length; --i >= 0;)
+ if (!equals(first[i], second[i], false))
+ return false;
+ return true;
+ }
+
+ /**
+ * Answers true if the two arrays are identical character by character,
+ * otherwise false.
+ * The equality is case sensitive.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = null
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { }
+ * second = null
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * second = { 'a' }
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'a' }
+ * second = { 'A' }
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array
+ * @param second
+ * the second array
+ * @return true if the two arrays are identical character by character,
+ * otherwise false
+ */
+ public static final boolean equals(char[] first, char[] second) {
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+ for (int i = first.length; --i >= 0;)
+ if (first[i] != second[i])
+ return false;
+ return true;
+ }
+
+ /**
+ * If isCaseSensite is true, answers true if the two arrays are identical
+ * character
+ * by character, otherwise false.
+ * If it is false, answers true if the two arrays are identical character by
+ * character without checking the case, otherwise false.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * first = null
+ * second = null
+ * isCaseSensitive = true
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { }
+ * second = null
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'A' }
+ * second = { 'a' }
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * first = { 'A' }
+ * second = { 'a' }
+ * isCaseSensitive = false
+ * result => true
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param first
+ * the first array
+ * @param second
+ * the second array
+ * @param isCaseSensitive
+ * check whether or not the equality should be case sensitive
+ * @return true if the two arrays are identical character by character
+ * according to the value
+ * of isCaseSensitive, otherwise false
+ */
+ public static final boolean equals(char[] first, char[] second,
+ boolean isCaseSensitive) {
+ if (isCaseSensitive) {
+ return equals(first, second);
+ }
+ if (first == second)
+ return true;
+ if (first == null || second == null)
+ return false;
+ if (first.length != second.length)
+ return false;
+ for (int i = first.length; --i >= 0;)
+ if (Character.toLowerCase(first[i]) != Character
+ .toLowerCase(second[i]))
+ return false;
+ return true;
+ }
+
+ /**
+ * If isCaseSensite is true, the equality is case sensitive, otherwise it is
+ * case insensitive.
+ *
+ * Answers true if the name contains the fragment at the starting index
+ * startIndex, otherwise false.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * fragment = { 'b', 'c' , 'd' }
+ * name = { 'a', 'b', 'c' , 'd' }
+ * startIndex = 1
+ * isCaseSensitive = true
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * fragment = { 'b', 'c' , 'd' }
+ * name = { 'a', 'b', 'C' , 'd' }
+ * startIndex = 1
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * fragment = { 'b', 'c' , 'd' }
+ * name = { 'a', 'b', 'C' , 'd' }
+ * startIndex = 0
+ * isCaseSensitive = false
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * fragment = { 'b', 'c' , 'd' }
+ * name = { 'a', 'b'}
+ * startIndex = 0
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param fragment
+ * the fragment to check
+ * @param name
+ * the array to check
+ * @param startIndex
+ * the starting index
+ * @param isCaseSensitive
+ * check whether or not the equality should be case sensitive
+ * @return true if the name contains the fragment at the starting index
+ * startIndex according to the
+ * value of isCaseSensitive, otherwise false.
+ * @exception NullPointerException
+ * if fragment or name is null.
+ */
+ public static final boolean fragmentEquals(char[] fragment, char[] name,
+ int startIndex, boolean isCaseSensitive) {
+ int max = fragment.length;
+ if (name.length < max + startIndex)
+ return false;
+ if (isCaseSensitive) {
+ for (int i = max; --i >= 0;)
+ // assumes the prefix is not larger than the name
+ if (fragment[i] != name[i + startIndex])
+ return false;
+ return true;
+ }
+ for (int i = max; --i >= 0;)
+ // assumes the prefix is not larger than the name
+ if (Character.toLowerCase(fragment[i]) != Character
+ .toLowerCase(name[i + startIndex]))
+ return false;
+ return true;
+ }
+
+ /**
+ * Answers a hashcode for the array
+ *
+ * @param array
+ * the array for which a hashcode is required
+ * @return the hashcode
+ * @exception NullPointerException
+ * if array is null
+ */
+ public static final int hashCode(char[] array) {
+ int hash = 0;
+ int offset = 0;
+ int length = array.length;
+ if (length < 16) {
+ for (int i = length; i > 0; i--)
+ hash = (hash * 37) + array[offset++];
+ } else {
+ // only sample some characters
+ int skip = length / 8;
+ for (int i = length; i > 0; i -= skip, offset += skip)
+ hash = (hash * 39) + array[offset];
+ }
+ return hash & 0x7FFFFFFF;
+ }
+
+ /**
+ * Answers true if c is a whitespace according to the JLS (&#92;u000a,
+ * &#92;u000c, &#92;u000d, &#92;u0009), otherwise false.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * c = ' '
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * c = '&#92;u3000'
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param c
+ * the character to check
+ * @return true if c is a whitespace according to the JLS, otherwise false.
+ */
+ public static boolean isWhitespace(char c) {
+ switch (c) {
+ case 10: /* \ u000a: LINE FEED */
+ case 12: /* \ u000c: FORM FEED */
+ case 13: /* \ u000d: CARRIAGE RETURN */
+ case 32: /* \ u0020: SPACE */
+ case 9: /* \ u0009: HORIZONTAL TABULATION */
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Answers the first index in the array for which the corresponding
+ * character is
+ * equal to toBeFound. Answers -1 if no occurrence of this character is
+ * found.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd' }
+ * result => 2
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'e'
+ * array = { ' a', 'b', 'c', 'd' }
+ * result => -1
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param toBeFound
+ * the character to search
+ * @param array
+ * the array to be searched
+ * @return the first index in the array for which the corresponding
+ * character is
+ * equal to toBeFound, -1 otherwise
+ * @exception NullPointerException
+ * if array is null
+ */
+ public static final int indexOf(char toBeFound, char[] array) {
+ for (int i = 0; i < array.length; i++)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ /**
+ * Answers the first index in the array for which the corresponding
+ * character is
+ * equal to toBeFound starting the search at index start.
+ * Answers -1 if no occurrence of this character is found.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd' }
+ * start = 2
+ * result => 2
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd' }
+ * start = 3
+ * result => -1
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'e'
+ * array = { ' a', 'b', 'c', 'd' }
+ * start = 1
+ * result => -1
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param toBeFound
+ * the character to search
+ * @param array
+ * the array to be searched
+ * @param start
+ * the starting index
+ * @return the first index in the array for which the corresponding
+ * character is
+ * equal to toBeFound, -1 otherwise
+ * @exception NullPointerException
+ * if array is null
+ * @exception ArrayIndexOutOfBoundsException
+ * if start is lower than 0
+ */
+ public static final int indexOf(char toBeFound, char[] array, int start) {
+ for (int i = start; i < array.length; i++)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ /**
+ * Answers the last index in the array for which the corresponding character
+ * is
+ * equal to toBeFound starting from the end of the array.
+ * Answers -1 if no occurrence of this character is found.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd' , 'c', 'e' }
+ * result => 4
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'e'
+ * array = { ' a', 'b', 'c', 'd' }
+ * result => -1
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param toBeFound
+ * the character to search
+ * @param array
+ * the array to be searched
+ * @return the last index in the array for which the corresponding character
+ * is
+ * equal to toBeFound starting from the end of the array, -1
+ * otherwise
+ * @exception NullPointerException
+ * if array is null
+ */
+ public static final int lastIndexOf(char toBeFound, char[] array) {
+ for (int i = array.length; --i >= 0;)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ /**
+ * Answers the last index in the array for which the corresponding character
+ * is
+ * equal to toBeFound stopping at the index startIndex.
+ * Answers -1 if no occurrence of this character is found.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd' }
+ * startIndex = 2
+ * result => 2
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd', 'e' }
+ * startIndex = 3
+ * result => -1
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'e'
+ * array = { ' a', 'b', 'c', 'd' }
+ * startIndex = 0
+ * result => -1
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param toBeFound
+ * the character to search
+ * @param array
+ * the array to be searched
+ * @param startIndex
+ * the stopping index
+ * @return the last index in the array for which the corresponding character
+ * is
+ * equal to toBeFound stopping at the index startIndex, -1 otherwise
+ * @exception NullPointerException
+ * if array is null
+ * @exception ArrayIndexOutOfBoundsException
+ * if startIndex is lower than 0
+ */
+ public static final int lastIndexOf(char toBeFound, char[] array,
+ int startIndex) {
+ for (int i = array.length; --i >= startIndex;)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ /**
+ * Answers the last index in the array for which the corresponding character
+ * is
+ * equal to toBeFound starting from endIndex to startIndex.
+ * Answers -1 if no occurrence of this character is found.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd' }
+ * startIndex = 2
+ * endIndex = 2
+ * result => 2
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { ' a', 'b', 'c', 'd', 'e' }
+ * startIndex = 3
+ * endIndex = 4
+ * result => -1
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'e'
+ * array = { ' a', 'b', 'c', 'd' }
+ * startIndex = 0
+ * endIndex = 3
+ * result => -1
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param toBeFound
+ * the character to search
+ * @param array
+ * the array to be searched
+ * @param startIndex
+ * the stopping index
+ * @param endIndex
+ * the starting index
+ * @return the last index in the array for which the corresponding character
+ * is
+ * equal to toBeFound starting from endIndex to startIndex, -1
+ * otherwise
+ * @exception NullPointerException
+ * if array is null
+ * @exception ArrayIndexOutOfBoundsException
+ * if endIndex is greater or equals to array length or
+ * starting is lower than 0
+ */
+ public static final int lastIndexOf(char toBeFound, char[] array,
+ int startIndex, int endIndex) {
+ for (int i = endIndex; --i >= startIndex;)
+ if (toBeFound == array[i])
+ return i;
+ return -1;
+ }
+
+ /**
+ * Answers the last portion of a name given a separator.
+ * <br>
+ * <br>
+ * For example,
+ * <pre>
+ * lastSegment("java.lang.Object".toCharArray(),'.') --> Object
+ * </pre>
+ *
+ * @param array
+ * the array
+ * @param separator
+ * the given separator
+ * @return the last portion of a name given a separator
+ * @exception NullPointerException
+ * if array is null
+ */
+ final static public char[] lastSegment(char[] array, char separator) {
+ int pos = lastIndexOf(separator, array);
+ if (pos < 0)
+ return array;
+ return subarray(array, pos + 1, array.length);
+ }
+
+ /**
+ * Answers true if the pattern matches the given name, false otherwise. This
+ * char[] pattern matching
+ * accepts wild-cards '*' and '?'.
+ *
+ * When not case sensitive, the pattern is assumed to already be lowercased,
+ * the
+ * name will be lowercased character per character as comparing.
+ * If name is null, the answer is false.
+ * If pattern is null, the answer is true if name is not null.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * pattern = { '?', 'b', '*' }
+ * name = { 'a', 'b', 'c' , 'd' }
+ * isCaseSensitive = true
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * pattern = { '?', 'b', '?' }
+ * name = { 'a', 'b', 'c' , 'd' }
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * <li><pre>
+ * pattern = { 'b', '*' }
+ * name = { 'a', 'b', 'c' , 'd' }
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param pattern
+ * the given pattern
+ * @param name
+ * the given name
+ * @param isCaseSensitive
+ * flag to know whether or not the matching should be case
+ * sensitive
+ * @return true if the pattern matches the given name, false otherwise
+ */
+ public static final boolean match(char[] pattern, char[] name,
+ boolean isCaseSensitive) {
+ if (name == null)
+ return false; // null name cannot match
+ if (pattern == null)
+ return true; // null pattern is equivalent to '*'
+ return match(pattern, 0, pattern.length, name, 0, name.length,
+ isCaseSensitive, true);
+ }
+
+ /**
+ * Answers true if the a sub-pattern matches the subpart of the given name,
+ * false otherwise.
+ * char[] pattern matching, accepting wild-cards '*' and '?'. Can match only
+ * subset of name/pattern.
+ * end positions are non-inclusive.
+ * The subpattern is defined by the patternStart and pattternEnd positions.
+ * When not case sensitive, the pattern is assumed to already be lowercased,
+ * the
+ * name will be lowercased character per character as comparing.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * pattern = { '?', 'b', '*' }
+ * patternStart = 1
+ * patternEnd = 3
+ * name = { 'a', 'b', 'c' , 'd' }
+ * nameStart = 1
+ * nameEnd = 4
+ * isCaseSensitive = true
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * pattern = { '?', 'b', '*' }
+ * patternStart = 1
+ * patternEnd = 2
+ * name = { 'a', 'b', 'c' , 'd' }
+ * nameStart = 1
+ * nameEnd = 2
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param pattern
+ * the given pattern
+ * @param patternStart
+ * the given pattern start
+ * @param patternEnd
+ * the given pattern end
+ * @param name
+ * the given name
+ * @param nameStart
+ * the given name start
+ * @param nameEnd
+ * the given name end
+ * @param isCaseSensitive
+ * flag to know if the matching should be case sensitive
+ * @return true if the a sub-pattern matches the subpart of the given name,
+ * false otherwise
+ */
+ public static final boolean match(char[] pattern, int patternStart,
+ int patternEnd, char[] name, int nameStart, int nameEnd,
+ boolean isCaseSensitive) {
+ return match(pattern, patternStart, patternEnd, name, nameStart,
+ nameEnd, isCaseSensitive, false);
+ }
+
+ public static final boolean match(char[] pattern, int patternStart,
+ int patternEnd, char[] name, int nameStart, int nameEnd,
+ boolean isCaseSensitive, boolean allowEscaping) {
+ if (name == null)
+ return false; // null name cannot match
+ if (pattern == null)
+ return true; // null pattern is equivalent to '*'
+ int iPattern = patternStart;
+ int iName = nameStart;
+ if (patternEnd < 0)
+ patternEnd = pattern.length;
+ if (nameEnd < 0)
+ nameEnd = name.length;
+ /* check first segment */
+ char patternChar = 0;
+ boolean isEscaped = false;
+ while ((iPattern < patternEnd)
+ && ((patternChar = pattern[iPattern]) != '*' || (patternChar == '*' && isEscaped))) {
+ if (allowEscaping && pattern[iPattern] == '\\' && !isEscaped) {
+ iPattern++;
+ isEscaped = true;
+ continue;
+ } else
+ isEscaped = false;
+ if (iName == nameEnd)
+ return false;
+ if (patternChar != (isCaseSensitive ? name[iName] : Character
+ .toLowerCase(name[iName])) && patternChar != '?') {
+ return false;
+ }
+ iName++;
+ iPattern++;
+ patternChar = 0;
+ }
+ /* check sequence of star+segment */
+ int segmentStart;
+ if (patternChar == '*') {
+ segmentStart = ++iPattern; // skip star
+ } else {
+ segmentStart = 0; // force iName check
+ }
+ int prefixStart = iName;
+ checkSegment: while (iName < nameEnd) {
+ if (iPattern == patternEnd) {
+ iPattern = segmentStart; // mismatch - restart current segment
+ iName = ++prefixStart;
+ continue checkSegment;
+ }
+ /* segment is ending */
+ if ((patternChar = pattern[iPattern]) == '*') {
+ segmentStart = ++iPattern; // skip start
+ if (segmentStart == patternEnd) {
+ return true;
+ }
+ prefixStart = iName;
+ continue checkSegment;
+ }
+ /* check current name character */
+ if ((isCaseSensitive ? name[iName] : Character
+ .toLowerCase(name[iName])) != patternChar
+ && patternChar != '?') {
+ iPattern = segmentStart; // mismatch - restart current segment
+ iName = ++prefixStart;
+ continue checkSegment;
+ }
+ iName++;
+ iPattern++;
+ }
+ return (segmentStart == patternEnd)
+ || (iName == nameEnd && iPattern == patternEnd)
+ || (iPattern == patternEnd - 1 && pattern[iPattern] == '*');
+ }
+
+ /**
+ * Answers true if the pattern matches the filepath using the pathSepatator,
+ * false otherwise.
+ *
+ * Path char[] pattern matching, accepting wild-cards '**', '*' and '?'
+ * (using Ant directory tasks
+ * conventions, also see
+ * "http://jakarta.apache.org/ant/manual/dirtasks.html#defaultexcludes").
+ * Path pattern matching is enhancing regular pattern matching in supporting
+ * extra rule where '**' represent
+ * any folder combination.
+ * Special rules:
+ * - foo\ is equivalent to foo\**
+ * - *.java is equivalent to **\*.java
+ * When not case sensitive, the pattern is assumed to already be lowercased,
+ * the
+ * name will be lowercased character per character as comparing.
+ *
+ * @param pattern
+ * the given pattern
+ * @param filepath
+ * the given path
+ * @param isCaseSensitive
+ * to find out whether or not the matching should be case
+ * sensitive
+ * @param pathSeparator
+ * the given path separator
+ * @return true if the pattern matches the filepath using the pathSepatator,
+ * false otherwise
+ */
+ public static final boolean pathMatch(char[] pattern, char[] filepath,
+ boolean isCaseSensitive, char pathSeparator) {
+ if (filepath == null)
+ return false; // null name cannot match
+ if (pattern == null)
+ return true; // null pattern is equivalent to '*'
+ // special case: pattern foo is equivalent to **\foo (not absolute)
+ boolean freeLeadingDoubleStar;
+ // offsets inside pattern
+ int pSegmentStart, pLength = pattern.length;
+ freeLeadingDoubleStar = (pattern[0] != pathSeparator);
+ if (freeLeadingDoubleStar) {
+ pSegmentStart = 0;
+ } else {
+ pSegmentStart = 1;
+ }
+ int pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
+ pSegmentStart + 1);
+ if (pSegmentEnd < 0)
+ pSegmentEnd = pLength;
+ // special case: pattern foo\ is equivalent to foo\**
+ boolean freeTrailingDoubleStar = pattern[pLength - 1] == pathSeparator;
+ // offsets inside filepath
+ int fSegmentStart, fLength = filepath.length;
+ if (filepath[0] != pathSeparator) {
+ fSegmentStart = 0;
+ } else {
+ fSegmentStart = 1;
+ }
+ if (fSegmentStart != pSegmentStart) {
+ return false; // both must start with a separator or none.
+ }
+ int fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
+ fSegmentStart + 1);
+ if (fSegmentEnd < 0)
+ fSegmentEnd = fLength;
+ // first segments
+ while (pSegmentStart < pLength
+ && !freeLeadingDoubleStar
+ && !(pSegmentEnd == pLength && freeTrailingDoubleStar || (pSegmentEnd == pSegmentStart + 2
+ && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*'))) {
+ if (fSegmentStart >= fLength)
+ return false;
+ if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd,
+ filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) {
+ return false;
+ }
+ // jump to next segment
+ pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
+ pSegmentStart = pSegmentEnd + 1);
+ // skip separator
+ if (pSegmentEnd < 0)
+ pSegmentEnd = pLength;
+ fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
+ fSegmentStart = fSegmentEnd + 1);
+ // skip separator
+ if (fSegmentEnd < 0)
+ fSegmentEnd = fLength;
+ }
+ /* check sequence of doubleStar+segment */
+ int pSegmentRestart;
+ if ((pSegmentStart >= pLength && freeTrailingDoubleStar)
+ || (pSegmentEnd == pSegmentStart + 2
+ && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')) {
+ pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
+ pSegmentStart = pSegmentEnd + 1);
+ // skip separator
+ if (pSegmentEnd < 0)
+ pSegmentEnd = pLength;
+ pSegmentRestart = pSegmentStart;
+ } else {
+ if (pSegmentStart >= pLength)
+ return fSegmentStart >= fLength; // true if filepath is done too.
+ pSegmentRestart = 0; // force fSegmentStart check
+ }
+ int fSegmentRestart = fSegmentStart;
+ checkSegment: while (fSegmentStart < fLength) {
+ if (pSegmentStart >= pLength) {
+ if (freeTrailingDoubleStar)
+ return true;
+ // mismatch - restart current path segment
+ pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
+ pSegmentStart = pSegmentRestart);
+ if (pSegmentEnd < 0)
+ pSegmentEnd = pLength;
+ fSegmentRestart = CharOperation.indexOf(pathSeparator,
+ filepath, fSegmentRestart + 1);
+ // skip separator
+ if (fSegmentRestart < 0) {
+ fSegmentRestart = fLength;
+ } else {
+ fSegmentRestart++;
+ }
+ fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
+ fSegmentStart = fSegmentRestart);
+ if (fSegmentEnd < 0)
+ fSegmentEnd = fLength;
+ continue checkSegment;
+ }
+ /* path segment is ending */
+ if (pSegmentEnd == pSegmentStart + 2
+ && pattern[pSegmentStart] == '*'
+ && pattern[pSegmentStart + 1] == '*') {
+ pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
+ pSegmentStart = pSegmentEnd + 1);
+ // skip separator
+ if (pSegmentEnd < 0)
+ pSegmentEnd = pLength;
+ pSegmentRestart = pSegmentStart;
+ fSegmentRestart = fSegmentStart;
+ if (pSegmentStart >= pLength)
+ return true;
+ continue checkSegment;
+ }
+ /* chech current path segment */
+ if (!CharOperation.match(pattern, pSegmentStart, pSegmentEnd,
+ filepath, fSegmentStart, fSegmentEnd, isCaseSensitive)) {
+ // mismatch - restart current path segment
+ pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
+ pSegmentStart = pSegmentRestart);
+ if (pSegmentEnd < 0)
+ pSegmentEnd = pLength;
+ fSegmentRestart = CharOperation.indexOf(pathSeparator,
+ filepath, fSegmentRestart + 1);
+ // skip separator
+ if (fSegmentRestart < 0) {
+ fSegmentRestart = fLength;
+ } else {
+ fSegmentRestart++;
+ }
+ fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
+ fSegmentStart = fSegmentRestart);
+ if (fSegmentEnd < 0)
+ fSegmentEnd = fLength;
+ continue checkSegment;
+ }
+ // jump to next segment
+ pSegmentEnd = CharOperation.indexOf(pathSeparator, pattern,
+ pSegmentStart = pSegmentEnd + 1);
+ // skip separator
+ if (pSegmentEnd < 0)
+ pSegmentEnd = pLength;
+ fSegmentEnd = CharOperation.indexOf(pathSeparator, filepath,
+ fSegmentStart = fSegmentEnd + 1);
+ // skip separator
+ if (fSegmentEnd < 0)
+ fSegmentEnd = fLength;
+ }
+ return (pSegmentRestart >= pSegmentEnd)
+ || (fSegmentStart >= fLength && pSegmentStart >= pLength)
+ || (pSegmentStart == pLength - 2
+ && pattern[pSegmentStart] == '*' && pattern[pSegmentStart + 1] == '*')
+ || (pSegmentStart == pLength && freeTrailingDoubleStar);
+ }
+
+ /**
+ * Answers the number of occurrences of the given character in the given
+ * array, 0 if any.
+ *
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * toBeFound = 'b'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => 3
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => 0
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param toBeFound
+ * the given character
+ * @param array
+ * the given array
+ * @return the number of occurrences of the given character in the given
+ * array, 0 if any
+ * @exception NullPointerException
+ * if array is null
+ */
+ public static final int occurencesOf(char toBeFound, char[] array) {
+ int count = 0;
+ for (char element : array)
+ if (toBeFound == element)
+ count++;
+ return count;
+ }
+
+ /**
+ * Answers the number of occurrences of the given character in the given
+ * array starting
+ * at the given index, 0 if any.
+ *
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * toBeFound = 'b'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * start = 2
+ * result => 2
+ * </pre>
+ * </li>
+ * <li><pre>
+ * toBeFound = 'c'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * start = 0
+ * result => 0
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param toBeFound
+ * the given character
+ * @param array
+ * the given array
+ * @return the number of occurrences of the given character in the given
+ * array, 0 if any
+ * @exception NullPointerException
+ * if array is null
+ * @exception ArrayIndexOutOfBoundsException
+ * if start is lower than 0
+ */
+ public static final int occurencesOf(char toBeFound, char[] array, int start) {
+ int count = 0;
+ for (int i = start; i < array.length; i++)
+ if (toBeFound == array[i])
+ count++;
+ return count;
+ }
+
+ /**
+ * Answers true if the given name starts with the given prefix, false
+ * otherwise.
+ * The comparison is case sensitive.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * prefix = { 'a' , 'b' }
+ * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * prefix = { 'a' , 'c' }
+ * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param prefix
+ * the given prefix
+ * @param name
+ * the given name
+ * @return true if the given name starts with the given prefix, false
+ * otherwise
+ * @exception NullPointerException
+ * if the given name is null or if the given prefix is null
+ */
+ public static final boolean prefixEquals(char[] prefix, char[] name) {
+ int max = prefix.length;
+ if (name.length < max)
+ return false;
+ for (int i = max; --i >= 0;)
+ // assumes the prefix is not larger than the name
+ if (prefix[i] != name[i])
+ return false;
+ return true;
+ }
+
+ /**
+ * Answers true if the given name starts with the given prefix, false
+ * otherwise.
+ * isCaseSensitive is used to find out whether or not the comparison should
+ * be case sensitive.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * prefix = { 'a' , 'B' }
+ * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * isCaseSensitive = false
+ * result => true
+ * </pre>
+ * </li>
+ * <li><pre>
+ * prefix = { 'a' , 'B' }
+ * name = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * isCaseSensitive = true
+ * result => false
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param prefix
+ * the given prefix
+ * @param name
+ * the given name
+ * @param isCaseSensitive
+ * to find out whether or not the comparison should be case
+ * sensitive
+ * @return true if the given name starts with the given prefix, false
+ * otherwise
+ * @exception NullPointerException
+ * if the given name is null or if the given prefix is null
+ */
+ public static final boolean prefixEquals(char[] prefix, char[] name,
+ boolean isCaseSensitive) {
+ int max = prefix.length;
+ if (name.length < max)
+ return false;
+ if (isCaseSensitive) {
+ for (int i = max; --i >= 0;)
+ // assumes the prefix is not larger than the name
+ if (prefix[i] != name[i])
+ return false;
+ return true;
+ }
+ for (int i = max; --i >= 0;)
+ // assumes the prefix is not larger than the name
+ if (Character.toLowerCase(prefix[i]) != Character
+ .toLowerCase(name[i]))
+ return false;
+ return true;
+ }
+
+ /**
+ * Replace all occurrence of the character to be replaced with the
+ * remplacement character in the
+ * given array.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * toBeReplaced = 'b'
+ * replacementChar = 'a'
+ * result => No returned value, but array is now equals to { 'a' , 'a', 'a',
+ * 'a', 'a', 'a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * toBeReplaced = 'c'
+ * replacementChar = 'a'
+ * result => No returned value, but array is now equals to { 'a' , 'b', 'b',
+ * 'a', 'b', 'a' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @param toBeReplaced
+ * the character to be replaced
+ * @param replacementChar
+ * the replacement character
+ * @exception NullPointerException
+ * if the given array is null
+ */
+ public static final void replace(char[] array, char toBeReplaced,
+ char replacementChar) {
+ if (toBeReplaced != replacementChar) {
+ for (int i = 0, max = array.length; i < max; i++) {
+ if (array[i] == toBeReplaced)
+ array[i] = replacementChar;
+ }
+ }
+ }
+
+ /**
+ * Answers a new array of characters with substitutions. No side-effect is
+ * operated on the original
+ * array, in case no substitution happened, then the result is the same as
+ * the
+ * original one.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * toBeReplaced = { 'b' }
+ * replacementChar = { 'a', 'a' }
+ * result => { 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * toBeReplaced = { 'c' }
+ * replacementChar = { 'a' }
+ * result => { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @param toBeReplaced
+ * characters to be replaced
+ * @param replacementChars
+ * the replacement characters
+ * @return a new array of characters with substitutions or the given array
+ * if none
+ * @exception NullPointerException
+ * if the given array is null
+ */
+ public static final char[] replace(char[] array, char[] toBeReplaced,
+ char[] replacementChars) {
+ int max = array.length;
+ int replacedLength = toBeReplaced.length;
+ int replacementLength = replacementChars.length;
+ int[] starts = new int[5];
+ int occurrenceCount = 0;
+ if (!equals(toBeReplaced, replacementChars)) {
+ next: for (int i = 0; i < max; i++) {
+ int j = 0;
+ while (j < replacedLength) {
+ if (i + j == max)
+ continue next;
+ if (array[i + j] != toBeReplaced[j++])
+ continue next;
+ }
+ if (occurrenceCount == starts.length) {
+ System.arraycopy(starts, 0,
+ starts = new int[occurrenceCount * 2], 0,
+ occurrenceCount);
+ }
+ starts[occurrenceCount++] = i;
+ }
+ }
+ if (occurrenceCount == 0)
+ return array;
+ char[] result = new char[max + occurrenceCount
+ * (replacementLength - replacedLength)];
+ int inStart = 0, outStart = 0;
+ for (int i = 0; i < occurrenceCount; i++) {
+ int offset = starts[i] - inStart;
+ System.arraycopy(array, inStart, result, outStart, offset);
+ inStart += offset;
+ outStart += offset;
+ System.arraycopy(replacementChars, 0, result, outStart,
+ replacementLength);
+ inStart += replacedLength;
+ outStart += replacementLength;
+ }
+ System.arraycopy(array, inStart, result, outStart, max - inStart);
+ return result;
+ }
+
+ /**
+ * Return a new array which is the split of the given array using the given
+ * divider and triming each subarray to remove
+ * whitespaces equals to ' '.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * divider = 'b'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => { { 'a' }, { }, { 'a' }, { 'a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * divider = 'c'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * divider = 'b'
+ * array = { 'a' , ' ', 'b', 'b', 'a', 'b', 'a' }
+ * result => { { 'a' }, { }, { 'a' }, { 'a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * divider = 'c'
+ * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
+ * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param divider
+ * the given divider
+ * @param array
+ * the given array
+ * @return a new array which is the split of the given array using the given
+ * divider and triming each subarray to remove
+ * whitespaces equals to ' '
+ */
+ public static final char[][] splitAndTrimOn(char divider, char[] array) {
+ if (array == null)
+ return NO_CHAR_CHAR;
+ final int length = array.length;
+ if (length == 0)
+ return NO_CHAR_CHAR;
+ int wordCount = 1;
+ for (int i = 0; i < length; i++)
+ if (array[i] == divider)
+ wordCount++;
+ char[][] split = new char[wordCount][];
+ int last = 0, currentWord = 0;
+ for (int i = 0; i < length; i++) {
+ if (array[i] == divider) {
+ int start = last, end = i - 1;
+ while (start < i && array[start] == ' ')
+ start++;
+ while (end > start && array[end] == ' ')
+ end--;
+ split[currentWord] = new char[end - start + 1];
+ System.arraycopy(array, start, split[currentWord++], 0, end
+ - start + 1);
+ last = i + 1;
+ }
+ }
+ int start = last, end = length - 1;
+ while (start < length && array[start] == ' ')
+ start++;
+ while (end > start && array[end] == ' ')
+ end--;
+ split[currentWord] = new char[end - start + 1];
+ System.arraycopy(array, start, split[currentWord++], 0, end - start + 1);
+ return split;
+ }
+
+ /**
+ * Return a new array which is the split of the given array using the given
+ * divider.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * divider = 'b'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => { { 'a' }, { }, { 'a' }, { 'a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * divider = 'c'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * result => { { 'a', 'b', 'b', 'a', 'b', 'a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * divider = 'c'
+ * array = { ' ', ' ', 'a' , 'b', 'b', 'a', 'b', 'a', ' ' }
+ * result => { { ' ', 'a', 'b', 'b', 'a', 'b', 'a', ' ' } }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param divider
+ * the given divider
+ * @param array
+ * the given array
+ * @return a new array which is the split of the given array using the given
+ * divider
+ */
+ public static final char[][] splitOn(char divider, char[] array) {
+ if (array == null)
+ return NO_CHAR_CHAR;
+ final int length = array.length;
+ if (length == 0)
+ return NO_CHAR_CHAR;
+ int wordCount = 1;
+ for (int i = 0; i < length; i++)
+ if (array[i] == divider)
+ wordCount++;
+ char[][] split = new char[wordCount][];
+ int last = 0, currentWord = 0;
+ for (int i = 0; i < length; i++) {
+ if (array[i] == divider) {
+ split[currentWord] = new char[i - last];
+ System.arraycopy(array, last, split[currentWord++], 0, i - last);
+ last = i + 1;
+ }
+ }
+ split[currentWord] = new char[length - last];
+ System.arraycopy(array, last, split[currentWord], 0, length - last);
+ return split;
+ }
+
+ /**
+ * Return a new array which is the split of the given array using the given
+ * divider. The given end
+ * is exclusive and the given start is inclusive.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * divider = 'b'
+ * array = { 'a' , 'b', 'b', 'a', 'b', 'a' }
+ * start = 2
+ * end = 5
+ * result => { { }, { }, { 'a' } }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param divider
+ * the given divider
+ * @param array
+ * the given array
+ * @param start
+ * the given starting index
+ * @param end
+ * the given ending index
+ * @return a new array which is the split of the given array using the given
+ * divider
+ * @exception ArrayIndexOutOfBoundsException
+ * if start is lower than 0 or end is greater than the array
+ * length
+ */
+ public static final char[][] splitOn(char divider, char[] array, int start,
+ int end) {
+ if (array == null)
+ return NO_CHAR_CHAR;
+ final int length = array.length;
+ if (length == 0 || start > end)
+ return NO_CHAR_CHAR;
+ int wordCount = 1;
+ for (int i = start; i < end; i++)
+ if (array[i] == divider)
+ wordCount++;
+ char[][] split = new char[wordCount][];
+ int last = start, currentWord = 0;
+ for (int i = start; i < end; i++) {
+ if (array[i] == divider) {
+ split[currentWord] = new char[i - last];
+ System.arraycopy(array, last, split[currentWord++], 0, i - last);
+ last = i + 1;
+ }
+ }
+ split[currentWord] = new char[end - last];
+ System.arraycopy(array, last, split[currentWord], 0, end - last);
+ return split;
+ }
+
+ /**
+ * Answers a new array which is a copy of the given array starting at the
+ * given start and
+ * ending at the given end. The given start is inclusive and the given end
+ * is exclusive.
+ * Answers null if start is greater than end, if start is lower than 0 or if
+ * end is greater
+ * than the length of the given array. If end equals -1, it is converted to
+ * the array length.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { { 'a' } , { 'b' } }
+ * start = 0
+ * end = 1
+ * result => { { 'a' } }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { { 'a' } , { 'b' } }
+ * start = 0
+ * end = -1
+ * result => { { 'a' }, { 'b' } }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @param start
+ * the given starting index
+ * @param end
+ * the given ending index
+ * @return a new array which is a copy of the given array starting at the
+ * given start and
+ * ending at the given end
+ * @exception NullPointerException
+ * if the given array is null
+ */
+ public static final char[][] subarray(char[][] array, int start, int end) {
+ if (end == -1)
+ end = array.length;
+ if (start > end)
+ return null;
+ if (start < 0)
+ return null;
+ if (end > array.length)
+ return null;
+ char[][] result = new char[end - start][];
+ System.arraycopy(array, start, result, 0, end - start);
+ return result;
+ }
+
+ /**
+ * Answers a new array which is a copy of the given array starting at the
+ * given start and
+ * ending at the given end. The given start is inclusive and the given end
+ * is exclusive.
+ * Answers null if start is greater than end, if start is lower than 0 or if
+ * end is greater
+ * than the length of the given array. If end equals -1, it is converted to
+ * the array length.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { 'a' , 'b' }
+ * start = 0
+ * end = 1
+ * result => { 'a' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'a', 'b' }
+ * start = 0
+ * end = -1
+ * result => { 'a' , 'b' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @param start
+ * the given starting index
+ * @param end
+ * the given ending index
+ * @return a new array which is a copy of the given array starting at the
+ * given start and
+ * ending at the given end
+ * @exception NullPointerException
+ * if the given array is null
+ */
+ public static final char[] subarray(char[] array, int start, int end) {
+ if (end == -1)
+ end = array.length;
+ if (start > end)
+ return null;
+ if (start < 0)
+ return null;
+ if (end > array.length)
+ return null;
+ char[] result = new char[end - start];
+ System.arraycopy(array, start, result, 0, end - start);
+ return result;
+ }
+
+ /**
+ * Answers the result of a char[] conversion to lowercase. Answers null if
+ * the given chars array is null.
+ * <br>
+ * NOTE: If no conversion was necessary, then answers back the argument one.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * chars = { 'a' , 'b' }
+ * result => { 'a' , 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'A', 'b' }
+ * result => { 'a' , 'b' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param chars
+ * the chars to convert
+ * @return the result of a char[] conversion to lowercase
+ */
+ final static public char[] toLowerCase(char[] chars) {
+ if (chars == null)
+ return null;
+ int length = chars.length;
+ char[] lowerChars = null;
+ for (int i = 0; i < length; i++) {
+ char c = chars[i];
+ char lc = Character.toLowerCase(c);
+ if ((c != lc) || (lowerChars != null)) {
+ if (lowerChars == null) {
+ System.arraycopy(chars, 0, lowerChars = new char[length],
+ 0, i);
+ }
+ lowerChars[i] = lc;
+ }
+ }
+ return lowerChars == null ? chars : lowerChars;
+ }
+
+ /**
+ * Answers a new array removing leading and trailing spaces (' '). Answers
+ * the given array if there is no
+ * space characters to remove.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * chars = { ' ', 'a' , 'b', ' ', ' ' }
+ * result => { 'a' , 'b' }
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { 'A', 'b' }
+ * result => { 'A' , 'b' }
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param chars
+ * the given array
+ * @return a new array removing leading and trailing spaces (' ')
+ */
+ final static public char[] trim(char[] chars) {
+ if (chars == null)
+ return null;
+ int start = 0, length = chars.length, end = length - 1;
+ while (start < length && chars[start] == ' ') {
+ start++;
+ }
+ while (end > start && chars[end] == ' ') {
+ end--;
+ }
+ if (start != 0 || end != length - 1) {
+ return subarray(chars, start, end + 1);
+ }
+ return chars;
+ }
+
+ /**
+ * Answers a string which is the concatenation of the given array using the
+ * '.' as a separator.
+ * <br>
+ * <br>
+ * For example:
+ * <ol>
+ * <li><pre>
+ * array = { { 'a' } , { 'b' } }
+ * result => "a.b"
+ * </pre>
+ * </li>
+ * <li><pre>
+ * array = { { ' ', 'a' } , { 'b' } }
+ * result => " a.b"
+ * </pre>
+ * </li>
+ * </ol>
+ *
+ * @param array
+ * the given array
+ * @return a string which is the concatenation of the given array using the
+ * '.' as a separator
+ */
+ final static public String toString(char[][] array) {
+ char[] result = concatWith(array, '.');
+ return new String(result);
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java
index e2187f5c30..f4c00f3166 100644
--- a/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java
+++ b/codan/org.eclipse.cdt.codan.core/src/org/eclipse/cdt/codan/internal/core/model/CodanProblem.java
@@ -70,7 +70,11 @@ public class CodanProblem implements IProblemWorkingCopy {
*/
@Override
public Object clone() throws CloneNotSupportedException {
- return super.clone();
+ CodanProblem prob = (CodanProblem) super.clone();
+ if (preference != null) {
+ prob.preference = (IProblemPreference) preference.clone();
+ }
+ return prob;
}
public void setPreference(IProblemPreference value) {
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java
index 004530e749..5b3134e5d3 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/CodanUIMessages.java
@@ -41,6 +41,40 @@ public class CodanUIMessages extends NLS {
public static String Job_TitleRunningAnalysis;
public static String ParametersComposite_NewValue;
public static String ParametersComposite_None;
+ //
+ public static String ExclusionInclusionDialog_title;
+ public static String ExclusionInclusionDialog_description;
+ public static String ExclusionInclusionDialog_description2;
+ public static String ExclusionInclusionDialog_exclusion_pattern_label;
+ public static String ExclusionInclusionDialog_inclusion_pattern_label;
+ public static String ExclusionInclusionDialog_inclusion_pattern_add;
+ public static String ExclusionInclusionDialog_inclusion_pattern_add_multiple;
+ public static String ExclusionInclusionDialog_inclusion_pattern_remove;
+ public static String ExclusionInclusionDialog_inclusion_pattern_edit;
+ public static String ExclusionInclusionDialog_exclusion_pattern_add;
+ public static String ExclusionInclusionDialog_exclusion_pattern_add_multiple;
+ public static String ExclusionInclusionDialog_exclusion_pattern_remove;
+ public static String ExclusionInclusionDialog_exclusion_pattern_edit;
+ public static String ExclusionInclusionDialog_ChooseExclusionPattern_title;
+ public static String ExclusionInclusionDialog_ChooseExclusionPattern_description;
+ public static String ExclusionInclusionDialog_ChooseInclusionPattern_title;
+ public static String ExclusionInclusionDialog_ChooseInclusionPattern_description;
+ public static String ExclusionInclusionEntryDialog_exclude_add_title;
+ public static String ExclusionInclusionEntryDialog_exclude_edit_title;
+ public static String ExclusionInclusionEntryDialog_exclude_description;
+ public static String ExclusionInclusionEntryDialog_exclude_pattern_label;
+ public static String ExclusionInclusionEntryDialog_include_add_title;
+ public static String ExclusionInclusionEntryDialog_include_edit_title;
+ public static String ExclusionInclusionEntryDialog_include_description;
+ public static String ExclusionInclusionEntryDialog_include_pattern_label;
+ public static String ExclusionInclusionEntryDialog_pattern_button;
+ public static String ExclusionInclusionEntryDialog_error_empty;
+ public static String ExclusionInclusionEntryDialog_error_notrelative;
+ public static String ExclusionInclusionEntryDialog_error_exists;
+ public static String ExclusionInclusionEntryDialog_ChooseExclusionPattern_title;
+ public static String ExclusionInclusionEntryDialog_ChooseExclusionPattern_description;
+ public static String ExclusionInclusionEntryDialog_ChooseInclusionPattern_title;
+ public static String ExclusionInclusionEntryDialog_ChooseInclusionPattern_description;
static {
// initialize resource bundle
NLS.initializeMessages(BUNDLE_NAME, CodanUIMessages.class);
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemDialog.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemDialog.java
index 6f24b251b9..f0f9f714b3 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemDialog.java
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemDialog.java
@@ -13,6 +13,8 @@ package org.eclipse.cdt.codan.internal.ui.dialogs;
import org.eclipse.cdt.codan.core.model.IProblem;
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
import org.eclipse.cdt.codan.internal.ui.CodanUIMessages;
+import org.eclipse.cdt.codan.internal.ui.widgets.CustomizeProblemComposite;
+import org.eclipse.core.resources.IResource;
import org.eclipse.jface.dialogs.TitleAreaDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
@@ -27,27 +29,37 @@ import org.eclipse.swt.widgets.Shell;
public class CustomizeProblemDialog extends TitleAreaDialog {
private CustomizeProblemComposite comp;
private IProblem problem;
+ private IResource resource;
/**
* @param parentShell
* @param selectedProblem
+ * @param iResource
*/
- public CustomizeProblemDialog(Shell parentShell, IProblem selectedProblem) {
+ public CustomizeProblemDialog(Shell parentShell, IProblem selectedProblem,
+ IResource resource) {
super(parentShell);
this.problem = selectedProblem;
+ this.resource = resource;
setShellStyle(getShellStyle() | SWT.RESIZE);
}
/**
* Stores edit values into problem working copy
- * @param problem - problem working copy
+ *
+ * @param problem
+ * - problem working copy
*/
public void save(IProblemWorkingCopy problem) {
comp.save(problem);
}
-
- /* (non-Javadoc)
- * @see org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * org.eclipse.jface.dialogs.TitleAreaDialog#createDialogArea(org.eclipse
+ * .swt.widgets.Composite)
*/
@Override
protected Control createDialogArea(Composite parent) {
@@ -55,14 +67,16 @@ public class CustomizeProblemDialog extends TitleAreaDialog {
setTitle(problem.getName());
setMessage(CodanUIMessages.CustomizeProblemDialog_Message);
Composite area = (Composite) super.createDialogArea(parent);
- comp = new CustomizeProblemComposite(area, problem);
+ comp = new CustomizeProblemComposite(area, problem, resource);
GridData ld = new GridData(GridData.FILL_BOTH);
- ld.minimumHeight=300;
+ ld.minimumHeight = 300;
comp.setLayoutData(ld);
return area;
}
-
- /* (non-Javadoc)
+
+ /*
+ * (non-Javadoc)
+ *
* @see org.eclipse.jface.dialogs.Dialog#okPressed()
*/
@Override
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/ExclusionInclusionEntryDialog.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/ExclusionInclusionEntryDialog.java
new file mode 100644
index 0000000000..ba35b389fb
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/ExclusionInclusionEntryDialog.java
@@ -0,0 +1,274 @@
+package org.eclipse.cdt.codan.internal.ui.dialogs;
+
+import java.text.MessageFormat;
+import java.util.List;
+
+import org.eclipse.cdt.codan.core.param.FileScopeProblemPreference;
+import org.eclipse.cdt.codan.internal.ui.CodanUIMessages;
+import org.eclipse.cdt.codan.internal.ui.widgets.BasicElementLabels;
+import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
+import org.eclipse.cdt.internal.ui.dialogs.TypedElementSelectionValidator;
+import org.eclipse.cdt.internal.ui.dialogs.TypedViewerFilter;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.DialogField;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.IStringButtonAdapter;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.StringButtonDialogField;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IFolder;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.StatusDialog;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ITreeContentProvider;
+import org.eclipse.jface.viewers.ViewerFilter;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+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.Label;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.dialogs.ElementTreeSelectionDialog;
+import org.eclipse.ui.dialogs.ISelectionStatusValidator;
+import org.eclipse.ui.model.WorkbenchContentProvider;
+import org.eclipse.ui.model.WorkbenchLabelProvider;
+import org.eclipse.ui.views.navigator.ResourceComparator;
+
+public class ExclusionInclusionEntryDialog extends StatusDialog {
+ private StringButtonDialogField fExclusionPatternDialog;
+ private StatusInfo fExclusionPatternStatus;
+ private IContainer fCurrSourceFolder;
+ private String fExclusionPattern;
+ private List fExistingPatterns;
+ private boolean fIsExclusion;
+
+ public ExclusionInclusionEntryDialog(Shell parent, boolean isExclusion,
+ String patternToEdit, List existingPatterns,
+ FileScopeProblemPreference entryToEdit) {
+ super(parent);
+ fIsExclusion = isExclusion;
+ fExistingPatterns = existingPatterns;
+ String title, message;
+ if (isExclusion) {
+ if (patternToEdit == null) {
+ title = CodanUIMessages.ExclusionInclusionEntryDialog_exclude_add_title;
+ } else {
+ title = CodanUIMessages.ExclusionInclusionEntryDialog_exclude_edit_title;
+ }
+ message = MessageFormat
+ .format(CodanUIMessages.ExclusionInclusionEntryDialog_exclude_pattern_label,
+ BasicElementLabels.getPathLabel(
+ entryToEdit.getPath(), false));
+ } else {
+ if (patternToEdit == null) {
+ title = CodanUIMessages.ExclusionInclusionEntryDialog_include_add_title;
+ } else {
+ title = CodanUIMessages.ExclusionInclusionEntryDialog_include_edit_title;
+ }
+ message = MessageFormat
+ .format(CodanUIMessages.ExclusionInclusionEntryDialog_include_pattern_label,
+ BasicElementLabels.getPathLabel(
+ entryToEdit.getPath(), false));
+ }
+ setTitle(title);
+ if (patternToEdit != null) {
+ fExistingPatterns.remove(patternToEdit);
+ }
+ IProject currProject = entryToEdit.getProject();
+ IWorkspaceRoot root = currProject != null ? currProject.getWorkspace()
+ .getRoot() : ResourcesPlugin.getWorkspace().getRoot();
+ IResource res = root.findMember(entryToEdit.getPath());
+ if (res instanceof IContainer) {
+ fCurrSourceFolder = (IContainer) res;
+ }
+ fExclusionPatternStatus = new StatusInfo();
+ ExclusionPatternAdapter adapter = new ExclusionPatternAdapter();
+ fExclusionPatternDialog = new StringButtonDialogField(adapter);
+ fExclusionPatternDialog.setLabelText(message);
+ fExclusionPatternDialog
+ .setButtonLabel(CodanUIMessages.ExclusionInclusionEntryDialog_pattern_button);
+ fExclusionPatternDialog.setDialogFieldListener(adapter);
+ fExclusionPatternDialog.enableButton(fCurrSourceFolder != null);
+ if (patternToEdit == null) {
+ fExclusionPatternDialog.setText(""); //$NON-NLS-1$
+ } else {
+ fExclusionPatternDialog.setText(patternToEdit.toString());
+ }
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+ int widthHint = convertWidthInCharsToPixels(60);
+ Composite inner = new Composite(composite, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layout.numColumns = 2;
+ inner.setLayout(layout);
+ Label description = new Label(inner, SWT.WRAP);
+ if (fIsExclusion) {
+ description
+ .setText(CodanUIMessages.ExclusionInclusionEntryDialog_exclude_description);
+ } else {
+ description
+ .setText(CodanUIMessages.ExclusionInclusionEntryDialog_include_description);
+ }
+ GridData gd = new GridData();
+ gd.horizontalSpan = 2;
+ gd.widthHint = convertWidthInCharsToPixels(80);
+ description.setLayoutData(gd);
+ fExclusionPatternDialog.doFillIntoGrid(inner, 3);
+ LayoutUtil.setWidthHint(fExclusionPatternDialog.getLabelControl(null),
+ widthHint);
+ LayoutUtil.setHorizontalSpan(
+ fExclusionPatternDialog.getLabelControl(null), 2);
+ LayoutUtil.setWidthHint(fExclusionPatternDialog.getTextControl(null),
+ widthHint);
+ LayoutUtil.setHorizontalGrabbing(fExclusionPatternDialog
+ .getTextControl(null));
+ fExclusionPatternDialog.postSetFocusOnDialogField(parent.getDisplay());
+ applyDialogFont(composite);
+ return composite;
+ }
+
+ // -------- ExclusionPatternAdapter --------
+ private class ExclusionPatternAdapter implements IDialogFieldListener,
+ IStringButtonAdapter {
+ // -------- IDialogFieldListener
+ public void dialogFieldChanged(DialogField field) {
+ doStatusLineUpdate();
+ }
+
+ public void changeControlPressed(DialogField field) {
+ doChangeControlPressed();
+ }
+ }
+
+ protected void doChangeControlPressed() {
+ IPath pattern = chooseExclusionPattern();
+ if (pattern != null) {
+ fExclusionPatternDialog.setText(pattern.toString());
+ }
+ }
+
+ protected void doStatusLineUpdate() {
+ checkIfPatternValid();
+ updateStatus(fExclusionPatternStatus);
+ }
+
+ protected void checkIfPatternValid() {
+ String pattern = fExclusionPatternDialog.getText().trim();
+ if (pattern.length() == 0) {
+ fExclusionPatternStatus
+ .setError(CodanUIMessages.ExclusionInclusionEntryDialog_error_empty);
+ return;
+ }
+ IPath path = new Path(pattern);
+ if (path.isAbsolute() || path.getDevice() != null) {
+ fExclusionPatternStatus
+ .setError(CodanUIMessages.ExclusionInclusionEntryDialog_error_notrelative);
+ return;
+ }
+ if (fExistingPatterns.contains(pattern)) {
+ fExclusionPatternStatus
+ .setError(CodanUIMessages.ExclusionInclusionEntryDialog_error_exists);
+ return;
+ }
+ fExclusionPattern = pattern;
+ fExclusionPatternStatus.setOK();
+ }
+
+ public String getExclusionPattern() {
+ return fExclusionPattern;
+ }
+
+ /*
+ * @see org.eclipse.jface.window.Window#configureShell(Shell)
+ */
+ @Override
+ protected void configureShell(Shell newShell) {
+ super.configureShell(newShell);
+ }
+
+ // ---------- util method ------------
+ private IPath chooseExclusionPattern() {
+ String title, message;
+ if (fIsExclusion) {
+ title = CodanUIMessages.ExclusionInclusionEntryDialog_ChooseExclusionPattern_title;
+ message = CodanUIMessages.ExclusionInclusionEntryDialog_ChooseExclusionPattern_description;
+ } else {
+ title = CodanUIMessages.ExclusionInclusionEntryDialog_ChooseInclusionPattern_title;
+ message = CodanUIMessages.ExclusionInclusionEntryDialog_ChooseInclusionPattern_description;
+ }
+ IPath initialPath = new Path(fExclusionPatternDialog.getText());
+ IPath[] res = chooseExclusionPattern(getShell(), fCurrSourceFolder,
+ title, message, initialPath, false);
+ if (res == null) {
+ return null;
+ }
+ return res[0];
+ }
+
+ public static IPath[] chooseExclusionPattern(Shell shell,
+ IContainer currentSourceFolder, String title, String message,
+ IPath initialPath, boolean multiSelection) {
+ Class[] acceptedClasses = new Class[] { IFolder.class, IFile.class,
+ IProject.class };
+ ISelectionStatusValidator validator = new TypedElementSelectionValidator(
+ acceptedClasses, multiSelection);
+ ViewerFilter filter = new TypedViewerFilter(acceptedClasses);
+ ILabelProvider lp = new WorkbenchLabelProvider();
+ ITreeContentProvider cp = new WorkbenchContentProvider();
+ IResource initialElement = null;
+ if (initialPath != null) {
+ IContainer curr = currentSourceFolder;
+ int nSegments = initialPath.segmentCount();
+ for (int i = 0; i < nSegments; i++) {
+ IResource elem = curr.findMember(initialPath.segment(i));
+ if (elem != null) {
+ initialElement = elem;
+ }
+ if (elem instanceof IContainer) {
+ curr = (IContainer) elem;
+ } else {
+ break;
+ }
+ }
+ }
+ ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(
+ shell, lp, cp);
+ dialog.setTitle(title);
+ dialog.setValidator(validator);
+ dialog.setMessage(message);
+ dialog.addFilter(filter);
+ dialog.setInput(currentSourceFolder);
+ dialog.setInitialSelection(initialElement);
+ dialog.setComparator(new ResourceComparator(ResourceComparator.NAME));
+ dialog.setHelpAvailable(false);
+ if (dialog.open() == Window.OK) {
+ Object[] objects = dialog.getResult();
+ int existingSegments = currentSourceFolder.getFullPath()
+ .segmentCount();
+ IPath[] resArr = new IPath[objects.length];
+ for (int i = 0; i < objects.length; i++) {
+ IResource currRes = (IResource) objects[i];
+ IPath path = currRes.getFullPath()
+ .removeFirstSegments(existingSegments).makeRelative();
+ if (currRes instanceof IContainer) {
+ path = path.addTrailingSeparator();
+ }
+ resArr[i] = path;
+ }
+ return resArr;
+ }
+ return null;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/messages.properties b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/messages.properties
index ddcfdfbfa7..3706083997 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/messages.properties
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/messages.properties
@@ -23,3 +23,53 @@ OverlayPage_Use_Project_Settings=Use pr&oject settings
OverlayPage_Configure_Workspace_Settings=&Configure Workspace Settings...
PropertyStore_Cannot_write_resource_property=Cannot write resource property
+# ------- ExclusionInclusionDialog -------
+
+ExclusionInclusionDialog_title=Inclusion and Exclusion Patterns
+ExclusionInclusionDialog_description=Included and excluded resources for ''{0}''.
+ExclusionInclusionDialog_description2=Add or remove inclusion and exclusion patterns to resources for which problem is reported
+
+ExclusionInclusionDialog_exclusion_pattern_label=E&xclusion patterns:
+ExclusionInclusionDialog_inclusion_pattern_label=I&nclusion patterns:
+
+ExclusionInclusionDialog_inclusion_pattern_add=A&dd...
+ExclusionInclusionDialog_inclusion_pattern_add_multiple=Add &Multiple...
+ExclusionInclusionDialog_inclusion_pattern_remove=&Remove
+ExclusionInclusionDialog_inclusion_pattern_edit=&Edit...
+
+ExclusionInclusionDialog_exclusion_pattern_add=&Add...
+ExclusionInclusionDialog_exclusion_pattern_add_multiple=Add M&ultiple...
+ExclusionInclusionDialog_exclusion_pattern_remove=Rem&ove
+ExclusionInclusionDialog_exclusion_pattern_edit=Edi&t...
+
+ExclusionInclusionDialog_ChooseExclusionPattern_title=Exclusion Pattern Selection
+ExclusionInclusionDialog_ChooseExclusionPattern_description=&Choose folders or files to exclude:
+
+ExclusionInclusionDialog_ChooseInclusionPattern_title=Inclusion Pattern Selection
+ExclusionInclusionDialog_ChooseInclusionPattern_description=&Choose folders or files to include:
+
+# ------- ExclusionInclusionEntryDialog -------
+
+ExclusionInclusionEntryDialog_exclude_add_title=Add Exclusion Pattern
+ExclusionInclusionEntryDialog_exclude_edit_title=Edit Exclusion Pattern
+ExclusionInclusionEntryDialog_exclude_description=Enter a pattern for excluding files from the source folder. Allowed wildcards are '*', '?' and '**'. Examples: 'src/util/a*.c', 'src/util/', '**/Test*'.
+
+ExclusionInclusionEntryDialog_exclude_pattern_label=E&xclusion pattern (Path relative to ''{0}''):
+
+ExclusionInclusionEntryDialog_include_add_title=Add Inclusion Pattern
+ExclusionInclusionEntryDialog_include_edit_title=Edit Inclusion Pattern
+ExclusionInclusionEntryDialog_include_description=Enter a pattern for including files to the source folder. Allowed wildcards are '*', '?' and '**'. Examples: 'src/util/a*.c', 'src/util/', '**/Test*'.
+
+ExclusionInclusionEntryDialog_include_pattern_label=I&nclusion pattern (Path relative to ''{0}''):
+
+ExclusionInclusionEntryDialog_pattern_button=Bro&wse...
+
+ExclusionInclusionEntryDialog_error_empty=Enter a pattern.
+ExclusionInclusionEntryDialog_error_notrelative=Pattern must be a relative path.
+ExclusionInclusionEntryDialog_error_exists=Pattern already exists.
+
+ExclusionInclusionEntryDialog_ChooseExclusionPattern_title=Exclusion Pattern Selection
+ExclusionInclusionEntryDialog_ChooseExclusionPattern_description=&Choose a folder or file to exclude:
+
+ExclusionInclusionEntryDialog_ChooseInclusionPattern_title=Inclusion Pattern Selection
+ExclusionInclusionEntryDialog_ChooseInclusionPattern_description=&Choose a folder or file to include: \ No newline at end of file
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/CodanPreferencePage.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/CodanPreferencePage.java
index 3a7330065f..1c436dde97 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/CodanPreferencePage.java
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/CodanPreferencePage.java
@@ -279,7 +279,7 @@ public class CodanPreferencePage extends FieldEditorOverlayPage implements
*/
protected void openCustomizeDialog() {
CustomizeProblemDialog d = new CustomizeProblemDialog(getShell(),
- selectedProblem);
+ selectedProblem, (IResource) getElement());
d.open();
}
} \ No newline at end of file
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/FileScopePreferencePage.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/FileScopePreferencePage.java
new file mode 100644
index 0000000000..ed78a3ce8f
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/preferences/FileScopePreferencePage.java
@@ -0,0 +1,302 @@
+package org.eclipse.cdt.codan.internal.ui.preferences;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.cdt.codan.core.param.FileScopeProblemPreference;
+import org.eclipse.cdt.codan.internal.ui.CodanUIActivator;
+import org.eclipse.cdt.codan.internal.ui.CodanUIMessages;
+import org.eclipse.cdt.codan.internal.ui.dialogs.ExclusionInclusionEntryDialog;
+import org.eclipse.cdt.codan.internal.ui.widgets.BasicElementLabels;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.DialogField;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.IDialogFieldListener;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.IListAdapter;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.LayoutUtil;
+import org.eclipse.cdt.internal.ui.wizards.dialogfields.ListDialogField;
+import org.eclipse.core.resources.IContainer;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.resources.IWorkspaceRoot;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.preference.PreferencePage;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.ViewerComparator;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Image;
+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.Shell;
+
+public class FileScopePreferencePage extends PreferencePage {
+ private ListDialogField fInclusionPatternList;
+ private ListDialogField fExclusionPatternList;
+ private FileScopeProblemPreference fCurrElement;
+ private IProject fCurrProject;
+ private IContainer fCurrSourceFolder;
+ private static final int IDX_ADD = 0;
+ private static final int IDX_ADD_MULTIPLE = 1;
+ private static final int IDX_EDIT = 2;
+ private static final int IDX_REMOVE = 4;
+
+ public FileScopePreferencePage(FileScopeProblemPreference entryToEdit) {
+ setTitle(CodanUIMessages.ExclusionInclusionDialog_title);
+ setDescription(CodanUIMessages.ExclusionInclusionDialog_description2);
+ fCurrElement = entryToEdit;
+ fCurrProject = entryToEdit.getProject();
+ IWorkspaceRoot root = fCurrProject != null ? fCurrProject
+ .getWorkspace().getRoot() : ResourcesPlugin.getWorkspace()
+ .getRoot();
+ IResource res = root.findMember(entryToEdit.getPath());
+ if (res instanceof IContainer) {
+ fCurrSourceFolder = (IContainer) res;
+ }
+ if (res == null)
+ fCurrSourceFolder = root;
+ String excLabel = CodanUIMessages.ExclusionInclusionDialog_exclusion_pattern_label;
+ ImageDescriptor excDescriptor = null; //JavaPluginImages.DESC_OBJS_EXCLUSION_FILTER_ATTRIB;
+ String[] excButtonLabels = new String[] {
+ CodanUIMessages.ExclusionInclusionDialog_exclusion_pattern_add,
+ CodanUIMessages.ExclusionInclusionDialog_exclusion_pattern_add_multiple,
+ CodanUIMessages.ExclusionInclusionDialog_exclusion_pattern_edit,
+ null,
+ CodanUIMessages.ExclusionInclusionDialog_exclusion_pattern_remove };
+ String incLabel = CodanUIMessages.ExclusionInclusionDialog_inclusion_pattern_label;
+ ImageDescriptor incDescriptor = null; //JavaPluginImages.DESC_OBJS_INCLUSION_FILTER_ATTRIB;
+ String[] incButtonLabels = new String[] {
+ CodanUIMessages.ExclusionInclusionDialog_inclusion_pattern_add,
+ CodanUIMessages.ExclusionInclusionDialog_inclusion_pattern_add_multiple,
+ CodanUIMessages.ExclusionInclusionDialog_inclusion_pattern_edit,
+ null,
+ CodanUIMessages.ExclusionInclusionDialog_inclusion_pattern_remove };
+ fExclusionPatternList = createListContents(entryToEdit,
+ FileScopeProblemPreference.EXCLUSION, excLabel, null,
+ excButtonLabels);
+ fInclusionPatternList = createListContents(entryToEdit,
+ FileScopeProblemPreference.INCLUSION, incLabel, null,
+ incButtonLabels);
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ Composite inner = new Composite(parent, SWT.NONE);
+ inner.setFont(parent.getFont());
+ GridLayout layout = new GridLayout();
+ layout.marginHeight = 0;
+ layout.marginWidth = 0;
+ layout.numColumns = 2;
+ inner.setLayout(layout);
+ inner.setLayoutData(new GridData(GridData.FILL_BOTH));
+ fInclusionPatternList.doFillIntoGrid(inner, 3);
+ LayoutUtil.setHorizontalSpan(
+ fInclusionPatternList.getLabelControl(null), 2);
+ LayoutUtil.setHorizontalGrabbing(fInclusionPatternList
+ .getListControl(null));
+ fExclusionPatternList.doFillIntoGrid(inner, 3);
+ LayoutUtil.setHorizontalSpan(
+ fExclusionPatternList.getLabelControl(null), 2);
+ LayoutUtil.setHorizontalGrabbing(fExclusionPatternList
+ .getListControl(null));
+ setControl(inner);
+ Dialog.applyDialogFont(inner);
+ return inner;
+ }
+
+ private static class ExclusionInclusionLabelProvider extends LabelProvider {
+ private Image fElementImage;
+
+ public ExclusionInclusionLabelProvider(String descriptorPath) {
+ if (descriptorPath != null) {
+ ImageDescriptor d = CodanUIActivator
+ .getImageDescriptor(descriptorPath);
+ }
+ fElementImage = null; // XXX
+ }
+
+ @Override
+ public Image getImage(Object element) {
+ return fElementImage;
+ }
+
+ @Override
+ public String getText(Object element) {
+ return BasicElementLabels.getFilePattern((String) element);
+ }
+ }
+
+ private ListDialogField createListContents(
+ FileScopeProblemPreference entryToEdit, String key, String label,
+ String descriptor, String[] buttonLabels) {
+ ExclusionPatternAdapter adapter = new ExclusionPatternAdapter();
+ ListDialogField patternList = new ListDialogField(adapter,
+ buttonLabels, new ExclusionInclusionLabelProvider(descriptor));
+ patternList.setDialogFieldListener(adapter);
+ patternList.setLabelText(label);
+ patternList.enableButton(IDX_EDIT, false);
+ IPath[] pattern = entryToEdit.getAttribute(key);
+ ArrayList elements = new ArrayList(pattern.length);
+ for (int i = 0; i < pattern.length; i++) {
+ String patternName = pattern[i].toString();
+ if (patternName.length() > 0)
+ elements.add(patternName);
+ }
+ patternList.setElements(elements);
+ patternList.selectFirstElement();
+ patternList.enableButton(IDX_ADD_MULTIPLE, fCurrSourceFolder != null);
+ patternList.setViewerComparator(new ViewerComparator());
+ return patternList;
+ }
+
+ protected void doCustomButtonPressed(ListDialogField field, int index) {
+ if (index == IDX_ADD) {
+ addEntry(field);
+ } else if (index == IDX_EDIT) {
+ editEntry(field);
+ } else if (index == IDX_ADD_MULTIPLE) {
+ addMultipleEntries(field);
+ } else if (index == IDX_REMOVE) {
+ field.removeElements(field.getSelectedElements());
+ }
+ updateStatus();
+ }
+
+ private void updateStatus() {
+ fCurrElement.setAttribute(FileScopeProblemPreference.INCLUSION,
+ getInclusionPattern());
+ fCurrElement.setAttribute(FileScopeProblemPreference.EXCLUSION,
+ getExclusionPattern());
+ }
+
+ protected void doDoubleClicked(ListDialogField field) {
+ editEntry(field);
+ updateStatus();
+ }
+
+ protected void doSelectionChanged(ListDialogField field) {
+ List selected = field.getSelectedElements();
+ field.enableButton(IDX_EDIT, canEdit(selected));
+ }
+
+ private boolean canEdit(List selected) {
+ return selected.size() == 1;
+ }
+
+ private void editEntry(ListDialogField field) {
+ List selElements = field.getSelectedElements();
+ if (selElements.size() != 1) {
+ return;
+ }
+ List existing = field.getElements();
+ String entry = (String) selElements.get(0);
+ ExclusionInclusionEntryDialog dialog = new ExclusionInclusionEntryDialog(
+ getShell(), isExclusion(field), entry, existing, fCurrElement);
+ if (dialog.open() == Window.OK) {
+ field.replaceElement(entry, dialog.getExclusionPattern());
+ }
+ }
+
+ private boolean isExclusion(ListDialogField field) {
+ return field == fExclusionPatternList;
+ }
+
+ private void addEntry(ListDialogField field) {
+ List existing = field.getElements();
+ ExclusionInclusionEntryDialog dialog = new ExclusionInclusionEntryDialog(
+ getShell(), isExclusion(field), null, existing, fCurrElement);
+ if (dialog.open() == Window.OK) {
+ field.addElement(dialog.getExclusionPattern());
+ }
+ }
+
+ // -------- ExclusionPatternAdapter --------
+ private class ExclusionPatternAdapter implements IListAdapter,
+ IDialogFieldListener {
+ /**
+ * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#customButtonPressed(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField,
+ * int)
+ */
+ public void customButtonPressed(ListDialogField field, int index) {
+ doCustomButtonPressed(field, index);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#selectionChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField)
+ */
+ public void selectionChanged(ListDialogField field) {
+ doSelectionChanged(field);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IListAdapter#doubleClicked(org.eclipse.jdt.internal.ui.wizards.dialogfields.ListDialogField)
+ */
+ public void doubleClicked(ListDialogField field) {
+ doDoubleClicked(field);
+ }
+
+ /**
+ * @see org.eclipse.jdt.internal.ui.wizards.dialogfields.IDialogFieldListener#dialogFieldChanged(org.eclipse.jdt.internal.ui.wizards.dialogfields.DialogField)
+ */
+ public void dialogFieldChanged(DialogField field) {
+ }
+ }
+
+ protected void doStatusLineUpdate() {
+ }
+
+ protected void checkIfPatternValid() {
+ }
+
+ private IPath[] getPattern(ListDialogField field) {
+ Object[] arr = field.getElements().toArray();
+ Arrays.sort(arr);
+ IPath[] res = new IPath[arr.length];
+ for (int i = 0; i < res.length; i++) {
+ res[i] = new Path((String) arr[i]);
+ }
+ return res;
+ }
+
+ public IPath[] getExclusionPattern() {
+ return getPattern(fExclusionPatternList);
+ }
+
+ public IPath[] getInclusionPattern() {
+ return getPattern(fInclusionPatternList);
+ }
+
+ /*
+ * @see org.eclipse.jface.window.Window#configureShell(Shell)
+ */
+ protected void configureShell(Shell newShell) {
+ }
+
+ private void addMultipleEntries(ListDialogField field) {
+ String title, message;
+ if (isExclusion(field)) {
+ title = CodanUIMessages.ExclusionInclusionDialog_ChooseExclusionPattern_title;
+ message = CodanUIMessages.ExclusionInclusionDialog_ChooseExclusionPattern_description;
+ } else {
+ title = CodanUIMessages.ExclusionInclusionDialog_ChooseInclusionPattern_title;
+ message = CodanUIMessages.ExclusionInclusionDialog_ChooseInclusionPattern_description;
+ }
+ IPath[] res = ExclusionInclusionEntryDialog.chooseExclusionPattern(
+ getShell(), fCurrSourceFolder, title, message, null, true);
+ if (res != null) {
+ for (int i = 0; i < res.length; i++) {
+ field.addElement(res[i].toString());
+ }
+ }
+ }
+
+ @Override
+ public void noDefaultAndApplyButton() {
+ super.noDefaultAndApplyButton();
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/BasicElementLabels.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/BasicElementLabels.java
new file mode 100644
index 0000000000..e0c7ddce31
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/BasicElementLabels.java
@@ -0,0 +1,147 @@
+package org.eclipse.cdt.codan.internal.ui.widgets;
+
+import java.io.File;
+
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.ui.IWorkingSet;
+
+/**
+ * A label provider for basic elements like paths. The label provider will make
+ * sure that the labels are correctly
+ * shown in RTL environments.
+ *
+ * @since 3.4
+ */
+public class BasicElementLabels {
+ // TextProcessor delimiters
+ private static final String CODE_DELIMITERS = TextProcessor
+ .getDefaultDelimiters() + "<>()?,{}+-*!%=^|&;[]~"; //$NON-NLS-1$
+ private static final String FILE_PATTERN_DELIMITERS = TextProcessor
+ .getDefaultDelimiters() + "*.?"; //$NON-NLS-1$
+ private static final String URL_DELIMITERS = TextProcessor
+ .getDefaultDelimiters() + ":@?-"; //$NON-NLS-1$
+
+ /**
+ * Returns the label of a path.
+ *
+ * @param path
+ * the path
+ * @param isOSPath
+ * if <code>true</code>, the path represents an OS path, if
+ * <code>false</code> it is a workspace path.
+ * @return the label of the path to be used in the UI.
+ */
+ public static String getPathLabel(IPath path, boolean isOSPath) {
+ String label;
+ if (isOSPath) {
+ label = path.toOSString();
+ } else {
+ label = path.makeRelative().toString();
+ }
+ return markLTR(label);
+ }
+
+ /**
+ * Returns the label of the path of a file.
+ *
+ * @param file
+ * the file
+ * @return the label of the file path to be used in the UI.
+ */
+ public static String getPathLabel(File file) {
+ return markLTR(file.getAbsolutePath());
+ }
+
+ /**
+ * Returns the label for a file pattern like '*.java'
+ *
+ * @param name
+ * the pattern
+ * @return the label of the pattern.
+ */
+ public static String getFilePattern(String name) {
+ return markLTR(name, FILE_PATTERN_DELIMITERS);
+ }
+
+ /**
+ * Returns the label for a URL, URI or URL part. Example is
+ * 'http://www.x.xom/s.html#1'
+ *
+ * @param name
+ * the URL string
+ * @return the label of the URL.
+ */
+ public static String getURLPart(String name) {
+ return markLTR(name, URL_DELIMITERS);
+ }
+
+ /**
+ * Returns a label for a resource name.
+ *
+ * @param resource
+ * the resource
+ * @return the label of the resource name.
+ */
+ public static String getResourceName(IResource resource) {
+ return markLTR(resource.getName());
+ }
+
+ /**
+ * Returns a label for a resource name.
+ *
+ * @param resourceName
+ * the resource name
+ * @return the label of the resource name.
+ */
+ public static String getResourceName(String resourceName) {
+ return markLTR(resourceName);
+ }
+
+ /**
+ * Returns a label for Java code snippet used in a label. Example is 'Test
+ * test= new Test<? extends List>() { ...}'.
+ *
+ * @param string
+ * the Java code snippet
+ * @return the label for the Java code snippet
+ */
+ public static String getJavaCodeString(String string) {
+ return markLTR(string, CODE_DELIMITERS);
+ }
+
+ /**
+ * Returns a label for a version name. Example is '1.4.1'
+ *
+ * @param name
+ * the version string
+ * @return the version label
+ */
+ public static String getVersionName(String name) {
+ return markLTR(name);
+ }
+
+ /**
+ * Returns a label for a working set
+ *
+ * @param set
+ * the working set
+ * @return the label of the working set
+ */
+ public static String getWorkingSetLabel(IWorkingSet set) {
+ return markLTR(set.getLabel());
+ }
+
+ /**
+ * It does not do anything now, but just in case we need to do the same as
+ * JDT does (see String.markLTR in JDT)
+ */
+ private static String markLTR(String label) {
+ return label;
+ }
+
+ private static String markLTR(String label, String delim) {
+ return label;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemComposite.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/CustomizeProblemComposite.java
index 9ec2d404b9..996d6bdbf4 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/CustomizeProblemComposite.java
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/CustomizeProblemComposite.java
@@ -8,16 +8,16 @@
* Contributors:
* Alena Laskavaia - initial API and implementation
*******************************************************************************/
-package org.eclipse.cdt.codan.internal.ui.dialogs;
+package org.eclipse.cdt.codan.internal.ui.widgets;
import org.eclipse.cdt.codan.core.model.IProblem;
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
import org.eclipse.cdt.codan.internal.ui.CodanUIMessages;
+import org.eclipse.core.resources.IResource;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
@@ -29,17 +29,21 @@ public class CustomizeProblemComposite extends Composite {
private Composite parametersTab;
private IProblem problem;
private ParametersComposite problemsComposite;
+ private FileScopeComposite scopeComposite;
+ private IResource resource;
/**
* @param parent
* @param selectedProblem
+ * @param resource
* @param style
*/
- public CustomizeProblemComposite(Composite parent, IProblem selectedProblem) {
+ public CustomizeProblemComposite(Composite parent,
+ IProblem selectedProblem, IResource resource) {
super(parent, SWT.NONE);
-
this.setLayout(new GridLayout(1, false));
this.problem = selectedProblem;
+ this.resource = resource;
final TabFolder tabFolder = new TabFolder(this, SWT.TOP);
tabFolder.setLayoutData(new GridData(GridData.FILL_BOTH));
// createMainTab(tabFolder);
@@ -49,6 +53,7 @@ public class CustomizeProblemComposite extends Composite {
public void save(IProblemWorkingCopy problem) {
problemsComposite.save(problem);
+ scopeComposite.save(problem);
}
/**
@@ -61,7 +66,8 @@ public class CustomizeProblemComposite extends Composite {
tabItem1.setControl(parametersTab);
parametersTab.setLayout(new GridLayout());
problemsComposite = new ParametersComposite(parametersTab, problem);
- problemsComposite.setLayoutData(new GridData(SWT.BEGINNING,SWT.BEGINNING, true, false));
+ problemsComposite.setLayoutData(new GridData(SWT.BEGINNING,
+ SWT.BEGINNING, true, false));
}
/**
@@ -73,8 +79,8 @@ public class CustomizeProblemComposite extends Composite {
Composite comp = new Composite(tabFolder, SWT.NONE);
tabItem1.setControl(comp);
comp.setLayout(new GridLayout());
- Label label = new Label(comp, SWT.NONE);
- label.setText("Scope: TODO"); //$NON-NLS-1$
- label.setLayoutData(new GridData(GridData.FILL_BOTH));
+ scopeComposite = new FileScopeComposite(comp, problem, resource);
+ scopeComposite.setLayoutData(new GridData(SWT.BEGINNING, SWT.BEGINNING,
+ true, false));
}
}
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/FileScopeComposite.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/FileScopeComposite.java
new file mode 100644
index 0000000000..37e75f497b
--- /dev/null
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/FileScopeComposite.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Alena Laskavaia
+ * 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
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Alena Laskavaia - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.codan.internal.ui.widgets;
+
+import org.eclipse.cdt.codan.core.model.IProblem;
+import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
+import org.eclipse.cdt.codan.core.param.FileScopeProblemPreference;
+import org.eclipse.cdt.codan.core.param.IProblemPreference;
+import org.eclipse.cdt.codan.core.param.MapProblemPreference;
+import org.eclipse.cdt.codan.internal.ui.CodanUIMessages;
+import org.eclipse.cdt.codan.internal.ui.preferences.FileScopePreferencePage;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.jface.preference.PreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+
+/**
+ * Composite to show problem scope
+ *
+ */
+public class FileScopeComposite extends Composite {
+ private FileScopePreferencePage page;
+ private IProblem problem;
+ private PreferenceStore prefStore;
+ private FileScopeProblemPreference scope;
+
+ /**
+ * @param parent
+ * @param problem
+ * @param resource
+ * @param style
+ */
+ public FileScopeComposite(Composite parent, final IProblem problem,
+ IResource resource) {
+ super(parent, SWT.NONE);
+ if (problem == null)
+ throw new NullPointerException();
+ this.setLayout(new GridLayout(2, false));
+ this.problem = problem;
+ this.prefStore = new PreferenceStore();
+ IProblemPreference info = problem.getPreference();
+ FileScopeProblemPreference scopeIn = null;
+ if (info == null
+ || (!(info instanceof MapProblemPreference))
+ || ((scopeIn = (FileScopeProblemPreference) ((MapProblemPreference) info)
+ .getChildDescriptor(FileScopeProblemPreference.KEY)) == null)) {
+ Label label = new Label(this, 0);
+ label.setText(CodanUIMessages.ParametersComposite_None);
+ return;
+ }
+ scope = (FileScopeProblemPreference) scopeIn.clone();
+ scope.setResource(resource);
+ initPrefStore();
+ page = new FileScopePreferencePage(scope);
+ page.setPreferenceStore(prefStore);
+ page.noDefaultAndApplyButton();
+ page.createControl(parent);
+ page.getControl().setLayoutData(new GridData(GridData.FILL_BOTH));
+ }
+
+ public void save(IProblemWorkingCopy problem) {
+ if (page != null)
+ page.performOk();
+ savePrefStore();
+ }
+
+ private void savePrefStore() {
+ if (scope == null)
+ return;
+ String key = scope.getQualifiedKey();
+ ((MapProblemPreference) problem.getPreference()).setChildValue(
+ FileScopeProblemPreference.KEY, scope);
+ prefStore.setValue(key, scope.exportValue());
+ }
+
+ private void initPrefStore() {
+ if (scope == null)
+ return;
+ String key = scope.getQualifiedKey();
+ prefStore.setValue(key, scope.exportValue());
+ }
+
+ /**
+ * @return the problem
+ */
+ public IProblem getProblem() {
+ return problem;
+ }
+}
diff --git a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/ParametersComposite.java b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/ParametersComposite.java
index 25100c8d3e..592b228c6e 100644
--- a/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/dialogs/ParametersComposite.java
+++ b/codan/org.eclipse.cdt.codan.ui/src/org/eclipse/cdt/codan/internal/ui/widgets/ParametersComposite.java
@@ -8,12 +8,13 @@
* Contributors:
* Alena Laskavaia - initial API and implementation
*******************************************************************************/
-package org.eclipse.cdt.codan.internal.ui.dialogs;
+package org.eclipse.cdt.codan.internal.ui.widgets;
import java.io.File;
import org.eclipse.cdt.codan.core.model.IProblem;
import org.eclipse.cdt.codan.core.model.IProblemWorkingCopy;
+import org.eclipse.cdt.codan.core.param.FileScopeProblemPreference;
import org.eclipse.cdt.codan.core.param.IProblemPreference;
import org.eclipse.cdt.codan.core.param.IProblemPreferenceCompositeDescriptor;
import org.eclipse.cdt.codan.core.param.ListProblemPreference;
@@ -21,6 +22,7 @@ import org.eclipse.cdt.codan.internal.ui.CodanUIMessages;
import org.eclipse.jface.dialogs.InputDialog;
import org.eclipse.jface.preference.BooleanFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.FileFieldEditor;
import org.eclipse.jface.preference.ListEditor;
import org.eclipse.jface.preference.PreferenceStore;
import org.eclipse.jface.preference.StringFieldEditor;
@@ -67,6 +69,8 @@ public class ParametersComposite extends Composite {
final IProblemPreference info) {
if (info == null)
return;
+ if (info.getKey() == FileScopeProblemPreference.KEY)
+ return; // skip the scope
switch (info.getType()) {
case TYPE_STRING: {
StringFieldEditor fe = new StringFieldEditor(
@@ -103,11 +107,12 @@ public class ParametersComposite extends Composite {
@Override
protected String getNewInputObject() {
ListProblemPreference list = (ListProblemPreference) info;
- String label = list
- .getChildDescriptor()
+ String label = list.getChildDescriptor()
.getLabel();
InputDialog dialog = new InputDialog(
- getShell(), CodanUIMessages.ParametersComposite_NewValue, label, "", null); //$NON-NLS-1$
+ getShell(),
+ CodanUIMessages.ParametersComposite_NewValue,
+ label, "", null); //$NON-NLS-1$
if (dialog.open() == Window.OK) {
return dialog.getValue();
}
@@ -136,6 +141,20 @@ public class ParametersComposite extends Composite {
createFieldEditorsForParameters(desc);
}
break;
+ case TYPE_CUSTOM: {
+ StringFieldEditor fe = new StringFieldEditor(
+ info.getQualifiedKey(), info.getLabel(),
+ getFieldEditorParent());
+ addField(fe);
+ break;
+ }
+ case TYPE_FILE: {
+ FileFieldEditor fe = new FileFieldEditor(
+ info.getQualifiedKey(), info.getLabel(),
+ getFieldEditorParent());
+ addField(fe);
+ break;
+ }
default:
throw new UnsupportedOperationException(info.getType()
.toString());
@@ -179,6 +198,9 @@ public class ParametersComposite extends Composite {
case TYPE_LIST:
desc.importValue(prefStore.getString(key));
break;
+ case TYPE_CUSTOM:
+ desc.importValue(prefStore.getString(key));
+ break;
case TYPE_MAP:
IProblemPreference[] childrenDescriptor = ((IProblemPreferenceCompositeDescriptor) desc)
.getChildDescriptors();
@@ -213,6 +235,9 @@ public class ParametersComposite extends Composite {
case TYPE_LIST:
prefStore.setValue(key, desc.exportValue());
break;
+ case TYPE_CUSTOM:
+ prefStore.setValue(key, desc.exportValue());
+ break;
case TYPE_MAP:
IProblemPreference[] childrenDescriptor = ((IProblemPreferenceCompositeDescriptor) desc)
.getChildDescriptors();

Back to the top