Ejemplo n.º 1
0
        /// <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;
                                }
                            }
                        }
                    }
                }
            }
        }
Ejemplo n.º 2
0
			/// <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;
				}
			}
Ejemplo n.º 3
0
            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);
            }
Ejemplo n.º 4
0
            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);
            }
Ejemplo n.º 5
0
        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);
        }