org.eclipse.imp.prefspecs.compiler.PrefspecsCompiler.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.imp.prefspecs.compiler.PrefspecsCompiler.java

Source

/*******************************************************************************
*  Copyright (c) 2007 IBM Corporation.
* 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:
*    Robert Fuhrer (rfuhrer@watson.ibm.com) - initial API and implementation
*******************************************************************************/

package org.eclipse.imp.prefspecs.compiler;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Stack;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspaceRunnable;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.imp.builder.MarkerCreator;
import org.eclipse.imp.core.ErrorHandler;
import org.eclipse.imp.model.ISourceProject;
import org.eclipse.imp.model.ModelFactory;
import org.eclipse.imp.model.ModelFactory.ModelException;
import org.eclipse.imp.parser.IParseController;
import org.eclipse.imp.preferences.IPreferencesService;
import org.eclipse.imp.prefspecs.PrefspecsPlugin;
import org.eclipse.imp.prefspecs.compiler.codegen.CodeGenerator;
import org.eclipse.imp.prefspecs.compiler.model.BooleanFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.ColorFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.ComboFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.DirListFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.DirectoryFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.DoubleFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.EnumFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.FieldGroup;
import org.eclipse.imp.prefspecs.compiler.model.FieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.FieldVisitor;
import org.eclipse.imp.prefspecs.compiler.model.FileFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.FontFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.IPageMemberContainer;
import org.eclipse.imp.prefspecs.compiler.model.ITabContainer;
import org.eclipse.imp.prefspecs.compiler.model.IntFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.PageInfo;
import org.eclipse.imp.prefspecs.compiler.model.PreferencesInfo;
import org.eclipse.imp.prefspecs.compiler.model.RadioFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.StringFieldInfo;
import org.eclipse.imp.prefspecs.compiler.model.TabInfo;
import org.eclipse.imp.prefspecs.parser.PrefspecsParseController;
import org.eclipse.imp.prefspecs.parser.Ast.ASTNode;
import org.eclipse.imp.prefspecs.parser.Ast.ASTNodeToken;
import org.eclipse.imp.prefspecs.parser.Ast.AbstractASTNodeList;
import org.eclipse.imp.prefspecs.parser.Ast.AbstractVisitor;
import org.eclipse.imp.prefspecs.parser.Ast.IbooleanValue;
import org.eclipse.imp.prefspecs.parser.Ast.IfontStyle;
import org.eclipse.imp.prefspecs.parser.Ast.IgeneralSpec;
import org.eclipse.imp.prefspecs.parser.Ast.IsignedNumber;
import org.eclipse.imp.prefspecs.parser.Ast.IstaticOrDynamicValues;
import org.eclipse.imp.prefspecs.parser.Ast.IstringEmptySpec;
import org.eclipse.imp.prefspecs.parser.Ast.ItypeOrValuesSpec;
import org.eclipse.imp.prefspecs.parser.Ast.booleanDefValueSpec;
import org.eclipse.imp.prefspecs.parser.Ast.booleanFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.booleanFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.booleanSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.colorDefValueSpec;
import org.eclipse.imp.prefspecs.parser.Ast.colorFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.colorFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.colorSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.columnsSpec;
import org.eclipse.imp.prefspecs.parser.Ast.comboFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.comboFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.comboSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.conditionType__IF;
import org.eclipse.imp.prefspecs.parser.Ast.conditionalSpec__identifier_AGAINST_identifier;
import org.eclipse.imp.prefspecs.parser.Ast.conditionalSpec__identifier_WITH_identifier;
import org.eclipse.imp.prefspecs.parser.Ast.configurationTabSpec;
import org.eclipse.imp.prefspecs.parser.Ast.defaultTabSpec;
import org.eclipse.imp.prefspecs.parser.Ast.dirListFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.directoryFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.directoryFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.dirlistFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.doubleDefValueSpec;
import org.eclipse.imp.prefspecs.parser.Ast.doubleFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.doubleFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.doubleRangeSpec;
import org.eclipse.imp.prefspecs.parser.Ast.doubleSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.enumDefValueSpec;
import org.eclipse.imp.prefspecs.parser.Ast.fileFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.fileFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.fontDefValueSpec;
import org.eclipse.imp.prefspecs.parser.Ast.fontFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.fontFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.fontSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.fontStyle__BOLD;
import org.eclipse.imp.prefspecs.parser.Ast.fontStyle__ITALIC;
import org.eclipse.imp.prefspecs.parser.Ast.fontStyle__NORMAL;
import org.eclipse.imp.prefspecs.parser.Ast.generalSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.groupSpec;
import org.eclipse.imp.prefspecs.parser.Ast.instanceTabSpec;
import org.eclipse.imp.prefspecs.parser.Ast.intDefValueSpec;
import org.eclipse.imp.prefspecs.parser.Ast.intFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.intFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.intRangeSpec;
import org.eclipse.imp.prefspecs.parser.Ast.intSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.isRemovableSpec;
import org.eclipse.imp.prefspecs.parser.Ast.labelledStringValueList;
import org.eclipse.imp.prefspecs.parser.Ast.optConditionalSpec;
import org.eclipse.imp.prefspecs.parser.Ast.optDetailsSpec;
import org.eclipse.imp.prefspecs.parser.Ast.optLabelSpec;
import org.eclipse.imp.prefspecs.parser.Ast.optPackageSpec;
import org.eclipse.imp.prefspecs.parser.Ast.optToolTipSpec;
import org.eclipse.imp.prefspecs.parser.Ast.pageSpec;
import org.eclipse.imp.prefspecs.parser.Ast.prefSpecs;
import org.eclipse.imp.prefspecs.parser.Ast.projectTabSpec;
import org.eclipse.imp.prefspecs.parser.Ast.radioFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.radioFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.radioSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.sign__MINUS;
import org.eclipse.imp.prefspecs.parser.Ast.signedNumber__INTEGER;
import org.eclipse.imp.prefspecs.parser.Ast.signedNumber__sign_INTEGER;
import org.eclipse.imp.prefspecs.parser.Ast.staticOrDynamicValues;
import org.eclipse.imp.prefspecs.parser.Ast.stringDefValueSpec;
import org.eclipse.imp.prefspecs.parser.Ast.stringEmptySpec__EMPTYALLOWED_FALSE_SEMICOLON;
import org.eclipse.imp.prefspecs.parser.Ast.stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON;
import org.eclipse.imp.prefspecs.parser.Ast.stringFieldPropertySpecs;
import org.eclipse.imp.prefspecs.parser.Ast.stringFieldSpec;
import org.eclipse.imp.prefspecs.parser.Ast.stringSpecificSpecList;
import org.eclipse.imp.prefspecs.parser.Ast.stringValidatorSpec;
import org.eclipse.imp.prefspecs.parser.Ast.stringValue;
import org.eclipse.imp.prefspecs.parser.Ast.typeOrValuesSpec__TYPE_identifier_SEMICOLON;
import org.eclipse.imp.prefspecs.parser.Ast.typeOrValuesSpec__valuesSpec_SEMICOLON;
import org.eclipse.imp.prefspecs.parser.Ast.typeSpec;
import org.eclipse.imp.wizards.CodeServiceWizard;
import org.eclipse.imp.wizards.ExtensionEnabler;
import org.eclipse.imp.wizards.ExtensionPointWizard;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.pde.core.plugin.IExtensions;
import org.eclipse.pde.core.plugin.IPluginAttribute;
import org.eclipse.pde.core.plugin.IPluginExtension;
import org.eclipse.pde.core.plugin.IPluginModel;
import org.eclipse.pde.core.plugin.IPluginObject;
import org.eclipse.pde.internal.core.bundle.BundlePluginModel;
import org.eclipse.pde.internal.core.bundle.WorkspaceBundleModel;
import org.eclipse.pde.internal.core.ibundle.IBundleModel;
import org.eclipse.pde.internal.core.plugin.ImpPluginElement;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.ui.console.MessageConsoleStream;

