();
+
+ /**
+ * Default constructor will initialize the error parser with the name of the class
+ * using reflection mechanism.
+ */
+ public RegexErrorParser() {
+ fName = this.getClass().getSimpleName();
+ fId = this.getClass().getCanonicalName();
+ }
+
+ /**
+ * Constructor to initialize ID and name of the error parser.
+ *
+ * @param id - ID of the error parser.
+ * @param name - name of the error parser.
+ */
+ public RegexErrorParser(String id, String name) {
+ fName = name;
+ fId = id;
+ }
+
+ /**
+ * Set error parser ID.
+ *
+ * @param id of error parser
+ */
+ public void setId(String id) {
+ fId = id;
+ }
+
+ /**
+ * Set error parser name.
+ *
+ * @param name of error parser
+ */
+ public void setName(String name) {
+ fName = name;
+ }
+
+ /**
+ * Add new {@link RegexErrorPattern}.
+ *
+ * @param pattern - new pattern
+ */
+ public void addPattern(RegexErrorPattern pattern) {
+ fPatterns.add(pattern);
+ }
+
+ /**
+ * Remove error pattern from processing.
+ *
+ * @param pattern - error pattern to remove
+ */
+ public void removePattern(RegexErrorPattern pattern) {
+ fPatterns.remove(pattern);
+ }
+
+ /**
+ * Remove all error patterns.
+ */
+ public void clearPatterns() {
+ fPatterns.clear();
+ }
+
+ /**
+ * Method toString() for debugging purposes.
+ */
+ @Override
+ public String toString() {
+ return "id="+fId+", name="+fName; //$NON-NLS-1$//$NON-NLS-2$
+ }
+
+ /**
+ * @return id of error parser
+ */
+ public String getId() {
+ return fId;
+ }
+
+ /**
+ * @return name of error parser
+ */
+ public String getName() {
+ return fName;
+ }
+
+ /**
+ * @return array of error patterns of this error parser.
+ */
+ public RegexErrorPattern[] getPatterns() {
+ return fPatterns.toArray(new RegexErrorPattern[0]);
+ }
+
+
+ /**
+ * Parse a line of build output and register errors/warnings/infos for
+ * Problems view in internal list of {@link ErrorParserManager}.
+ *
+ * @param line - line of the input
+ * @param epManager - error parsers manager
+ * @return true if error parser recognized and accepted line, false otherwise
+ */
+ public boolean processLine(String line, ErrorParserManager epManager) {
+ for (RegexErrorPattern pattern : fPatterns)
+ try {
+ if (pattern.processLine(line, epManager))
+ return true;
+ } catch (Exception e){
+ String message = "Error parsing line [" + line + "]"; //$NON-NLS-1$//$NON-NLS-2$
+ CCorePlugin.log(message, e);
+ }
+
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof RegexErrorParser) {
+ RegexErrorParser that = (RegexErrorParser)o;
+ return this.fId.equals(that.fId)
+ && this.fName.equals(that.fName)
+ && this.fPatterns.equals(that.fPatterns);
+ }
+ return false;
+
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ RegexErrorParser that = new RegexErrorParser(fId, fName);
+ for (RegexErrorPattern pattern : fPatterns) {
+ that.addPattern((RegexErrorPattern)pattern.clone());
+ }
+ return that;
+ }
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/errorparsers/RegexErrorPattern.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/errorparsers/RegexErrorPattern.java
new file mode 100644
index 00000000000..95cc485fea7
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/core/errorparsers/RegexErrorPattern.java
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andrew Gvozdev (Quoin Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.core.errorparsers;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.cdt.utils.CygPath;
+import org.eclipse.core.resources.IResource;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.Path;
+
+/**
+ * RegexErrorPattern specifies a regular expression and rules how to create markers for
+ * Problems View. It is used by {@link RegexErrorParser} to process build output.
+ *
+ *
Regex pattern used by this class is Java regular expression and defines capturing groups.
+ * Those capturing groups are used in file, line, description expressions to get the values.
+ *
For example: pattern "(../../..) (.*):(\d*): (Error:.*)" could go along with
+ * file-expression "$2", line-expression "$3" and description-expression "$1 $4".
+ *
+ *
Note: variable name is being stored in marker tag. However currently it is not being used.
+ *
+ *
Severity could be one of:
+ *
- {@link IMarkerGenerator#SEVERITY_INFO},
+ *
- {@link IMarkerGenerator#SEVERITY_WARNING},
+ *
- {@link IMarkerGenerator#SEVERITY_ERROR_RESOURCE},
+ *
- {@link IMarkerGenerator#SEVERITY_ERROR_BUILD}
+ *
- {@link RegexErrorPattern#SEVERITY_SKIP}
+ *
{@code SEVERITY_SKIP} means that output line is checked to match the pattern
+ * but won't be parsed to create a marker. It is useful with conjunction with
+ * {@code eatProcessedLine=true} to filter out certain lines.
+ *
+ *
{@code eatProcessedLine} specifies if the current output line is being passed
+ * to the rest of patterns for further processing or consumed by the pattern.
+ *
+ *
Clients may extend this class. As it implements {@link Cloneable} interface those clients
+ * must implement {@link Object#clone} and {@link Object#equals} methods to avoid slicing.
+ * @since 5.2
+ */
+public class RegexErrorPattern implements Cloneable {
+ /**
+ * Additional "severity" flag which tells if qualified output line should be ignored.
+ */
+ public static final int SEVERITY_SKIP = -1;
+ private static final String EMPTY_STR=""; //$NON-NLS-1$
+
+ private Pattern pattern;
+ private String fileExpression;
+ private String lineExpression;
+ private String descriptionExpression;
+ private String varNameExpression;
+ private int severity;
+ private boolean eatProcessedLine;
+
+ private static boolean isCygwin = true;
+
+ /**
+ * Constructor.
+ *
+ * @param pattern - regular expression describing the capturing groups
+ * @param fileExpression - capturing group expression defining file name
+ * @param lineExpression - capturing group expression defining line number
+ * @param descriptionExpression - capturing group expression defining description
+ * @param varNameExpression -capturing group expression defining variable name
+ * @param severity - severity, one of
+ *
{@link IMarkerGenerator#SEVERITY_INFO},
+ *
{@link IMarkerGenerator#SEVERITY_WARNING},
+ *
{@link IMarkerGenerator#SEVERITY_ERROR_RESOURCE},
+ *
{@link IMarkerGenerator#SEVERITY_ERROR_BUILD}
+ *
{@link RegexErrorPattern#SEVERITY_SKIP}
+ * @param eat - defines whether to consume output line avoiding further processing by other patterns
+ *
+ *
See general description for this class {@link RegexErrorPattern} for more details.
+ */
+ public RegexErrorPattern(String pattern,
+ String fileExpression,
+ String lineExpression,
+ String descriptionExpression,
+ String varNameExpression,
+ int severity,
+ boolean eat) {
+ this.pattern = Pattern.compile(pattern!=null ? pattern : EMPTY_STR);
+ this.fileExpression = fileExpression!=null ? fileExpression : EMPTY_STR;
+ this.lineExpression = lineExpression!=null ? lineExpression : EMPTY_STR;
+ this.descriptionExpression = descriptionExpression!=null ? descriptionExpression : EMPTY_STR;
+ this.varNameExpression = varNameExpression!=null ? varNameExpression : EMPTY_STR;
+ this.severity = severity;
+ this.eatProcessedLine = eat;
+ }
+
+ /**
+ * @return regular expression pattern
+ */
+ public String getPattern() {
+ return pattern.toString();
+ }
+
+ /**
+ * @return expression defining file name
+ */
+ public String getFileExpression() {
+ return fileExpression;
+ }
+
+ /**
+ * @return expression defining line number
+ */
+ public String getLineExpression() {
+ return lineExpression;
+ }
+
+ /**
+ * @return expression defining description
+ */
+ public String getDescriptionExpression() {
+ return descriptionExpression;
+ }
+
+ /**
+ * @return expression defining variable name
+ */
+ public String getVarNameExpression() {
+ return varNameExpression;
+ }
+
+ /**
+ * @return severity of the marker, one of:
+ *
{@link IMarkerGenerator#SEVERITY_INFO},
+ *
{@link IMarkerGenerator#SEVERITY_WARNING},
+ *
{@link IMarkerGenerator#SEVERITY_ERROR_RESOURCE},
+ *
{@link IMarkerGenerator#SEVERITY_ERROR_BUILD}
+ */
+ public int getSeverity() {
+ return severity;
+ }
+
+ /**
+ * @return whether output line is consumed and not processed further by other patterns
+ */
+ public boolean isEatProcessedLine() {
+ return eatProcessedLine;
+ }
+
+ /**
+ * @param pattern - regular expression pattern describing the capturing groups
+ */
+ public void setPattern(String pattern) {
+ this.pattern = Pattern.compile(pattern);
+ }
+
+ /**
+ * @param fileExpression - capturing group expression defining file name
+ */
+ public void setFileExpression(String fileExpression) {
+ this.fileExpression = fileExpression;
+ }
+
+ /**
+ * @param lineExpression - capturing group expression defining line number
+ */
+ public void setLineExpression(String lineExpression) {
+ this.lineExpression = lineExpression;
+ }
+
+ /**
+ * @param descriptionExpression - capturing group expression defining description
+ */
+ public void setDescriptionExpression(String descriptionExpression) {
+ this.descriptionExpression = descriptionExpression;
+ }
+
+ /**
+ * @param varNameExpression -capturing group expression defining variable name
+ */
+ public void setVarNameExpression(String varNameExpression) {
+ this.varNameExpression = varNameExpression;
+ }
+
+ /**
+ * @param severity - severity, one of
+ *
{@link IMarkerGenerator#SEVERITY_INFO},
+ *
{@link IMarkerGenerator#SEVERITY_WARNING},
+ *
{@link IMarkerGenerator#SEVERITY_ERROR_RESOURCE},
+ *
{@link IMarkerGenerator#SEVERITY_ERROR_BUILD}
+ *
{@link RegexErrorPattern#SEVERITY_SKIP}
+ */
+ public void setSeverity(int severity) {
+ this.severity = severity;
+ }
+
+ /**
+ * @param eatProcessedLine - whether to consume output line avoiding further processing by other patterns
+ */
+ public void setEatProcessedLine(boolean eatProcessedLine) {
+ this.eatProcessedLine = eatProcessedLine;
+ }
+
+ /**
+ * @param input - input line.
+ * @return matcher to interpret the input line.
+ */
+ private Matcher getMatcher(CharSequence input) {
+ return pattern.matcher(input);
+ }
+
+ private String parseStr(Matcher matcher, String str) {
+ if (str!=null)
+ return matcher.replaceAll(str);
+ return null;
+ }
+ /**
+ * @param matcher - matcher to parse the input line.
+ * @return parsed file name or {@code null}.
+ */
+ protected String getFileName(Matcher matcher) {
+ return parseStr(matcher, fileExpression);
+ }
+
+ /**
+ * @param matcher - matcher to parse the input line.
+ * @return parsed line number or {@code 0}.
+ */
+ protected int getLineNum(Matcher matcher) {
+ if (lineExpression != null)
+ try {
+ return Integer.valueOf(matcher.replaceAll(lineExpression)).intValue();
+ } catch (NumberFormatException e) {
+ }
+ return 0;
+ }
+
+ /**
+ * @param matcher - matcher to parse the input line.
+ * @return parsed description or {@code null}.
+ */
+ protected String getDesc(Matcher matcher) {
+ return parseStr(matcher, descriptionExpression);
+ }
+
+ /**
+ * @param matcher - matcher to parse the input line.
+ * @return parsed variable name or {@code null}.
+ */
+ protected String getVarName(Matcher matcher) {
+ return parseStr(matcher, varNameExpression);
+ }
+
+ /**
+ * @param matcher - matcher to parse the input line.
+ * @return severity of the problem.
+ */
+ protected int getSeverity(Matcher matcher) {
+ return severity;
+ }
+
+ /**
+ * Parse a line of build output and register error/warning for
+ * Problems view.
+ *
+ * @param line - one line of output.
+ * @param eoParser - {@link ErrorParserManager}.
+ * @return {@code true} if error/warning/info problem was found.
+ */
+ public boolean processLine(String line, ErrorParserManager eoParser) {
+ Matcher matcher = getMatcher(line);
+ if (!matcher.find())
+ return false;
+
+ recordError(matcher, eoParser);
+ return eatProcessedLine;
+ }
+
+ /**
+ * Register the error in {@link ErrorParserManager}.
+ *
+ * @param matcher - matcher to parse the input line.
+ * @param eoParser - {@link ErrorParserManager}.
+ * @return {@code true} indicating that error was found.
+ */
+ protected boolean recordError(Matcher matcher, ErrorParserManager eoParser) {
+ int severity = getSeverity(matcher);
+ if (severity == SEVERITY_SKIP)
+ return true;
+
+ String fileName = getFileName(matcher);
+ int lineNum = getLineNum(matcher);
+ String desc = getDesc(matcher);
+ String varName = getVarName(matcher);
+ IPath externalPath = null ;
+
+ IResource file = null;
+ if (fileName != null) {
+ file = eoParser.findFileName(fileName);
+
+ if (file == null) {
+ // If the file is not found in the workspace we attach the problem to the project
+ // and add the external path to the file.
+ file = eoParser.getProject();
+ externalPath = getLocation(fileName);
+ }
+ }
+
+ eoParser.generateExternalMarker(file, lineNum, desc, severity, varName, externalPath);
+ return true;
+ }
+
+ /**
+ * If the file designated by filename exists, return the IPath representation of the filename
+ * If it does not exist, try cygpath translation
+ *
+ * @param filename - file name
+ * @return location (outside of the workspace).
+ */
+ private IPath getLocation(String filename) {
+ IPath path = new Path(filename);
+ File file = path.toFile() ;
+ if (!file.exists() && isCygwin && path.isAbsolute()) {
+ CygPath cygpath = null ;
+ try {
+ cygpath = new CygPath("cygpath"); //$NON-NLS-1$
+ String cygfilename = cygpath.getFileName(filename);
+ IPath convertedPath = new Path(cygfilename);
+ file = convertedPath.toFile() ;
+ if (file.exists()) {
+ path = convertedPath;
+ }
+ } catch (UnsupportedOperationException e) {
+ isCygwin = false;
+ } catch (IOException e) {
+ } finally {
+ if (null!=cygpath) {
+ cygpath.dispose();
+ }
+ }
+ }
+ return path ;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object o) {
+ if (o instanceof RegexErrorPattern) {
+ RegexErrorPattern that = (RegexErrorPattern)o;
+ return this.pattern.toString().equals(that.pattern.toString())
+ && this.fileExpression.equals(that.fileExpression)
+ && this.lineExpression.equals(that.lineExpression)
+ && this.descriptionExpression.equals(that.descriptionExpression)
+ && this.varNameExpression.equals(that.varNameExpression)
+ && this.severity==that.severity
+ && this.eatProcessedLine==that.eatProcessedLine;
+ }
+ return false;
+
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#clone()
+ */
+ @Override
+ public Object clone() throws CloneNotSupportedException {
+ return new RegexErrorPattern(pattern.toString(),
+ fileExpression,
+ lineExpression,
+ descriptionExpression,
+ varNameExpression,
+ severity,
+ eatProcessedLine);
+ }
+}
diff --git a/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorParserExtensionManager.java b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorParserExtensionManager.java
new file mode 100644
index 00000000000..d2e4ba56b9b
--- /dev/null
+++ b/core/org.eclipse.cdt.core/src/org/eclipse/cdt/internal/errorparsers/ErrorParserExtensionManager.java
@@ -0,0 +1,726 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 Andrew Gvozdev (Quoin Inc.) and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andrew Gvozdev (Quoin Inc.) - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.internal.errorparsers;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+import java.util.Map.Entry;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.eclipse.cdt.core.CCorePlugin;
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IErrorParser;
+import org.eclipse.cdt.core.IErrorParserNamed;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.cdt.core.errorparsers.ErrorParserNamedWrapper;
+import org.eclipse.cdt.core.errorparsers.RegexErrorParser;
+import org.eclipse.cdt.core.errorparsers.RegexErrorPattern;
+import org.eclipse.cdt.internal.core.XmlUtil;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.preferences.IEclipsePreferences;
+import org.eclipse.core.runtime.preferences.InstanceScope;
+import org.osgi.service.prefs.BackingStoreException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.SAXException;
+
+/**
+ * ErrorParserExtensionManager manages error parser extensions, serialization and preferences
+ *
+ */
+public class ErrorParserExtensionManager {
+ private static final String STORAGE_ERRORPARSER_EXTENSIONS = "model.extensions.xml"; //$NON-NLS-1$
+ private static final String PREFERENCE_ERRORPARSER_DEFAULT_IDS = "errorparser.default.ids"; //$NON-NLS-1$
+ private static final String NONE = ""; //$NON-NLS-1$
+
+ private static final String EXTENSION_POINT_ERROR_PARSER = "org.eclipse.cdt.core.ErrorParser"; //$NON-NLS-1$
+ private static final String ELEM_PLUGIN = "plugin"; //$NON-NLS-1$
+ private static final String ELEM_EXTENSION = "extension"; //$NON-NLS-1$
+ private static final String ELEM_ERRORPARSER = "errorparser"; //$NON-NLS-1$
+ private static final String ELEM_PATTERN = "pattern"; //$NON-NLS-1$
+ private static final String ATTR_CLASS = "class"; //$NON-NLS-1$
+ private static final String ATTR_ID = "id"; //$NON-NLS-1$
+ private static final String ATTR_NAME = "name"; //$NON-NLS-1$
+ private static final String ATTR_POINT = "point"; //$NON-NLS-1$
+
+ private static final String ATTR_REGEX = "regex"; //$NON-NLS-1$
+ private static final String ATTR_SEVERITY = "severity"; //$NON-NLS-1$
+ private static final String ATTR_FILE = "file-expr"; //$NON-NLS-1$
+ private static final String ATTR_LINE = "line-expr"; //$NON-NLS-1$
+ private static final String ATTR_DESCRIPTION = "description-expr"; //$NON-NLS-1$
+ private static final String ATTR_VARIABLE = "variable-expr"; //$NON-NLS-1$
+ private static final String ATTR_EAT_LINE = "eat-processed-line"; //$NON-NLS-1$
+
+ private static final String ATTR_VALUE_WARNING = "Warning"; //$NON-NLS-1$
+ private static final String ATTR_VALUE_ERROR = "Error"; //$NON-NLS-1$
+ private static final String ATTR_VALUE_INFO = "Info"; //$NON-NLS-1$
+ private static final String ATTR_VALUE_IGNORE = "Ignore"; //$NON-NLS-1$
+
+ private static final LinkedHashMap fExtensionErrorParsers = new LinkedHashMap();
+ private static final LinkedHashMap fAvailableErrorParsers = new LinkedHashMap();
+ private static LinkedHashMap fUserDefinedErrorParsers = null;
+ private static List fDefaultErrorParserIds = null;
+
+ static {
+ loadUserDefinedErrorParsers();
+ loadDefaultErrorParserIds();
+ loadErrorParserExtensions();
+ }
+
+ /**
+ * Load user defined error parsers from workspace preference storage.
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ */
+ synchronized public static void loadUserDefinedErrorParsers() {
+ fUserDefinedErrorParsers = null;
+ Document doc = null;
+ try {
+ doc = loadXml(getStoreLocation(STORAGE_ERRORPARSER_EXTENSIONS));
+ } catch (Exception e) {
+ CCorePlugin.log("Can't load preferences from file "+STORAGE_ERRORPARSER_EXTENSIONS, e); //$NON-NLS-1$
+ }
+
+ if (doc!=null) {
+ Set errorParsers = new LinkedHashSet();
+ loadErrorParserExtensions(doc, errorParsers);
+
+ if (errorParsers.size()>0) {
+ fUserDefinedErrorParsers = new LinkedHashMap();
+ for (IErrorParserNamed errorParser : errorParsers) {
+ fUserDefinedErrorParsers.put(errorParser.getId(), errorParser);
+ }
+ }
+ }
+ recalculateAvailableErrorParsers();
+ }
+
+ /**
+ * Load XML from file to DOM Document.
+ *
+ * @param location - location of XML file
+ * @return new loaded XML Document or {@code null} if file does not exist
+ * @throws ParserConfigurationException
+ * @throws SAXException
+ * @throws IOException
+ */
+ private static Document loadXml(IPath location) throws ParserConfigurationException, SAXException, IOException {
+ java.io.File storeFile = location.toFile();
+ if (storeFile.exists()) {
+ InputStream xmlStream = new FileInputStream(storeFile);
+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ return builder.parse(xmlStream);
+ }
+ return null;
+ }
+
+ /**
+ * Parse error parser contributed extensions from XML document.
+ *
+ * @param doc - source XML
+ * @param errorParsers - resulting list of error parsers
+ */
+ private static void loadErrorParserExtensions(Document doc, Set errorParsers) {
+ errorParsers.clear();
+ NodeList extentionNodes = doc.getElementsByTagName(ELEM_EXTENSION);
+ for (int iext=0;iext sortedErrorParsers = new TreeSet(new Comparator() {
+ public int compare(IErrorParserNamed errorParser1, IErrorParserNamed errorParser2) {
+ return errorParser1.getName().compareTo(errorParser2.getName());
+ }
+ });
+
+ loadErrorParserExtensions(Platform.getExtensionRegistry(), sortedErrorParsers);
+
+ fExtensionErrorParsers.clear();
+ for (IErrorParserNamed errorParser : sortedErrorParsers) {
+ fExtensionErrorParsers.put(errorParser.getId(), errorParser);
+ }
+ recalculateAvailableErrorParsers();
+ }
+
+ /**
+ * Load error parser contributed extensions from extension registry.
+ *
+ * @param registry - extension registry
+ * @param errorParsers - resulting set of error parsers
+ */
+ private static void loadErrorParserExtensions(IExtensionRegistry registry, Set errorParsers) {
+ errorParsers.clear();
+ IExtensionPoint extension = registry.getExtensionPoint(CCorePlugin.PLUGIN_ID, CCorePlugin.ERROR_PARSER_SIMPLE_ID);
+ if (extension != null) {
+ IExtension[] extensions = extension.getExtensions();
+ for (IExtension ext : extensions) {
+ try {
+ String extensionID = ext.getUniqueIdentifier();
+ String oldStyleId = extensionID;
+ String oldStyleName = ext.getLabel();
+ for (IConfigurationElement cfgEl : ext.getConfigurationElements()) {
+ if (cfgEl.getName().equals(ELEM_ERRORPARSER)) {
+ IErrorParserNamed errorParser = createErrorParserCarcass(oldStyleId, oldStyleName, cfgEl);
+ if (errorParser!=null) {
+ configureErrorParser(errorParser, cfgEl);
+ errorParsers.add(errorParser);
+ }
+ }
+ }
+ } catch (Exception e) {
+ CCorePlugin.log("Cannot load ErrorParser extension " + ext.getUniqueIdentifier(), e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
+
+ /**
+ * Populate the list of available error parsers where workspace level user defined parsers
+ * overwrite contributed through error parser extension point.
+ */
+ private static void recalculateAvailableErrorParsers() {
+ fAvailableErrorParsers.clear();
+ if (fUserDefinedErrorParsers!=null) {
+ fAvailableErrorParsers.putAll(fUserDefinedErrorParsers);
+ }
+ for (IErrorParserNamed errorParser : fExtensionErrorParsers.values()) {
+ String id = errorParser.getId();
+ if (!fAvailableErrorParsers.containsKey(id)) {
+ fAvailableErrorParsers.put(id, errorParser);
+ }
+ }
+ }
+
+ /**
+ * Serialize error parsers in workspace level storage.
+ *
+ * @throws CoreException if something goes wrong
+ */
+ public static void serializeUserDefinedErrorParsers() throws CoreException {
+ try {
+ DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ Document doc = builder.newDocument();
+ Element elementPlugin = doc.createElement(ELEM_PLUGIN);
+ doc.appendChild(elementPlugin);
+
+ if (fUserDefinedErrorParsers!=null) {
+ for (Entry entry: fUserDefinedErrorParsers.entrySet()) {
+ IErrorParserNamed errorParser = entry.getValue();
+ addErrorParserExtension(elementPlugin, errorParser);
+ }
+ }
+
+ serializeXml(doc, getStoreLocation(STORAGE_ERRORPARSER_EXTENSIONS));
+
+ } catch (Exception e) {
+ throw new CoreException(new Status(IStatus.ERROR, "Failed serializing to file " + STORAGE_ERRORPARSER_EXTENSIONS, CCorePlugin.PLUGIN_ID, e)); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Utility method to convert severity to string for the purpose of serializing in XML.
+ *
+ * @param severity - severity
+ * @return string representation
+ */
+ private static String severityToString(int severity) {
+ switch (severity) {
+ case IMarkerGenerator.SEVERITY_INFO:
+ return ATTR_VALUE_INFO;
+ case IMarkerGenerator.SEVERITY_WARNING:
+ return ATTR_VALUE_WARNING;
+ case IMarkerGenerator.SEVERITY_ERROR_BUILD:
+ case IMarkerGenerator.SEVERITY_ERROR_RESOURCE:
+ return ATTR_VALUE_ERROR;
+ }
+ return ATTR_VALUE_IGNORE;
+ }
+
+ /**
+ * Utility method to de-serialize severity from XML.
+ *
+ * @param attrSeverity - string representation of the severity
+ * @return severity
+ */
+ private static int stringToSeverity(String attrSeverity) {
+ if (ATTR_VALUE_ERROR.equals(attrSeverity))
+ return IMarkerGenerator.SEVERITY_ERROR_RESOURCE;
+ if (ATTR_VALUE_WARNING.equals(attrSeverity))
+ return IMarkerGenerator.SEVERITY_WARNING;
+ if (ATTR_VALUE_INFO.equals(attrSeverity))
+ return IMarkerGenerator.SEVERITY_INFO;
+
+ return RegexErrorPattern.SEVERITY_SKIP;
+ }
+
+ /**
+ * Add error parser extension to XML fragment, normally under element.
+ *
+ * @param elementPlugin - element where to add error parser extension
+ * @param errorParserNamed - error parser to add
+ */
+ private static void addErrorParserExtension(Element elementPlugin, IErrorParserNamed errorParserNamed) {
+ String id = errorParserNamed.getId();
+ String name = errorParserNamed.getName();
+ String simpleId = getSimpleId(id);
+
+ IErrorParser errorParser = errorParserNamed;
+ if (errorParser instanceof ErrorParserNamedWrapper)
+ errorParser = ((ErrorParserNamedWrapper)errorParser).getErrorParser();
+
+ Document doc = elementPlugin.getOwnerDocument();
+
+ //
+ Element elementExtension = doc.createElement(ELEM_EXTENSION);
+ elementExtension.setAttribute(ATTR_ID, simpleId);
+ elementExtension.setAttribute(ATTR_NAME, name);
+ elementExtension.setAttribute(ATTR_POINT, EXTENSION_POINT_ERROR_PARSER);
+
+ elementPlugin.appendChild(elementExtension);
+
+ //
+ Element elementErrorParser = doc.createElement(ELEM_ERRORPARSER);
+ elementErrorParser.setAttribute(ATTR_ID, id);
+ elementErrorParser.setAttribute(ATTR_NAME, name);
+ elementErrorParser.setAttribute(ATTR_CLASS, errorParser.getClass().getCanonicalName());
+
+ elementExtension.appendChild(elementErrorParser);
+
+ if (errorParserNamed instanceof RegexErrorParser) {
+ RegexErrorParser regexErrorParser = (RegexErrorParser)errorParserNamed;
+ RegexErrorPattern[] patterns = regexErrorParser.getPatterns();
+
+ for (RegexErrorPattern pattern : patterns) {
+ //
+ Element elementPattern = doc.createElement(ELEM_PATTERN);
+ elementPattern.setAttribute(ATTR_SEVERITY, severityToString(pattern.getSeverity()));
+ elementPattern.setAttribute(ATTR_REGEX, pattern.getPattern());
+ elementPattern.setAttribute(ATTR_FILE, pattern.getFileExpression());
+ elementPattern.setAttribute(ATTR_LINE, pattern.getLineExpression());
+ elementPattern.setAttribute(ATTR_DESCRIPTION, pattern.getDescriptionExpression());
+ elementPattern.setAttribute(ATTR_EAT_LINE, String.valueOf(pattern.isEatProcessedLine()));
+
+ elementErrorParser.appendChild(elementPattern);
+ }
+
+ }
+ }
+
+ /**
+ * Determine simple ID of error parser as last segment of full or unique ID.
+ *
+ * @param uniqueId - full ID of error parser
+ * @return simple ID of error parser
+ */
+ private static String getSimpleId(String uniqueId) {
+ String simpleId = uniqueId;
+ int dot = uniqueId.lastIndexOf('.');
+ if (dot>=0) {
+ simpleId = uniqueId.substring(dot+1);
+ }
+ return simpleId;
+ }
+
+ /**
+ * Serialize XML Document in a file.
+ *
+ * @param doc - XML to serialize
+ * @param location - location of the file
+ * @throws IOException in case of problems with file I/O
+ * @throws TransformerException in case of problems with XML output
+ */
+ synchronized private static void serializeXml(Document doc, IPath location) throws IOException, TransformerException {
+
+ java.io.File storeFile = location.toFile();
+ if (!storeFile.exists()) {
+ storeFile.createNewFile();
+ }
+ OutputStream fileStream = new FileOutputStream(storeFile);
+
+ TransformerFactory transformerFactory = TransformerFactory.newInstance();
+ Transformer transformer = transformerFactory.newTransformer();
+ transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
+ transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); //$NON-NLS-1$
+ transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
+
+ XmlUtil.prettyFormat(doc);
+ DOMSource source = new DOMSource(doc);
+ StreamResult result = new StreamResult(new FileOutputStream(storeFile));
+ transformer.transform(source, result);
+
+ fileStream.close();
+ }
+
+ /**
+ * Save the list of default error parsers in preferences.
+ *
+ * @throws BackingStoreException in case of problem storing
+ */
+ public static void serializeDefaultErrorParserIds() throws BackingStoreException {
+ IEclipsePreferences preferences = new InstanceScope().getNode(CCorePlugin.PLUGIN_ID);
+ String ids = NONE;
+ if (fDefaultErrorParserIds!=null) {
+ ids = ErrorParserManager.toDelimitedString(fDefaultErrorParserIds.toArray(new String[0]));
+ }
+
+ preferences.put(PREFERENCE_ERRORPARSER_DEFAULT_IDS, ids);
+ preferences.flush();
+ }
+
+ /**
+ * @param store - name of the store
+ * @return location of the store in the plug-in state area
+ */
+ private static IPath getStoreLocation(String store) {
+ return CCorePlugin.getDefault().getStateLocation().append(store);
+ }
+
+ /**
+ * Creates empty non-configured error parser from extension point definition looking at "class" attribute.
+ * ID and name of error parser are assigned from first extension point encountered.
+ *
+ * @param className - full qualified class name of error parser.
+ * @param registry - extension registry
+ * @return new non-configured error parser
+ */
+ private static IErrorParserNamed createErrorParserCarcass(String className, IExtensionRegistry registry) {
+ if (className==null || className.length()==0 || className.equals(RegexErrorParser.class.getName()))
+ return new RegexErrorParser();
+
+ try {
+ IExtensionPoint extension = registry.getExtensionPoint(CCorePlugin.PLUGIN_ID, CCorePlugin.ERROR_PARSER_SIMPLE_ID);
+ if (extension != null) {
+ IExtension[] extensions = extension.getExtensions();
+ for (IExtension ext : extensions) {
+ String extensionID = ext.getUniqueIdentifier();
+ String oldStyleId = extensionID;
+ String oldStyleName = ext.getLabel();
+ for (IConfigurationElement cfgEl : ext.getConfigurationElements()) {
+ if (cfgEl.getName().equals(ELEM_ERRORPARSER) && className.equals(cfgEl.getAttribute(ATTR_CLASS))) {
+ return createErrorParserCarcass(oldStyleId, oldStyleName, cfgEl);
+ }
+ }
+ }
+ }
+ } catch (Exception e) {
+ CCorePlugin.log("Error creating error parser", e); //$NON-NLS-1$
+ }
+ return null;
+ }
+
+ /**
+ * Creates empty non-configured error parser as executable extension from extension point definition.
+ * If "class" attribute is empty RegexErrorParser is created.
+ *
+ * @param initialId - nominal ID of error parser
+ * @param initialName - nominal name of error parser
+ * @param ce - configuration element with error parser definition
+ * @return new non-configured error parser
+ * @throws CoreException in case of failure
+ */
+ private static IErrorParserNamed createErrorParserCarcass(String initialId, String initialName, IConfigurationElement ce) throws CoreException {
+ IErrorParserNamed errorParser = null;
+ if (ce.getAttribute(ATTR_CLASS)!=null) {
+ IErrorParser ep = (IErrorParser)ce.createExecutableExtension(ATTR_CLASS);
+ if (ep instanceof IErrorParserNamed) {
+ errorParser = (IErrorParserNamed)ep;
+ errorParser.setId(initialId);
+ errorParser.setName(initialName);
+ } else if (ep!=null) {
+ errorParser = new ErrorParserNamedWrapper(initialId, initialName, ep);
+ }
+ }
+ if (errorParser==null) {
+ errorParser = new RegexErrorParser(initialId, initialName);
+ }
+ return errorParser;
+ }
+
+ /**
+ * Configure error parser from XML error parser node.
+ *
+ * @param errorParser - error parser to configure
+ * @param errorparserNode - XML error parser node
+ */
+ private static void configureErrorParser(IErrorParserNamed errorParser, Node errorparserNode) {
+ NamedNodeMap errorParserAttributes = errorparserNode.getAttributes();
+ String id = determineNodeValue(errorParserAttributes.getNamedItem(ATTR_ID));
+ String name = determineNodeValue(errorParserAttributes.getNamedItem(ATTR_NAME));
+ errorParser.setId(id);
+ errorParser.setName(name);
+ if (errorParser instanceof RegexErrorParser) {
+ RegexErrorParser regexErrorParser = (RegexErrorParser)errorParser;
+
+ NodeList patternNodes = errorparserNode.getChildNodes();
+ for (int ipat=0;ipat0)
+ errorParser.setId(id);
+ String name = cfgEl.getAttribute(ATTR_NAME);
+ if (name!=null && name.length()>0)
+ errorParser.setName(name);
+
+ if (errorParser instanceof RegexErrorParser) {
+ RegexErrorParser regexErrorParser = (RegexErrorParser)errorParser;
+
+ for (IConfigurationElement cepat : cfgEl.getChildren()) {
+ if (cepat.getName().equals(ELEM_PATTERN)) {
+
+ boolean eat = ! Boolean.FALSE.toString().equals(cepat.getAttribute(ATTR_EAT_LINE));
+ regexErrorParser.addPattern(new RegexErrorPattern(cepat.getAttribute(ATTR_REGEX),
+ cepat.getAttribute(ATTR_FILE),
+ cepat.getAttribute(ATTR_LINE),
+ cepat.getAttribute(ATTR_DESCRIPTION),
+ cepat.getAttribute(ATTR_VARIABLE),
+ stringToSeverity(cepat.getAttribute(ATTR_SEVERITY)),
+ eat));
+ }
+ }
+ }
+ }
+
+ /**
+ * Return error parser as stored in internal list.
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ * Use {@link #getErrorParserCopy(String)} instead.
+ *
+ * @param id - ID of error parser
+ * @return internal instance of error parser
+ */
+ public static IErrorParser getErrorParserInternal(String id) {
+ IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
+ if (errorParser instanceof ErrorParserNamedWrapper)
+ return ((ErrorParserNamedWrapper)errorParser).getErrorParser();
+ return errorParser;
+ }
+
+ /**
+ * Set and store in workspace area user defined error parsers.
+ *
+ * @param errorParsers - array of user defined error parsers
+ * @throws CoreException in case of problems
+ */
+ public static void setUserDefinedErrorParsers(IErrorParserNamed[] errorParsers) throws CoreException {
+ setUserDefinedErrorParsersInternal(errorParsers);
+ serializeUserDefinedErrorParsers();
+ }
+
+ /**
+ * Internal method to set user defined error parsers in memory.
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ * Use {@link #setUserDefinedErrorParsers(IErrorParserNamed[])}.
+ *
+ * @param errorParsers - array of user defined error parsers
+ */
+ public static void setUserDefinedErrorParsersInternal(IErrorParserNamed[] errorParsers) {
+ if (errorParsers==null) {
+ fUserDefinedErrorParsers = null;
+ } else {
+ fUserDefinedErrorParsers= new LinkedHashMap();
+ // set customized list
+ for (IErrorParserNamed errorParser : errorParsers) {
+ fUserDefinedErrorParsers.put(errorParser.getId(), errorParser);
+ }
+ }
+ recalculateAvailableErrorParsers();
+ }
+
+ /**
+ * @return available error parsers IDs which include contributed through extension + user defined ones
+ * from workspace
+ */
+ public static String[] getErrorParserAvailableIds() {
+ return fAvailableErrorParsers.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * @return IDs of error parsers contributed through error parser extension point.
+ */
+ public static String[] getErrorParserExtensionIds() {
+ return fExtensionErrorParsers.keySet().toArray(new String[0]);
+ }
+
+ /**
+ * Set and store default error parsers IDs to be used if error parser list is empty.
+ *
+ * @param ids - default error parsers IDs
+ * @throws BackingStoreException in case of problem with storing
+ */
+ public static void setDefaultErrorParserIds(String[] ids) throws BackingStoreException {
+ setDefaultErrorParserIdsInternal(ids);
+ serializeDefaultErrorParserIds();
+ }
+
+ /**
+ * Set default error parsers IDs in internal list.
+ *
+ * @noreference This method is not intended to be referenced by clients.
+ * Use {@link #setDefaultErrorParserIds(String[])}.
+ *
+ * @param ids - default error parsers IDs
+ */
+ public static void setDefaultErrorParserIdsInternal(String[] ids) {
+ if (ids==null) {
+ fDefaultErrorParserIds = null;
+ } else {
+ fDefaultErrorParserIds = new ArrayList(Arrays.asList(ids));
+ }
+ }
+
+ /**
+ * @return default error parsers IDs to be used if error parser list is empty.
+ */
+ public static String[] getDefaultErrorParserIds() {
+ if (fDefaultErrorParserIds==null) {
+ return fAvailableErrorParsers.keySet().toArray(new String[0]);
+ }
+ return fDefaultErrorParserIds.toArray(new String[0]);
+ }
+
+ /**
+ * @param id - ID of error parser
+ * @return cloned copy of error parser. Note that {@link ErrorParserNamedWrapper} returns
+ * shallow copy with the same instance of underlying error parser.
+ */
+ public static IErrorParserNamed getErrorParserCopy(String id) {
+ IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
+
+ try {
+ if (errorParser instanceof RegexErrorParser) {
+ return (RegexErrorParser) ((RegexErrorParser)errorParser).clone();
+ } else if (errorParser instanceof ErrorParserNamedWrapper) {
+ return (ErrorParserNamedWrapper) ((ErrorParserNamedWrapper)errorParser).clone();
+ }
+ } catch (CloneNotSupportedException e) {
+ CCorePlugin.log(e);
+ }
+ return errorParser;
+ }
+
+
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/IInputStatusValidator.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/IInputStatusValidator.java
new file mode 100644
index 00000000000..57c100929ef
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/IInputStatusValidator.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 Andrew Gvozdev and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.dialogs;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+
+/**
+ * The IInputStatusValidator is the interface for IStatus validators.
+ */
+public interface IInputStatusValidator {
+ /**
+ * Validates the given string. Returns the status with an error/warning/info message to display if the new
+ * text fails validation.
+ *
+ * @param newText
+ * the text to check for validity
+ *
+ * @return {@link IStatus} object. For the purpose of validation severity and message are considered.
+ * {@link Status#OK_STATUS} or any {@link IStatus#OK} to indicate no error.
+ * {@link IStatus#ERROR} indicates an error.
+ * {@link IStatus#WARNING} indicates a warning.
+ * {@link IStatus#INFO} indicates an informational message.
+ */
+ public IStatus isValid(String newText);
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/InputStatusDialog.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/InputStatusDialog.java
new file mode 100644
index 00000000000..1c5d84b5079
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/dialogs/InputStatusDialog.java
@@ -0,0 +1,208 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 Andrew Gvozdev and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andrew Gvozdev - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.cdt.internal.ui.dialogs;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.StatusDialog;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.layout.GridData;
+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.swt.widgets.Text;
+
+/**
+ * An input dialog for soliciting an input string from the user.
+ * The string can be validated. In case of problem error/warning/info message
+ * is shown in status line and decorated with appropriate status icon.
+ *
+ * This concrete dialog class can be instantiated as is, or further subclassed as required.
+ *
+ */
+public class InputStatusDialog extends StatusDialog {
+ /**
+ * The title of the dialog.
+ */
+ private String title;
+
+ /**
+ * The message to display, or null
if none.
+ */
+ private String message;
+
+ /**
+ * The input value; the empty string by default.
+ */
+ private String value = "";//$NON-NLS-1$
+
+ /**
+ * The input validator, or null
if none.
+ */
+ private IInputStatusValidator validator;
+
+ /**
+ * Input text widget.
+ */
+ private Text text;
+
+ /**
+ * Creates an input dialog with OK and Cancel buttons. Note that the dialog
+ * will have no visual representation (no widgets) until it is told to open.
+ *
+ * Note that the open
method blocks for input dialogs.
+ *
+ *
+ * @param parentShell
+ * the parent shell, or null
to create a top-level
+ * shell
+ * @param dialogTitle
+ * the dialog title, or null
if none
+ * @param dialogMessage
+ * the dialog message, or null
if none
+ * @param initialValue
+ * the initial input value, or null
if none
+ * (equivalent to the empty string)
+ * @param validator
+ * an input validator, or null
if none
+ * For a validator, following return statuses are recognized:
+ * {@link Status#OK_STATUS} or any {@link IStatus#OK} to indicate no error.
+ * {@link IStatus#ERROR} indicates an error.
+ * {@link IStatus#WARNING} indicates a warning.
+ * {@link IStatus#INFO} indicates an informational message
+ */
+ public InputStatusDialog(Shell parentShell, String dialogTitle, String dialogMessage,
+ String initialValue, IInputStatusValidator validator) {
+ super(parentShell);
+ this.title = dialogTitle;
+ if (dialogMessage == null) {
+ this.message = ""; //$NON-NLS-1$
+ } else {
+ this.message = dialogMessage;
+ }
+ if (initialValue == null) {
+ this.value = ""; //$NON-NLS-1$
+ } else {
+ this.value = initialValue;
+ }
+ this.validator = validator;
+ }
+
+ /*
+ * (non-Javadoc) Method declared on Dialog.
+ */
+ @Override
+ protected void buttonPressed(int buttonId) {
+ if (buttonId == IDialogConstants.OK_ID) {
+ value = text.getText();
+ } else {
+ value = null;
+ }
+ super.buttonPressed(buttonId);
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell)
+ */
+ @Override
+ protected void configureShell(Shell shell) {
+ super.configureShell(shell);
+ if (title != null) {
+ shell.setText(title);
+ }
+ }
+
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Composite composite = (Composite) super.createDialogArea(parent);
+
+ Label label = new Label(composite, SWT.WRAP);
+ label.setText(message);
+ GridData data = new GridData(GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL
+ | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER);
+ data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.MINIMUM_MESSAGE_AREA_WIDTH);
+ label.setLayoutData(data);
+ label.setFont(parent.getFont());
+
+ text = new Text(composite, getInputTextStyle());
+ text.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
+ text.addModifyListener(new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ validateInput();
+ }
+ });
+ text.setFocus();
+ if (value != null) {
+ text.setText(value);
+ text.selectAll();
+ }
+
+ applyDialogFont(composite);
+
+ return composite;
+ }
+
+ /**
+ * Returns the text area.
+ *
+ * @return the text area
+ */
+ protected Text getText() {
+ return text;
+ }
+
+ /**
+ * Returns the validator.
+ *
+ * @return the validator
+ */
+ protected IInputStatusValidator getValidator() {
+ return validator;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * Validates the input.
+ *
+ * The default implementation of this framework method delegates the request to the supplied input
+ * validator object; if it finds the input invalid, the error message is displayed in the dialog's message
+ * line. This hook method is called whenever the text changes in the input field.
+ *
+ */
+ protected void validateInput() {
+ IStatus status = Status.OK_STATUS;
+ if (validator != null) {
+ status = validator.isValid(text.getText());
+ }
+ updateStatus(status);
+ }
+
+ /**
+ * Returns the style bits that should be used for the input text field. Defaults to a single line entry.
+ * Subclasses may override.
+ *
+ * @return the integer style bits that should be used when creating the input text
+ *
+ */
+ protected int getInputTextStyle() {
+ return SWT.SINGLE | SWT.BORDER;
+ }
+
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.java
index 80ac136bd43..73b8abf0b45 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.java
@@ -57,6 +57,52 @@ public class DialogsMessages extends NLS {
public static String DocCommentOwnerBlock_SelectDocToolDescription;
public static String DocCommentOwnerCombo_None;
public static String DocCommentOwnerComposite_DocumentationToolGroupTitle;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_ConsumeNo;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_ConsumeYes;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_DescriptionColumn;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_EatColumn;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_FileColumn;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_LineColumn;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_LinkToPreferencesMessage;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_Pattern_Column;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_SeverityColumn;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_SeverityError;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_SeverityIgnore;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_SeverityInfo;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_SeverityWarning;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_Title;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_TooltipConsume;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_TooltipDescription;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_TooltipFile;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_TooltipLine;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_TooltipPattern;
+ /** @since 5.2 */
+ public static String RegexErrorParserOptionPage_TooltipSeverity;
+ /** @since 5.2 */
+ public static String RegularExpression_EmptyPattern;
+ /** @since 5.2 */
+ public static String RegularExpression_Validate;
+ /** @since 5.2 */
+ public static String RegularExpression_Enter;
static {
// initialize resource bundle
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.properties
index f415fe0cdc9..7511ed91e5d 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/DialogsMessages.properties
@@ -41,3 +41,26 @@ IndexerStrategyBlock_immediateUpdate=Update index immediately after every file-s
IndexerStrategyBlock_buildConfigGroup=Build configuration for the indexer
IndexerStrategyBlock_activeBuildConfig=Use active build configuration
IndexerStrategyBlock_specificBuildConfig=Use the build configuration specified in the project's indexer settings
+RegexErrorParserOptionPage_ConsumeNo=No
+RegexErrorParserOptionPage_ConsumeYes=
+RegexErrorParserOptionPage_DescriptionColumn=Description
+RegexErrorParserOptionPage_EatColumn=Consume
+RegexErrorParserOptionPage_FileColumn=File
+RegexErrorParserOptionPage_LineColumn=Line
+RegexErrorParserOptionPage_LinkToPreferencesMessage=These options are workspace-wide and can be changed in Workspace Settings.
+RegexErrorParserOptionPage_Pattern_Column=Pattern
+RegexErrorParserOptionPage_SeverityColumn=Severity
+RegexErrorParserOptionPage_SeverityError=Error
+RegexErrorParserOptionPage_SeverityIgnore=Ignore
+RegexErrorParserOptionPage_SeverityInfo=Info
+RegexErrorParserOptionPage_SeverityWarning=Warning
+RegexErrorParserOptionPage_Title=Error Parser Options
+RegexErrorParserOptionPage_TooltipConsume=Use ''{0}'' to allow to re-process matching input line by other patterns
+RegexErrorParserOptionPage_TooltipDescription=Description as replacement expression (i.e. $3)
+RegexErrorParserOptionPage_TooltipFile=File as replacement expression (i.e. $1)
+RegexErrorParserOptionPage_TooltipLine=Line as replacement expression (i.e. $2)
+RegexErrorParserOptionPage_TooltipPattern=Java regular expression specifying capturing groups for 'File', 'Line' and 'Description'
+RegexErrorParserOptionPage_TooltipSeverity=Severity of marker
+RegularExpression_EmptyPattern=Empty pattern
+RegularExpression_Validate=Validate Regular Expression
+RegularExpression_Enter=Enter regular expression (use Ctrl+Space for content assist):
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/RegexErrorParserOptionPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/RegexErrorParserOptionPage.java
new file mode 100644
index 00000000000..adb46b9b5b3
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/RegexErrorParserOptionPage.java
@@ -0,0 +1,752 @@
+/*******************************************************************************
+ * Copyright (c) 2009, 2009 Andrew Gvozdev and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andrew Gvozdev - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.ui.dialogs;
+
+import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.text.FindReplaceDocumentAdapterContentProposalProvider;
+import org.eclipse.jface.viewers.ArrayContentProvider;
+import org.eclipse.jface.viewers.CellEditor;
+import org.eclipse.jface.viewers.ColumnLabelProvider;
+import org.eclipse.jface.viewers.ColumnWeightData;
+import org.eclipse.jface.viewers.ComboBoxCellEditor;
+import org.eclipse.jface.viewers.EditingSupport;
+import org.eclipse.jface.viewers.TableLayout;
+import org.eclipse.jface.viewers.TableViewer;
+import org.eclipse.jface.viewers.TableViewerColumn;
+import org.eclipse.jface.viewers.TextCellEditor;
+import org.eclipse.jface.window.Window;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Link;
+import org.eclipse.swt.widgets.Listener;
+import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.ISharedImages;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.PreferencesUtil;
+import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
+
+import com.ibm.icu.text.MessageFormat;
+
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IErrorParserNamed;
+import org.eclipse.cdt.core.IMarkerGenerator;
+import org.eclipse.cdt.core.errorparsers.RegexErrorParser;
+import org.eclipse.cdt.core.errorparsers.RegexErrorPattern;
+import org.eclipse.cdt.ui.newui.AbstractCPropertyTab;
+
+import org.eclipse.cdt.internal.ui.dialogs.MessageLine;
+import org.eclipse.cdt.internal.ui.util.PixelConverter;
+import org.eclipse.cdt.internal.ui.util.SWTUtil;
+import org.eclipse.cdt.internal.ui.util.TableLayoutComposite;
+
+/**
+ * Options page for RegexErrorParser in Error Parsers Tab of properties/preferences.
+ *
+ * @noextend This class is not intended to be subclassed by clients.
+ * @since 5.2
+ */
+public final class RegexErrorParserOptionPage extends AbstractCOptionPage {
+
+ private static final String WORKSPACE_PREFERENCE_PAGE = "org.eclipse.cdt.make.ui.preferences.BuildSettings"; //$NON-NLS-1$
+
+ private static final int BUTTON_ADD = 0;
+ private static final int BUTTON_DELETE = 1;
+ private static final int BUTTON_MOVEUP = 2;
+ private static final int BUTTON_MOVEDOWN = 3;
+
+ private static final String[] BUTTONS = new String[] {
+ AbstractCPropertyTab.ADD_STR,
+ AbstractCPropertyTab.DEL_STR,
+ AbstractCPropertyTab.MOVEUP_STR,
+ AbstractCPropertyTab.MOVEDOWN_STR,
+ };
+
+ private static final String OOPS = "OOPS"; //$NON-NLS-1$
+
+ private Table fTable;
+ private TableViewer fTableViewer;
+ private Button[] fButtons = null;
+
+ private RegexErrorParser fErrorParser;
+ private boolean fEditable;
+
+ /**
+ * Provides generic implementation for overridden methods.
+ * One purpose is to make it easier for subclasses to operate with {@link RegexErrorPattern},
+ * another is to provide content assist.
+ *
+ */
+ private abstract class RegexPatternEditingSupport extends EditingSupport {
+ private final TableViewer tableViewer;
+
+ /**
+ * Constructor.
+ *
+ * @param viewer - table viewer where to provide editing support.
+ * @param isFindStyle - if "find" or "replace" style for potential content assist,
+ * see {@link FindReplaceDocumentAdapterContentProposalProvider}.
+ */
+ public RegexPatternEditingSupport(TableViewer viewer, boolean isFindStyle) {
+ super(viewer);
+ tableViewer = viewer;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.EditingSupport#canEdit(java.lang.Object)
+ */
+ @Override
+ protected boolean canEdit(Object element) {
+ return fEditable;
+ }
+
+ /**
+ * The intention of RegexPatternEditingSupport is to provide Regex content assist
+ * during in-table editing. However having problems with mouse selection and
+ * {@link ContentAssistCommandAdapter} using {@link FindReplaceDocumentAdapterContentProposalProvider}
+ * is removed for time being. See bug 288982 for more details.
+ *
+ * @see org.eclipse.jface.viewers.EditingSupport#getCellEditor(java.lang.Object)
+ */
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ CellEditor editor = new TextCellEditor(tableViewer.getTable());
+ return editor;
+ }
+
+ /**
+ * Get value from {@link RegexErrorPattern}. This is column-specific value.
+ *
+ * @param regexErrorPattern - pattern to query.
+ * @return retrieved value
+ */
+ abstract protected Object getFromPattern(RegexErrorPattern regexErrorPattern);
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.EditingSupport#getValue(java.lang.Object)
+ */
+ @Override
+ protected Object getValue(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regexErrorPattern = (RegexErrorPattern) element;
+ return getFromPattern(regexErrorPattern);
+ }
+ return OOPS;
+ }
+
+ /**
+ * Set value into one of the pattern's field. Which field - it's column-specific.
+ *
+ * @param regexErrorPattern - pattern to set the field
+ * @param value - value to set
+ */
+ abstract protected void setToPattern(RegexErrorPattern regexErrorPattern, String value);
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.EditingSupport#setValue(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ protected void setValue(Object element, Object value) {
+ if (element instanceof RegexErrorPattern && (value instanceof String)) {
+ String stringValue = (String) value;
+ RegexErrorPattern errorPattern = (RegexErrorPattern) element;
+ setToPattern(errorPattern, stringValue);
+ tableViewer.update(element, null);
+ }
+ }
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param errorparser - regex error parser for which to display options.
+ * @param editable - if error parser is editable and allowed to change its patterns
+ */
+ public RegexErrorParserOptionPage(RegexErrorParser errorparser, boolean editable) {
+ fErrorParser = errorparser;
+ fEditable = editable;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public void createControl(Composite parent) {
+ Group group = new Group(parent, SWT.SHADOW_ETCHED_IN);
+ group.setText(DialogsMessages.RegexErrorParserOptionPage_Title);
+
+ GridLayout gridLayout = new GridLayout(2, true);
+ gridLayout.makeColumnsEqualWidth = false;
+ gridLayout.marginRight = -10;
+ gridLayout.marginLeft = -4;
+ group.setLayout(gridLayout);
+ group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ Composite composite = new Composite(group, SWT.NONE);
+ GridLayout layout = new GridLayout();
+ layout.numColumns = 2;
+ layout.marginWidth = 1;
+ layout.marginHeight = 1;
+ layout.marginRight = 1;
+ composite.setLayout(layout);
+ composite.setLayoutData(new GridData(GridData.FILL_BOTH));
+ Dialog.applyDialogFont(composite);
+
+ if (!fEditable)
+ createLinkToPreferences(composite);
+
+ createPatternsTable(group, composite);
+
+ if (fEditable) {
+ createButtons(composite);
+
+ // TODO: remove the warning before 6.1
+ MessageLine errorImageLabel = new MessageLine(composite, SWT.NONE);
+ errorImageLabel.setImage(JFaceResources.getImage(Dialog.DLG_IMG_MESSAGE_WARNING));
+ errorImageLabel.setText("Error Parser Options user entries may be lost on CDT update as persistence will be finalized with CDT 6.1 final release.");
+ }
+
+ setControl(group);
+ group.update();
+ }
+
+ private void createLinkToPreferences(final Composite parent) {
+ // must not be editable as error parser gets desynchronized with ErrorParsTab
+ Assert.isTrue(!fEditable);
+
+ Link link = new Link(parent, SWT.NONE);
+ link.setText(DialogsMessages.RegexErrorParserOptionPage_LinkToPreferencesMessage);
+
+ link.addListener(SWT.Selection, new Listener() {
+ public void handleEvent(Event event) {
+ // Use event.text to tell which link was used
+ PreferencesUtil.createPreferenceDialogOn(parent.getShell(), WORKSPACE_PREFERENCE_PAGE, null, null).open();
+
+ IErrorParserNamed errorParser = ErrorParserManager.getErrorParserCopy(fErrorParser.getId());
+ if (errorParser instanceof RegexErrorParser)
+ fErrorParser = (RegexErrorParser) errorParser;
+ else
+ fErrorParser = null;
+
+ initializeTable();
+ }
+ });
+
+ GridData gridData = new GridData(SWT.FILL, SWT.BOTTOM, true, false);
+ gridData.horizontalSpan = 2;
+ link.setLayoutData(gridData);
+ }
+
+ private static RegexErrorPattern newDummyPattern() {
+ return new RegexErrorPattern(null, null, null, null, null, IMarker.SEVERITY_ERROR, true);
+ }
+
+ private static String severityToString(int severity) {
+ switch (severity) {
+ case IMarkerGenerator.SEVERITY_INFO:
+ return DialogsMessages.RegexErrorParserOptionPage_SeverityInfo;
+ case IMarkerGenerator.SEVERITY_WARNING:
+ return DialogsMessages.RegexErrorParserOptionPage_SeverityWarning;
+ case IMarkerGenerator.SEVERITY_ERROR_BUILD:
+ case IMarkerGenerator.SEVERITY_ERROR_RESOURCE:
+ return DialogsMessages.RegexErrorParserOptionPage_SeverityError;
+ }
+ return DialogsMessages.RegexErrorParserOptionPage_SeverityIgnore;
+ }
+
+ private void initializeTable() {
+ RegexErrorPattern[] errorParserPatterns = fErrorParser!=null
+ ? errorParserPatterns = fErrorParser.getPatterns()
+ : new RegexErrorPattern[0];
+
+ int len = errorParserPatterns.length;
+ int newLen = len;
+
+ RegexErrorPattern[] tablePatterns = new RegexErrorPattern[newLen];
+ System.arraycopy(errorParserPatterns, 0, tablePatterns, 0, len);
+
+ fTableViewer.setInput(tablePatterns);
+ fTableViewer.refresh();
+ }
+
+ private void createPatternsTable(Group group, Composite parent) {
+ TableLayoutComposite tableLayouter = new TableLayoutComposite(parent, SWT.NONE);
+ tableLayouter.addColumnData(new ColumnWeightData(10, true)); // severity
+ tableLayouter.addColumnData(new ColumnWeightData(40, true)); // pattern
+ tableLayouter.addColumnData(new ColumnWeightData(10, true)); // file
+ tableLayouter.addColumnData(new ColumnWeightData(10, true)); // line
+ tableLayouter.addColumnData(new ColumnWeightData(15, true)); // description
+ tableLayouter.addColumnData(new ColumnWeightData(10, true)); // eat line
+
+ int style= SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER;
+ if (fEditable) {
+ style = style | SWT.FULL_SELECTION;
+ }
+ fTable = new Table(tableLayouter, style);
+ fTable.setHeaderVisible(true);
+ fTable.setLinesVisible(true);
+ fTable.setEnabled(fEditable);
+
+ GridData gridData = new GridData(GridData.FILL_BOTH);
+ gridData.heightHint = SWTUtil.getTableHeightHint(fTable, 10);
+ gridData.widthHint = new PixelConverter(group).convertWidthInCharsToPixels(100);
+ tableLayouter.setLayoutData(gridData);
+ fTable.setLayout(new TableLayout());
+
+ fTable.addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ updateButtons();
+ }
+ });
+
+ fTableViewer = new TableViewer(fTable);
+ fTableViewer.setUseHashlookup(true);
+ fTableViewer.setContentProvider(new ArrayContentProvider());
+
+ createSeverityColumn();
+ createPatternColumn();
+ createFileColumn();
+ createLineColumn();
+ createDescriptionColumn();
+ createEatLineColumn();
+
+ initializeTable();
+ }
+
+ private void createSeverityColumn() {
+ TableViewerColumn columnViewer = new TableViewerColumn(fTableViewer, SWT.NONE);
+ columnViewer.getColumn().setText(DialogsMessages.RegexErrorParserOptionPage_SeverityColumn);
+ columnViewer.getColumn().setResizable(true);
+ columnViewer.getColumn().setToolTipText(DialogsMessages.RegexErrorParserOptionPage_TooltipSeverity);
+ columnViewer.setLabelProvider(new ColumnLabelProvider() {
+ final ISharedImages images = PlatformUI.getWorkbench().getSharedImages();
+
+ @Override
+ public Image getImage(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regexErrorPattern = (RegexErrorPattern) element;
+ switch (regexErrorPattern.getSeverity()) {
+ case IMarkerGenerator.SEVERITY_INFO:
+ return images.getImage(ISharedImages.IMG_OBJS_INFO_TSK);
+ case IMarkerGenerator.SEVERITY_WARNING:
+ return images.getImage(ISharedImages.IMG_OBJS_WARN_TSK);
+ case IMarkerGenerator.SEVERITY_ERROR_BUILD:
+ case IMarkerGenerator.SEVERITY_ERROR_RESOURCE:
+ return images.getImage(ISharedImages.IMG_OBJS_ERROR_TSK);
+ case RegexErrorPattern.SEVERITY_SKIP:
+ return images.getImage(ISharedImages.IMG_ELCL_REMOVE_DISABLED);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regex = (RegexErrorPattern) element;
+ return severityToString(regex.getSeverity());
+ }
+ return severityToString(RegexErrorPattern.SEVERITY_SKIP);
+ }
+ });
+ columnViewer.setEditingSupport(new EditingSupport(fTableViewer) {
+ final String[] severityComboBoxArray = new String[] {
+ severityToString(IMarkerGenerator.SEVERITY_ERROR_RESOURCE),
+ severityToString(IMarkerGenerator.SEVERITY_WARNING),
+ severityToString(IMarkerGenerator.SEVERITY_INFO),
+ severityToString(RegexErrorPattern.SEVERITY_SKIP),
+ };
+
+ private int severityToIndex(int severity) {
+ String strSeverity = severityToString(severity);
+ for (int i = 0; i < severityComboBoxArray.length; i++) {
+ if (strSeverity.equals(severityComboBoxArray[i]))
+ return i;
+ }
+ return 0;
+ }
+
+ private int indexToSeverity(int index) {
+ String strCombo = severityComboBoxArray[index];
+ for (int i = 0; i < severityComboBoxArray.length; i++) {
+ if (severityToString(i).equals(strCombo))
+ return i;
+ }
+ return RegexErrorPattern.SEVERITY_SKIP;
+ }
+
+ @Override
+ protected boolean canEdit(Object element) {
+ return (element instanceof RegexErrorPattern) && fEditable;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ return new ComboBoxCellEditor(fTableViewer.getTable(), severityComboBoxArray, SWT.READ_ONLY);
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ if (element instanceof RegexErrorPattern)
+ return severityToIndex(((RegexErrorPattern) element).getSeverity());
+ return RegexErrorPattern.SEVERITY_SKIP;
+ }
+
+ @Override
+ protected void setValue(Object element, Object value) {
+ if (element instanceof RegexErrorPattern && (value instanceof Integer)) {
+ ((RegexErrorPattern) element).setSeverity(indexToSeverity(((Integer) value).intValue()));
+ fTableViewer.update(element, null);
+ }
+ }
+
+ });
+ }
+
+ private void createPatternColumn() {
+ TableViewerColumn columnViewer = new TableViewerColumn(fTableViewer, SWT.NONE);
+ columnViewer.getColumn().setText(DialogsMessages.RegexErrorParserOptionPage_Pattern_Column);
+ columnViewer.getColumn().setResizable(true);
+ columnViewer.getColumn().setToolTipText(DialogsMessages.RegexErrorParserOptionPage_TooltipPattern);
+ columnViewer.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regex = (RegexErrorPattern) element;
+ String pattern = regex.getPattern();
+ return pattern;
+ }
+ return OOPS;
+ }
+ });
+
+ columnViewer.setEditingSupport(new RegexPatternEditingSupport(fTableViewer, true) {
+ @Override
+ protected Object getFromPattern(RegexErrorPattern regexErrorPattern) {
+ return regexErrorPattern.getPattern();
+ }
+
+ @Override
+ protected void setToPattern(RegexErrorPattern regexErrorPattern, String value) {
+ if (!fEditable)
+ return;
+ try{
+ regexErrorPattern.setPattern(value);
+ } catch (Exception e) {
+ // to avoid recursive edits. the dialog is needed to ensure valid pattern on losing focus.
+ // this looks ugly and likely incorrect
+ fEditable = false;
+ RegularExpressionStatusDialog dialog= new RegularExpressionStatusDialog(getShell(), value);
+ if (dialog.open() == Window.OK) {
+ regexErrorPattern.setPattern(dialog.getValue());
+ }
+ fEditable = true;
+ }
+ }
+ });
+ }
+
+ private void createFileColumn() {
+ TableViewerColumn columnViewer = new TableViewerColumn(fTableViewer, SWT.NONE);
+ columnViewer.getColumn().setText(DialogsMessages.RegexErrorParserOptionPage_FileColumn);
+ columnViewer.getColumn().setToolTipText(DialogsMessages.RegexErrorParserOptionPage_TooltipFile);
+ columnViewer.getColumn().setResizable(true);
+ columnViewer.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regex = (RegexErrorPattern) element;
+ return regex.getFileExpression();
+ }
+ return OOPS;
+ }
+ });
+ columnViewer.setEditingSupport(new RegexPatternEditingSupport(fTableViewer, false) {
+ @Override
+ protected Object getFromPattern(RegexErrorPattern regexErrorPattern) {
+ return regexErrorPattern.getFileExpression();
+ }
+
+ @Override
+ protected void setToPattern(RegexErrorPattern regexErrorPattern, String value) {
+ regexErrorPattern.setFileExpression(value);
+ }
+ });
+ }
+
+ private void createLineColumn() {
+ TableViewerColumn columnViewer = new TableViewerColumn(fTableViewer, SWT.NONE);
+ columnViewer.getColumn().setText(DialogsMessages.RegexErrorParserOptionPage_LineColumn);
+ columnViewer.getColumn().setResizable(true);
+ columnViewer.getColumn().setToolTipText(DialogsMessages.RegexErrorParserOptionPage_TooltipLine);
+ columnViewer.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regex = (RegexErrorPattern) element;
+ return regex.getLineExpression();
+ }
+ return OOPS;
+ }
+ });
+ columnViewer.setEditingSupport(new RegexPatternEditingSupport(fTableViewer, false) {
+ @Override
+ protected Object getFromPattern(RegexErrorPattern regexErrorPattern) {
+ return regexErrorPattern.getLineExpression();
+ }
+
+ @Override
+ protected void setToPattern(RegexErrorPattern regexErrorPattern, String value) {
+ regexErrorPattern.setLineExpression(value);
+ }
+ });
+ }
+
+ private void createDescriptionColumn() {
+ TableViewerColumn columnViewer = new TableViewerColumn(fTableViewer, SWT.NONE);
+ columnViewer.getColumn().setText(DialogsMessages.RegexErrorParserOptionPage_DescriptionColumn);
+ columnViewer.getColumn().setResizable(true);
+ columnViewer.getColumn().setToolTipText(DialogsMessages.RegexErrorParserOptionPage_TooltipDescription);
+ columnViewer.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regex = (RegexErrorPattern) element;
+ return regex.getDescriptionExpression();
+ }
+ return OOPS;
+ }
+ });
+ columnViewer.setEditingSupport(new RegexPatternEditingSupport(fTableViewer, false) {
+ @Override
+ protected Object getFromPattern(RegexErrorPattern regexErrorPattern) {
+ return regexErrorPattern.getDescriptionExpression();
+ }
+
+ @Override
+ protected void setToPattern(RegexErrorPattern regexErrorPattern, String value) {
+ regexErrorPattern.setDescriptionExpression(value);
+ }
+ });
+ }
+
+ private void createEatLineColumn() {
+ final String EAT_NO = DialogsMessages.RegexErrorParserOptionPage_ConsumeNo;
+ final String EAT_YES = DialogsMessages.RegexErrorParserOptionPage_ConsumeYes;
+
+ final String[] eatLineComboBoxArray = new String[] { EAT_YES, EAT_NO, };
+ final int EAT_YES_INDEX = 0;
+ final int EAT_NO_INDEX = 1;
+
+ TableViewerColumn columnViewer = new TableViewerColumn(fTableViewer, SWT.NONE);
+ columnViewer.getColumn().setText(DialogsMessages.RegexErrorParserOptionPage_EatColumn);
+ columnViewer.getColumn().setResizable(true);
+
+ String message = MessageFormat.format(DialogsMessages.RegexErrorParserOptionPage_TooltipConsume, new Object[] { EAT_NO });
+ columnViewer.getColumn().setToolTipText(message);
+ columnViewer.setLabelProvider(new ColumnLabelProvider() {
+
+ @Override
+ public String getText(Object element) {
+ if (element instanceof RegexErrorPattern) {
+ RegexErrorPattern regex = (RegexErrorPattern) element;
+ if (!regex.isEatProcessedLine())
+ return EAT_NO;
+ }
+ return EAT_YES;
+ }
+ });
+ columnViewer.setEditingSupport(new EditingSupport(fTableViewer) {
+ @Override
+ protected boolean canEdit(Object element) {
+ return (element instanceof RegexErrorPattern) && fEditable;
+ }
+
+ @Override
+ protected CellEditor getCellEditor(Object element) {
+ return new ComboBoxCellEditor(fTableViewer.getTable(), eatLineComboBoxArray, SWT.READ_ONLY);
+ }
+
+ @Override
+ protected Object getValue(Object element) {
+ if (element instanceof RegexErrorPattern)
+ if (!((RegexErrorPattern) element).isEatProcessedLine())
+ return EAT_NO_INDEX;
+ return EAT_YES_INDEX;
+ }
+
+ @Override
+ protected void setValue(Object element, Object value) {
+ if ((element instanceof RegexErrorPattern) && (value instanceof Integer)) {
+ ((RegexErrorPattern) element).setEatProcessedLine((Integer) value != EAT_NO_INDEX);
+ fTableViewer.update(element, null);
+ }
+ }
+
+ });
+ }
+
+ private void createButtons(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ composite.setLayoutData(new GridData(GridData.FILL_VERTICAL));
+ composite.setLayout(new GridLayout(1, false));
+
+ fButtons = new Button[BUTTONS.length];
+ for (int i = 0; i < BUTTONS.length; i++) {
+ fButtons[i] = new Button(composite, SWT.PUSH);
+ GridData gridData = new GridData(SWT.FILL, SWT.CENTER, false, false);
+ gridData.minimumWidth = 80;
+
+ if (BUTTONS[i] != null) {
+ fButtons[i].setText(BUTTONS[i]);
+ fButtons[i].setEnabled(false);
+ } else {
+ // no button, but placeholder
+ fButtons[i].setVisible(false);
+ fButtons[i].setEnabled(false);
+ gridData.heightHint = 10;
+ }
+
+ fButtons[i].setLayoutData(gridData);
+ fButtons[i].addSelectionListener(new SelectionAdapter() {
+ @Override
+ public void widgetSelected(SelectionEvent event) {
+ for (int i=0; i=0 && pos<=last;
+
+ fButtons[BUTTON_ADD].setEnabled(true);
+ fButtons[BUTTON_DELETE].setEnabled(selected);
+ fButtons[BUTTON_MOVEUP].setEnabled(selected && pos != 0);
+ fButtons[BUTTON_MOVEDOWN].setEnabled(selected && pos != last);
+ }
+ }
+
+ private void buttonPressed (int button) {
+ switch (button) {
+ case BUTTON_ADD:
+ addErrorPattern();
+ break;
+ case BUTTON_DELETE:
+ deleteErrorPattern();
+ break;
+ case BUTTON_MOVEUP:
+ moveItem(true);
+ break;
+ case BUTTON_MOVEDOWN:
+ moveItem(false);
+ break;
+ default:
+ break;
+ }
+ updateButtons();
+ }
+
+ private void addErrorPattern() {
+ int pos = fTable.getSelectionIndex();
+ int last = fTable.getItemCount()-1;
+ if (pos<0 || pos>last)
+ pos = last;
+
+ int newPos = pos + 1;
+ fTableViewer.insert(newDummyPattern(), newPos);
+ fTable.setSelection(newPos);
+ }
+
+ private void deleteErrorPattern() {
+ int pos = fTable.getSelectionIndex();
+ int last = fTable.getItemCount()-1;
+
+ if (pos>=0 && pos<=last) {
+ fTableViewer.remove(fTableViewer.getElementAt(pos));
+ fTable.setSelection(pos);
+ }
+ }
+
+ private void moveItem(boolean up) {
+ int pos = fTable.getSelectionIndex();
+ int count = fTable.getItemCount();
+ int last = count-1;
+ boolean selected = pos>=0 && pos<=last;
+
+ if (!selected || (up && pos==0) || (!up && pos==last))
+ return;
+
+ Object item = fTableViewer.getElementAt(pos);
+ fTableViewer.remove(item);
+ int newPos = up ? pos-1 : pos+1;
+ fTableViewer.insert(item, newPos);
+ fTable.setSelection(newPos);
+ }
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.cdt.ui.dialogs.ICOptionPage#performApply(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ public void performApply(IProgressMonitor monitor) throws CoreException {
+ if (fErrorParser!=null && fEditable) {
+ fErrorParser.clearPatterns();
+ for (TableItem tableItem : fTable.getItems()) {
+ Object item = tableItem.getData();
+ if (item instanceof RegexErrorPattern) {
+ fErrorParser.addPattern((RegexErrorPattern)item);
+ }
+ }
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.eclipse.cdt.ui.dialogs.ICOptionPage#performDefaults()
+ */
+ @Override
+ public void performDefaults() {
+ // ErrorParsTas.performDefaults() will do all the work
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/RegularExpressionStatusDialog.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/RegularExpressionStatusDialog.java
new file mode 100644
index 00000000000..9b816b4469d
--- /dev/null
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/dialogs/RegularExpressionStatusDialog.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 2009,2009 Andrew Gvozdev and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Andrew Gvozdev - Initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.cdt.ui.dialogs;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.jface.fieldassist.TextContentAdapter;
+import org.eclipse.jface.text.FindReplaceDocumentAdapterContentProposalProvider;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter;
+
+import org.eclipse.cdt.internal.ui.dialogs.IInputStatusValidator;
+import org.eclipse.cdt.internal.ui.dialogs.InputStatusDialog;
+import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
+
+/**
+ * Input Dialog for validating regular expression syntax.
+ *
+ * @since 5.2
+ */
+public class RegularExpressionStatusDialog extends InputStatusDialog {
+ private static final IInputStatusValidator fValidator = new IInputStatusValidator() {
+ public IStatus isValid(String newText) {
+ StatusInfo status = new StatusInfo();
+ if (newText.length() == 0) {
+ status.setWarning(DialogsMessages.RegularExpression_EmptyPattern);
+ } else {
+ try {
+ Pattern.compile(newText);
+ } catch (Exception e) {
+ // only first line of PatternSyntaxException is really descriptive
+ status.setError(e.getMessage().split("[\n\r]", 2)[0]); //$NON-NLS-1$
+ }
+ }
+ return status;
+ }
+ };
+
+ /**
+ * Constructor
+ *
+ * @param shell - the parent shell, or null
to create a top-level shell
+ * @param initialValue the initial input value, or null
if none
+ * (equivalent to the empty string)
+ */
+ public RegularExpressionStatusDialog(Shell shell, String initialValue) {
+ super(shell, DialogsMessages.RegularExpression_Validate,
+ DialogsMessages.RegularExpression_Enter,
+ initialValue, fValidator);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param shell - the parent shell, or null
to create a top-level shell
+ * @param dialogTitle - the dialog title, or null
if none
+ * @param dialogMessage - the dialog message, or null
if none
+ * @param initialValue the initial input value, or null
if none
+ * (equivalent to the empty string)
+ */
+ public RegularExpressionStatusDialog(Shell shell, String dialogTitle, String dialogMessage, String initialValue) {
+ super(shell, dialogTitle, dialogMessage, initialValue, fValidator);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.internal.ui.dialogs.InputStatusDialog#createDialogArea(org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ protected Control createDialogArea(Composite parent) {
+ Control control = super.createDialogArea(parent);
+
+ new ContentAssistCommandAdapter(
+ getText(),
+ new TextContentAdapter(),
+ new FindReplaceDocumentAdapterContentProposalProvider(true),
+ null,
+ null,
+ true);
+
+
+ setHelpAvailable(false);
+ return control;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.dialogs.StatusDialog#create()
+ */
+ @Override
+ public void create() {
+ super.create();
+ if (getValue().length()>0)
+ validateInput();
+ }
+}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java
index 1fb30db8027..92627095854 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/AbstractPage.java
@@ -339,7 +339,7 @@ implements
GridData gd;
parentComposite = new Composite(c, SWT.NONE);
parentComposite.setLayoutData(gd= new GridData(GridData.FILL_BOTH));
- gd.widthHint= 200;
+ gd.widthHint= 800;
itabs.clear();
if (!isSingle()) {
parentComposite.setLayout(new FillLayout());
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/ErrorParsTab.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/ErrorParsTab.java
index 6dd2faa2f63..95e86c3b8b6 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/ErrorParsTab.java
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/ErrorParsTab.java
@@ -7,234 +7,568 @@
*
* Contributors:
* Intel Corporation - Initial API and implementation
+ * Andrew Gvozdev (Quoin Inc.) - Regular expression error parsers
*******************************************************************************/
package org.eclipse.cdt.ui.newui;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
-import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
-import org.eclipse.core.runtime.IExtension;
-import org.eclipse.core.runtime.IExtensionPoint;
-import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTableViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.layout.FillLayout;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
+import org.eclipse.swt.widgets.TableItem;
+import org.eclipse.ui.PlatformUI;
+import org.osgi.service.prefs.BackingStoreException;
-import org.eclipse.cdt.core.CCorePlugin;
+import com.ibm.icu.text.MessageFormat;
+
+import org.eclipse.cdt.core.ErrorParserManager;
+import org.eclipse.cdt.core.IErrorParserNamed;
+import org.eclipse.cdt.core.errorparsers.RegexErrorParser;
import org.eclipse.cdt.core.settings.model.ICConfigurationDescription;
import org.eclipse.cdt.core.settings.model.ICMultiConfigDescription;
import org.eclipse.cdt.core.settings.model.ICResourceDescription;
+import org.eclipse.cdt.ui.CUIPlugin;
+import org.eclipse.cdt.ui.dialogs.ICOptionPage;
+import org.eclipse.cdt.ui.dialogs.RegexErrorParserOptionPage;
+import org.eclipse.cdt.utils.ui.controls.TabFolderLayout;
+
+import org.eclipse.cdt.internal.ui.ICHelpContextIds;
+import org.eclipse.cdt.internal.ui.dialogs.IInputStatusValidator;
+import org.eclipse.cdt.internal.ui.dialogs.InputStatusDialog;
+import org.eclipse.cdt.internal.ui.dialogs.StatusInfo;
+import org.eclipse.cdt.internal.ui.util.PixelConverter;
/**
+ * This class represents Error Parser Tab in Project Properties or workspace Preferences
+ *
* @noextend This class is not intended to be subclassed by clients.
*/
public class ErrorParsTab extends AbstractCPropertyTab {
- private HashMap mapParsers = new HashMap();
- private Table table;
- private CheckboxTableViewer tv;
- private ICConfigurationDescription cfgd;
-
+ private static final int DEFAULT_HEIGHT = 130;
+ private static final int BUTTON_ADD = 0;
+ private static final int BUTTON_EDIT = 1;
+ private static final int BUTTON_DELETE = 2;
+ // there is a separator instead of button = 3
+ private static final int BUTTON_MOVEUP = 4;
+ private static final int BUTTON_MOVEDOWN = 5;
+
+ private static final String[] BUTTONS = new String[] {
+ ADD_STR,
+ EDIT_STR,
+ DEL_STR,
+ null,
+ MOVEUP_STR,
+ MOVEDOWN_STR,
+ };
+
+ private static final String OOPS = "OOPS"; //$NON-NLS-1$
+
+ private Table fTable;
+ private CheckboxTableViewer fTableViewer;
+ private ICConfigurationDescription fCfgDesc;
+
+ private final Map fAvailableErrorParsers = new LinkedHashMap();
+ private final Map fOptionsPageMap = new HashMap();
+ private ICOptionPage fCurrentOptionsPage = null;
+
+ private Composite fCompositeForOptionsPage;
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#createControls(org.eclipse.swt.widgets.Composite)
+ */
@Override
public void createControls(Composite parent) {
+
super.createControls(parent);
- usercomp.setLayout(new FillLayout());
- table = new Table(usercomp, SWT.BORDER | SWT.CHECK | SWT.SINGLE);
- table.addSelectionListener(new SelectionAdapter() {
+ PlatformUI.getWorkbench().getHelpSystem().setHelp(usercomp, ICHelpContextIds.ERROR_PARSERS_PAGE);
+
+ usercomp.setLayout(new GridLayout(1, false));
+
+ // SashForm
+ SashForm sashForm = new SashForm(usercomp, SWT.NONE);
+ sashForm.setBackground(sashForm.getDisplay().getSystemColor(SWT.COLOR_GRAY));
+ sashForm.setOrientation(SWT.VERTICAL);
+ sashForm.setLayoutData(new GridData(GridData.FILL_BOTH));
+
+ GridLayout layout = new GridLayout(2, false);
+ layout.marginHeight = 5;
+ sashForm.setLayout(layout);
+
+ // table
+ Composite compositeSashForm = new Composite(sashForm, SWT.NONE);
+ compositeSashForm.setLayout(new GridLayout(2, false));
+ fTable = new Table(compositeSashForm, SWT.BORDER | SWT.CHECK | SWT.SINGLE);
+ fTable.setLayoutData(new GridData(GridData.FILL_BOTH));
+ fTable.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
+ displaySelectedOptionPage();
updateButtons();
}});
- tv = new CheckboxTableViewer(table);
- tv.setContentProvider(new IStructuredContentProvider() {
+ fTableViewer = new CheckboxTableViewer(fTable);
+ fTableViewer.setContentProvider(new IStructuredContentProvider() {
public Object[] getElements(Object inputElement) {
return (Object[])inputElement;
}
public void dispose() {}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
});
-
- tv.addCheckStateListener(new ICheckStateListener() {
- public void checkStateChanged(CheckStateChangedEvent e) {
- saveChecked();
+ fTableViewer.setLabelProvider(new LabelProvider() {
+ @Override
+ public String getText(Object element) {
+ if (element instanceof String) {
+ String id = (String)element;
+ IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
+ if (errorParser!=null) {
+ String name = errorParser.getName();
+ if (name!=null && name.length()>0) {
+ return name;
+ }
+ }
+ return UIMessages.getFormattedString("ErrorParsTab.error.NonAccessibleID", id); //$NON-NLS-1$
+ }
+ return OOPS;
}
});
-
- initButtons(new String[] {
- MOVEUP_STR, MOVEDOWN_STR, null,
- UIMessages.getString("ErrorParsTab.0"), //$NON-NLS-1$
- UIMessages.getString("ErrorParsTab.1") //$NON-NLS-1$
- });
+
+ fTableViewer.addCheckStateListener(new ICheckStateListener() {
+ public void checkStateChanged(CheckStateChangedEvent e) {
+ saveChecked();
+ }});
+
+ // Buttons
+ Composite compositeButtons = new Composite(compositeSashForm, SWT.NONE);
+ compositeButtons.setLayoutData(new GridData(GridData.END));
+ initButtons(compositeButtons, BUTTONS);
+
+ fCompositeForOptionsPage = new Composite(sashForm, SWT.NULL);
+ GridData gd = new GridData();
+ fCompositeForOptionsPage.setLayout(new TabFolderLayout());
+
+ PixelConverter converter = new PixelConverter(parent);
+ gd.heightHint = converter.convertHorizontalDLUsToPixels(DEFAULT_HEIGHT);
+
+ gd.horizontalAlignment = GridData.FILL;
+ gd.grabExcessHorizontalSpace = true;
+ gd.grabExcessVerticalSpace = true;
+ gd.horizontalSpan = 2;
+ fCompositeForOptionsPage.setLayoutData(gd);
+
+ sashForm.setWeights(new int[] {50, 50});
+
+ // init data
+ ICResourceDescription resDecs = getResDesc();
+ fCfgDesc = resDecs!=null ? resDecs.getConfiguration() : null;
initMapParsers();
+ updateData(getResDesc());
}
-
- protected void initMapParsers() {
- mapParsers.clear();
- IExtensionPoint point = Platform.getExtensionRegistry().getExtensionPoint(
- CCorePlugin.PLUGIN_ID,
- CCorePlugin.ERROR_PARSER_SIMPLE_ID
- );
- if (point != null) {
- IExtension[] exts = point.getExtensions();
- for (IExtension ext : exts) {
- if (ext.getConfigurationElements().length > 0) {
- mapParsers.put(ext.getUniqueIdentifier(), ext.getLabel());
+
+ private void initMapParsers() {
+ fAvailableErrorParsers.clear();
+ fOptionsPageMap.clear();
+ for (String id : ErrorParserManager.getErrorParserAvailableIds()) {
+ IErrorParserNamed errorParser = ErrorParserManager.getErrorParserCopy(id);
+ fAvailableErrorParsers.put(id, errorParser);
+ initializeOptionsPage(id);
+ }
+
+ String ids[];
+ if (fCfgDesc!=null) {
+ ICConfigurationDescription srcCfgDesc = fCfgDesc.getConfiguration();
+ if (srcCfgDesc instanceof ICMultiConfigDescription) {
+ String[][] ss = ((ICMultiConfigDescription)srcCfgDesc).getErrorParserIDs();
+ ids = CDTPrefUtil.getStrListForDisplay(ss);
+ } else {
+ ids = srcCfgDesc.getBuildSetting().getErrorParserIDs();
+ }
+ Set setIds = new LinkedHashSet(Arrays.asList(ids));
+ setIds.addAll(fAvailableErrorParsers.keySet());
+ fTableViewer.setInput(setIds.toArray(new String[0]));
+ } else {
+ fTableViewer.setInput(fAvailableErrorParsers.keySet().toArray(new String[0]));
+ ids = ErrorParserManager.getDefaultErrorParserIds();
+ }
+ fTableViewer.setCheckedElements(ids);
+
+ displaySelectedOptionPage();
+ }
+
+ private void initializeOptionsPage(String id) {
+ IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
+ if (errorParser!=null) {
+ String name = errorParser.getName();
+ if (name!=null && name.length()>0) {
+ // RegexErrorParser has an Options page
+ if (errorParser instanceof RegexErrorParser) {
+ // allow to edit only for Build Settings Preference Page (where cfgd==null)
+ RegexErrorParserOptionPage optionsPage = new RegexErrorParserOptionPage((RegexErrorParser) errorParser, isErrorParsersEditable());
+ fOptionsPageMap.put(id, optionsPage);
+ optionsPage.setContainer(page);
+ optionsPage.createControl(fCompositeForOptionsPage);
+ optionsPage.setVisible(false);
+ fCompositeForOptionsPage.layout(true);
}
}
}
}
-
+
+ private void displaySelectedOptionPage() {
+ if (fCurrentOptionsPage != null)
+ fCurrentOptionsPage.setVisible(false);
+
+ int pos = fTable.getSelectionIndex();
+ if (pos<0)
+ return;
+
+ String parserId = (String)fTable.getItem(pos).getData();
+ ICOptionPage optionsPage = fOptionsPageMap.get(parserId);
+ if (optionsPage != null) {
+ optionsPage.setVisible(true);
+ }
+ fCurrentOptionsPage = optionsPage;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#buttonPressed(int)
+ */
@Override
public void buttonPressed (int n) {
switch (n) {
- case 0: // up
+ case BUTTON_ADD:
+ addErrorParser();
+ break;
+ case BUTTON_EDIT:
+ editErrorParser();
+ break;
+ case BUTTON_DELETE:
+ deleteErrorParser();
+ break;
+ case BUTTON_MOVEUP:
moveItem(true);
break;
- case 1: // down
+ case BUTTON_MOVEDOWN:
moveItem(false);
break;
- case 2: // do nothing - it's not a button
- break;
-
- case 3: // check all
- tv.setAllChecked(true);
- saveChecked();
- break;
- case 4: // uncheck all
- tv.setAllChecked(false);
- saveChecked();
- break;
default:
break;
}
+ updateButtons();
}
// Move item up / down
private void moveItem(boolean up) {
- int n = table.getSelectionIndex();
- if (n < 0 ||
- (up && n == 0) ||
- (!up && n+1 == table.getItemCount()))
+ int n = fTable.getSelectionIndex();
+ if (n < 0 || (up && n == 0) || (!up && n+1 == fTable.getItemCount()))
return;
- TableData d = (TableData)tv.getElementAt(n);
- boolean checked = tv.getChecked(d);
- tv.remove(d);
- n = up ? n - 1 : n + 1;
- tv.insert(d, n);
- tv.setChecked(d, checked);
- table.setSelection(n);
+
+ String id = (String)fTableViewer.getElementAt(n);
+ boolean checked = fTableViewer.getChecked(id);
+ fTableViewer.remove(id);
+ n = up ? n-1 : n+1;
+ fTableViewer.insert(id, n);
+ fTableViewer.setChecked(id, checked);
+ fTable.setSelection(n);
+
saveChecked();
}
-
- class TableData {
- String key;
- String value;
- public TableData (String _key, String _value) {
- key = _key;
- value = _value;
- }
- @Override
- public String toString() { return value; }
- }
-
- @Override
- public void updateData(ICResourceDescription _cfgd) {
- cfgd = _cfgd.getConfiguration();
- if (mapParsers == null) return;
- String[] ss = null;
- if (page.isMultiCfg()) {
- String[][] ids = ((ICMultiConfigDescription)cfgd).getErrorParserIDs();
- ss = CDTPrefUtil.getStrListForDisplay(ids);
- } else {
- ss = cfgd.getBuildSetting().getErrorParserIDs();
- }
-
- ArrayList data = new ArrayList(mapParsers.size());
- ArrayList checked = new ArrayList(ss.length);
- HashMap cloneMap = new HashMap(mapParsers);
- // add checked elements
- for (String element : ss) {
- String s = cloneMap.get(element);
- if (s != null) {
- TableData d = new TableData(element,s);
- data.add(d);
- checked.add(d);
- cloneMap.remove(element);
+ private String makeId(String name) {
+ return CUIPlugin.PLUGIN_ID+'.'+name;
+ }
+
+ private void addErrorParser() {
+ IInputStatusValidator inputValidator = new IInputStatusValidator() {
+ public IStatus isValid(String newText) {
+ StatusInfo status = new StatusInfo();
+ if (newText.trim().length() == 0) {
+ status.setError(UIMessages.getString("ErrorParsTab.error.NonEmptyName")); //$NON-NLS-1$
+ } else if (newText.indexOf(ErrorParserManager.ERROR_PARSER_DELIMITER)>=0) {
+ String message = MessageFormat.format( UIMessages.getString("ErrorParsTab.error.IllegalCharacter"), //$NON-NLS-1$
+ new Object[] { ErrorParserManager.ERROR_PARSER_DELIMITER });
+ status.setError(message);
+ } else if (fAvailableErrorParsers.containsKey(makeId(newText))) {
+ status.setError(UIMessages.getString("ErrorParsTab.error.NonUniqueID")); //$NON-NLS-1$
+ }
+ return status;
}
+
+ };
+ InputStatusDialog addDialog = new InputStatusDialog(usercomp.getShell(),
+ UIMessages.getString("ErrorParsTab.title.Add"), //$NON-NLS-1$
+ UIMessages.getString("ErrorParsTab.label.EnterName"), //$NON-NLS-1$
+ UIMessages.getString("ErrorParsTab.label.DefaultRegexErrorParserName"), //$NON-NLS-1$
+ inputValidator);
+ addDialog.setHelpAvailable(false);
+
+ if (addDialog.open() == Window.OK) {
+ String newName = addDialog.getValue();
+ String newId = makeId(newName);
+ IErrorParserNamed errorParser = new RegexErrorParser(newId, newName);
+ fAvailableErrorParsers.put(newId, errorParser);
+
+ fTableViewer.add(newId);
+ fTableViewer.setChecked(newId, true);
+ fTable.setSelection(fTable.getItemCount()-1);
+
+ initializeOptionsPage(newId);
+ displaySelectedOptionPage();
+ updateButtons();
}
- // add remaining parsers (unchecked)
- Iterator it = cloneMap.keySet().iterator();
- while (it.hasNext()) {
- String s = it.next();
- data.add(new TableData(s, cloneMap.get(s)));
+ }
+
+ private void editErrorParser() {
+ int n = fTable.getSelectionIndex();
+ Assert.isTrue(n>=0);
+
+ String id = (String)fTableViewer.getElementAt(n);
+ IErrorParserNamed errorParser = fAvailableErrorParsers.get(id);
+
+ IInputStatusValidator inputValidator = new IInputStatusValidator() {
+ public IStatus isValid(String newText) {
+ StatusInfo status = new StatusInfo();
+ if (newText.trim().length() == 0) {
+ status.setError(UIMessages.getString("ErrorParsTab.error.NonEmptyName")); //$NON-NLS-1$
+ } else if (newText.indexOf(ErrorParserManager.ERROR_PARSER_DELIMITER)>=0) {
+ String message = MessageFormat.format( UIMessages.getString("ErrorParsTab.error.IllegalCharacter"), //$NON-NLS-1$
+ new Object[] { ErrorParserManager.ERROR_PARSER_DELIMITER });
+ status.setError(message);
+ }
+ return status;
+ }
+
+ };
+ InputStatusDialog addDialog = new InputStatusDialog(usercomp.getShell(),
+ UIMessages.getString("ErrorParsTab.title.Edit"), //$NON-NLS-1$
+ UIMessages.getString("ErrorParsTab.label.EnterName"), //$NON-NLS-1$
+ errorParser.getName(),
+ inputValidator);
+ addDialog.setHelpAvailable(false);
+
+ if (addDialog.open() == Window.OK) {
+ errorParser.setName(addDialog.getValue());
+ fTableViewer.refresh(id);
}
- tv.setInput(data.toArray());
- tv.setCheckedElements(checked.toArray());
+ }
+
+ private void deleteErrorParser() {
+ int n = fTable.getSelectionIndex();
+ if (n < 0)
+ return;
+
+ fTableViewer.remove(fTableViewer.getElementAt(n));
+
+ int last = fTable.getItemCount() - 1;
+ if (n>last)
+ n = last;
+ if (n>=0)
+ fTable.setSelection(n);
+
+ saveChecked();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#updateData(org.eclipse.cdt.core.settings.model.ICResourceDescription)
+ */
+ @Override
+ public void updateData(ICResourceDescription resDecs) {
+ ICConfigurationDescription oldCfgDesc = fCfgDesc;
+ fCfgDesc = resDecs!=null ? resDecs.getConfiguration() : null;
+ if (oldCfgDesc!=fCfgDesc) {
+ initMapParsers();
+ }
+ displaySelectedOptionPage();
updateButtons();
}
+ private static boolean isExtensionId(String id) {
+ for (String extId : ErrorParserManager.getErrorParserExtensionIds()) {
+ if (extId.equals(id)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#updateButtons()
+ */
@Override
public void updateButtons() {
- int cnt = table.getItemCount();
- int pos = table.getSelectionIndex();
- buttonSetEnabled(0, pos > 0);
- buttonSetEnabled(1, pos != -1 && pos < (cnt - 1));
- buttonSetEnabled(3, cnt > 0);
- buttonSetEnabled(4, cnt > 0);
+ int pos = fTable.getSelectionIndex();
+ int count = fTable.getItemCount();
+ int last = count - 1;
+ boolean selected = pos >= 0 && pos <= last;
+ String id = (String)fTableViewer.getElementAt(pos);
+
+ buttonSetEnabled(BUTTON_ADD, isErrorParsersEditable());
+ buttonSetEnabled(BUTTON_EDIT, isErrorParsersEditable() && selected);
+ buttonSetEnabled(BUTTON_DELETE, isErrorParsersEditable() && selected && !isExtensionId(id));
+ buttonSetEnabled(BUTTON_MOVEUP, selected && pos != 0);
+ buttonSetEnabled(BUTTON_MOVEDOWN, selected && pos != last);
}
-
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performApply(org.eclipse.cdt.core.settings.model.ICResourceDescription, org.eclipse.cdt.core.settings.model.ICResourceDescription)
+ */
@Override
protected void performApply(ICResourceDescription src, ICResourceDescription dst) {
- ICConfigurationDescription sd = src.getConfiguration();
- ICConfigurationDescription dd = dst.getConfiguration();
- String[] s = null;
- if (sd instanceof ICMultiConfigDescription) {
- String[][] ss = ((ICMultiConfigDescription)sd).getErrorParserIDs();
- s = CDTPrefUtil.getStrListForDisplay(ss);
- } else {
- s = sd.getBuildSetting().getErrorParserIDs();
+ performOK();
+
+ if (!page.isForPrefs()) {
+ ICConfigurationDescription sd = src.getConfiguration();
+ ICConfigurationDescription dd = dst.getConfiguration();
+ String[] s = null;
+ if (sd instanceof ICMultiConfigDescription) {
+ String[][] ss = ((ICMultiConfigDescription)sd).getErrorParserIDs();
+ s = CDTPrefUtil.getStrListForDisplay(ss);
+ } else {
+ s = sd.getBuildSetting().getErrorParserIDs();
+ }
+ if (dd instanceof ICMultiConfigDescription)
+ ((ICMultiConfigDescription)dd).setErrorParserIDs(s);
+ else
+ dd.getBuildSetting().setErrorParserIDs(s);
+ initMapParsers();
}
- if (dd instanceof ICMultiConfigDescription)
- ((ICMultiConfigDescription)dd).setErrorParserIDs(s);
- else
- dd.getBuildSetting().setErrorParserIDs(s);
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performOK()
+ */
+ @Override
+ protected void performOK() {
+ informPages(true);
+
+ if (page.isForPrefs()) {
+ if (fCfgDesc==null) {
+ // Build Settings page
+ try {
+ IErrorParserNamed[] errorParsers = new IErrorParserNamed[fTable.getItemCount()];
+ int i=0;
+ for (TableItem item : fTable.getItems()) {
+ if (item.getData() instanceof String) {
+ String id = (String) item.getData();
+ errorParsers[i] = fAvailableErrorParsers.get(id);
+ i++;
+ }
+ }
- private void saveChecked() {
- Object[] objs = tv.getCheckedElements();
- ArrayList lst = new ArrayList();
- if (objs != null) {
- for (Object ob : objs)
- lst.add(((TableData)ob).key);
+ Object[] checkedElements = fTableViewer.getCheckedElements();
+ String[] checkedErrorParserIds = new String[checkedElements.length];
+ System.arraycopy(checkedElements, 0, checkedErrorParserIds, 0, checkedElements.length);
+
+ ErrorParserManager.setUserDefinedErrorParsers(errorParsers);
+ ErrorParserManager.setDefaultErrorParserIds(checkedErrorParserIds);
+ } catch (BackingStoreException e) {
+ CUIPlugin.log(UIMessages.getString("ErrorParsTab.error.OnApplyingSettings"), e); //$NON-NLS-1$
+ } catch (CoreException e) {
+ CUIPlugin.log(UIMessages.getString("ErrorParsTab.error.OnApplyingSettings"), e); //$NON-NLS-1$
+ }
+ }
+ initMapParsers();
}
- String[] s = lst.toArray(new String[lst.size()]);
- if (cfgd instanceof ICMultiConfigDescription)
- ((ICMultiConfigDescription)cfgd).setErrorParserIDs(s);
- else
- cfgd.getBuildSetting().setErrorParserIDs(s);
}
- // This page can be displayed for project only
+
+ private void saveChecked() {
+ if (fCfgDesc!=null) {
+ Object[] objs = fTableViewer.getCheckedElements();
+ String[] ids = new String[objs.length];
+ System.arraycopy(objs, 0, ids, 0, objs.length);
+
+ if (fCfgDesc instanceof ICMultiConfigDescription)
+ ((ICMultiConfigDescription)fCfgDesc).setErrorParserIDs(ids);
+ else
+ fCfgDesc.getBuildSetting().setErrorParserIDs(ids);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#canBeVisible()
+ */
@Override
public boolean canBeVisible() {
return page.isForProject() || page.isForPrefs();
}
+ /**
+ * @return {@code true} if the error parsers are allowed to be editable,
+ * i.e. Add/Edit/Delete buttons are enabled and Options page edits enabled.
+ * This will evaluate to {@code true} for Preference Build Settings page but
+ * not for Preference New CDT Project Wizard/Makefile Project.
+ */
+ private boolean isErrorParsersEditable() {
+ return fCfgDesc==null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.cdt.ui.newui.AbstractCPropertyTab#performDefaults()
+ */
@Override
protected void performDefaults() {
- if (cfgd instanceof ICMultiConfigDescription)
- ((ICMultiConfigDescription)cfgd).setErrorParserIDs(null);
- else
- cfgd.getBuildSetting().setErrorParserIDs(null);
- updateData(getResDesc());
- }
+ if (isErrorParsersEditable()) {
+ // Must be Build Settings Preference Page
+ if (MessageDialog.openQuestion(usercomp.getShell(),
+ UIMessages.getString(UIMessages.getString("ErrorParsTab.title.ConfirmReset")), //$NON-NLS-1$
+ UIMessages.getString(UIMessages.getString("ErrorParsTab.message.ConfirmReset")))) { //$NON-NLS-1$
+
+ try {
+ ErrorParserManager.setUserDefinedErrorParsers(null);
+ ErrorParserManager.setDefaultErrorParserIds(null);
+ } catch (BackingStoreException e) {
+ CUIPlugin.log(UIMessages.getString("ErrorParsTab.error.OnRestoring"), e); //$NON-NLS-1$
+ } catch (CoreException e) {
+ CUIPlugin.log(UIMessages.getString("ErrorParsTab.error.OnRestoring"), e); //$NON-NLS-1$
+ }
+ }
+ } else {
+ if (fCfgDesc instanceof ICMultiConfigDescription)
+ ((ICMultiConfigDescription) fCfgDesc).setErrorParserIDs(null);
+ else
+ fCfgDesc.getBuildSetting().setErrorParserIDs(null);
+ }
+ initMapParsers();
+ updateButtons();
+ }
+
+ private void informPages(boolean apply) {
+ Collection pages = fOptionsPageMap.values();
+ for (ICOptionPage dynamicPage : pages) {
+ if (dynamicPage!=null && dynamicPage.isValid() && dynamicPage.getControl() != null) {
+ try {
+ if (apply)
+ dynamicPage.performApply(new NullProgressMonitor());
+ else
+ dynamicPage.performDefaults();
+ } catch (CoreException e) {
+ CUIPlugin.log(UIMessages.getString("ErrorParsTab.error.OnApplyingSettings"), e); //$NON-NLS-1$
+ }
+ }
+ }
+ }
}
diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/PluginResources.properties b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/PluginResources.properties
index 024be6f9eba..2f330529b4c 100644
--- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/PluginResources.properties
+++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/ui/newui/PluginResources.properties
@@ -443,8 +443,18 @@ ConfigDescriptionTab.0=Project Description
ConfigDescriptionTab.1=Configuration Description
ConfigDescriptionTab.2=Resource Description
BinaryParsTab.0=Binary parser:
-ErrorParsTab.0=Check all
-ErrorParsTab.1=Uncheck all
+ErrorParsTab.error.NonEmptyName=Specify non empty name
+ErrorParsTab.error.NonUniqueID=Error parser ID is not unique, specify different name
+ErrorParsTab.error.OnApplyingSettings=Error applying Error Parser Tab settings
+ErrorParsTab.error.OnRestoring=Error restoring default Error Parser Tab settings
+ErrorParsTab.error.NonAccessibleID=[ Not accessible id={0} ]
+ErrorParsTab.error.IllegalCharacter=Special character ''{0}'' is not allowed
+ErrorParsTab.label.EnterName=Enter name of new error parser:
+ErrorParsTab.label.DefaultRegexErrorParserName=Regex Error Parser
+ErrorParsTab.message.ConfirmReset=Are you sure you want to delete all customized error parsers?
+ErrorParsTab.title.Add=Add Regex Error Parser
+ErrorParsTab.title.ConfirmReset=Confirm Resetting Error Parsers
+ErrorParsTab.title.Edit=Edit Regex Error Parser name
StructureTreeTab.0=Level:
StructureTreeTab.1=Maximal tree nesting
StructureTreeTab.2=Long