/******************************************************************************* * Copyright (c) 2007, 2010 Intel Corporation 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: * Intel Corporation - Initial API and implementation * James Blackburn (Broadcom Corp.) *******************************************************************************/ package org.eclipse.cdt.internal.core.settings.model; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICSettingBase; import org.eclipse.cdt.core.settings.model.ICSettingContainer; import org.eclipse.cdt.core.settings.model.ICSettingObject; import org.eclipse.cdt.core.settings.model.ICSettingsStorage; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.core.settings.model.WriteAccessException; import org.eclipse.cdt.core.settings.model.extension.CConfigurationData; import org.eclipse.cdt.core.settings.model.util.CSettingEntryFactory; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.QualifiedName; public class CProjectDescription implements ICProjectDescription, ICDataProxyContainer { private static final String ACTIVE_CFG = "activeConfiguration"; //$NON-NLS-1$ private static final QualifiedName ACTIVE_CFG_PROPERTY = new QualifiedName(CCorePlugin.PLUGIN_ID, ACTIVE_CFG); private static final String SETTING_CFG = "settingConfiguration"; //$NON-NLS-1$ private static final QualifiedName SETTING_CFG_PROPERTY = new QualifiedName(CCorePlugin.PLUGIN_ID, SETTING_CFG); private CfgIdPair fActiveCfgInfo; private CfgIdPair fSettingCfgInfo; private CProjectDescriptionPreferences fPrefs; // private ICConfigurationDescription fActiveCfg; // private String fActiveCfgId; // private ICConfigurationDescription fIndexCfg; // private String fIndexCfgId; private volatile IProject fProject; private final ICSettingsStorage fStorage; private final ICStorageElement fRootStorageElement; private final HashMap<String, ICConfigurationDescription> fCfgMap = new LinkedHashMap<String, ICConfigurationDescription>(); private boolean fIsReadOnly; private boolean fIsModified; private HashMap<QualifiedName, Object> fPropertiesMap; // private boolean fNeedsActiveCfgIdPersistence; private boolean fIsLoading; private boolean fIsApplying; private boolean fIsCreating; private class CfgIdPair { private String fId; private ICConfigurationDescription fCfg; private QualifiedName fPersistanceName; private boolean fNeedsPersistance; private boolean fIsCfgModified; CfgIdPair(CfgIdPair base){ fId = base.fId; fPersistanceName = base.fPersistanceName; } CfgIdPair(QualifiedName persistanceName){ fPersistanceName = persistanceName; } public String getId(){ if(fId == null){ fId = load(); if(fId == null){ fId = getFirstCfgId(); if(fId != null){ fNeedsPersistance = true; } } } return fId; } public ICConfigurationDescription getConfiguration() { if(fCfg == null){ String id = getId(); if(id != null){ fCfg = getConfigurationById(id); if(fCfg == null){ fId = getFirstCfgId(); if(fId != null){ fCfg = getConfigurationById(fId); fNeedsPersistance = true; } } } } return fCfg; } public void setConfiguration(ICConfigurationDescription cfg){ if(cfg.getProjectDescription() != CProjectDescription.this) throw new IllegalArgumentException(); if(cfg.getId().equals(getId())) return; fCfg = cfg; fId = cfg.getId(); fIsCfgModified = true; fNeedsPersistance = true; } public void configurationRemoved(ICConfigurationDescription cfg){ if(cfg.getProjectDescription() != CProjectDescription.this) throw new IllegalArgumentException(); if(!cfg.getId().equals(getId())) return; fIsCfgModified = true; fCfg = null; getConfiguration(); } private String load(){ try { return getProject().getPersistentProperty(fPersistanceName); } catch (CoreException e) { CCorePlugin.log(e); } return null; } private boolean store(String oldId, boolean force){ if(force || fIsCfgModified || fNeedsPersistance || oldId == null || !oldId.equals(fId)){ try { getProject().setPersistentProperty(fPersistanceName, fId); fIsCfgModified = false; fNeedsPersistance = false; return true; } catch (CoreException e) { CCorePlugin.log(e); } } return false; } } public CProjectDescription(IProject project, ICSettingsStorage storage, ICStorageElement element, boolean loading, boolean isCreating) throws CoreException { fProject = project; fStorage = storage; fRootStorageElement = element; fIsReadOnly = loading; fIsLoading = loading; fActiveCfgInfo = new CfgIdPair(ACTIVE_CFG_PROPERTY); fSettingCfgInfo = new CfgIdPair(SETTING_CFG_PROPERTY); fIsCreating = isCreating; ICStorageElement el = null; CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance(); if(loading){ Map<String, ICStorageElement> cfgStorMap = mngr.createCfgStorages(this); for (ICStorageElement sel : cfgStorMap.values()) { CConfigurationDescriptionCache cache = new CConfigurationDescriptionCache(sel, this); configurationCreated(cache); } el = getStorage(CProjectDescriptionManager.MODULE_ID, false); } fPrefs = new CProjectDescriptionPreferences(el, (CProjectDescriptionPreferences)mngr.getProjectDescriptionWorkspacePreferences(false), false); fPropertiesMap = new HashMap<QualifiedName, Object>(); } public void updateProject(IProject project){ fProject = project; } public void loadDatas(){ if(!fIsReadOnly || !fIsLoading) return; CSettingEntryFactory factory = new CSettingEntryFactory(); for(Iterator<ICConfigurationDescription> iter = fCfgMap.values().iterator(); iter.hasNext();){ CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache)iter.next(); try { cache.loadData(factory); factory.clear(); } catch (CoreException e) { CCorePlugin.log(e); iter.remove(); } } // doneInitializing(); // fIsLoading = false; } public boolean applyDatas(SettingsContext context){ if(!fIsReadOnly || !fIsApplying) return false; CSettingEntryFactory factory = new CSettingEntryFactory(); boolean modified = false; for (Iterator<ICConfigurationDescription> iter = fCfgMap.values().iterator(); iter.hasNext();) { CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache)iter.next(); try { if(cache.applyData(factory, context)) modified = true; factory.clear(); } catch (CoreException e) { CCorePlugin.log(e); e.printStackTrace(); iter.remove(); } } // doneInitializing(); // fIsApplying = false; return modified; } /** * Called when the read-only project description has / is being set * fIsApplying => false * setModified (false) * set the ICSettingsStorage to readonly */ public void doneApplying(){ doneInitializing(); fIsApplying = false; try { getStorageBase().setReadOnly(true, false); } catch (CoreException e1) { CCorePlugin.log(e1); } setModified(false); } public void doneLoading(){ doneInitializing(); fIsLoading = false; } public void setLoading(boolean loading){ fIsLoading = loading; } private void doneInitializing(){ for (ICConfigurationDescription cfg : fCfgMap.values()) { // FIXME How and why are we down casting to a CConfigurationDescriptionCache. Comments, please! CConfigurationDescriptionCache cache = (CConfigurationDescriptionCache)cfg; cache.doneInitialization(); } if(fIsReadOnly) fPrefs.setReadOnly(true); } public boolean isLoading(){ return fIsLoading; } public boolean isApplying(){ return fIsApplying; } /** * Create a project description based on another project description * * @param base * @param saving * @param storage * @param el * @param isCreating */ public CProjectDescription(CProjectDescription base, boolean saving, ICSettingsStorage storage, ICStorageElement el, boolean isCreating) { fActiveCfgInfo = new CfgIdPair(base.fActiveCfgInfo); fSettingCfgInfo = new CfgIdPair(base.fSettingCfgInfo); fProject = base.fProject; fStorage = storage; fRootStorageElement = el; fIsReadOnly = saving; fIsLoading = base.fIsLoading; fIsApplying = saving || base.fIsApplying; fIsCreating = isCreating; fPrefs = new CProjectDescriptionPreferences(base.fPrefs, (CProjectDescriptionPreferences)CProjectDescriptionManager.getInstance().getProjectDescriptionWorkspacePreferences(false), false); for(Iterator<ICConfigurationDescription> iter = base.fCfgMap.values().iterator(); iter.hasNext();){ try { IInternalCCfgInfo cfgDes = (IInternalCCfgInfo)iter.next(); if(fIsReadOnly){ CConfigurationData baseData = cfgDes.getConfigurationData(false); CConfigurationDescriptionCache baseCache = null; if(baseData instanceof CConfigurationDescriptionCache){ baseCache = (CConfigurationDescriptionCache)baseData; baseData = baseCache.getConfigurationData(); } CConfigurationDescriptionCache cache = new CConfigurationDescriptionCache((ICConfigurationDescription)cfgDes, baseData, baseCache, cfgDes.getSpecSettings(), this, null); configurationCreated(cache); } else { CConfigurationData baseData = cfgDes.getConfigurationData(false); CConfigurationDescription cfg = new CConfigurationDescription(baseData, this); configurationCreated(cfg); } } catch (CoreException e){ CCorePlugin.log(e); } } @SuppressWarnings("unchecked") HashMap<QualifiedName, Object> cloneMap = (HashMap<QualifiedName, Object>)base.fPropertiesMap.clone(); fPropertiesMap = cloneMap; } /** * Convert the current CConfigurationDescriptions to cached versions * This occurs during the SetCProjectDescription Operation */ void switchToCachedConfigurationDescriptions() throws CoreException { for (Map.Entry<String, ICConfigurationDescription> e : fCfgMap.entrySet()) { if (e.getValue() instanceof CConfigurationDescription) { CConfigurationDescription cfgDes = (CConfigurationDescription)e.getValue(); CConfigurationData baseData = ((IInternalCCfgInfo)cfgDes).getConfigurationData(false); CConfigurationDescriptionCache baseCache = null; if(baseData instanceof CConfigurationDescriptionCache){ baseCache = (CConfigurationDescriptionCache)baseData; baseData = baseCache.getConfigurationData(); } CConfigurationDescriptionCache cache = new CConfigurationDescriptionCache(cfgDes, baseData, baseCache, cfgDes.getSpecSettings(), this, null); e.setValue(cache); } } } void configurationCreated(ICConfigurationDescription des){ fCfgMap.put(des.getId(), des); } public ICConfigurationDescription createConfiguration(String id, String name, ICConfigurationDescription base) throws CoreException{ if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); CConfigurationDescription cfg = new CConfigurationDescription(id, name, base, this); configurationCreated(cfg); return cfg; } public ICConfigurationDescription getActiveConfiguration() { return fActiveCfgInfo.getConfiguration(); } private String getFirstCfgId(){ if(!fCfgMap.isEmpty()){ return fCfgMap.keySet().iterator().next(); } return null; } public ICConfigurationDescription getConfigurationById(String id) { return fCfgMap.get(id); } public ICConfigurationDescription getConfigurationByName(String name) { for(Iterator<ICConfigurationDescription> iter = fCfgMap.values().iterator(); iter.hasNext();){ ICConfigurationDescription cfg = iter.next(); if(name.equals(cfg.getName())) return cfg; } return null; } public ICConfigurationDescription[] getConfigurations() { return fCfgMap.values().toArray(new ICConfigurationDescription[fCfgMap.size()]); } public void removeConfiguration(String name) throws WriteAccessException { if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); CConfigurationDescription cfgDes = (CConfigurationDescription)getConfigurationByName(name); if(cfgDes != null){ cfgDes.removeConfiguration(); } } void configurationRemoved(CConfigurationDescription des){ fCfgMap.remove(des.getId()); fIsModified = true; fActiveCfgInfo.configurationRemoved(des); fSettingCfgInfo.configurationRemoved(des); } public void removeConfiguration(ICConfigurationDescription cfg) throws WriteAccessException { if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); ((CConfigurationDescription)cfg).removeConfiguration(); } public void setActiveConfiguration( ICConfigurationDescription cfg) throws WriteAccessException { if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); if(cfg == null) throw new NullPointerException(); fActiveCfgInfo.setConfiguration(cfg); if(getConfigurationRelations() == CONFIGS_LINK_SETTINGS_AND_ACTIVE) fSettingCfgInfo.setConfiguration(cfg); } public IProject getProject() { return fProject; } public ICStorageElement getStorage(String moduleId, boolean create) throws CoreException { return getStorageBase().getStorage(moduleId, create); } public ICStorageElement importStorage(String id, ICStorageElement el) throws UnsupportedOperationException, CoreException { return getStorageBase().importStorage(id, el); } // public boolean containsStorage(String id) throws CoreException { // return getStorageBase().containsStorage(id); // } public ICSettingObject[] getChildSettings() { return getConfigurations(); } public ICConfigurationDescription getConfiguration() { return null; } public String getId() { //TODO: return null; } public final int getType() { return ICSettingBase.SETTING_PROJECT; } public String getName() { return fProject.getName(); } public ICSettingContainer getParent() { return null; } public boolean isValid() { return /*fProject.exists() &&*/ fCfgMap.size() > 0; } public void updateChild(CDataProxy child, boolean write) { if(write){ try { String oldId = child.getId(); CConfigurationDescription cfgDes = ((CConfigurationDescription)child); cfgDes.doWritable(); updateMap(cfgDes, oldId); } catch (CoreException e) { CCorePlugin.log(e); } } } void updateMap(CConfigurationDescription des, String oldId){ if(!oldId.equals(des.getId())){ fCfgMap.remove(oldId); fCfgMap.put(des.getId(), des); } } public ICStorageElement getRootStorageElement() throws CoreException { if (fRootStorageElement == null) throw ExceptionFactory.createCoreException("CProjectDescription ICStorageElement == null"); //$NON-NLS-1$ // if(fRootStorageElement == null){ // fRootStorageElement = CProjectDescriptionManager.getInstance().createStorage(fProject, true, true, isReadOnly()); // } return fRootStorageElement; } // ICStorageElement doGetCachedRootStorageElement(){ // return fRootStorageElement; // } ICSettingsStorage getStorageBase() throws CoreException{ if(fStorage == null) // fStorage = new CStorage((InternalXmlStorageElement)getRootStorageElement()); throw ExceptionFactory.createCoreException("CProjectDescription ICSettingsStorage == null"); //$NON-NLS-1$ return fStorage; } public ICConfigurationDescription createConfiguration(String buildSystemId, CConfigurationData data) throws CoreException { if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); CConfigurationDescription cfg = new CConfigurationDescription(data, buildSystemId, this); configurationCreated(cfg); return cfg; } public CConfigurationDescription createConvertedConfiguration(String id, String name, ICStorageElement el) throws CoreException{ if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); CConfigurationDescription cfg = new CConfigurationDescription(id, name, el, this); configurationCreated(cfg); return cfg; } public boolean isModified() { if(fIsModified) return true; if(fActiveCfgInfo.fIsCfgModified) return true; if(fSettingCfgInfo.fIsCfgModified) return true; if(fPrefs.isModified()) return true; if(fStorage.isModified()) return true; for(ICConfigurationDescription cfgDes : fCfgMap.values()) if(cfgDes.isModified()) return true; return false; } private void setModified(boolean modified){ fIsModified = modified; if(!modified){ fActiveCfgInfo.fIsCfgModified = false; fSettingCfgInfo.fIsCfgModified = false; fPrefs.setModified(false); //no need to do that for config cache since they always maintain the "isModified == false" } } public boolean isReadOnly() { return fIsReadOnly && !(fIsLoading || fIsApplying); } public void setReadOnly(boolean readOnly, boolean keepModify) { fIsReadOnly = readOnly; try { getStorageBase().setReadOnly(readOnly, keepModify); } catch (CoreException e) { CCorePlugin.log(e); } } public ICSettingObject getChildSettingById(String id) { return getConfigurationById(id); } public ICConfigurationDescription getDefaultSettingConfiguration(){ if(getConfigurationRelations() == CONFIGS_LINK_SETTINGS_AND_ACTIVE) return getActiveConfiguration(); return fSettingCfgInfo.getConfiguration(); } public void setDefaultSettingConfiguration(ICConfigurationDescription cfg) throws WriteAccessException { if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); if(cfg == null) throw new NullPointerException(); fSettingCfgInfo.setConfiguration(cfg); if(getConfigurationRelations() == CONFIGS_LINK_SETTINGS_AND_ACTIVE) fActiveCfgInfo.setConfiguration(cfg); } public Object getSessionProperty(QualifiedName name) { return fPropertiesMap.get(name); } public void setSessionProperty(QualifiedName name, Object value) { if(value != null) fPropertiesMap.put(name, value); else fPropertiesMap.remove(name); fIsModified = true; } public void removeStorage(String id) throws CoreException { getStorageBase().removeStorage(id); } void switchToCachedAppliedData(CProjectDescription appliedCache){ if(fIsReadOnly) return; ICConfigurationDescription[] cfgs = appliedCache.getConfigurations(); for(int i = 0; i < cfgs.length; i++){ CConfigurationDescriptionCache cfgCache = (CConfigurationDescriptionCache)cfgs[i]; CConfigurationDescription des = (CConfigurationDescription)getChildSettingById(cfgCache.getId()); if(des != null){ des.setData(cfgCache); // ICResourceDescription rcDes = des.getResourceDescription(new Path("dd"), false); // rcDes = des.getResourceDescription(new Path("dd"), false); // ICBuildSetting bs = des.getBuildSetting(); // ICLanguageSetting lss[] = ((ICFolderDescription)rcDes).getLanguageSettings(); } } } // boolean checkPersistCfgChanges(boolean force){ // boolean stored = false; // stored |= checkPersistActiveCfg(force); // stored |= checkPersistSettingCfg(force); // return stored; // } boolean checkPersistActiveCfg(String oldId, boolean force){ return fActiveCfgInfo.store(oldId, force); } boolean checkPersistSettingCfg(String oldId, boolean force){ return fSettingCfgInfo.store(oldId, force); } boolean needsActiveCfgPersistence(){ return fActiveCfgInfo.fIsCfgModified; } boolean needsSettingCfgPersistence(){ return fSettingCfgInfo.fIsCfgModified; } CProjectDescriptionPreferences getPreferences(){ return fPrefs; } public int getConfigurationRelations() { return fPrefs.getConfigurationRelations(); } public boolean isDefaultConfigurationRelations() { return fPrefs.isDefaultConfigurationRelations(); } public void setConfigurationRelations(int status) { fPrefs.setConfigurationRelations(status); } public void useDefaultConfigurationRelations() { fPrefs.useDefaultConfigurationRelations(); } public boolean isCdtProjectCreating() { return fIsCreating; } public void setCdtProjectCreated() { if(!fIsCreating) return; if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); fIsCreating = false; fIsModified = true; } public void touch() throws WriteAccessException { if(fIsReadOnly) throw ExceptionFactory.createIsReadOnlyException(); fIsModified = true; } }