/// <summary> /// Helper method for matching value ranges. Called after an /// <see cref="IElementEquivalence"/> implementation has determined /// that this <see cref="CardinalityConstraint"/> and <paramref name="otherCardinalityConstraint"/> /// correspond to the same instance. /// </summary> /// <param name="otherCardinalityConstraint">The equivalent value constraint.</param> /// <param name="elementTracker">The <see cref="IEquivalentElementTracker"/> used /// to equate ranges.</param> protected void MatchRanges(CardinalityConstraint otherCardinalityConstraint, IEquivalentElementTracker elementTracker) { LinkedElementCollection <CardinalityRange> ranges = RangeCollection; int rangeCount = ranges.Count; if (rangeCount != 0) { LinkedElementCollection <CardinalityRange> otherRanges = otherCardinalityConstraint.RangeCollection; int otherRangeCount = otherRanges.Count; if (otherRangeCount != 0) { BitTracker otherMatches = new BitTracker(otherRangeCount); for (int i = 0; i < rangeCount; ++i) { CardinalityRange range = ranges[i]; int lower = range.LowerBound; int upper = range.UpperBound; for (int j = 0; j < otherRangeCount; ++j) { if (!otherMatches[j]) { CardinalityRange otherRange = otherRanges[j]; if (otherRange.LowerBound == lower && otherRange.UpperBound == upper) { elementTracker.AddEquivalentElement(range, otherRange); otherMatches[j] = true; break; } } } } } } }
/// <summary> /// Eliminates any <see cref="Permutation"/>s that contain cyclical deep <see cref="FactTypeMapping"/>s. /// </summary> /// <param name="chain"> /// The <see cref="Chain"/> for which invalid <see cref="Permutation"/>s should be eliminated. /// </param> /// <param name="nonPreferredFuntionalObjectTypes">A dictionary to cache state information /// for potentially deeply mapped <see cref="ObjectType"/>s</param> private static void EliminateInvalidPermutations(Chain chain, Dictionary<ObjectType, bool> nonPreferredFuntionalObjectTypes) { Debug.Assert(chain.UndecidedOneToOneFactTypeMappings.Count > 0); int factTypeCount = chain.OneToOneFactTypeCount; FactTypeMappingList predecidedOneToOneFactTypeMappings = chain.PredecidedOneToOneFactTypeMappings; IList<Permutation> possiblePermutations = chain.PossiblePermutations; Dictionary<FactType, object> visited = new Dictionary<FactType, object>(factTypeCount); Dictionary<FactType, object> current = new Dictionary<FactType, object>(factTypeCount); Debug.Assert(possiblePermutations[0].Mappings.Count > 0); // All of the permutations will always contain the same number of mappings, so we can calculate it here. int mappingsCount = possiblePermutations[0].Mappings.Count; int permutationIndex; for (permutationIndex = possiblePermutations.Count - 1; permutationIndex >= 0; permutationIndex--) { // We're checking a new permutation, so clear the visited dictionary. visited.Clear(); bool permutationIsInvalid = false; Permutation permutation = possiblePermutations[permutationIndex]; FactTypeMappingList mappings = permutation.Mappings; int mappingIndex = 0; do { FactTypeMapping mapping = null; FactType factType = null; // Find a deep mapping that we haven't already visited. while (mappingIndex < mappingsCount) { mapping = mappings[mappingIndex++]; factType = mapping.FactType; if (mapping.MappingDepth == MappingDepth.Deep && !visited.ContainsKey(factType)) { break; } } if (mapping == null) { break; } // Record that the fact type has been visited visited[factType] = null; if (mapping.MappingDepth != MappingDepth.Deep) { // If we hit this, we have no more deep mappings in the permutation. break; } // We're following a new path, so clear the current dictionary. current.Clear(); // Follow this path until we hit an object type that has no deep mappings away from it, or find a cycle. while (true) { if (current.ContainsKey(factType)) { // We're back to a fact type we already processed, which means that there is a cycle, and this permutation is illegal. possiblePermutations.RemoveAt(permutationIndex); permutationIsInvalid = true; break; } // Add the fact type to the list of those seen on this path already. current[factType] = null; // Also add the fact type to the list of those seen already. visited[factType] = null; // Find the next hop on this path. ObjectType towardsObjectType = mapping.TowardsObjectType; mapping = FindDeepMappingAwayFromObjectType(towardsObjectType, predecidedOneToOneFactTypeMappings, mappings); if (mapping == null) { // The object type has no deep mappings away from it, so we continue with the outer loop. break; } // Let this loop continue and process the fact type for the next hop. factType = mapping.FactType; } } while (!permutationIsInvalid && (visited.Count < factTypeCount)); if (!permutationIsInvalid) { // We now filter out a common pattern where an ObjectType plays // no functional roles to justify a ConceptType and is not chained with // another deep mapping that satisfies this criteria. // If the permuation is valid at this point, then there are no cycles // in the deep maps for the permuation, so we can safely run this routine // recursively. for (int i = 0; i < mappingsCount; ++i) { if (IsBlockedDeepMapping(mappings, i, nonPreferredFuntionalObjectTypes)) { possiblePermutations.RemoveAt(permutationIndex); break; } } } } // If there are two or more remaining permutations with a deep mapping away // from the same object type via two different non-subtype fact types, or if // there is a subtype deep mapping away and other fact type deep mappings away, // then eliminate the fact type-based deep mappings. The choice of which of these // deep mappings ends up as an assimilation is arbitrary, so we choose to allow none // of them. permutationIndex = possiblePermutations.Count - 1; BitTracker usesDeepFromSameObjectType = new BitTracker(); while (permutationIndex > 0) // There is no previous to check for the last item, so stop at 1 { FactTypeMappingList mappings = possiblePermutations[permutationIndex].Mappings; for (int i = 0; i < mappingsCount; ++i) { FactTypeMapping mapping = mappings[i]; if (mapping.MappingDepth == MappingDepth.Deep) { ObjectType fromObjectType = mapping.FromObjectType; FactType viaFactType = mapping.FactType; bool viaSubtype = mapping.IsSubtype; usesDeepFromSameObjectType.Reset(permutationIndex + 1); bool removeTrackedPermutation = false; if (!viaSubtype) { usesDeepFromSameObjectType[permutationIndex] = true; } for (int j = permutationIndex - 1; j >= 0; --j) { FactTypeMappingList testMappings = possiblePermutations[j].Mappings; for (int k = 0; k < mappingsCount; ++k) { FactTypeMapping testMapping = testMappings[k]; if (testMapping.MappingDepth == MappingDepth.Deep && testMapping.FromObjectType == fromObjectType) { FactType testViaFactType = testMapping.FactType; if (viaSubtype) { if (!(testMapping.IsSubtype)) { usesDeepFromSameObjectType[j] = true; removeTrackedPermutation = true; } } else if (testMapping.IsSubtype) { removeTrackedPermutation = true; } else { usesDeepFromSameObjectType[j] = true; if (testViaFactType != viaFactType) { removeTrackedPermutation = true; } } } } } if (removeTrackedPermutation) { for (int j = permutationIndex; j >= 0; --j) { if (usesDeepFromSameObjectType[j]) { possiblePermutations.RemoveAt(j); if (j != permutationIndex) { --permutationIndex; } } } break; } } } --permutationIndex; } }
VirtualTreeDisplayData IBranch.GetDisplayData(int row, int column, VirtualTreeDisplayDataMasks requiredData) { VirtualTreeDisplayData displayData = VirtualTreeDisplayData.Empty; SingleRingTypeInfo typeNode = mySingleNodes[row]; if (mySelectedCount != 0) { BitTracker selection = mySelectionTracker; bool isSelected = false; bool isImplied = false; bool isBold = false; if (selection[row]) { // Currently on, nothing to check isBold = isSelected = true; } else { // Current state depends on state of other rows int[] positionMap = myEnumValueToPositionMap; RingConstraintType[] relatedTypes = typeNode.ImpliedBy; if (relatedTypes != null) { for (int i = 0; i < relatedTypes.Length; ++i) { if (selection[positionMap[(int)relatedTypes[i]]]) { isImplied = true; break; } } } if (!isImplied && null != (relatedTypes = typeNode.ImpliedByCombination)) { isImplied = true; for (int i = 0; i < relatedTypes.Length; ++i) { if (!selection[positionMap[(int)relatedTypes[i]]]) { isImplied = false; break; } } } if (!isImplied) // Implied items are never bold { isBold = true; // Assume true, determine otherwise relatedTypes = typeNode.IncompatibleWith; for (int i = 0; i < relatedTypes.Length; ++i) { if (selection[positionMap[(int)relatedTypes[i]]]) { isBold = false; break; } } if (isBold && null != (relatedTypes = typeNode.IncompatibleWithCombination)) { isBold = false; for (int i = 0; i < relatedTypes.Length; ++i) { if (!selection[positionMap[(int)relatedTypes[i]]]) { isBold = true; break; } } } } } displayData.Bold = isBold; if (isSelected) { displayData.StateImageIndex = (short)StandardCheckBoxImage.CheckedFlat; } else if (isImplied) { displayData.StateImageIndex = (short)StandardCheckBoxImage.IndeterminateFlat; } else { displayData.StateImageIndex = (short)StandardCheckBoxImage.UncheckedFlat; } } else { displayData.StateImageIndex = (short)StandardCheckBoxImage.UncheckedFlat; } int imageIndex = myImageBase; if (imageIndex != -1) { displayData.SelectedImage = displayData.Image = (short)(imageIndex + (int)typeNode.Glyph); } return(displayData); }
StateRefreshChanges IBranch.ToggleState(int row, int column) { BitTracker tracker = mySelectionTracker; if (tracker[row]) { // Just turn it off, other states will display differently with the refresh mySelectionTracker[row] = false; --mySelectedCount; } else { // Turning this item on turns off implied and incompatible items. Find them and turn them off. int count = mySelectedCount; tracker[row] = true; ++count; SingleRingTypeInfo info = mySingleNodes[row]; int[] positionMap = myEnumValueToPositionMap; // Process single items RingConstraintType[] relatedTypes = info.ImpliedBy; bool checkedIncompatible = false; if (relatedTypes == null) { checkedIncompatible = true; relatedTypes = info.IncompatibleWith; } while (relatedTypes != null) { for (int i = 0; i < relatedTypes.Length; ++i) { int position = positionMap[(int)relatedTypes[i]]; if (tracker[position]) { tracker[position] = false; --count; } } if (checkedIncompatible) { break; } else { checkedIncompatible = true; relatedTypes = info.IncompatibleWith; } } // Turn off full combination items relatedTypes = info.ImpliedByCombination; checkedIncompatible = false; if (relatedTypes == null) { checkedIncompatible = true; relatedTypes = info.IncompatibleWithCombination; } while (relatedTypes != null) { int i = 0; int combinationCount = relatedTypes.Length; for (; i < combinationCount; ++i) { if (!tracker[positionMap[(int)relatedTypes[i]]]) { break; } } if (i == combinationCount) { // Turn them all off for (i = 0; i < combinationCount; ++i) { tracker[positionMap[(int)relatedTypes[i]]] = false; } count -= combinationCount; } if (checkedIncompatible) { break; } else { checkedIncompatible = true; relatedTypes = info.IncompatibleWithCombination; } } // Check if this is part of a complete combination and // make sure the combined item is turned off RingConstraintType[] usedInCombination = info.UsedInCombinationBy; if (usedInCombination != null) { for (int j = 0; j < usedInCombination.Length; ++j) { int usedByPosition = positionMap[(int)usedInCombination[j]]; if (tracker[usedByPosition]) { SingleRingTypeInfo usedByInfo = mySingleNodes[usedByPosition]; relatedTypes = usedByInfo.ImpliedByCombination; checkedIncompatible = false; if (relatedTypes == null) { checkedIncompatible = true; relatedTypes = usedByInfo.IncompatibleWithCombination; } while (relatedTypes != null) { int i = 0; int combinationCount = relatedTypes.Length; for (; i < combinationCount; ++i) { if (!tracker[positionMap[(int)relatedTypes[i]]]) { break; } } if (i == combinationCount) { tracker[usedByPosition] = false; --count; break; } if (checkedIncompatible) { break; } else { checkedIncompatible = true; relatedTypes = usedByInfo.IncompatibleWithCombination; } } } } } mySelectionTracker = tracker; mySelectedCount = count; } return(StateRefreshChanges.Entire); }
protected override void OnClosed(EventArgs e) { if (_savedChanges) { // Make sure the current document has the necessary // extensions loaded. // UNDONE: We should be able to do this with the document // closed or open as text as well via a registered service // on the ORMDesignerPackage, but this is sufficient for now. Dictionary <string, string> requiredExtensions = null; string[] loadedExtensions = null; foreach (IORMGenerator selectedGenerator in _mainBranch.SelectedGenerators) { foreach (string requiredExtension in selectedGenerator.GetRequiredExtensionsForInputFormat("ORM")) { if (loadedExtensions == null) { loadedExtensions = (new ORMExtensionManager(_projectItem)).GetLoadedExtensions(_serviceProvider); } if (Array.BinarySearch <string>(loadedExtensions, requiredExtension) < 0) { if (requiredExtensions == null) { requiredExtensions = new Dictionary <string, string>(); } else if (requiredExtensions.ContainsKey(requiredExtension)) { continue; } requiredExtensions.Add(requiredExtension, requiredExtension); } } } if (requiredExtensions != null) { _savedChanges = ORMExtensionManager.EnsureExtensions(_projectItem, _serviceProvider, requiredExtensions.Values); } } if (_savedChanges) { #if VISUALSTUDIO_10_0 ProjectItemGroupElement itemGroup = _originalItemGroup; ProjectRootElement project = _project; #else // VISUALSTUDIO_10_0 BuildItemGroup itemGroup = _originalItemGroup; Microsoft.Build.BuildEngine.Project project = _project; #endif // VISUALSTUDIO_10_0 EnvDTE.ProjectItem projectItem = _projectItem; string sourceFileName = _sourceFileName; Dictionary <string, PseudoBuildItem> pseudoItems = _pseudoItemsByOutputFormat; IDictionary <string, IORMGenerator> generators = #if VISUALSTUDIO_15_0 ORMCustomTool.GetORMGenerators(_serviceProvider); #else ORMCustomTool.ORMGenerators; #endif PseudoBuildItem pseudoItem; string generatorNameData; // The first string is the primary generator, others are the format modifiers, space delimited IVsShell shell; Dictionary <string, IORMGenerator> generatorsWithTargetsByOutputFormat = null; IDictionary <string, ORMCustomToolUtility.GeneratorTargetSet> targetSetsByFormatName = null; foreach (PseudoBuildItem testPseudoItem in pseudoItems.Values) { string primaryGeneratorName; IList <string> generatorTargets; IORMGenerator generator; if (!string.IsNullOrEmpty(generatorNameData = testPseudoItem.CurrentGeneratorNames) && null != (primaryGeneratorName = ORMCustomToolUtility.GetPrimaryGeneratorName(generatorNameData)) && generators.TryGetValue(primaryGeneratorName, out generator) && null != (generatorTargets = generator.GeneratorTargetTypes) && 0 != generatorTargets.Count) { (generatorsWithTargetsByOutputFormat ?? (generatorsWithTargetsByOutputFormat = new Dictionary <string, IORMGenerator>(StringComparer.OrdinalIgnoreCase)))[generator.ProvidesOutputFormat] = generator; } } if (generatorsWithTargetsByOutputFormat != null) { IDictionary <string, GeneratorTarget[]> docTargets = null; EnvDTE.Document projectItemDocument = projectItem.Document; string itemPath; if (projectItemDocument != null) { using (Stream targetsStream = ORMCustomToolUtility.GetDocumentExtension <Stream>(projectItemDocument, "ORMGeneratorTargets", itemPath = projectItem.get_FileNames(0), _serviceProvider)) { if (targetsStream != null) { targetsStream.Seek(0, SeekOrigin.Begin); docTargets = new BinaryFormatter().Deserialize(targetsStream) as IDictionary <string, GeneratorTarget[]>; } } } else if (null != (shell = _serviceProvider.GetService(typeof(SVsShell)) as IVsShell)) { Guid pkgId = typeof(ORMDesignerPackage).GUID; IVsPackage package; if (0 != shell.IsPackageLoaded(ref pkgId, out package) || package == null) { shell.LoadPackage(ref pkgId, out package); } // Temporarily load the document so that the generator targets can be resolved. using (Store store = new ModelLoader(ORMDesignerPackage.ExtensionLoader, true).Load(projectItem.get_FileNames(0))) { docTargets = GeneratorTarget.ConsolidateGeneratorTargets(store as IFrameworkServices); } } // We have generators that care about targets, which means that ExpandGeneratorTargets will // product placeholder targets for these generators even if docTargets is currently null. // This allows the dialog to turn on a generator before the data (or even extension) to feed // it is available in the model and provides a smooth transition in and out of this placeholder // state. It is up to the individual generators to proceed without explicit target data or // to produce a message for the user with instructions on how to add the data to the model. Dictionary <string, string> generatorNamesByOutputFormat = new Dictionary <string, string>(); foreach (KeyValuePair <string, PseudoBuildItem> pair in pseudoItems) { generatorNameData = pair.Value.CurrentGeneratorNames; if (!string.IsNullOrEmpty(generatorNameData)) { generatorNamesByOutputFormat[pair.Key] = ORMCustomToolUtility.GetPrimaryGeneratorName(generatorNameData); } } targetSetsByFormatName = ORMCustomToolUtility.ExpandGeneratorTargets(generatorNamesByOutputFormat, docTargets #if VISUALSTUDIO_15_0 , _serviceProvider #endif // VISUALSTUDIO_15_0 ); } Dictionary <string, BitTracker> processedGeneratorTargets = null; if (targetSetsByFormatName != null) { processedGeneratorTargets = new Dictionary <string, BitTracker>(); foreach (KeyValuePair <string, ORMCustomToolUtility.GeneratorTargetSet> kvp in targetSetsByFormatName) { processedGeneratorTargets[kvp.Key] = new BitTracker(kvp.Value.Instances.Length); } } if (null != itemGroup) { #if VISUALSTUDIO_10_0 Dictionary <string, ProjectItemElement> removedItems = null; foreach (ProjectItemElement item in itemGroup.Items) #else // VISUALSTUDIO_10_0 Dictionary <string, BuildItem> removedItems = null; foreach (BuildItem item in itemGroup) #endif // VISUALSTUDIO_10_0 { string primaryGeneratorName; string outputFormat; IORMGenerator generator; if (null != (primaryGeneratorName = ORMCustomToolUtility.GetPrimaryGeneratorName(item.GetEvaluatedMetadata(ITEMMETADATA_ORMGENERATOR))) && string.Equals(item.GetEvaluatedMetadata(ITEMMETADATA_DEPENDENTUPON), sourceFileName, StringComparison.OrdinalIgnoreCase) && generators.TryGetValue(primaryGeneratorName, out generator) && pseudoItems.TryGetValue(outputFormat = generator.ProvidesOutputFormat, out pseudoItem)) { generatorNameData = pseudoItem.CurrentGeneratorNames; ORMCustomToolUtility.GeneratorTargetSet targetSet = null; BitTracker processedForFormat = default(BitTracker); if (targetSetsByFormatName != null) { if (targetSetsByFormatName.TryGetValue(outputFormat, out targetSet)) { processedForFormat = processedGeneratorTargets[outputFormat]; } } List <PseudoBuildInstance> originalInstances; bool removeInstance = false; if (string.IsNullOrEmpty(generatorNameData)) { // The item is deleted, mark for removal removeInstance = true; } else if (null != (originalInstances = pseudoItem.OriginalInstances)) { for (int i = 0, count = originalInstances.Count; i < count && !removeInstance; ++i) { PseudoBuildInstance instance = originalInstances[i]; if (instance.IsRemoved) { continue; } GeneratorTarget[] targets = instance.OriginalGeneratorTargets; if (targetSet != null) { if (targets == null) { // Remove, if a target set is available then it must be used removeInstance = true; } else { int instanceIndex = targetSet.IndexOfInstance(targets, delegate(int ignoreInstance) { return(processedForFormat[ignoreInstance]); }); if (instanceIndex == -1) { removeInstance = true; } else if (!processedForFormat[instanceIndex]) { if (instance.OriginalGeneratorNames != generatorNameData) { // This is a preexisting item, update its meta information ORMCustomToolUtility.SetItemMetaData(item, ITEMMETADATA_ORMGENERATOR, generatorNameData); } processedForFormat[instanceIndex] = true; processedGeneratorTargets[outputFormat] = processedForFormat; break; } } } else if (targets != null) { // Remove, formatter changed to one that does not use a generator target removeInstance = true; } else if (instance.OriginalGeneratorNames != generatorNameData) { // This is a preexisting item, update its meta information ORMCustomToolUtility.SetItemMetaData(item, ITEMMETADATA_ORMGENERATOR, generatorNameData); } if (removeInstance) { instance.IsRemoved = true; } } } if (removeInstance) { if (removedItems == null) { #if VISUALSTUDIO_10_0 removedItems = new Dictionary <string, ProjectItemElement>(); #else // VISUALSTUDIO_10_0 removedItems = new Dictionary <string, BuildItem>(); #endif // VISUALSTUDIO_10_0 } removedItems[ORMCustomToolUtility.GetItemInclude(item)] = item; } } } if (removedItems != null) { EnvDTE.ProjectItems subItems = projectItem.ProjectItems; #if VISUALSTUDIO_10_0 foreach (KeyValuePair <string, ProjectItemElement> removePair in removedItems) { ProjectItemElement removeItem = removePair.Value; ProjectElementContainer removeFrom; if (null != (removeFrom = removeItem.Parent)) { removeFrom.RemoveChild(removeItem); } #else // VISUALSTUDIO_10_0 foreach (KeyValuePair <string, BuildItem> removePair in removedItems) { project.RemoveItem(removePair.Value); #endif // VISUALSTUDIO_10_0 try { EnvDTE.ProjectItem subItem = subItems.Item(removePair.Key); if (subItem != null) { subItem.Delete(); } } catch (ArgumentException) { // Swallow } } } #if !VISUALSTUDIO_10_0 // Empty item groups remove themselves from the project, we'll need // to recreate below if the group is empty after the remove phase. if (itemGroup.Count == 0) { itemGroup = null; } #endif } // Removes and changes are complete, proceed with adds for any new items string newItemDirectory = null; string projectPath = null; EnvDTE.ProjectItems projectItems = null; string tmpFile = null; // Adding a file to our special item group adds it to the build system. However, // it does not add it to the parallel project system, which is what displays in // the solution explorer. Therefore, we also explicitly add the item to the // project system as well. Unfortunately, this extra add automatically creates // a redundant item (usually in a new item group) for our adding item. Track anything // we add through the project system so that we can remove these redundant items from the // build system when we're done. Dictionary <string, string> sideEffectItemNames = null; try { Action <IORMGenerator, string, ORMCustomToolUtility.GeneratorTargetSet, GeneratorTarget[]> addProjectItem = delegate(IORMGenerator generator, string allGenerators, ORMCustomToolUtility.GeneratorTargetSet targetSet, GeneratorTarget[] targetInstance) { if (itemGroup == null) { #if VISUALSTUDIO_10_0 itemGroup = project.AddItemGroup(); #else itemGroup = project.AddNewItemGroup(); #endif itemGroup.Condition = string.Concat(ITEMGROUP_CONDITIONSTART, _projectItemRelativePath, ITEMGROUP_CONDITIONEND); } if (newItemDirectory == null) { // Initialize general information #if VISUALSTUDIO_10_0 projectPath = project.FullPath; #else projectPath = project.FullFileName; #endif newItemDirectory = Path.GetDirectoryName(new Uri(projectPath).MakeRelativeUri(new Uri((string)projectItem.Properties.Item("LocalPath").Value)).ToString()); projectItems = projectItem.ProjectItems; } string defaultFileName = generator.GetOutputFileDefaultName(sourceFileName); string fileName = targetInstance == null ? defaultFileName : ORMCustomToolUtility.GeneratorTargetSet.DecorateFileName(defaultFileName, targetInstance); string fileRelativePath = Path.Combine(newItemDirectory, fileName); string fileAbsolutePath = string.Concat(new FileInfo(projectPath).DirectoryName, Path.DirectorySeparatorChar, fileRelativePath); #if VISUALSTUDIO_10_0 ProjectItemElement newBuildItem; #else BuildItem newBuildItem; #endif newBuildItem = generator.AddGeneratedFileItem(itemGroup, sourceFileName, fileRelativePath); if (allGenerators != null) { ORMCustomToolUtility.SetItemMetaData(newBuildItem, ITEMMETADATA_ORMGENERATOR, allGenerators); } if (targetInstance != null) { ORMCustomToolUtility.SetGeneratorTargetMetadata(newBuildItem, targetInstance); } (sideEffectItemNames ?? (sideEffectItemNames = new Dictionary <string, string>()))[fileRelativePath] = null; if (File.Exists(fileAbsolutePath)) { try { projectItems.AddFromFile(fileAbsolutePath); } catch (ArgumentException) { // Swallow } } else { if (tmpFile == null) { tmpFile = Path.GetTempFileName(); } EnvDTE.ProjectItem newProjectItem = projectItems.AddFromTemplate(tmpFile, fileName); string customTool; if (!string.IsNullOrEmpty(customTool = newBuildItem.GetMetadata(ITEMMETADATA_GENERATOR))) { newProjectItem.Properties.Item("CustomTool").Value = customTool; } } }; foreach (KeyValuePair <string, PseudoBuildItem> keyedPseudoItem in pseudoItems) { pseudoItem = keyedPseudoItem.Value; string allGenerators = pseudoItem.CurrentGeneratorNames; string primaryGenerator = ORMCustomToolUtility.GetPrimaryGeneratorName(allGenerators); if (allGenerators == primaryGenerator) { allGenerators = null; } IORMGenerator generator = generators[primaryGenerator]; string outputFormat = generator.ProvidesOutputFormat; ORMCustomToolUtility.GeneratorTargetSet targetSet = null; if (targetSetsByFormatName != null) { targetSetsByFormatName.TryGetValue(outputFormat, out targetSet); } if (targetSet != null) { // OriginalInstances were already updated in the remove loop and processed // instances were flagged. Find additional instances from the target set (created // just now from the current model), not from the pseudoItem (created from the project // files that possibly reflect a previous version of the model). GeneratorTarget[][] instances = targetSet.Instances; BitTracker processed = processedGeneratorTargets[outputFormat]; for (int i = 0, count = instances.Length; i < count; ++i) { if (!processed[i]) { addProjectItem(generator, allGenerators, targetSet, instances[i]); } } } else if (pseudoItem.OriginalInstances == null) { addProjectItem(generator, allGenerators, null, null); } else { // Make sure there was an original instance that did not have a target set. List <PseudoBuildInstance> originals = pseudoItem.OriginalInstances; int i = 0, count = originals.Count; for (; i < count; ++i) { if (originals[i].OriginalGeneratorTargets == null) { break; } } if (i == count) { addProjectItem(generator, allGenerators, null, null); } } } } finally { if (tmpFile != null) { File.Delete(tmpFile); } } if (sideEffectItemNames != null) { ORMCustomToolUtility.RemoveSideEffectItems(sideEffectItemNames, project, itemGroup); } #if VISUALSTUDIO_10_0 // Old group remove themselves when empty, but this is // not true in the new build system. Clean up as needed. if (itemGroup != null && itemGroup.Items.Count == 0) { project.RemoveChild(itemGroup); } #endif VSLangProj.VSProjectItem vsProjectItem = projectItem.Object as VSLangProj.VSProjectItem; if (vsProjectItem != null) { vsProjectItem.RunCustomTool(); } } base.OnClosed(e); }