public class PrefspecsCompiler {
    public static String PROBLEM_MARKER_ID = PrefspecsPlugin.kPluginID + ".problem";

    private final String ENUM_VALUE_PROVIDER_INTF_QUAL_NAME = "org.eclipse.imp.preferences.fields.IEnumValueProvider";

    private static final String VALIDATOR_INTF_QUAL_NAME = "org.eclipse.imp.preferences.fields.StringFieldEditor.Validator";

    protected IProject fProject = null;
    protected String fProjectName = null;
    protected String fLanguageName = null;

    private IFile fSpecFile;

    protected PreferencesInfo fPreferencesInfo = new PreferencesInfo();
    protected List<PageInfo> fPages = new ArrayList<PageInfo>();
    protected ITabContainer fTabContainer = null;
    protected Stack<IPageMemberContainer> fMemberContainer = new Stack<IPageMemberContainer>();
    protected PageInfo fCurPageInfo = null;

    // Parameters gathered from the page.genparameters file
    protected String fPageClassNameBase = null;
    protected String fPageId = null;
    protected String fAlternativeMessage = null;
    protected String fPageName = null; // ignored - page names come directly from the "page xxx { }" construct
    protected String fPageMenuItem = null; // ignored - page names come directly from the "page xxx { }" construct

    protected String fPagePackageName = null;

    protected boolean fNoDetails = false;

    private Map<String, IEnumValueSource> fTypeMap = new HashMap<String, IEnumValueSource>();

    private final MessageConsoleStream fConsoleStream;

    public PrefspecsCompiler(String problem_marker_id, MessageConsoleStream messageConsoleStream) {
        PROBLEM_MARKER_ID = problem_marker_id;
        this.fConsoleStream = messageConsoleStream;
    }

    protected void parseAndProduceModel(IFile specFile) {
        if (specFile == null) {
            fConsoleStream.println("PrefspecsCompiler.parseAndProduceModel(..): no specification file?");
        }
        IProject project = specFile.getProject();
        if (project == null) {
            fConsoleStream.println("PrefspecsCompiler.parseAndProduceModel(..): project is null");
        }
        ISourceProject sourceProject = null;
        try {
            sourceProject = ModelFactory.open(project);
        } catch (ModelException me) {
            fConsoleStream
                    .println("PrefspecsCompiler.parseAndProduceModel(..): exception while opening source project:\n"
                            + me.getMessage() + "\n");
        }
        IParseController parseController = new PrefspecsParseController();

        // Marker creator handles error messages from the parse controller
        MarkerCreator markerCreator = new MarkerCreator(specFile, PROBLEM_MARKER_ID);

        // If we have a kind of parser that might be receptive, tell it
        // what types of problem marker the builder will create
        parseController.getAnnotationTypeInfo().addProblemMarkerType(PROBLEM_MARKER_ID);
        parseController.initialize(specFile.getProjectRelativePath(), sourceProject, markerCreator);
        parseController.parse(getFileContents(specFile), new NullProgressMonitor());

        ASTNode currentAst = (ASTNode) parseController.getCurrentAst();

        if (currentAst == null) {
            fConsoleStream.println(
                    "PrefspecsCompiler.parseAndProduceModel(): current AST is null (parse errors?); unable to compute page info.");
            return;
        }

        TranslatorVisitor visitor = new TranslatorVisitor();

        currentAst.accept(visitor);
    }

    private void createErrorMarker(String msg, ASTNode node) {
        int startLine = node.getLeftIToken().getLine();
        int startOffset = node.getLeftIToken().getStartOffset();
        int endOffset = node.getRightIToken().getEndOffset() + 1;

        createMarker(msg, startLine, startOffset, endOffset, IMarker.SEVERITY_ERROR);
    }

    private void createMarker(String msg, int startLine, int startOffset, int endOffset, int severity) {
        try {
            IMarker m = PrefspecsCompiler.this.fSpecFile.createMarker(PROBLEM_MARKER_ID);
            String[] attributeNames = new String[] { IMarker.LINE_NUMBER, IMarker.CHAR_START, IMarker.CHAR_END,
                    IMarker.MESSAGE, IMarker.PRIORITY, IMarker.SEVERITY };
            Object[] values = new Object[] { startLine, startOffset, endOffset, msg, IMarker.PRIORITY_HIGH,
                    severity };

            m.setAttributes(attributeNames, values);
        } catch (CoreException e) {
            PrefspecsPlugin.getInstance()
                    .logException("PrefspecsCompiler.createMarker: CoreException trying to create marker", e);
        } catch (Exception e) {
            PrefspecsPlugin.getInstance()
                    .logException("PrefspecsCompiler.createMarker: Exception trying to create marker", e);
        }
    }

    private final class TranslatorVisitor extends AbstractVisitor {
        @Override
        public boolean visit(prefSpecs n) {
            fTabContainer = fPreferencesInfo;
            if (n.gettabsSpec() == null) {
                createStandardTab(IPreferencesService.DEFAULT_LEVEL, false);
                createStandardTab(IPreferencesService.CONFIGURATION_LEVEL, true);
                createStandardTab(IPreferencesService.INSTANCE_LEVEL, true);
                createStandardTab(IPreferencesService.PROJECT_LEVEL, true);
            }
            return super.visit(n);
        }

        @Override
        public void unimplementedVisitor(String s) {
            // fConsoleStream.println("Don't know how to translate node type '" + s + "'.");
        }

        @Override
        public boolean visit(optPackageSpec ps) {
            PrefspecsCompiler.this.fPagePackageName = ps.getpackageName().toString();
            return false;
        }

        @Override
        public boolean visit(optDetailsSpec n) {
            PrefspecsCompiler.this.fNoDetails = n.getonOff().toString().equalsIgnoreCase("off");
            return false;
        }

        @Override
        public boolean visit(pageSpec p) {
            final String pageName = p.getpageName().toString();
            fCurPageInfo = new PageInfo(pageName);
            fCurPageInfo.setNoDetails(PrefspecsCompiler.this.fNoDetails);
            fPages.add(fCurPageInfo);
            fTabContainer = fCurPageInfo;
            fMemberContainer.push(fCurPageInfo);
            return true;
        }

