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);
75 DefinedInFileName = importedProject != null ? importedProject.FullFileName :
76 (project != null ? project.FullFileName : null);
79 public BuildProperty AddNewProperty (string propertyName,
82 return AddNewProperty (propertyName, propertyValue, false);
85 public BuildProperty AddNewProperty (string propertyName,
87 bool treatPropertyValueAsLiteral)
90 throw new InvalidOperationException ("This method is only valid for persisted property groups.");
92 if (treatPropertyValueAsLiteral)
93 propertyValue = Utilities.Escape (propertyValue);
95 XmlElement element = propertyGroup.OwnerDocument.CreateElement (propertyName, Project.XmlNamespace);
96 propertyGroup.AppendChild (element);
98 BuildProperty property = new BuildProperty (parentProject, element);
99 property.Value = propertyValue;
100 AddProperty (property);
102 parentProject.MarkProjectAsDirty ();
103 parentProject.NeedToReevaluate ();
108 internal void AddProperty (BuildProperty property)
111 properties.Add (property);
113 if (propertiesByName.ContainsKey (property.Name)) {
114 BuildProperty existing = propertiesByName [property.Name];
115 if (property.PropertyType <= existing.PropertyType) {
116 propertiesByName.Remove (property.Name);
117 propertiesByName.Add (property.Name, property);
120 propertiesByName.Add (property.Name, property);
127 propertyGroup.RemoveAll ();
128 properties = new List <BuildProperty> ();
130 propertiesByName = new Dictionary <string, BuildProperty> ();
134 public BuildPropertyGroup Clone (bool deepClone)
136 BuildPropertyGroup bpg = new BuildPropertyGroup (propertyGroup, parentProject, importedProject, read_only);
138 foreach (BuildProperty bp in properties) {
140 bpg.AddProperty (bp.Clone (true));
142 bpg.AddNewProperty (bp.Name, bp.FinalValue);
145 foreach (BuildProperty bp in propertiesByName.Values) {
147 bpg.AddProperty (bp.Clone (true));
149 bpg.AddNewProperty (bp.Name, bp.FinalValue);
156 public IEnumerator GetEnumerator ()
159 foreach (BuildProperty bp in properties)
162 foreach (KeyValuePair <string, BuildProperty> kvp in propertiesByName)
163 yield return kvp.Value;
166 public void RemoveProperty (BuildProperty propertyToRemove)
168 if (propertyToRemove == null)
169 throw new ArgumentNullException ("propertyToRemove");
172 if (!propertyToRemove.FromXml)
173 throw new InvalidOperationException ("The specified property does not belong to the current property group.");
175 propertyToRemove.XmlElement.ParentNode.RemoveChild (propertyToRemove.XmlElement);
176 properties.Remove (propertyToRemove);
178 propertiesByName.Remove (propertyToRemove.Name);
181 public void RemoveProperty (string propertyName)
184 foreach (BuildProperty bp in properties)
185 if (bp.Name == propertyName) {
190 propertiesByName.Remove (propertyName);
193 public void SetProperty (string propertyName,
194 string propertyValue)
196 SetProperty (propertyName, propertyValue, false);
199 public void SetProperty (string propertyName,
200 string propertyValue,
201 bool treatPropertyValueAsLiteral)
206 throw new InvalidOperationException (
207 "This method is only valid for virtual property groups, not <PropertyGroup> elements.");
209 if (treatPropertyValueAsLiteral)
210 propertyValue = Utilities.Escape (propertyValue);
212 if (propertiesByName.ContainsKey (propertyName))
213 propertiesByName.Remove (propertyName);
215 BuildProperty bp = new BuildProperty (propertyName, propertyValue);
216 if (Char.IsDigit (propertyName [0]))
217 throw new ArgumentException (String.Format (
218 "The name \"{0}\" contains an invalid character \"{1}\".", propertyName, propertyName [0]));
223 parentProject.NeedToReevaluate ();
226 internal void Evaluate ()
231 foreach (BuildProperty bp in properties)
232 if (ConditionParser.ParseAndEvaluate (bp.Condition, parentProject))
238 public string Condition {
242 return propertyGroup.GetAttribute ("Condition");
246 throw new InvalidOperationException (
247 "Cannot set a condition on an object not represented by an XML element in the project file.");
248 propertyGroup.SetAttribute ("Condition", value);
255 return properties.Count;
257 return propertiesByName.Count;
261 public bool IsImported {
263 return importedProject != null;
267 internal bool FromXml {
269 return propertyGroup != null;
275 return parentProject != null && propertyGroup == null;
279 public BuildProperty this [string propertyName] {
282 throw new InvalidOperationException ("Properties in persisted property groups cannot be accessed by name.");
284 if (propertiesByName.ContainsKey (propertyName))
285 return propertiesByName [propertyName];
290 propertiesByName [propertyName] = value;
294 internal string DefinedInFileName { get; private set; }
296 internal GroupingCollection GroupingCollection {
297 get { return parentCollection; }
298 set { parentCollection = value; }
301 internal XmlElement XmlElement {
302 get { return propertyGroup; }