2 // BuildPropertyGroup.cs: Represents a group of properties
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
7 // (C) 2005 Marek Sieradzki
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Reflection;
37 namespace Microsoft.Build.BuildEngine {
38 public class BuildPropertyGroup : IEnumerable {
41 ImportedProject importedProject;
42 XmlElement propertyGroup;
43 GroupingCollection parentCollection;
44 Project parentProject;
45 List <BuildProperty> properties;
46 Dictionary <string, BuildProperty> propertiesByName;
49 public BuildPropertyGroup ()
50 : this (null, null, null, false)
54 internal BuildPropertyGroup (XmlElement xmlElement, Project project, ImportedProject importedProject, bool readOnly)
56 this.importedProject = importedProject;
57 this.parentCollection = null;
58 this.parentProject = project;
59 this.propertyGroup = xmlElement;
60 this.read_only = readOnly;
63 this.properties = new List <BuildProperty> ();
64 foreach (XmlNode xn in propertyGroup.ChildNodes) {
65 if (!(xn is XmlElement))
68 XmlElement xe = (XmlElement) xn;
69 BuildProperty bp = new BuildProperty (parentProject, xe);
73 this.propertiesByName = new Dictionary <string, BuildProperty> (StringComparer.InvariantCultureIgnoreCase);
76 public BuildProperty AddNewProperty (string propertyName,
79 return AddNewProperty (propertyName, propertyValue, false);
82 public BuildProperty AddNewProperty (string propertyName,
84 bool treatPropertyValueAsLiteral)
87 throw new InvalidOperationException ("This method is only valid for persisted property groups.");
89 if (treatPropertyValueAsLiteral)
90 propertyValue = Utilities.Escape (propertyValue);
92 XmlElement element = propertyGroup.OwnerDocument.CreateElement (propertyName, Project.XmlNamespace);
93 propertyGroup.AppendChild (element);
95 BuildProperty property = new BuildProperty (parentProject, element);
96 property.Value = propertyValue;
97 AddProperty (property);
99 parentProject.MarkProjectAsDirty ();
100 parentProject.NeedToReevaluate ();
105 internal void AddProperty (BuildProperty property)
108 properties.Add (property);
110 if (propertiesByName.ContainsKey (property.Name)) {
111 BuildProperty existing = propertiesByName [property.Name];
112 if (property.PropertyType <= existing.PropertyType) {
113 propertiesByName.Remove (property.Name);
114 propertiesByName.Add (property.Name, property);
117 propertiesByName.Add (property.Name, property);
124 propertyGroup.RemoveAll ();
125 properties = new List <BuildProperty> ();
127 propertiesByName = new Dictionary <string, BuildProperty> ();
131 public BuildPropertyGroup Clone (bool deepClone)
133 BuildPropertyGroup bpg = new BuildPropertyGroup (propertyGroup, parentProject, importedProject, read_only);
135 foreach (BuildProperty bp in properties) {
137 bpg.AddProperty (bp.Clone (true));
139 bpg.AddNewProperty (bp.Name, bp.FinalValue);
142 foreach (BuildProperty bp in propertiesByName.Values) {
144 bpg.AddProperty (bp.Clone (true));
146 bpg.AddNewProperty (bp.Name, bp.FinalValue);
153 public IEnumerator GetEnumerator ()
156 foreach (BuildProperty bp in properties)
159 foreach (KeyValuePair <string, BuildProperty> kvp in propertiesByName)
160 yield return kvp.Value;
163 public void RemoveProperty (BuildProperty propertyToRemove)
165 if (propertyToRemove == null)
166 throw new ArgumentNullException ("propertyToRemove");
169 if (!propertyToRemove.FromXml)
170 throw new InvalidOperationException ("The specified property does not belong to the current property group.");
172 propertyToRemove.XmlElement.ParentNode.RemoveChild (propertyToRemove.XmlElement);
173 properties.Remove (propertyToRemove);
175 propertiesByName.Remove (propertyToRemove.Name);
178 public void RemoveProperty (string propertyName)
181 foreach (BuildProperty bp in properties)
182 if (bp.Name == propertyName) {
187 propertiesByName.Remove (propertyName);
190 public void SetProperty (string propertyName,
191 string propertyValue)
193 SetProperty (propertyName, propertyValue, false);
196 public void SetProperty (string propertyName,
197 string propertyValue,
198 bool treatPropertyValueAsLiteral)
203 throw new InvalidOperationException (
204 "This method is only valid for virtual property groups, not <PropertyGroup> elements.");
206 if (treatPropertyValueAsLiteral)
207 propertyValue = Utilities.Escape (propertyValue);
209 if (propertiesByName.ContainsKey (propertyName))
210 propertiesByName.Remove (propertyName);
212 BuildProperty bp = new BuildProperty (propertyName, propertyValue);
213 if (Char.IsDigit (propertyName [0]))
214 throw new ArgumentException (String.Format (
215 "The name \"{0}\" contains an invalid character \"{1}\".", propertyName, propertyName [0]));
220 parentProject.NeedToReevaluate ();
223 internal void Evaluate ()
228 foreach (BuildProperty bp in properties)
229 if (ConditionParser.ParseAndEvaluate (bp.Condition, parentProject))
235 public string Condition {
239 return propertyGroup.GetAttribute ("Condition");
243 throw new InvalidOperationException (
244 "Cannot set a condition on an object not represented by an XML element in the project file.");
245 propertyGroup.SetAttribute ("Condition", value);
252 return properties.Count;
254 return propertiesByName.Count;
258 public bool IsImported {
260 return importedProject != null;
264 internal bool FromXml {
266 return propertyGroup != null;
272 return parentProject != null && propertyGroup == null;
276 public BuildProperty this [string propertyName] {
279 throw new InvalidOperationException ("Properties in persisted property groups cannot be accessed by name.");
281 if (propertiesByName.ContainsKey (propertyName))
282 return propertiesByName [propertyName];
287 propertiesByName [propertyName] = value;
291 internal GroupingCollection GroupingCollection {
292 get { return parentCollection; }
293 set { parentCollection = value; }
296 internal XmlElement XmlElement {
297 get { return propertyGroup; }