        private void createStandardTab(String level, boolean editableRemovable) {
            TabInfo tab = new TabInfo(fTabContainer, level);
            tab.setIsEditable(editableRemovable);
            tab.setIsRemovable(editableRemovable);
            tab.setIsUsed(true);
        }

        @Override
        public void endVisit(pageSpec p) {
            fCurPageInfo.dump(PrefspecsCompiler.this.fConsoleStream);
            fMemberContainer.pop();
        }

        private <T> T findSpec(generalSpecList specs, Class<T> type) {
            for (int i = 0; i < specs.size(); i++) {
                IgeneralSpec spec = specs.getgeneralSpecAt(i);
                if (type.isInstance(spec)) {
                    return (T) spec;
                }
            }
            return null;
        }

        private void checkGeneralSpecs(AbstractASTNodeList specs) {
            Set<Class> specsSeen = new HashSet<Class>();
            for (int i = 0; i < specs.size(); i++) {
                Object elt = specs.getElementAt(i);
                if (specsSeen.contains(elt.getClass())) {
                    createErrorMarker("Multiple property specifications of the same type for single entity.",
                            specs);
                }
                specsSeen.add(elt.getClass());
            }
        }

        @Override
        public boolean visit(defaultTabSpec tabSpec) {
            TabInfo tabInfo = new TabInfo(fTabContainer, IPreferencesService.DEFAULT_LEVEL);

            tabInfo.setIsRemovable(false);
            tabInfo.setIsUsed(tabSpec.getinout().toString().equals("in")); // Should always have an inout spec
            return false;
        }

        @Override
        public boolean visit(configurationTabSpec tabSpec) {
            TabInfo tabInfo = new TabInfo(fTabContainer, IPreferencesService.CONFIGURATION_LEVEL);
            tabInfo.setIsUsed(tabSpec.getinout().toString().equals("in")); // Should always have an inout spec
            return false;
        }

        @Override
        public boolean visit(instanceTabSpec tabSpec) {
            TabInfo tabInfo = new TabInfo(fTabContainer, IPreferencesService.INSTANCE_LEVEL);
            tabInfo.setIsUsed(tabSpec.getinout().toString().equals("in")); // Should always have an inout spec
            return false;
        }

        @Override
        public boolean visit(projectTabSpec tabSpec) {
            TabInfo tabInfo = new TabInfo(fTabContainer, IPreferencesService.PROJECT_LEVEL);
            tabInfo.setIsUsed(tabSpec.getinout().toString().equals("in")); // Should always have an inout spec
            return false;
        }

        private String unquoteString(ASTNodeToken stringLit) {
            String text = stringLit.toString();
            return unquoteString(text);
        }

        private String unquoteString(String text) {
            return text.substring(1, text.length() - 1);
        }

        private String getLabel(optLabelSpec labelSpec) {
            return unquoteString(labelSpec.getSTRING_LITERAL());
        }

        private boolean getValueOf(IbooleanValue bv) {
            return bv.toString().equals("true");
        }

        private String getValueOf(stringValue sv) {
            return sv.getSTRING_LITERAL().toString();
        }

        private int getValueOf(IsignedNumber sn) {
            if (sn instanceof signedNumber__INTEGER) {
                return Integer.parseInt(((signedNumber__INTEGER) sn).getINTEGER().toString());
            } else {
                signedNumber__sign_INTEGER sn1 = (signedNumber__sign_INTEGER) sn;
                int absVal = Integer.parseInt(sn1.getINTEGER().toString());
                return (sn1.getsign() instanceof sign__MINUS) ? -absVal : absVal;
            }
        }

        private int getValueOf(IfontStyle style) {
            if (style instanceof fontStyle__NORMAL) {
                return SWT.NORMAL;
            }
            if (style instanceof fontStyle__BOLD) {
                return SWT.BOLD;
            }
            if (style instanceof fontStyle__ITALIC) {
                return SWT.ITALIC;
            }
            return SWT.NORMAL;
        }

        @Override
        public boolean visit(groupSpec n) {
            FieldGroup group = new FieldGroup(n.getSTRING_LITERAL().toString(), fMemberContainer.peek());

            fMemberContainer.push(group);
            return true;
        }

        @Override
        public void endVisit(groupSpec n) {
            fMemberContainer.pop();
        }

        private BooleanFieldInfo findConditionalField(final optConditionalSpec condSpec, String depFieldName) {
            final String name = condSpec.getidentifier().getIDENTIFIER().toString();
            final BooleanFieldInfo[] result = new BooleanFieldInfo[1];

            new FieldVisitor() {
                public void visitField(FieldInfo fieldInfo) {
                    String fieldName = fieldInfo.getName();
                    if (fieldName.equals(name)) {
                        if (fieldInfo instanceof BooleanFieldInfo) {
                            result[0] = (BooleanFieldInfo) fieldInfo;
                        } else {
                            createErrorMarker("A field can only be made conditional on a boolean field", condSpec);
                        }
                    }
                }
            }.visit(fCurPageInfo);

            if (result[0] == null) {
                createErrorMarker("Field " + depFieldName + " is conditional on a non-existent field", condSpec);
            }
            return result[0];
        }

        private void setFieldProperties(FieldInfo field, AbstractASTNodeList generalSpecs,
                optConditionalSpec condSpec) {
            checkGeneralSpecs(generalSpecs);
            isRemovableSpec removableSpec = findSpec(generalSpecs, isRemovableSpec.class);
            if (removableSpec != null) {
                field.setIsRemovable(getValueOf(removableSpec.getbooleanValue()));
            }
            optLabelSpec labelSpec = findSpec(generalSpecs, optLabelSpec.class);
            if (labelSpec != null) {
                field.setLabel(unquoteString(labelSpec.getSTRING_LITERAL()));
            }
            optToolTipSpec toolTipSpec = findSpec(generalSpecs, optToolTipSpec.class);
            if (toolTipSpec != null) {
                field.setToolTipText(unquoteString(toolTipSpec.getSTRING_LITERAL()));
            }
            if (condSpec != null) {
                field.setIsConditional(true);
                field.setConditionalWith(condSpec.getconditionType() instanceof conditionType__IF);
                field.setConditionField(findConditionalField(condSpec, field.getName()));
            }
        }

        private <T> T findSpec(AbstractASTNodeList specs, Class<T> type) {
            for (int i = 0; i < specs.size(); i++) {
                Object elt = specs.getElementAt(i);
                if (type.isInstance(elt)) {
                    return (T) elt;
                }
            }
            return null;
        }

        @Override
        public boolean visit(booleanFieldSpec boolField) {
            BooleanFieldInfo boolInfo = new BooleanFieldInfo(fMemberContainer.peek(),
                    boolField.getidentifier().toString());
            booleanFieldPropertySpecs propSpecs = boolField.getbooleanFieldPropertySpecs();

            if (propSpecs != null) {
                booleanSpecificSpecList booleanSpecificSpecs = propSpecs.getbooleanSpecificSpecs();
                setFieldProperties(boolInfo, booleanSpecificSpecs, boolField.getoptConditionalSpec());

                booleanDefValueSpec defValueSpec = findSpec(booleanSpecificSpecs, booleanDefValueSpec.class);
                if (defValueSpec != null) {
                    boolInfo.setDefaultValue(getValueOf(defValueSpec.getbooleanValue()));
                }
            }
            return false;
        }

