code: package org.omnetpp.cdt.ui;
  
  import java.util.ArrayList;
  import java.util.List;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.resources.IProject;
  import org.eclipse.core.resources.IResource;
  import org.eclipse.core.resources.IResourceChangeEvent;
  import org.eclipse.core.resources.IResourceChangeListener;
  import org.eclipse.core.resources.IResourceDelta;
  import org.eclipse.core.resources.IResourceDeltaVisitor;
  import org.eclipse.core.resources.ResourcesPlugin;
  import org.eclipse.core.runtime.Assert;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.jface.dialogs.ErrorDialog;
  import org.eclipse.swt.widgets.Display;
  import org.eclipse.swt.widgets.Shell;
  import org.eclipse.ui.PlatformUI;
  import org.omnetpp.cdt.Activator;
  import org.omnetpp.cdt.build.ProjectFeaturesManager;
  import org.omnetpp.cdt.build.ProjectFeaturesManager.Problem;
  import org.omnetpp.common.Debug;
  import org.omnetpp.common.project.ProjectUtils;
  import org.omnetpp.common.ui.ProblemsMessageDialog;
  import org.omnetpp.common.util.UIUtils;
  
  /**
   * Responsible for keeping a project's configuration (NED excluded packages, CDT
   * source folders and exclusions, preprocessor symbols etc.) reasonably in sync
   * with the enabled project features. This is achieved by listening on various
   * resource change events.
   *
   * In principle, it should do the following:
   * <ul>
   * <li>when a project is created (e.g. via import), it should silently (no
   * dialog!) initialize the "enabled" state of project features to the default
   * state (see the "initiallyEnabled" attribute in ".oppfeatures"), and modify
   * the project's configuration (CDT and NED) accordingly.
   * <li>when "something" changes in the project, check that the project state
   * (CDT and NED) still corresponds to the list of enabled features, and if not,
   * offer fixing it to the user. However, these checks (and corresponding pop-up
   * dialogs) should not be too aggressive in order not to annoy the user, and
   * especially it should NOT take place when the Project Properties dialog is
   * open (the Properties dialog edits its own working copy of the config, so
   * fixing the original copy would only create confusion.)
   * </ul>
   *
   * Currently it does the following:
   * <ul>
   * <li>when an ".oppfeatures" file is created, and it updates CDT and NED
   * setting according to the default feature selection (without asking)
   * <li>when an ".oppfeatures" is modified, it checks the project state (CDT and
   * NED), and offers the user to fix it if it was not consistent with the feature
   * selection.
   * <li>at project build, we also perform the checks and offer the user to fix
   * any inconsistency (this is done in MakefileBuilder)
   * </ul>
   *
   * We could also listen on CDT config changes, folder creation notifications
   * etc., but this is not done (it was too aggressive and annoying).
   *
   * @author Andras
   */
  public class ProjectFeaturesListener implements IResourceChangeListener /*,ICProjectDescriptionListener*/ {
  
      public void hookListeners() {
          ResourcesPlugin.getWorkspace().addResourceChangeListener(this, IResourceChangeEvent.POST_CHANGE);
          //CoreModel.getDefault().addCProjectDescriptionListener(this, CProjectDescriptionEvent.APPLIED);
      }
  
      public void unhookListeners() {
          ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
          //CoreModel.getDefault().removeCProjectDescriptionListener(this);
      }
  
      //public void handleEvent(CProjectDescriptionEvent event) {
      //    verifyProjectConfiguration(event.getProject());
      //}
  
      public void resourceChanged(IResourceChangeEvent event) {
          Assert.isTrue(event.getType() == IResourceChangeEvent.POST_CHANGE);
          try {
              event.getDelta().accept(new IResourceDeltaVisitor() {
                  public boolean visit(IResourceDelta delta) throws CoreException {
                      IResource resource = delta.getResource();
                      if (isFeaturesDescriptionFile(resource)) {
                          if (delta.getKind() == IResourceDelta.ADDED)
                              omnetppProjectWithFeaturesCreated(resource.getProject());
                          else if (delta.getKind() == IResourceDelta.CHANGED)
                              verifyProjectConfiguration(resource.getProject());
                          return false;
                      }
                      return true;
                  }
  
                  protected boolean isFeaturesDescriptionFile(IResource resource) throws CoreException {
                      return (resource.getParent() instanceof IProject &&   // note: least costly/more selective checks first
                              resource instanceof IFile &&
                              resource.getName().equals(ProjectFeaturesManager.PROJECTFEATURES_FILENAME) &&
                              ProjectUtils.isOpenOmnetppProject(resource.getProject()));
                  }
  
              });
          }
          catch (CoreException e) {
              Activator.logError(e);
          }
      }
  
      protected void omnetppProjectWithFeaturesCreated(final IProject project) {
          Display.getDefault().asyncExec(new Runnable() {
              public void run() {
                  try {
                      // we need to run it in asyncExec() because the workspace is locked during a resource change
                      // notification so we would not be able to save the updated CDT configuration
                      ProjectFeaturesManager features = new ProjectFeaturesManager(project);
                      if (features.loadFeaturesFile()) {
                          Debug.println("Project Features: activating default feature selection for new project " + project.getName());
                          features.initializeProjectState();
                      }
                  }
                  catch (CoreException e) {
                      Activator.logError(e);
                  }
              }
          });
      }
  
      protected void verifyProjectConfiguration(IProject project) {
          try {
              if (ProjectUtils.isOpenOmnetppProject(project)) {
                  final ProjectFeaturesManager features = new ProjectFeaturesManager(project);
                  if (features.loadFeaturesFile()) {
                      Debug.println("Project Features: checking project " + project.getName());
                      final List<Problem> problems = features.validateProjectState();
                      if (!problems.isEmpty()) {
                          Display.getDefault().asyncExec(new Runnable() {
                              public void run() {
                                  offerFixingProblems(features, problems);
                              }
                          });
                      }
  
                  }
              }
          }
          catch (CoreException e) {
              Activator.logError("Error checking project state wrt. project features", e);
          }
      }
  
      protected void offerFixingProblems(ProjectFeaturesManager features, List<Problem> problems) {
          if (isOkToFixConfigProblems(features.getProject(), problems)) {
              try {
                  features.fixupProjectState();
              }
              catch (CoreException e) {
                  Activator.logError(e);
                  Shell parentShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
                  ErrorDialog.openError(parentShell, "Error", "Error fixing project state", e.getStatus());
              }
          }
      }
  
      protected boolean isOkToFixConfigProblems(IProject project, List<Problem> problems) {
          List<String> problemTexts = new ArrayList<String>();
          for (Problem p : problems)
              problemTexts.add(p.toString());
          Shell parentShell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
          return ProblemsMessageDialog.openConfirm(parentShell, "Project Setup Inconsistency",
                  "Some configuration settings in project \"" + project.getName() + "\" do not correspond " +
                  "to the enabled project features. Do you want to fix the project state?",
                  problemTexts, UIUtils.ICON_ERROR);
      }
  
  }
  