1 // Copyright (c) Microsoft. All rights reserved. 2 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 4 using System; 5 using System.Data; 6 using System.Xml; 7 using System.Collections; 8 9 using Microsoft.Build.BuildEngine.Shared; 10 11 using error = Microsoft.Build.BuildEngine.Shared.ErrorUtilities; 12 13 namespace Microsoft.Build.BuildEngine 14 { 15 /// <summary> 16 /// This class represents a collection of persisted <ItemGroup>'s. Each 17 /// MSBuild project has exactly one BuildItemGroupCollection, which includes 18 /// all the imported ItemGroups as well as the ones in the main project file. 19 /// 20 /// The implementation of this class is that it's basically a Facade. It just 21 /// calls into the GroupingCollection within the Project to do it's work. It 22 /// doesn't maintain any BuildPropertyGroup state on its own. 23 /// </summary> 24 /// <owner>DavidLe</owner> 25 public class BuildItemGroupCollection : IEnumerable, ICollection 26 { 27 #region Member Data 28 29 private GroupingCollection groupingCollection; 30 #endregion 31 32 #region Constructors 33 34 /// <summary> 35 /// Private default constructor. This object can't be instantiated by 36 /// OM consumers. 37 /// </summary> 38 /// <owner>DavidLe, RGoel</owner> BuildItemGroupCollection( )39 private BuildItemGroupCollection 40 ( 41 ) 42 { 43 } 44 45 /// <summary> 46 /// Constructor that takes the GroupingCollection that this sits over. 47 /// </summary> 48 /// <remarks> 49 /// </remarks> 50 /// <owner>DavidLe</owner> 51 /// <param name="groupingCollection"></param> BuildItemGroupCollection( GroupingCollection groupingCollection )52 internal BuildItemGroupCollection 53 ( 54 GroupingCollection groupingCollection 55 ) 56 { 57 error.VerifyThrow(groupingCollection != null, "GroupingCollection is null!"); 58 59 this.groupingCollection = groupingCollection; 60 } 61 #endregion 62 63 #region Properties 64 65 /// <summary> 66 /// Read-only property which returns the number of ItemGroups contained 67 /// in our collection. 68 /// </summary> 69 /// <remarks> 70 /// </remarks> 71 /// <owner>DavidLe</owner> 72 public int Count 73 { 74 get 75 { 76 return this.groupingCollection.ItemGroupCount; 77 } 78 } 79 80 /// <summary> 81 /// This ICollection property tells whether this object is thread-safe. 82 /// </summary> 83 /// <owner>DavidLe</owner> 84 public bool IsSynchronized 85 { 86 get 87 { 88 return this.groupingCollection.IsSynchronized; 89 } 90 } 91 92 /// <summary> 93 /// This ICollection property returns the object to be used to synchronize 94 /// access to the class. 95 /// </summary> 96 /// <owner>DavidLe</owner> 97 public object SyncRoot 98 { 99 get 100 { 101 return this.groupingCollection.SyncRoot; 102 } 103 } 104 105 /// <summary> 106 /// This looks through all the local item groups (those in the main 107 /// project file, as opposed to any imported project files). It returns 108 /// the last one that comes before any imported item groups. This 109 /// is the heuristic we use to determine where to add new item groups 110 /// into the project file. 111 /// </summary> 112 /// <owner>DavidLe</owner> 113 internal BuildItemGroup LastLocalItemGroup 114 { 115 get 116 { 117 BuildItemGroup lastLocalItemGroup = null; 118 119 foreach (BuildItemGroup itemGroup in this.groupingCollection.ItemGroupsTopLevel) 120 { 121 if (itemGroup.IsImported) 122 { 123 // As soon as we hit an imported BuildItemGroup, we want to 124 // completely bail out. The goal of this function is 125 // to return the last itemGroup that is *before* any 126 // imported itemGroups. 127 break; 128 } 129 else 130 { 131 lastLocalItemGroup = itemGroup; 132 } 133 } 134 135 return lastLocalItemGroup; 136 } 137 } 138 139 #endregion 140 141 #region Methods 142 143 /// <summary> 144 /// This ICollection method copies the contents of this collection to an 145 /// array. 146 /// </summary> 147 /// <owner>DavidLe</owner> 148 /// <param name="array"></param> 149 /// <param name="index"></param> CopyTo( Array array, int index )150 public void CopyTo 151 ( 152 Array array, 153 int index 154 ) 155 { 156 this.groupingCollection.ItemCopyTo(array, index); 157 } 158 159 /// <summary> 160 /// This IEnumerable method returns an IEnumerator object, which allows 161 /// the caller to enumerate through the BuildItemGroup objects contained in 162 /// this BuildItemGroupCollection. 163 /// </summary> 164 /// <owner>DavidLe</owner> GetEnumerator( )165 public IEnumerator GetEnumerator 166 ( 167 ) 168 { 169 return this.groupingCollection.GetItemEnumerator(); 170 } 171 172 /// <summary> 173 /// Adds a new BuildItemGroup to our collection, at the specified insertion 174 /// point. This method does nothing to manipulate the project's XML content. 175 /// </summary> 176 /// <owner>DavidLe</owner> 177 /// <param name="insertionPoint"></param> 178 /// <param name="newItemGroup"></param> InsertAfter( BuildItemGroup newItemGroup, BuildItemGroup insertionPoint )179 internal void InsertAfter 180 ( 181 BuildItemGroup newItemGroup, 182 BuildItemGroup insertionPoint 183 ) 184 { 185 this.groupingCollection.InsertAfter(newItemGroup, insertionPoint); 186 } 187 188 /// <summary> 189 /// Adds a new BuildItemGroup as the last element of our collection. 190 /// This method does nothing to manipulate the project's XML content. 191 /// </summary> 192 /// <owner>DavidLe</owner> 193 /// <param name="newItemGroup"></param> InsertAtEnd( BuildItemGroup newItemGroup )194 internal void InsertAtEnd 195 ( 196 BuildItemGroup newItemGroup 197 ) 198 { 199 this.groupingCollection.InsertAtEnd(newItemGroup); 200 } 201 202 /// <summary> 203 /// Removes a BuildItemGroup from our collection. This method does nothing 204 /// to manipulate the project's XML content. 205 /// </summary> 206 /// <owner>DavidLe</owner> 207 /// <param name="itemGroup"></param> RemoveItemGroup( BuildItemGroup itemGroup )208 internal void RemoveItemGroup 209 ( 210 BuildItemGroup itemGroup 211 ) 212 { 213 this.groupingCollection.RemoveItemGroup(itemGroup); 214 } 215 216 #endregion 217 } 218 } 219