/*******************************************************************************
* Copyright (c) 2006, 2010 Wind River Systems, 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.pdom;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.core.dom.IPDOMIndexer;
import org.eclipse.cdt.core.dom.IPDOMManager;
import org.eclipse.cdt.core.model.ElementChangedEvent;
import org.eclipse.cdt.core.model.ICElement;
import org.eclipse.cdt.core.model.ICElementDelta;
import org.eclipse.cdt.core.model.ICProject;
import org.eclipse.cdt.core.model.IElementChangedListener;
import org.eclipse.cdt.core.model.ITranslationUnit;
import org.eclipse.cdt.internal.core.pdom.indexer.DeltaAnalyzer;
import org.eclipse.core.resources.IResourceChangeEvent;
import org.eclipse.core.resources.IResourceChangeListener;
import org.eclipse.core.runtime.CoreException;
/**
* CModel listener used for the PDOMManager.
* @since 4.0
*/
public class CModelListener implements IElementChangedListener, IResourceChangeListener {
private static final int UPDATE_LR_CHANGED_FILES_COUNT = 5;
// For testing purposes, only.
public static boolean sSuppressUpdateOfLastRecentlyUsed = false;
private PDOMManager fManager;
private LinkedHashMap<ITranslationUnit, ITranslationUnit> fLRUs= new LinkedHashMap<ITranslationUnit, ITranslationUnit>(UPDATE_LR_CHANGED_FILES_COUNT, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry<ITranslationUnit, ITranslationUnit> eldest) {
return size() > UPDATE_LR_CHANGED_FILES_COUNT;
}
};
public CModelListener(PDOMManager manager) {
fManager= manager;
}
@Override
public void elementChanged(ElementChangedEvent event) {
// Only respond to post change events
if (event.getType() != ElementChangedEvent.POST_CHANGE)
return;
// Walk the delta collecting tu's per project
HashMap<ICProject, DeltaAnalyzer> changeMap= new HashMap<ICProject, DeltaAnalyzer>();
processDelta(event.getDelta(), changeMap);
// bug 171834 update last recently changed sources
if (!sSuppressUpdateOfLastRecentlyUsed) {
addLastRecentlyUsed(changeMap);
}
for (Map.Entry<ICProject, DeltaAnalyzer> entry : changeMap.entrySet()) {
ICProject cproject = entry.getKey();
DeltaAnalyzer analyzer= entry.getValue();
fManager.changeProject(cproject, analyzer.getForcedTUs(), analyzer.getChangedTUs(), analyzer.getRemovedTUs());
}
}
private void processDelta(ICElementDelta delta, HashMap<ICProject, DeltaAnalyzer> changeMap) {
int type = delta.getElement().getElementType();
switch (type) {
case ICElement.C_MODEL:
// Loop through the children
ICElementDelta[] children = delta.getAffectedChildren();
for (int i = 0; i < children.length; ++i) {
processDelta(children[i], changeMap);
}
break;
case ICElement.C_PROJECT:
// Find the appropriate indexer and pass the delta on
final ICProject project = (ICProject)delta.getElement();
switch (delta.getKind()) {
case ICElementDelta.ADDED:
fManager.addProject(project);
break;
case ICElementDelta.CHANGED:
processProjectDelta(project, delta, changeMap);
break;
case ICElementDelta.REMOVED:
fManager.removeProject(project, delta);
break;
}
}
}
private void processProjectDelta(ICProject project, ICElementDelta delta, HashMap<ICProject, DeltaAnalyzer> changeMap) {
IPDOMIndexer indexer = fManager.getIndexer(project);
if (indexer != null && indexer.getID().equals(IPDOMManager.ID_NO_INDEXER)) {
return;
}
DeltaAnalyzer deltaAnalyzer = new DeltaAnalyzer();
try {
deltaAnalyzer.analyzeDelta(delta);
} catch (CoreException e) {
CCorePlugin.log(e);
}
changeMap.put(project, deltaAnalyzer);
}
private void addLastRecentlyUsed(HashMap<ICProject, DeltaAnalyzer> changeMap) {
boolean addLRUs= false;
int count= 0;
ITranslationUnit[] newLRUs= new ITranslationUnit[UPDATE_LR_CHANGED_FILES_COUNT];
for (DeltaAnalyzer analyzer : changeMap.values()) {
for (ITranslationUnit tu : analyzer.getChangedList()) {
newLRUs[count++ % UPDATE_LR_CHANGED_FILES_COUNT]= tu;
if (!addLRUs && tu.isHeaderUnit()) {
addLRUs= true;
}
}
}
if (count > 0) {
if (addLRUs) {
for (final ITranslationUnit tu : fLRUs.keySet()) {
if (tu.getResource().exists()) {
final ICProject cproject= tu.getCProject();
DeltaAnalyzer analyzer= changeMap.get(cproject);
if (analyzer == null) {
analyzer= new DeltaAnalyzer();
changeMap.put(cproject, analyzer);
}
analyzer.getForcedList().add(tu);
}
}
}
count= Math.min(count, newLRUs.length);
for (int i = 0; i < count; i++) {
final ITranslationUnit tu = newLRUs[i];
fLRUs.put(tu, tu);
}
}
}
@Override
public void resourceChanged(IResourceChangeEvent event) {
if (event.getType() == IResourceChangeEvent.POST_BUILD) {
fManager.handlePostBuildEvent();
}
}
}