dd3259675c920b8bb89c01c44b980f1b58a6fe08
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / BuildPropertyGroup.cs
1 //
2 // BuildPropertyGroup.cs: Represents a group of properties
3 //
4 // Author:
5 //   Marek Sieradzki (marek.sieradzki@gmail.com)
6 // 
7 // (C) 2005 Marek Sieradzki
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27
28 #if NET_2_0
29
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Reflection;
34 using System.Text;
35 using System.Xml;
36
37 namespace Microsoft.Build.BuildEngine {
38         public class BuildPropertyGroup : IEnumerable {
39         
40                 bool                    read_only;
41                 ImportedProject         importedProject;
42                 XmlElement              propertyGroup;
43                 GroupingCollection      parentCollection;
44                 Project                 parentProject;
45                 List <BuildProperty>    properties;
46                 Dictionary <string, BuildProperty>      propertiesByName;
47                 bool evaluated;
48
49                 public BuildPropertyGroup ()
50                         : this (null, null, null, false)
51                 {
52                 }
53
54                 internal BuildPropertyGroup (XmlElement xmlElement, Project project, ImportedProject importedProject, bool readOnly)
55                 {
56                         this.importedProject = importedProject;
57                         this.parentCollection = null;
58                         this.parentProject = project;
59                         this.propertyGroup = xmlElement;
60                         this.read_only = readOnly;
61
62                         if (FromXml) {
63                                 this.properties = new List <BuildProperty> ();
64                                 foreach (XmlNode xn in propertyGroup.ChildNodes) {
65                                         if (!(xn is XmlElement))
66                                                 continue;
67                                         
68                                         XmlElement xe = (XmlElement) xn;
69                                         BuildProperty bp = new BuildProperty (parentProject, xe);
70                                         AddProperty (bp);
71                                 } 
72                         } else
73                                 this.propertiesByName = new Dictionary <string, BuildProperty> (StringComparer.InvariantCultureIgnoreCase);
74                 }
75
76                 public BuildProperty AddNewProperty (string propertyName,
77                                                      string propertyValue)
78                 {
79                         return AddNewProperty (propertyName, propertyValue, false);
80                 }
81                 
82                 public BuildProperty AddNewProperty (string propertyName,
83                                                      string propertyValue,
84                                                      bool treatPropertyValueAsLiteral)
85                 {
86                         if (!FromXml)
87                                 throw new InvalidOperationException ("This method is only valid for persisted property groups.");
88
89                         if (treatPropertyValueAsLiteral)
90                                 propertyValue = Utilities.Escape (propertyValue);
91
92                         XmlElement element = propertyGroup.OwnerDocument.CreateElement (propertyName, Project.XmlNamespace);
93                         propertyGroup.AppendChild (element);
94
95                         BuildProperty property = new BuildProperty (parentProject, element);
96                         property.Value = propertyValue;
97                         AddProperty (property);
98
99                         parentProject.MarkProjectAsDirty ();
100                         parentProject.NeedToReevaluate ();
101
102                         return property;
103                 }
104
105                 internal void AddProperty (BuildProperty property)
106                 {
107                         if (FromXml)
108                                 properties.Add (property);
109                         else {
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);
115                                         }
116                                 } else
117                                         propertiesByName.Add (property.Name, property);
118                         }
119                 }
120                 
121                 public void Clear ()
122                 {
123                         if (FromXml) {
124                                 propertyGroup.RemoveAll ();
125                                 properties = new List <BuildProperty> ();
126                         } else
127                                 propertiesByName = new Dictionary <string, BuildProperty> ();
128                 }
129
130                 [MonoTODO]
131                 public BuildPropertyGroup Clone (bool deepClone)
132                 {
133                         BuildPropertyGroup bpg = new BuildPropertyGroup (propertyGroup, parentProject, importedProject, read_only);
134                         if (FromXml) {
135                                 foreach (BuildProperty bp in properties) {
136                                         if (deepClone)
137                                                 bpg.AddProperty (bp.Clone (true));
138                                         else
139                                                 bpg.AddNewProperty (bp.Name, bp.FinalValue);
140                                 }
141                         } else {
142                                 foreach (BuildProperty bp in propertiesByName.Values) {
143                                         if (deepClone)
144                                                 bpg.AddProperty (bp.Clone (true));
145                                         else
146                                                 bpg.AddNewProperty (bp.Name, bp.FinalValue);
147                                 }
148                         }
149
150                         return bpg;
151                 }
152
153                 public IEnumerator GetEnumerator ()
154                 {
155                         if (FromXml)
156                                 foreach (BuildProperty bp in properties)
157                                         yield return bp;
158                         else 
159                                 foreach (KeyValuePair <string, BuildProperty> kvp in propertiesByName)
160                                         yield return kvp.Value;
161                 }
162
163                 public void RemoveProperty (BuildProperty propertyToRemove)
164                 {
165                         if (propertyToRemove == null)
166                                 throw new ArgumentNullException ("propertyToRemove");
167
168                         if (FromXml) {
169                                 if (!propertyToRemove.FromXml)
170                                         throw new InvalidOperationException ("The specified property does not belong to the current property group.");
171
172                                 propertyToRemove.XmlElement.ParentNode.RemoveChild (propertyToRemove.XmlElement);
173                                 properties.Remove (propertyToRemove);
174                         } else
175                                 propertiesByName.Remove (propertyToRemove.Name);
176                 }
177
178                 public void RemoveProperty (string propertyName)
179                 {
180                         if (FromXml) {
181                                 foreach (BuildProperty bp in properties)
182                                         if (bp.Name == propertyName) {
183                                                 RemoveProperty (bp);
184                                                 break;
185                                         }
186                         } else
187                                 propertiesByName.Remove (propertyName);
188                 }
189
190                 public void SetProperty (string propertyName,
191                                          string propertyValue)
192                 {
193                         SetProperty (propertyName, propertyValue, false);
194                 }
195                 
196                 public void SetProperty (string propertyName,
197                                          string propertyValue,
198                                          bool treatPropertyValueAsLiteral)
199                 {
200                         if (read_only)
201                                 return;
202                         if (FromXml)
203                                 throw new InvalidOperationException (
204                                         "This method is only valid for virtual property groups, not <PropertyGroup> elements.");
205
206                         if (treatPropertyValueAsLiteral)
207                                 propertyValue = Utilities.Escape (propertyValue);
208
209                         if (propertiesByName.ContainsKey (propertyName))
210                                 propertiesByName.Remove (propertyName);
211
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]));
216
217                         AddProperty (bp);
218
219                         if (IsGlobal)
220                                 parentProject.NeedToReevaluate ();
221                 }
222                 
223                 internal void Evaluate ()
224                 {
225                         if (evaluated)
226                                 return;
227
228                         foreach (BuildProperty bp in properties)
229                                 if (ConditionParser.ParseAndEvaluate (bp.Condition, parentProject))
230                                         bp.Evaluate ();
231
232                         evaluated = true;
233                 }
234                 
235                 public string Condition {
236                         get {
237                                 if (!FromXml)
238                                         return String.Empty;
239                                 return propertyGroup.GetAttribute ("Condition");
240                         }
241                         set {
242                                 if (!FromXml)
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);
246                         }
247                 }
248
249                 public int Count {
250                         get {
251                                 if (FromXml)
252                                         return properties.Count;
253                                 else
254                                         return propertiesByName.Count;
255                         }
256                 }
257
258                 public bool IsImported {
259                         get {
260                                 return importedProject != null;
261                         }
262                 }
263
264                 internal bool FromXml {
265                         get {
266                                 return propertyGroup != null;
267                         }
268                 }
269
270                 bool IsGlobal {
271                         get {
272                                 return parentProject != null && propertyGroup == null;
273                         }
274                 }
275
276                 public BuildProperty this [string propertyName] {
277                         get {
278                                 if (FromXml)
279                                         throw new InvalidOperationException ("Properties in persisted property groups cannot be accessed by name.");
280                                 
281                                 if (propertiesByName.ContainsKey (propertyName))
282                                         return propertiesByName [propertyName];
283                                 else
284                                         return null;
285                         }
286                         set {
287                                 propertiesByName [propertyName] = value;
288                         }
289                 }
290                 
291                 internal GroupingCollection GroupingCollection {
292                         get { return parentCollection; }
293                         set { parentCollection = value; }
294                 }
295
296                 internal XmlElement XmlElement {
297                         get { return propertyGroup; }
298                 }
299         }
300 }
301
302 #endif