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 &lt;ItemGroup&gt;'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