        @Override
        public boolean visit(dirListFieldSpec dirListField) {
            DirListFieldInfo dirListInfo = new DirListFieldInfo(fMemberContainer.peek(),
                    dirListField.getidentifier().toString());
            dirlistFieldPropertySpecs propSpecs = dirListField.getdirlistFieldPropertySpecs();

            if (propSpecs != null) {
                stringSpecificSpecList stringSpecificSpecs = propSpecs.getstringSpecificSpecs();
                setFieldProperties(dirListInfo, stringSpecificSpecs, dirListField.getoptConditionalSpec());

                stringDefValueSpec defValueSpec = findSpec(stringSpecificSpecs, stringDefValueSpec.class);
                if (defValueSpec != null) {
                    dirListInfo.setDefaultValue(getValueOf(defValueSpec.getstringValue()));
                }

                IstringEmptySpec emptyValueSpec = findSpec(stringSpecificSpecs, IstringEmptySpec.class);
                if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_FALSE_SEMICOLON) {
                    dirListInfo.setEmptyValueAllowed(false);
                    dirListInfo.setEmptyValue(null);
                } else if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) {
                    stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON ses1 = (stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) emptyValueSpec;
                    dirListInfo.setEmptyValueAllowed(true);
                    dirListInfo.setEmptyValue(getValueOf(ses1.getstringValue()));
                }
            }
            return false;
        }

        @Override
        public boolean visit(directoryFieldSpec directoryField) {
            DirectoryFieldInfo dirInfo = new DirectoryFieldInfo(fMemberContainer.peek(),
                    directoryField.getidentifier().toString());
            directoryFieldPropertySpecs propSpecs = directoryField.getdirectoryFieldPropertySpecs();

            if (propSpecs != null) {
                stringSpecificSpecList stringSpecificSpecs = propSpecs.getstringSpecificSpecs();
                setFieldProperties(dirInfo, stringSpecificSpecs, directoryField.getoptConditionalSpec());

                stringDefValueSpec defValueSpec = findSpec(stringSpecificSpecs, stringDefValueSpec.class);
                if (defValueSpec != null) {
                    dirInfo.setDefaultValue(getValueOf(defValueSpec.getstringValue()));
                }

                IstringEmptySpec emptyValueSpec = findSpec(stringSpecificSpecs, IstringEmptySpec.class);
                if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_FALSE_SEMICOLON) {
                    dirInfo.setEmptyValueAllowed(false);
                    dirInfo.setEmptyValue(null);
                } else if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) {
                    stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON ses1 = (stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) emptyValueSpec;
                    dirInfo.setEmptyValueAllowed(true);
                    dirInfo.setEmptyValue(getValueOf(ses1.getstringValue()));
                }
            }
            return false;
        }

        @Override
        public boolean visit(fileFieldSpec fileField) {
            FileFieldInfo fileInfo = new FileFieldInfo(fMemberContainer.peek(),
                    fileField.getidentifier().toString());
            fileFieldPropertySpecs propSpecs = fileField.getfileFieldPropertySpecs();

            if (propSpecs != null) {
                stringSpecificSpecList stringSpecificSpecs = propSpecs.getstringSpecificSpecs();
                setFieldProperties(fileInfo, stringSpecificSpecs, fileField.getoptConditionalSpec());

                stringDefValueSpec defValueSpec = findSpec(stringSpecificSpecs, stringDefValueSpec.class);
                if (defValueSpec != null) {
                    fileInfo.setDefaultValue(getValueOf(defValueSpec.getstringValue()));
                }

                IstringEmptySpec emptyValueSpec = findSpec(stringSpecificSpecs, IstringEmptySpec.class);
                if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_FALSE_SEMICOLON) {
                    fileInfo.setEmptyValueAllowed(false);
                    fileInfo.setEmptyValue(null);
                } else if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) {
                    stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON ses1 = (stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) emptyValueSpec;
                    fileInfo.setEmptyValueAllowed(true);
                    fileInfo.setEmptyValue(getValueOf(ses1.getstringValue()));
                }
            }
            return false;
        }

        @Override
        public boolean visit(intFieldSpec intField) {
            IntFieldInfo intInfo = new IntFieldInfo(fMemberContainer.peek(), intField.getidentifier().toString());
            intFieldPropertySpecs propSpecs = intField.getintFieldPropertySpecs();

            if (propSpecs != null) {
                // Create a virtual field
                intSpecificSpecList intSpecificSpecs = propSpecs.getintSpecificSpecs();
                setFieldProperties(intInfo, intSpecificSpecs, intField.getoptConditionalSpec());

                intDefValueSpec defValueSpec = findSpec(intSpecificSpecs, intDefValueSpec.class);
                if (defValueSpec != null) {
                    intInfo.setDefaultValue(getValueOf(defValueSpec.getsignedNumber()));
                }

                intRangeSpec rangeSpec = findSpec(intSpecificSpecs, intRangeSpec.class);
                if (rangeSpec != null) {
                    int lowValue = getValueOf(rangeSpec.getlow());
                    int hiValue = getValueOf(rangeSpec.gethigh());

                    intInfo.setRange(lowValue, hiValue);
                }
            }
            return false;
        }

        @Override
        public boolean visit(doubleFieldSpec doubleField) {
            DoubleFieldInfo doubleInfo = new DoubleFieldInfo(fMemberContainer.peek(),
                    doubleField.getidentifier().toString());
            doubleFieldPropertySpecs propSpecs = doubleField.getdoubleFieldPropertySpecs();

            if (propSpecs != null) {
                doubleSpecificSpecList doubleSpecificSpecs = propSpecs.getdoubleSpecificSpecs();
                setFieldProperties(doubleInfo, doubleSpecificSpecs, doubleField.getoptConditionalSpec());

                doubleRangeSpec rangeSpec = findSpec(doubleSpecificSpecs, doubleRangeSpec.class);
                doubleDefValueSpec defValueSpec = findSpec(doubleSpecificSpecs, doubleDefValueSpec.class);

                if (defValueSpec != null) {
                    doubleInfo.setDefaultValue(Double.parseDouble(defValueSpec.getDECIMAL().toString()));
                }

                if (rangeSpec != null) {
                    double lowValue = Double.parseDouble(rangeSpec.getlow().toString());
                    double hiValue = Double.parseDouble(rangeSpec.gethigh().toString());

                    doubleInfo.setRange(lowValue, hiValue);
                }
            }
            return false;
        }

        @Override
        public boolean visit(stringFieldSpec stringField) {
            StringFieldInfo stringInfo = new StringFieldInfo(fMemberContainer.peek(),
                    stringField.getidentifier().toString());
            stringFieldPropertySpecs propSpecs = stringField.getstringFieldPropertySpecs();

            if (propSpecs != null) {
                stringSpecificSpecList stringSpecificSpecs = propSpecs.getstringSpecificSpecs();
                setFieldProperties(stringInfo, stringSpecificSpecs, stringField.getoptConditionalSpec());

                stringDefValueSpec defValueSpec = findSpec(stringSpecificSpecs, stringDefValueSpec.class);
                if (defValueSpec != null) {
                    stringInfo.setDefaultValue(getValueOf(defValueSpec.getstringValue()));
                }

                IstringEmptySpec emptyValueSpec = findSpec(stringSpecificSpecs, IstringEmptySpec.class);
                if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_FALSE_SEMICOLON) {
                    stringInfo.setEmptyValueAllowed(false);
                    stringInfo.setEmptyValue(null);
                } else if (emptyValueSpec instanceof stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) {
                    stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON ses1 = (stringEmptySpec__EMPTYALLOWED_TRUE_stringValue_SEMICOLON) emptyValueSpec;
                    stringInfo.setEmptyValueAllowed(true);
                    stringInfo.setEmptyValue(getValueOf(ses1.getstringValue()));
                }
                stringValidatorSpec validatorSpec = findSpec(stringSpecificSpecs, stringValidatorSpec.class);
                if (validatorSpec != null) {
                    String validatorQualClass = unquoteString(
                            validatorSpec.getqualClassName().getSTRING_LITERAL().toString());
                    IType validatorClass = findClass(validatorQualClass);

                    stringInfo.setValidatorQualClass(validatorQualClass);
                    if (validatorClass == null) {
                        createErrorMarker("Validator class " + validatorQualClass + " does not exist",
                                validatorSpec);
                    } else if (!classImplementsInterface(validatorClass, VALIDATOR_INTF_QUAL_NAME)) {
                        createErrorMarker("Validator class " + validatorQualClass + " must implement "
                                + VALIDATOR_INTF_QUAL_NAME, validatorSpec);
                    }
                }
            }
            return false;
        }

        @Override
        public boolean visit(colorFieldSpec colorField) {
            ColorFieldInfo colorInfo = new ColorFieldInfo(fMemberContainer.peek(),
                    colorField.getidentifier().toString());
            colorFieldPropertySpecs propSpecs = colorField.getcolorFieldPropertySpecs();

            if (propSpecs != null) {
                colorSpecificSpecList colorSpecificSpecs = propSpecs.getcolorSpecificSpecs();
                setFieldProperties(colorInfo, colorSpecificSpecs, colorField.getoptConditionalSpec());

                colorDefValueSpec defValueSpec = findSpec(colorSpecificSpecs, colorDefValueSpec.class);

                if (defValueSpec != null) {
                    int r = Integer.parseInt(defValueSpec.getred().toString());
                    int g = Integer.parseInt(defValueSpec.getgreen().toString());
                    int b = Integer.parseInt(defValueSpec.getblue().toString());
                    colorInfo.setDefaultColor(StringConverter.asString(new RGB(r, g, b)));
                }
            }
            return false;
        }

        @Override
        public boolean visit(fontFieldSpec fontField) {
            FontFieldInfo fontInfo = new FontFieldInfo(fMemberContainer.peek(),
                    fontField.getidentifier().toString());
            fontFieldPropertySpecs propSpecs = fontField.getfontFieldPropertySpecs();

            if (propSpecs != null) {
                fontSpecificSpecList fontSpecificSpecs = propSpecs.getfontSpecificSpecs();
                setFieldProperties(fontInfo, fontSpecificSpecs, fontField.getoptConditionalSpec());

                fontDefValueSpec defValueSpec = findSpec(fontSpecificSpecs, fontDefValueSpec.class);

                if (defValueSpec != null) {
                    fontInfo.setDefaultName(getValueOf(defValueSpec.getname()));
                    fontInfo.setDefaultHeight(Integer.parseInt(defValueSpec.getheight().toString()));
                    fontInfo.setDefaultStyle(getValueOf(defValueSpec.getstyle()));
                }
            }
            return false;
        }

        private IEnumValueSource getValueSourceFrom(IstaticOrDynamicValues sodv) {
            if (sodv instanceof labelledStringValueList) {
                return new LiteralEnumValueSource((labelledStringValueList) sodv);
            } else if (sodv instanceof staticOrDynamicValues) {
                String qualClassName = unquoteString(((staticOrDynamicValues) sodv).getqualClassName().toString());
                IType qualClass = findClass(qualClassName);

                if (qualClass == null) {
                    createErrorMarker("Value provider class '" + qualClassName
                            + "' does not exist in this project's classpath.", (ASTNode) sodv);
                } else if (!classImplementsInterface(qualClass, ENUM_VALUE_PROVIDER_INTF_QUAL_NAME)) {
                    createErrorMarker("Value provider class '" + qualClassName + "' must implement "
                            + ENUM_VALUE_PROVIDER_INTF_QUAL_NAME, (ASTNode) sodv);
                }
                return new DynamicEnumValueSource(qualClassName);
            }
            throw new IllegalStateException(
                    "Unexpected type of enum value source: " + sodv.getClass().getCanonicalName());
        }

        @Override
        public boolean visit(typeSpec n) {
            String typeName = n.getidentifier().getIDENTIFIER().toString();
            IEnumValueSource vs = getValueSourceFrom(n.getstaticOrDynamicValues());

            fTypeMap.put(typeName, vs);
            return false;
        }

        @Override
        public boolean visit(comboFieldSpec comboField) {
            ComboFieldInfo comboInfo = new ComboFieldInfo(fMemberContainer.peek(),
                    comboField.getidentifier().toString());
            comboFieldPropertySpecs propSpecs = comboField.getcomboFieldPropertySpecs();

            if (propSpecs != null) {
                comboSpecificSpecList comboSpecificSpecs = propSpecs.getcomboSpecificSpecs();
                enumDefValueSpec defValueSpec = findSpec(comboSpecificSpecs, enumDefValueSpec.class);
                ItypeOrValuesSpec tovSpec = findSpec(comboSpecificSpecs, ItypeOrValuesSpec.class);
                columnsSpec columnsSpec = findSpec(comboSpecificSpecs, columnsSpec.class);

                setFieldProperties(comboInfo, comboSpecificSpecs, comboField.getoptConditionalSpec());
                setupValueSource(comboInfo, tovSpec, defValueSpec);

                if (columnsSpec != null) {
                    comboInfo.setNumColumns(Integer.parseInt((columnsSpec.getINTEGER().toString())));
                }
            }
            return false;
        }

        private void setupValueSource(EnumFieldInfo enumField, ItypeOrValuesSpec tovSpec,
                enumDefValueSpec defValueSpec) {
            IEnumValueSource vs;

            if (tovSpec instanceof typeOrValuesSpec__TYPE_identifier_SEMICOLON) {
                vs = fTypeMap.get(((typeOrValuesSpec__TYPE_identifier_SEMICOLON) tovSpec).getidentifier()
                        .getIDENTIFIER().toString());
            } else {
                typeOrValuesSpec__valuesSpec_SEMICOLON tovs1 = (typeOrValuesSpec__valuesSpec_SEMICOLON) tovSpec;
                vs = getValueSourceFrom(tovs1.getvaluesSpec().getstaticOrDynamicValues());
            }

            if (defValueSpec != null) {
                if (vs instanceof LiteralEnumValueSource) {
                    LiteralEnumValueSource levs = (LiteralEnumValueSource) vs;

                    levs.setDefaultKey(defValueSpec.getidentifier().getIDENTIFIER().toString());
                } else {
                    createErrorMarker("Can't specify a hard-wired default value for a dynamic value provider",
                            defValueSpec);
                }
            }

            enumField.setValueSource(vs);
        }

        @Override
        public boolean visit(radioFieldSpec radioField) {
            RadioFieldInfo radioInfo = new RadioFieldInfo(fMemberContainer.peek(),
                    radioField.getidentifier().toString());
            radioFieldPropertySpecs propSpecs = radioField.getradioFieldPropertySpecs();

            if (propSpecs != null) {
                radioSpecificSpecList radioSpecificSpecs = propSpecs.getradioSpecificSpecs();
                enumDefValueSpec defValueSpec = findSpec(radioSpecificSpecs, enumDefValueSpec.class);
                ItypeOrValuesSpec tovSpec = findSpec(radioSpecificSpecs, ItypeOrValuesSpec.class);
                columnsSpec columnsSpec = findSpec(radioSpecificSpecs, columnsSpec.class);

                setFieldProperties(radioInfo, radioSpecificSpecs, radioField.getoptConditionalSpec());
                setupValueSource(radioInfo, tovSpec, defValueSpec);

                if (columnsSpec != null) {
                    radioInfo.setNumColumns(Integer.parseInt((columnsSpec.getINTEGER().toString())));
                }
            }
            return false;
        }

        // Use endVisit(..) methods to get information from specs because when
        // visit(..)ed they don't yet have the info that's needed

        /*
         * For "with" condition rules
         */
        @Override
        public boolean visit(conditionalSpec__identifier_WITH_identifier rule) {
            final String conditionalFieldName = rule.getidentifier().toString();
            final String conditionFieldName = rule.getidentifier3().toString();

            processConditionalSpec(conditionalFieldName, conditionFieldName, true);
            return false;
        }

        /*
         * For "against" condition rules
         */
        @Override
        public boolean visit(conditionalSpec__identifier_AGAINST_identifier rule) {
            String conditionalFieldName = rule.getidentifier().toString();
            String conditionFieldName = rule.getidentifier3().toString();

            processConditionalSpec(conditionalFieldName, conditionFieldName, false);
            return false;
        }

        private void processConditionalSpec(final String conditionalFieldName, final String conditionFieldName,
                boolean sense) {
            final FieldInfo[] conditionalFieldInfo = new FieldInfo[1];
            final FieldInfo[] conditionFieldInfo = new FieldInfo[1];

            new FieldVisitor() {
                public void visitField(FieldInfo fieldInfo) {
                    String nextName = fieldInfo.getName();
                    if (nextName.equals(conditionalFieldName)) {
                        conditionalFieldInfo[0] = fieldInfo;
                    } else if (nextName.equals(conditionFieldName)) {
                        conditionFieldInfo[0] = fieldInfo;
                    }
                }
            }.visit(fCurPageInfo);

            if (conditionalFieldInfo[0] != null) {
                conditionalFieldInfo[0].setIsConditional(true);
                conditionalFieldInfo[0].setConditionalWith(sense);
                // if we're compiling, then the AST should be correct,
                // in which case the condition field should always be
                // a boolean field
                conditionalFieldInfo[0].setConditionField((BooleanFieldInfo) conditionFieldInfo[0]);
            }
        }
    }

    public IType findClass(String validatorQualClass) {
        IJavaProject javaProj = JavaCore.create(fProject);
        //      String validatorPathSuffix= validatorQualClass.replace('.', File.separatorChar);
        try {
            return javaProj.findType(validatorQualClass);
            //          return javaProj.findElement(new Path(validatorPathSuffix).addFileExtension("java")) != null;
        } catch (JavaModelException e) {
            return null;
        }
    }

    public boolean classImplementsInterface(IType clazz, String interfaceQualName) {
        try {
            String[] supers = clazz.getSuperInterfaceNames(); // Blah! - These aren't qualified unless they appeared that way in the source
            for (String sup : supers) {
                // The following hack works around not having qualified type names - accept unqualified ones too
                if (sup.equals(interfaceQualName)
                        || sup.equals(interfaceQualName.substring(interfaceQualName.lastIndexOf('.') + 1))) {
                    return true;
                }
            }
        } catch (JavaModelException e) {
        }
        return false;
    }

    private List<IClasspathEntry> getSourceCPEntries(IJavaProject javaProj) {
        List<IClasspathEntry> result = new ArrayList<IClasspathEntry>();
        try {
            IClasspathEntry[] cpEntries = javaProj.getResolvedClasspath(true);
            for (int i = 0; i < cpEntries.length; i++) {
                if (cpEntries[i].getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                    result.add(cpEntries[i]);
                }
            }
        } catch (JavaModelException e) {

        }
        return result;
    }

    public String getFileContents(IFile file) {
        char[] buf = null;
        try {
            File javaFile = new File(file.getLocation().toOSString());
            FileReader fileReader = new FileReader(javaFile);
            int len = (int) javaFile.length();

            buf = new char[len];
            fileReader.read(buf, 0, len);
            return new String(buf);
        } catch (FileNotFoundException fnf) {
            fConsoleStream.println(fnf.getMessage());
            return "";
        } catch (IOException io) {
            fConsoleStream.println(io.getMessage());
            return "";
        }
    }

    public void compile(final IFile specFile, final IProgressMonitor mon) {
        this.fSpecFile = specFile;

        IWorkspaceRunnable wsop = new IWorkspaceRunnable() {
            public void run(IProgressMonitor monitor) throws CoreException {
                collectCodeParms(specFile);
                if (fPageId == null) {
                    PrefspecsCompiler.this.fPageId = PrefspecsCompiler.this.fPagePackageName;
                }

                IProject project = specFile.getProject();
                IPluginModel pluginModel = getPluginModel(project);

                if (pluginModel == null) {
                    createMarker("Unable to read plugin.xml; possibly it or MANIFEST.MF is missing?", 1, 0, 0,
                            IMarker.SEVERITY_WARNING);
                } else {
                    // Load the IMP way to get the complete model
                    ExtensionEnabler.loadImpExtensionsModel(pluginModel, project);
                    IExtensions pmExtensions = pluginModel.getExtensions();
                    IPluginExtension[] pluginExtensions = pmExtensions.getExtensions();

                    removeOldPageExtensions(pmExtensions, pluginExtensions);

                    ExtensionEnabler.saveAndRefresh(pluginModel);
                }

                generateCodeStubs(specFile, mon);

                addNewPageExtensions(specFile, monitor);
            }

            private IPluginModel getPluginModel(IProject project) {
                IPluginModel pluginModel;
                pluginModel = ExtensionEnabler.getPluginModel(project);

                // SMS 30 Jul 2008
                if (pluginModel instanceof BundlePluginModel) {
                    BundlePluginModel bpm = (BundlePluginModel) pluginModel;
                    IBundleModel bm = bpm.getBundleModel();
                    if (bm instanceof WorkspaceBundleModel) {
                        ((WorkspaceBundleModel) bm).setEditable(true);
                    }
                }
                return pluginModel;
            }

            private void addNewPageExtensions(final IFile specFile, IProgressMonitor monitor) {
                for (PageInfo pageInfo : fPages) {
                    String pageName = pageInfo.getName();
                    int lastCompIdx = (pageName.indexOf('.') > 0) ? pageName.lastIndexOf('.') + 1 : 0;
                    String pageParent = (lastCompIdx > 0) ? (fPageId + "." + pageName.substring(0, lastCompIdx - 1))
                            : "";
                    String pageLabel = pageName.substring(lastCompIdx);

                    ExtensionEnabler.enable(specFile.getProject(), "org.eclipse.ui", "preferencePages",
                            new String[][] { { "page:id", fPageId + "." + pageName }, { "page:name", pageLabel },
                                    { "page:class",
                                            fPagePackageName + "." + (pageName.replaceAll("\\.", ""))
                                                    + "PreferencePage" },
                                    { "page:category", pageParent }, },
                            false, // do not just replace previous extension, there may be more than one page
                            getPluginDependencies(), monitor);
                }
            }

            private void removeOldPageExtensions(IExtensions pmExtensions, IPluginExtension[] pluginExtensions)
                    throws CoreException {
                // Remove previous extensions of this point, but only if they have the same extension id
                // (extension "id" is an attribute of the "page" child of the "preferencePage" extension)
                for (int i = 0; i < pluginExtensions.length; i++) {
                    IPluginExtension pluginExtension = pluginExtensions[i];
                    if (pluginExtension == null)
                        continue;
                    if (pluginExtension.getPoint() == null)
                        continue;
                    String point = "org.eclipse.ui" + "." + "preferencePages";
                    if (pluginExtension.getPoint() == null)
                        continue;
                    if (pluginExtension.getPoint().equals(point)) {
                        IPluginObject[] children = pluginExtension.getChildren();
                        for (int j = 0; j < children.length; j++) {
                            if (children[j].getName().equals("page")) {
                                ImpPluginElement ipe = (ImpPluginElement) children[j];
                                IPluginAttribute pa = ipe.getAttribute("id");
                                if (pa != null && pa.getValue().startsWith(fPageId)) {
                                    pmExtensions.remove(pluginExtension);
                                }
                            }
                        }
                    }
                }
            }
        };
        try {
            wsop.run(new NullProgressMonitor());
        } catch (CoreException e) {
            ErrorHandler.reportError("PrefspecsCompiler.performGeneration:  CoreException:  ", e);
        }
    }

    protected void collectCodeParms(IFile file) {
        fProject = file.getProject();
        fProjectName = fProject.getName();

        IPath filePath = file.getLocation();
        IPath projectPath = file.getProject().getLocation();
        IPath packagePath = filePath
                .removeFirstSegments(projectPath.segmentCount() + getProjectSourceLocationPath().segmentCount());
        packagePath = packagePath.removeLastSegments(1);
        fPagePackageName = packagePath.toString();
        fPagePackageName = fPagePackageName.substring(fPagePackageName.indexOf(':') + 1);
        fPagePackageName = fPagePackageName.replace('\\', '.');
        fPagePackageName = fPagePackageName.replace('/', '.');

        // Obtain through getGenerationParameters()
        //fPageClassNameBase = getPageInfo(file, new NullProgressMonitor()).getPageName();
        fLanguageName = CodeServiceWizard.discoverProjectLanguage(file.getProject());
    }

    public void generateCodeStubs(IFile specFile, IProgressMonitor mon) throws CoreException {
        IProject fProject = specFile.getProject();
        Map<String, String> subs = getStandardSubstitutions(fProject);

        parseAndProduceModel(specFile);

        // Abort before code gen if there are any errors
        if (specFile.findMaxProblemSeverity(PROBLEM_MARKER_ID, true, 0) >= IMarker.SEVERITY_ERROR) {
            return;
        }

        ISourceProject sourceProject = null;
        try {
            sourceProject = ModelFactory.open(fProject);
        } catch (ModelException me) {
            fConsoleStream.println("PrefspecsCompiler.generateCodeStubs(..): exception opening source project:\n"
                    + me.getMessage() + "\nReturning without parsing");
            return;
        }

        fPageClassNameBase = fPages.get(0).getName(); // TODO Is it appropriate to use the first page name for this?
        String constantsClassName = fPageClassNameBase + "Constants";
        String initializerClassName = fPageClassNameBase + "Initializer";

        subs.put("$PREFS_CLASS_NAME$", fPageClassNameBase);
        subs.put("$PREFS_PACKAGE_NAME$", fPagePackageName);
        subs.put("$PREFS_INIT_CLASS_NAME$", initializerClassName);

        CodeGenerator prefFactory = new CodeGenerator(fConsoleStream);

        String projectSourceLoc = ExtensionPointWizard.getProjectSourceLocation(fProject);
        String pluginPkgName = getPluginPackageName(fProject, null);
        String pluginClassName = getPluginClassName(fProject, null);

        prefFactory.generatePreferenceConstantsClass(fPages, sourceProject, projectSourceLoc, fPagePackageName,
                constantsClassName, mon);

        prefFactory.generatePreferenceInitializerClass(fPages, pluginPkgName, pluginClassName, constantsClassName,
                sourceProject, projectSourceLoc, fPagePackageName, initializerClassName, mon);

        for (PageInfo pageInfo : fPages) {
            final String javaPageName = pageInfo.getName().replaceAll("\\.", "");
            ITabContainer tabContainer = pageInfo.getTabInfos().hasNext() ? pageInfo : fPreferencesInfo;

            subs.put("$PREFS_CLASS_NAME$", javaPageName);

            prefFactory.generatePreferencePageClass(pageInfo, tabContainer, pluginPkgName, pluginClassName,
                    constantsClassName, initializerClassName, sourceProject, projectSourceLoc, fPagePackageName,
                    javaPageName + "PreferencePage", mon);

            TabInfo defTabInfo = findTabInfo(IPreferencesService.DEFAULT_LEVEL, pageInfo);
            if (defTabInfo != null && defTabInfo.getIsUsed()) {
                prefFactory.generateDefaultTabClass(pageInfo, pluginPkgName, pluginClassName, constantsClassName,
                        initializerClassName, sourceProject, projectSourceLoc, fPagePackageName,
                        javaPageName + "DefaultTab", mon);
            }
            TabInfo confTabInfo = findTabInfo(IPreferencesService.CONFIGURATION_LEVEL, pageInfo);
            if (confTabInfo != null && confTabInfo.getIsUsed()) {
                prefFactory.generateConfigurationTabClass(pageInfo, pluginPkgName, pluginClassName,
                        constantsClassName, sourceProject, projectSourceLoc, fPagePackageName,
                        javaPageName + "ConfigurationTab", mon);
            }
            TabInfo instTabInfo = findTabInfo(IPreferencesService.INSTANCE_LEVEL, pageInfo);
            if (instTabInfo != null && instTabInfo.getIsUsed()) {
                prefFactory.generateInstanceTabClass(pageInfo, pluginPkgName, pluginClassName, constantsClassName,
                        sourceProject, projectSourceLoc, fPagePackageName, javaPageName + "InstanceTab", mon);
            }
            TabInfo projTabInfo = findTabInfo(IPreferencesService.PROJECT_LEVEL, pageInfo);
            if (projTabInfo != null && projTabInfo.getIsUsed()) {
                prefFactory.generateProjectTabClass(pageInfo, pluginPkgName, pluginClassName, constantsClassName,
                        sourceProject, projectSourceLoc, fPagePackageName, javaPageName + "ProjectTab", mon);
            }
        }
    }

    private TabInfo findTabInfo(String tabName, ITabContainer tabContainer) {
        TabInfo result = tabContainer.getTabInfo(tabName);
        if (result == null) {
            result = fPreferencesInfo.getTabInfo(tabName);
        }
        return result;
    }

    /**
     * Get the name of the package in which a plugin class is defined
     * for this project, or a default value if there is no such package
     * or if the project is null.  If no default name is provided, then
     * the name of the language is used for a default.
     * 
     * The intention here is to return a the name of the plugin package,
     * if the package exists, or a name that could be used as the name
     * of the plugin package, if the package does not exist.  So this
     * method should not return null and should not be used as a test
     * of whether a given project contains a plugin package or class.
     * 
     * 
     * 
     * SMS 23 Mar 2007
     * 
     * @param project      The project for which the plugin package name is sought;
     *                   may be null
     * @param defaultName   A name to return if the given package lacks a plugin class;
     *                   may be null
     * @return            The name of the package that contains the project's plugin
     *                   class, if there is one, or a name that could be used for the
     *                   plugin package, if there is none.
     */
    public String getPluginPackageName(IProject project, String defaultName) {
        String result = defaultName;
        if (result == null)
            result = fLanguageName;
        if (project != null) {
            String activator = null;
            IPluginModel pm = ExtensionEnabler.getPluginModelForProject(project);
            if (pm != null) {
                WorkspaceBundleModel wbm = new WorkspaceBundleModel(project.getFile("META-INF/MANIFEST.MF")); //$NON-NLS-1$
                activator = wbm.getBundle().getHeader("Bundle-Activator");
            }

            if (activator != null && !activator.equals("")) {
                if (activator.lastIndexOf(".") >= 0)
                    result = activator.substring(0, activator.lastIndexOf("."));
            }
        }
        return result;
    }

    /**
     * Get the name of the plugin class for this project, or a default
     * name if there is no plugin class or if the given project is null.
     * If no default name is provided, then a name based on the name of
     * the language is used for a default.
     * 
     * The intention here is to return a the name of the plugin class,
     * if it exists, or a name that could be used as the name of the
     * plugin class, if it does not exist.  So this method should not
     * return null and should not be used as a test of whether a given
     * project contains a plugin class.
     * 
     * SMS 27 Mar 2007
     * 
     * @param project      The project for which the plugin class name is sought;
     *                   may be null
     * @param defaultName   A name to return if the given package lacks a plugin class;
     *                   may be null
     * @return            The name of the project's plugin class, if there is one,
     *                   or a name that could be used for the plugin class, if there
     *                   is none.
     */
    public String getPluginClassName(IProject project, String defaultName) {
        String result = defaultName;
        if (result == null)
            result = fPageClassNameBase + "Plugin";
        if (project != null) {
            String activator = null;
            IPluginModel pm = ExtensionEnabler.getPluginModelForProject(project);
            if (pm != null) {
                WorkspaceBundleModel wbm = new WorkspaceBundleModel(project.getFile("META-INF/MANIFEST.MF")); //$NON-NLS-1$   
                activator = wbm.getBundle().getHeader("Bundle-Activator");
            }

            if (activator != null) {
                result = activator.substring(activator.lastIndexOf(".") + 1);
            }
        }
        return result;
    }

    /**
     * Get the plugin id defined for this project, or a default value if
     * there is no plugin id or if the given project is null.   If no default
     * id is provided, then an id based on the name of the project is used
     * for a default.
     * 
     * The intention here is to return a plugin id, if it exists, or a
     * value that could be used as the id of the plugin, if it does not
     * exist.  So this method should not return null and should not be
     * used as a test of whether a given project has a plugin id.
     * 
     * SMS 27 Mar 2007
     * 
     * @param project      The project for which the plugin id name is sought;
     *                   may be null
     * @param defaultID      A value to return if the given package lacks a plugin id;
     *                   may be null
     * @return            The plugin id of the project, if there is one, or a value
     *                   that could be used as the plugin id, if there is none.
     */
    public String getPluginID(IProject project, String defaultID) {
        String result = defaultID;
        if (result == null)
            getPluginPackageName(project, null);
        if (project != null) {
            result = ExtensionEnabler.getPluginIDForProject(project);
        }
        return result;
    }

    // SMS 23 Mar 2007
    // This version takes an IProject and provides mappings
    // related to the project's plugin aspect
    public Map<String, String> getStandardSubstitutions(IProject project) {
        Map<String, String> result = new HashMap<String, String>();
        //result = ExtensionPointUtils.getASTInformation((IPluginModel)pages[0].getPluginModel(), project);
        result.put("$LANG_NAME$", fLanguageName);
        result.put("$CLASS_NAME_PREFIX$", fPageClassNameBase);
        result.put("$PACKAGE_NAME$", fPagePackageName);
        // SMS 22 Mar 2007
        result.put("$PROJECT_NAME$", fProjectName);
        // SMS 23 Mar 2007
        // Not the greatest solution, but if we don't have the
        // project then we may as well assume that $PLUGIN_PACKAGE$
        // has a default value
        result.put("$PLUGIN_PACKAGE$", getPluginPackageName(null, null));
        // SMS 27 Mar 2007:  ditto
        result.put("$PLUGIN_CLASS$", getPluginClassName(null, null));
        result.put("$PLUGIN_ID$", getPluginID(null, null));

        result.remove("$PLUGIN_PACKAGE$");
        result.put("$PLUGIN_PACKAGE$", getPluginPackageName(project, null));
        // SMS 27 Mar 2007
        result.remove("$PLUGIN_CLASS$");
        result.put("$PLUGIN_CLASS$", getPluginClassName(project, null));
        result.remove("$PLUGIN_ID$");
        result.put("$PLUGIN_ID$", getPluginID(project, null));
        return result;
    }

    public IPath getProjectSourceLocationPath() {
        return new Path(ExtensionPointWizard.getProjectSourceLocation(fProject));
    }

    protected List<String> getPluginDependencies() {
        return Arrays.asList(new String[] { "org.eclipse.core.runtime", "org.eclipse.core.resources",
                "org.eclipse.imp.runtime" });
    }

    private void logError(Exception e) {
        final Status status = new Status(IStatus.ERROR, PrefspecsPlugin.kPluginID, 0, e.getMessage(), e);
        PrefspecsPlugin.getInstance().getLog().log(status);
    }
}