/******************************************************************************* * 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 org.eclipse.cdt.core.CCorePlugin; import org.eclipse.cdt.core.model.CModelException; import org.eclipse.cdt.core.model.ICElementDelta; import org.eclipse.cdt.core.model.ICProject; import org.eclipse.cdt.core.settings.model.CProjectDescriptionEvent; import org.eclipse.cdt.core.settings.model.ICConfigurationDescription; import org.eclipse.cdt.core.settings.model.ICDescriptionDelta; import org.eclipse.cdt.core.settings.model.ICProjectDescription; import org.eclipse.cdt.core.settings.model.ICProjectDescriptionManager; import org.eclipse.cdt.core.settings.model.ICSettingsStorage; import org.eclipse.cdt.core.settings.model.ICStorageElement; import org.eclipse.cdt.internal.core.model.CModelOperation; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; /** * The operation which actually causes the CProjectDescription to be serialized * * This organizes the firing the {@link CProjectDescriptionEvent}s to all listeners */ public class SetCProjectDescriptionOperation extends CModelOperation { /** The ProjectDescription Storage being used for this project description */ private final AbstractCProjectDescriptionStorage fPrjDescStorage; private final CProjectDescription fSetDescription; private final int fFlags; /** * Operation used for persisting the new CProjectDescription * @param prjDescStorage * @param cProject * @param description * @param flags */ public SetCProjectDescriptionOperation(AbstractCProjectDescriptionStorage prjDescStorage, ICProject cProject, CProjectDescription description, int flags){ super(cProject); this.fPrjDescStorage = prjDescStorage; fFlags = flags; fSetDescription = description; } @Override protected void executeOperation() throws CModelException { CProjectDescriptionManager mngr = CProjectDescriptionManager.getInstance(); ICProject cProject = (ICProject)getElementToProcess(); final IProject project = cProject.getProject(); ICProjectDescription fOldDescriptionCache = mngr.getProjectDescription(project, false); AbstractCProjectDescriptionStorage.fireAboutToApplyEvent(fSetDescription, fOldDescriptionCache); CProjectDescription fNewDescriptionCache = null; SettingsContext context = new SettingsContext(project); boolean modified = false; if(fSetDescription != null){ ICStorageElement newEl = null; ICSettingsStorage newStorage = null; try { ICStorageElement base = fSetDescription.getRootStorageElement(); modified = fSetDescription.isModified(); // el = base; // FIXME JBB there is deep magic going on here. The project descriptions are being // changed in non-obvious ways newEl = fPrjDescStorage.copyElement(base, false); newStorage = fPrjDescStorage.getStorageForElement(newEl); } catch (CoreException e) { CCorePlugin.log(e); } boolean creating = fOldDescriptionCache != null ? fOldDescriptionCache.isCdtProjectCreating() : true; if(creating) creating = fSetDescription.isCdtProjectCreating(); if(!fSetDescription.isValid() && (!mngr.isEmptyCreatingDescriptionAllowed() || !creating)) throw new CModelException(ExceptionFactory.createCoreException(SettingsModelMessages.getString("CProjectDescriptionManager.17") + project.getName())); //$NON-NLS-1$ fNewDescriptionCache = new CProjectDescription(fSetDescription, true, newStorage, newEl, creating); boolean envStates[] = getEnvStates(fNewDescriptionCache); try { fPrjDescStorage.setThreadLocalProjectDesc(fNewDescriptionCache); modified |= fNewDescriptionCache.applyDatas(context); } finally { fPrjDescStorage.setThreadLocalProjectDesc(null); setEnvStates(fNewDescriptionCache, envStates); } } else { modified = fOldDescriptionCache != null; } ICDescriptionDelta delta = mngr.createDelta(fNewDescriptionCache, fOldDescriptionCache); mngr.checkRemovedConfigurations(delta); // Generate the c element deltas ICElementDelta cElementDeltas[] = mngr.generateCElementDeltas(cProject, delta); for (ICElementDelta d : cElementDeltas) addDelta(d); if(fSetDescription != null) fSetDescription.switchToCachedAppliedData(fNewDescriptionCache); try { final IProjectDescription eDes = context.getEclipseProjectDescription(); if(mngr.checkHandleActiveCfgChange(fNewDescriptionCache, fOldDescriptionCache, eDes, new NullProgressMonitor())){ context.setEclipseProjectDescription(eDes); } } catch (CoreException e2) { CCorePlugin.log(e2); } // fNewDescriptionCache is still writable and may be written to at this point AbstractCProjectDescriptionStorage.fireDataAppliedEvent(fNewDescriptionCache, fOldDescriptionCache, fSetDescription, delta); cProject.close(); // Why? // ExternalSettingsManager.getInstance().updateDepentents(delta); if(fNewDescriptionCache != null){ fNewDescriptionCache.doneApplying(); } // Set 'fSetProjectDescription' as the new read-only project description on the block fPrjDescStorage.setCurrentDescription(fNewDescriptionCache, true); CProjectDescriptionEvent event = AbstractCProjectDescriptionStorage.createAppliedEvent(fNewDescriptionCache, fOldDescriptionCache, fSetDescription, delta); mngr.notifyListeners(event); try { IWorkspaceRunnable toRun = null; if(fNewDescriptionCache != null && !CProjectDescriptionManager.checkFlags(fFlags, ICProjectDescriptionManager.SET_NO_SERIALIZE)){ if(modified || isPersistentCoreSettingChanged(event)){ toRun = fPrjDescStorage.createDesSerializationRunnable(); if (toRun != null) context.addWorkspaceRunnable(toRun); } } toRun = context.createOperationRunnable(); if(toRun != null) CProjectDescriptionManager.runWspModification(toRun, getSchedulingRule(), new NullProgressMonitor()); } catch (CoreException e) { throw new CModelException(e); } } // Can't use project scoped rule see CProjectDescriptionBasicTests... // /* // * Instead of using the workspace scheduling rule, use a more refined project scoped rule. // * This must contain the rule in CConfigBasedDescriptor.setApply(...) // * (non-Javadoc) // * @see org.eclipse.cdt.internal.core.model.CModelOperation#getSchedulingRule() // */ // @Override // public ISchedulingRule getSchedulingRule() { //// return null; // return fPrjDescStorage.getProject(); // } private static boolean isPersistentCoreSettingChanged(CProjectDescriptionEvent event){ ICDescriptionDelta delta = event.getProjectDelta(); if(delta == null) return false; if(delta.getDeltaKind() != ICDescriptionDelta.CHANGED) return true; if(delta.getChildren().length != 0) return true; int flags = delta.getChangeFlags(); if(flags != 0 && flags != ICDescriptionDelta.ACTIVE_CFG) return true; return false; } @Override public boolean isReadOnly() { return false; } /** * Returns a boolean array corresponding to whether the environemnt is * dirty on the configurations in the array returned by projDesc.getConfigurations() * @param pd * @return boolean[] indicating which configurations have a dirty environment */ private boolean[] getEnvStates(CProjectDescription pd) { ICConfigurationDescription[] cfs = pd.getConfigurations(); boolean[] result = new boolean[cfs.length]; for (int i=0; i<cfs.length; i++) { if (cfs[i] instanceof IInternalCCfgInfo) { try { CConfigurationSpecSettings ss = ((IInternalCCfgInfo)cfs[i]).getSpecSettings(); if (ss != null && ss.getEnvironment() != null) result[i] = ss.getEnvironment().isDirty(); } catch (CoreException e) { CCorePlugin.log(e); } } } return result; } /** * Set * @param pd * @param data */ private void setEnvStates(CProjectDescription pd, boolean[] data) { ICConfigurationDescription[] cfs = pd.getConfigurations(); if (cfs == null || data == null) return; for (int i=0; i<cfs.length; i++) { if (data.length <= i) { CCorePlugin.log("Error: setEnvStates: different number of configurations as there are envDatas...", new Exception()); //$NON-NLS-1$ break; } if (!data[i]) continue; // write only TRUE values if (cfs[i] instanceof IInternalCCfgInfo) { try { CConfigurationSpecSettings ss = ((IInternalCCfgInfo)cfs[i]).getSpecSettings(); if (ss != null && ss.getEnvironment() != null) ss.getEnvironment().setDirty(true); } catch (CoreException e) { CCorePlugin.log(e); } } } } }