aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Compiler_UI.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2019-05-08 14:13:31 -0700
committerRob Mensching <rob@firegiant.com>2019-05-08 14:44:43 -0700
commit75fd55d5a71c492c6ea904768858c51aa97da29f (patch)
tree610047db1d5759a726ce88277bb2dfddcd01da45 /src/WixToolset.Core/Compiler_UI.cs
parentd1dbe29f3856d012acf5f96e8e66c43b74ab490d (diff)
downloadwix-75fd55d5a71c492c6ea904768858c51aa97da29f.tar.gz
wix-75fd55d5a71c492c6ea904768858c51aa97da29f.tar.bz2
wix-75fd55d5a71c492c6ea904768858c51aa97da29f.zip
Use new strongly typed tuples
Diffstat (limited to 'src/WixToolset.Core/Compiler_UI.cs')
-rw-r--r--src/WixToolset.Core/Compiler_UI.cs1730
1 files changed, 1730 insertions, 0 deletions
diff --git a/src/WixToolset.Core/Compiler_UI.cs b/src/WixToolset.Core/Compiler_UI.cs
new file mode 100644
index 00000000..fddb9061
--- /dev/null
+++ b/src/WixToolset.Core/Compiler_UI.cs
@@ -0,0 +1,1730 @@
1// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.
2
3namespace WixToolset.Core
4{
5 using System;
6 using System.Collections;
7 using System.Xml.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.Tuples;
10 using WixToolset.Data.WindowsInstaller;
11 using WixToolset.Extensibility;
12
13 /// <summary>
14 /// Compiler of the WiX toolset.
15 /// </summary>
16 internal partial class Compiler : ICompiler
17 {
18 // NameToBit arrays
19 private static readonly string[] TextControlAttributes = { "Transparent", "NoPrefix", "NoWrap", "FormatSize", "UserLanguage" };
20 private static readonly string[] HyperlinkControlAttributes = { "Transparent" };
21 private static readonly string[] EditControlAttributes = { "Multiline", null, null, null, null, "Password" };
22 private static readonly string[] ProgressControlAttributes = { "ProgressBlocks" };
23 private static readonly string[] VolumeControlAttributes = { "Removable", "Fixed", "Remote", "CDROM", "RAMDisk", "Floppy", "ShowRollbackCost" };
24 private static readonly string[] ListboxControlAttributes = { "Sorted", null, null, null, "UserLanguage" };
25 private static readonly string[] ListviewControlAttributes = { "Sorted", null, null, null, "FixedSize", "Icon16", "Icon32" };
26 private static readonly string[] ComboboxControlAttributes = { "Sorted", "ComboList", null, null, "UserLanguage" };
27 private static readonly string[] RadioControlAttributes = { "Image", "PushLike", "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32", null, "HasBorder" };
28 private static readonly string[] ButtonControlAttributes = { "Image", null, "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32", "ElevationShield" };
29 private static readonly string[] IconControlAttributes = { "Image", null, null, null, "FixedSize", "Icon16", "Icon32" };
30 private static readonly string[] BitmapControlAttributes = { "Image", null, null, null, "FixedSize" };
31 private static readonly string[] CheckboxControlAttributes = { null, "PushLike", "Bitmap", "Icon", "FixedSize", "Icon16", "Icon32" };
32
33 /// <summary>
34 /// Parses UI elements.
35 /// </summary>
36 /// <param name="node">Element to parse.</param>
37 private void ParseUIElement(XElement node)
38 {
39 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
40 Identifier id = null;
41 var embeddedUICount = 0;
42
43 foreach (var attrib in node.Attributes())
44 {
45 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
46 {
47 switch (attrib.Name.LocalName)
48 {
49 case "Id":
50 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
51 break;
52 default:
53 this.Core.UnexpectedAttribute(node, attrib);
54 break;
55 }
56 }
57 else
58 {
59 this.Core.ParseExtensionAttribute(node, attrib);
60 }
61 }
62
63 foreach (var child in node.Elements())
64 {
65 if (CompilerCore.WixNamespace == child.Name.Namespace)
66 {
67 switch (child.Name.LocalName)
68 {
69 case "BillboardAction":
70 this.ParseBillboardActionElement(child);
71 break;
72 case "ComboBox":
73 this.ParseControlGroupElement(child, TupleDefinitionType.ComboBox, "ListItem");
74 break;
75 case "Dialog":
76 this.ParseDialogElement(child);
77 break;
78 case "DialogRef":
79 this.ParseSimpleRefElement(child, "Dialog");
80 break;
81 case "EmbeddedUI":
82 if (0 < embeddedUICount) // there can be only one embedded UI
83 {
84 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
85 this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName));
86 }
87 this.ParseEmbeddedUIElement(child);
88 ++embeddedUICount;
89 break;
90 case "Error":
91 this.ParseErrorElement(child);
92 break;
93 case "ListBox":
94 this.ParseControlGroupElement(child, TupleDefinitionType.ListBox, "ListItem");
95 break;
96 case "ListView":
97 this.ParseControlGroupElement(child, TupleDefinitionType.ListView, "ListItem");
98 break;
99 case "ProgressText":
100 this.ParseActionTextElement(child);
101 break;
102 case "Publish":
103 var order = 0;
104 this.ParsePublishElement(child, null, null, ref order);
105 break;
106 case "RadioButtonGroup":
107 var radioButtonType = this.ParseRadioButtonGroupElement(child, null, RadioButtonType.NotSet);
108 if (RadioButtonType.Bitmap == radioButtonType || RadioButtonType.Icon == radioButtonType)
109 {
110 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
111 this.Core.Write(ErrorMessages.RadioButtonBitmapAndIconDisallowed(childSourceLineNumbers));
112 }
113 break;
114 case "TextStyle":
115 this.ParseTextStyleElement(child);
116 break;
117 case "UIText":
118 this.ParseUITextElement(child);
119 break;
120
121 // the following are available indentically under the UI and Product elements for document organization use only
122 case "AdminUISequence":
123 case "InstallUISequence":
124 this.ParseSequenceElement(child, child.Name.LocalName);
125 break;
126 case "Binary":
127 this.ParseBinaryElement(child);
128 break;
129 case "Property":
130 this.ParsePropertyElement(child);
131 break;
132 case "PropertyRef":
133 this.ParseSimpleRefElement(child, "Property");
134 break;
135 case "UIRef":
136 this.ParseSimpleRefElement(child, "WixUI");
137 break;
138
139 default:
140 this.Core.UnexpectedElement(node, child);
141 break;
142 }
143 }
144 else
145 {
146 this.Core.ParseExtensionElement(node, child);
147 }
148 }
149
150 if (null != id && !this.Core.EncounteredError)
151 {
152 this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.WixUI, id);
153 }
154 }
155
156 /// <summary>
157 /// Parses a list item element.
158 /// </summary>
159 /// <param name="node">Element to parse.</param>
160 /// <param name="table">Table to add row to.</param>
161 /// <param name="property">Identifier of property referred to by list item.</param>
162 /// <param name="order">Relative order of list items.</param>
163 private void ParseListItemElement(XElement node, TupleDefinitionType tableName, string property, ref int order)
164 {
165 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
166 string icon = null;
167 string text = null;
168 string value = null;
169
170 foreach (var attrib in node.Attributes())
171 {
172 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
173 {
174 switch (attrib.Name.LocalName)
175 {
176 case "Icon":
177 if (TupleDefinitionType.ListView == tableName)
178 {
179 icon = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
180 this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", icon);
181 }
182 else
183 {
184 this.Core.Write(ErrorMessages.IllegalAttributeExceptOnElement(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "ListView"));
185 }
186 break;
187 case "Text":
188 text = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
189 break;
190 case "Value":
191 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
192 break;
193 default:
194 this.Core.UnexpectedAttribute(node, attrib);
195 break;
196 }
197 }
198 else
199 {
200 this.Core.ParseExtensionAttribute(node, attrib);
201 }
202 }
203
204 if (null == value)
205 {
206 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
207 }
208
209 this.Core.ParseForExtensionElements(node);
210
211 if (!this.Core.EncounteredError)
212 {
213 var row = this.Core.CreateRow(sourceLineNumbers, tableName);
214 row.Set(0, property);
215 row.Set(1, ++order);
216 row.Set(2, value);
217 row.Set(3, text);
218 if (null != icon)
219 {
220 row.Set(4, icon);
221 }
222 }
223 }
224
225 /// <summary>
226 /// Parses a radio button element.
227 /// </summary>
228 /// <param name="node">Element to parse.</param>
229 /// <param name="property">Identifier of property referred to by radio button.</param>
230 /// <param name="order">Relative order of radio buttons.</param>
231 /// <returns>Type of this radio button.</returns>
232 private RadioButtonType ParseRadioButtonElement(XElement node, string property, ref int order)
233 {
234 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
235 var type = RadioButtonType.NotSet;
236 string value = null;
237 string x = null;
238 string y = null;
239 string width = null;
240 string height = null;
241 string text = null;
242 string tooltip = null;
243 string help = null;
244
245 foreach (var attrib in node.Attributes())
246 {
247 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
248 {
249 switch (attrib.Name.LocalName)
250 {
251 case "Bitmap":
252 if (RadioButtonType.NotSet != type)
253 {
254 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Icon", "Text"));
255 }
256 text = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
257 this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text);
258 type = RadioButtonType.Bitmap;
259 break;
260 case "Height":
261 height = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
262 break;
263 case "Help":
264 help = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
265 break;
266 case "Icon":
267 if (RadioButtonType.NotSet != type)
268 {
269 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttributes(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Text"));
270 }
271 text = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
272 this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text);
273 type = RadioButtonType.Icon;
274 break;
275 case "Text":
276 if (RadioButtonType.NotSet != type)
277 {
278 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bitmap", "Icon"));
279 }
280 text = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
281 type = RadioButtonType.Text;
282 break;
283 case "ToolTip":
284 tooltip = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
285 break;
286 case "Value":
287 value = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
288 break;
289 case "Width":
290 width = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
291 break;
292 case "X":
293 x = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
294 break;
295 case "Y":
296 y = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
297 break;
298 default:
299 this.Core.UnexpectedAttribute(node, attrib);
300 break;
301 }
302 }
303 else
304 {
305 this.Core.ParseExtensionAttribute(node, attrib);
306 }
307 }
308
309 if (null == value)
310 {
311 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value"));
312 }
313
314 if (null == x)
315 {
316 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X"));
317 }
318
319 if (null == y)
320 {
321 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y"));
322 }
323
324 if (null == width)
325 {
326 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width"));
327 }
328
329 if (null == height)
330 {
331 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height"));
332 }
333
334 this.Core.ParseForExtensionElements(node);
335
336 if (!this.Core.EncounteredError)
337 {
338 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.RadioButton);
339 row.Set(0, property);
340 row.Set(1, ++order);
341 row.Set(2, value);
342 row.Set(3, x);
343 row.Set(4, y);
344 row.Set(5, width);
345 row.Set(6, height);
346 row.Set(7, text);
347 if (null != tooltip || null != help)
348 {
349 row.Set(8, String.Concat(tooltip, "|", help));
350 }
351 }
352
353 return type;
354 }
355
356 /// <summary>
357 /// Parses a billboard element.
358 /// </summary>
359 /// <param name="node">Element to parse.</param>
360 private void ParseBillboardActionElement(XElement node)
361 {
362 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
363 string action = null;
364 var order = 0;
365
366 foreach (var attrib in node.Attributes())
367 {
368 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
369 {
370 switch (attrib.Name.LocalName)
371 {
372 case "Id":
373 action = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
374 this.Core.CreateSimpleReference(sourceLineNumbers, "WixAction", "InstallExecuteSequence", action);
375 break;
376 default:
377 this.Core.UnexpectedAttribute(node, attrib);
378 break;
379 }
380 }
381 else
382 {
383 this.Core.ParseExtensionAttribute(node, attrib);
384 }
385 }
386
387 if (null == action)
388 {
389 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
390 }
391
392 foreach (var child in node.Elements())
393 {
394 if (CompilerCore.WixNamespace == child.Name.Namespace)
395 {
396 switch (child.Name.LocalName)
397 {
398 case "Billboard":
399 order = order + 1;
400 this.ParseBillboardElement(child, action, order);
401 break;
402 default:
403 this.Core.UnexpectedElement(node, child);
404 break;
405 }
406 }
407 else
408 {
409 this.Core.ParseExtensionElement(node, child);
410 }
411 }
412 }
413
414 /// <summary>
415 /// Parses a billboard element.
416 /// </summary>
417 /// <param name="node">Element to parse.</param>
418 /// <param name="action">Action for the billboard.</param>
419 /// <param name="order">Order of the billboard.</param>
420 private void ParseBillboardElement(XElement node, string action, int order)
421 {
422 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
423 Identifier id = null;
424 string feature = null;
425
426 foreach (var attrib in node.Attributes())
427 {
428 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
429 {
430 switch (attrib.Name.LocalName)
431 {
432 case "Id":
433 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
434 break;
435 case "Feature":
436 feature = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
437 this.Core.CreateSimpleReference(sourceLineNumbers, "Feature", feature);
438 break;
439 default:
440 this.Core.UnexpectedAttribute(node, attrib);
441 break;
442 }
443 }
444 else
445 {
446 this.Core.ParseExtensionAttribute(node, attrib);
447 }
448 }
449
450 if (null == id)
451 {
452 id = this.Core.CreateIdentifier("bil", action, order.ToString(), feature);
453 }
454
455 foreach (var child in node.Elements())
456 {
457 if (CompilerCore.WixNamespace == child.Name.Namespace)
458 {
459 switch (child.Name.LocalName)
460 {
461 case "Control":
462 // These are all thrown away.
463 IntermediateTuple lastTabRow = null;
464 string firstControl = null;
465 string defaultControl = null;
466 string cancelControl = null;
467
468 this.ParseControlElement(child, id.Id, TupleDefinitionType.BBControl, ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, false);
469 break;
470 default:
471 this.Core.UnexpectedElement(node, child);
472 break;
473 }
474 }
475 else
476 {
477 this.Core.ParseExtensionElement(node, child);
478 }
479 }
480
481
482 if (!this.Core.EncounteredError)
483 {
484 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.Billboard, id);
485 row.Set(1, feature);
486 row.Set(2, action);
487 row.Set(3, order);
488 }
489 }
490
491 /// <summary>
492 /// Parses a control group element.
493 /// </summary>
494 /// <param name="node">Element to parse.</param>
495 /// <param name="table">Table referred to by control group.</param>
496 /// <param name="childTag">Expected child elements.</param>
497 private void ParseControlGroupElement(XElement node, TupleDefinitionType tableName, string childTag)
498 {
499 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
500 var order = 0;
501 string property = null;
502
503 foreach (var attrib in node.Attributes())
504 {
505 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
506 {
507 switch (attrib.Name.LocalName)
508 {
509 case "Property":
510 property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
511 break;
512 default:
513 this.Core.UnexpectedAttribute(node, attrib);
514 break;
515 }
516 }
517 else
518 {
519 this.Core.ParseExtensionAttribute(node, attrib);
520 }
521 }
522
523 if (null == property)
524 {
525 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property"));
526 }
527
528 foreach (var child in node.Elements())
529 {
530 if (CompilerCore.WixNamespace == child.Name.Namespace)
531 {
532 if (childTag != child.Name.LocalName)
533 {
534 this.Core.UnexpectedElement(node, child);
535 }
536
537 switch (child.Name.LocalName)
538 {
539 case "ListItem":
540 this.ParseListItemElement(child, tableName, property, ref order);
541 break;
542 case "Property":
543 this.ParsePropertyElement(child);
544 break;
545 default:
546 this.Core.UnexpectedElement(node, child);
547 break;
548 }
549 }
550 else
551 {
552 this.Core.ParseExtensionElement(node, child);
553 }
554 }
555
556 }
557
558 /// <summary>
559 /// Parses a radio button control group element.
560 /// </summary>
561 /// <param name="node">Element to parse.</param>
562 /// <param name="property">Property associated with this radio button group.</param>
563 /// <param name="groupType">Specifies the current type of radio buttons in the group.</param>
564 /// <returns>The current type of radio buttons in the group.</returns>
565 private RadioButtonType ParseRadioButtonGroupElement(XElement node, string property, RadioButtonType groupType)
566 {
567 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
568 var order = 0;
569
570 foreach (var attrib in node.Attributes())
571 {
572 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
573 {
574 switch (attrib.Name.LocalName)
575 {
576 case "Property":
577 property = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
578 this.Core.CreateSimpleReference(sourceLineNumbers, "Property", property);
579 break;
580 default:
581 this.Core.UnexpectedAttribute(node, attrib);
582 break;
583 }
584 }
585 else
586 {
587 this.Core.ParseExtensionAttribute(node, attrib);
588 }
589 }
590
591 if (null == property)
592 {
593 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property"));
594 }
595
596 foreach (var child in node.Elements())
597 {
598 if (CompilerCore.WixNamespace == child.Name.Namespace)
599 {
600 switch (child.Name.LocalName)
601 {
602 case "RadioButton":
603 var type = this.ParseRadioButtonElement(child, property, ref order);
604 if (RadioButtonType.NotSet == groupType)
605 {
606 groupType = type;
607 }
608 else if (groupType != type)
609 {
610 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
611 this.Core.Write(ErrorMessages.RadioButtonTypeInconsistent(childSourceLineNumbers));
612 }
613 break;
614 default:
615 this.Core.UnexpectedElement(node, child);
616 break;
617 }
618 }
619 else
620 {
621 this.Core.ParseExtensionElement(node, child);
622 }
623 }
624
625
626 return groupType;
627 }
628
629 /// <summary>
630 /// Parses an action text element.
631 /// </summary>
632 /// <param name="node">Element to parse.</param>
633 private void ParseActionTextElement(XElement node)
634 {
635 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
636 string action = null;
637 string template = null;
638
639 foreach (var attrib in node.Attributes())
640 {
641 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
642 {
643 switch (attrib.Name.LocalName)
644 {
645 case "Action":
646 action = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
647 break;
648 case "Template":
649 template = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
650 break;
651 default:
652 this.Core.UnexpectedAttribute(node, attrib);
653 break;
654 }
655 }
656 else
657 {
658 this.Core.ParseExtensionAttribute(node, attrib);
659 }
660 }
661
662 if (null == action)
663 {
664 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Action"));
665 }
666
667 this.Core.ParseForExtensionElements(node);
668
669 if (!this.Core.EncounteredError)
670 {
671 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ActionText);
672 row.Set(0, action);
673 row.Set(1, Common.GetInnerText(node));
674 row.Set(2, template);
675 }
676 }
677
678 /// <summary>
679 /// Parses an ui text element.
680 /// </summary>
681 /// <param name="node">Element to parse.</param>
682 private void ParseUITextElement(XElement node)
683 {
684 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
685 Identifier id = null;
686 string text = null;
687
688 foreach (var attrib in node.Attributes())
689 {
690 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
691 {
692 switch (attrib.Name.LocalName)
693 {
694 case "Id":
695 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
696 break;
697 default:
698 this.Core.UnexpectedAttribute(node, attrib);
699 break;
700 }
701 }
702 else
703 {
704 this.Core.ParseExtensionAttribute(node, attrib);
705 }
706 }
707
708 text = Common.GetInnerText(node);
709
710 if (null == id)
711 {
712 id = this.Core.CreateIdentifier("txt", text);
713 }
714
715 this.Core.ParseForExtensionElements(node);
716
717 if (!this.Core.EncounteredError)
718 {
719 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.UIText, id);
720 row.Set(1, text);
721 }
722 }
723
724 /// <summary>
725 /// Parses a text style element.
726 /// </summary>
727 /// <param name="node">Element to parse.</param>
728 private void ParseTextStyleElement(XElement node)
729 {
730 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
731 Identifier id = null;
732 var color = CompilerConstants.IntegerNotSet;
733 var bold = false;
734 var italic = false;
735 var strike = false;
736 var underline = false;
737 string faceName = null;
738 var size = "0";
739
740 foreach (var attrib in node.Attributes())
741 {
742 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
743 {
744 switch (attrib.Name.LocalName)
745 {
746 case "Id":
747 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
748 break;
749
750 // RGB Values
751 case "Red":
752 var redColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue);
753 if (CompilerConstants.IllegalInteger != redColor)
754 {
755 if (CompilerConstants.IntegerNotSet == color)
756 {
757 color = redColor;
758 }
759 else
760 {
761 color += redColor;
762 }
763 }
764 break;
765 case "Green":
766 var greenColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue);
767 if (CompilerConstants.IllegalInteger != greenColor)
768 {
769 if (CompilerConstants.IntegerNotSet == color)
770 {
771 color = greenColor * 256;
772 }
773 else
774 {
775 color += greenColor * 256;
776 }
777 }
778 break;
779 case "Blue":
780 var blueColor = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Byte.MaxValue);
781 if (CompilerConstants.IllegalInteger != blueColor)
782 {
783 if (CompilerConstants.IntegerNotSet == color)
784 {
785 color = blueColor * 65536;
786 }
787 else
788 {
789 color += blueColor * 65536;
790 }
791 }
792 break;
793
794 // Style values
795 case "Bold":
796 bold = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
797 break;
798 case "Italic":
799 italic = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
800 break;
801 case "Strike":
802 strike = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
803 break;
804 case "Underline":
805 underline = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
806 break;
807
808 // Font values
809 case "FaceName":
810 faceName = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
811 break;
812 case "Size":
813 size = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
814 break;
815
816 default:
817 this.Core.UnexpectedAttribute(node, attrib);
818 break;
819 }
820 }
821 else
822 {
823 this.Core.ParseExtensionAttribute(node, attrib);
824 }
825 }
826
827 if (null == id)
828 {
829 this.Core.CreateIdentifier("txs", faceName, size.ToString(), color.ToString(), bold.ToString(), italic.ToString(), strike.ToString(), underline.ToString());
830 }
831
832 if (null == faceName)
833 {
834 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "FaceName"));
835 }
836
837 this.Core.ParseForExtensionElements(node);
838
839 if (!this.Core.EncounteredError)
840 {
841 var tuple = new TextStyleTuple(sourceLineNumbers, id)
842 {
843 FaceName = faceName,
844 Color = color,
845 Bold = bold,
846 Italic = italic,
847 Strike = strike,
848 Underline = underline,
849 };
850
851 tuple.Set((int)TextStyleTupleFields.Size, size);
852
853 this.Core.AddTuple(tuple);
854 }
855 }
856
857 /// <summary>
858 /// Parses a dialog element.
859 /// </summary>
860 /// <param name="node">Element to parse.</param>
861 private void ParseDialogElement(XElement node)
862 {
863 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
864 Identifier id = null;
865 var hidden = false;
866 var modal = true;
867 var minimize = true;
868 var customPalette = false;
869 var errorDialog = false;
870 var keepModeless = false;
871 var height = 0;
872 string title = null;
873 var leftScroll = false;
874 var rightAligned = false;
875 var rightToLeft = false;
876 var systemModal = false;
877 var trackDiskSpace = false;
878 var width = 0;
879 var x = 50;
880 var y = 50;
881
882 foreach (var attrib in node.Attributes())
883 {
884 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
885 {
886 switch (attrib.Name.LocalName)
887 {
888 case "Id":
889 id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
890 break;
891 case "Height":
892 height = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
893 break;
894 case "Title":
895 title = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
896 break;
897 case "Width":
898 width = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
899 break;
900 case "X":
901 x = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100);
902 break;
903 case "Y":
904 y = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 100);
905 break;
906 case "CustomPalette":
907 customPalette = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
908 break;
909 case "ErrorDialog":
910 errorDialog = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
911 break;
912 case "Hidden":
913 hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
914 break;
915 case "KeepModeless":
916 keepModeless = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
917 break;
918 case "LeftScroll":
919 leftScroll = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
920 break;
921 case "Modeless":
922 modal = YesNoType.Yes != this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
923 break;
924 case "NoMinimize":
925 minimize = YesNoType.Yes != this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
926 break;
927 case "RightAligned":
928 rightAligned = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
929 break;
930 case "RightToLeft":
931 rightToLeft = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
932 break;
933 case "SystemModal":
934 systemModal = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
935 break;
936 case "TrackDiskSpace":
937 trackDiskSpace = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
938 break;
939
940 default:
941 this.Core.UnexpectedAttribute(node, attrib);
942 break;
943 }
944 }
945 else
946 {
947 this.Core.ParseExtensionAttribute(node, attrib);
948 }
949 }
950
951 if (null == id)
952 {
953 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
954 id = Identifier.Invalid;
955 }
956
957 IntermediateTuple lastTabRow = null;
958 string cancelControl = null;
959 string defaultControl = null;
960 string firstControl = null;
961
962 foreach (var child in node.Elements())
963 {
964 if (CompilerCore.WixNamespace == child.Name.Namespace)
965 {
966 switch (child.Name.LocalName)
967 {
968 case "Control":
969 this.ParseControlElement(child, id.Id, TupleDefinitionType.Control, ref lastTabRow, ref firstControl, ref defaultControl, ref cancelControl, trackDiskSpace);
970 break;
971 default:
972 this.Core.UnexpectedElement(node, child);
973 break;
974 }
975 }
976 else
977 {
978 this.Core.ParseExtensionElement(node, child);
979 }
980 }
981
982 if (null != lastTabRow && null != lastTabRow[1])
983 {
984 if (firstControl != lastTabRow[1].ToString())
985 {
986 lastTabRow.Set(10, firstControl);
987 }
988 }
989
990 if (null == firstControl)
991 {
992 this.Core.Write(ErrorMessages.NoFirstControlSpecified(sourceLineNumbers, id.Id));
993 }
994
995 if (!this.Core.EncounteredError)
996 {
997 var tuple = new DialogTuple(sourceLineNumbers, id)
998 {
999 HCentering = x,
1000 VCentering = y,
1001 Width = width,
1002 Height = height,
1003 CustomPalette = customPalette,
1004 ErrorDialog = errorDialog,
1005 Visible = !hidden,
1006 Modal = modal,
1007 KeepModeless = keepModeless,
1008 LeftScroll = leftScroll,
1009 Minimize = minimize,
1010 RightAligned = rightAligned,
1011 RightToLeft = rightToLeft,
1012 SystemModal = systemModal,
1013 TrackDiskSpace = trackDiskSpace,
1014 Title = title,
1015 Control_First = firstControl,
1016 Control_Default = defaultControl,
1017 Control_Cancel = cancelControl,
1018 };
1019
1020 this.Core.AddTuple(tuple);
1021 }
1022 }
1023
1024 /// <summary>
1025 /// Parses a control element.
1026 /// </summary>
1027 /// <param name="node">Element to parse.</param>
1028 /// <param name="dialog">Identifier for parent dialog.</param>
1029 /// <param name="table">Table control belongs in.</param>
1030 /// <param name="lastTabTuple">Last row in the tab order.</param>
1031 /// <param name="firstControl">Name of the first control in the tab order.</param>
1032 /// <param name="defaultControl">Name of the default control.</param>
1033 /// <param name="cancelControl">Name of the candle control.</param>
1034 /// <param name="trackDiskSpace">True if the containing dialog tracks disk space.</param>
1035 private void ParseControlElement(XElement node, string dialog, TupleDefinitionType tupleType, ref IntermediateTuple lastTabTuple, ref string firstControl, ref string defaultControl, ref string cancelControl, bool trackDiskSpace)
1036 {
1037 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1038 Identifier controlId = null;
1039 var bits = new BitArray(32);
1040 string checkBoxPropertyRef = null;
1041 string checkboxValue = null;
1042 string controlType = null;
1043 var disabled = false;
1044 string height = null;
1045 string help = null;
1046 var isCancel = false;
1047 var isDefault = false;
1048 var notTabbable = false;
1049 string property = null;
1050 var publishOrder = 0;
1051 string sourceFile = null;
1052 string text = null;
1053 string tooltip = null;
1054 var radioButtonsType = RadioButtonType.NotSet;
1055 string width = null;
1056 string x = null;
1057 string y = null;
1058
1059 var hidden = false;
1060 var sunken = false;
1061 var indirect = false;
1062 var integer = false;
1063 var rightToLeft = false;
1064 var rightAligned = false;
1065 var leftScroll = false;
1066
1067 // The rest of the method relies on the control's Type, so we have to get that first.
1068 var typeAttribute = node.Attribute("Type");
1069 if (null == typeAttribute)
1070 {
1071 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Type"));
1072 }
1073 else
1074 {
1075 controlType = this.Core.GetAttributeValue(sourceLineNumbers, typeAttribute);
1076 }
1077
1078 string[] specialAttributes;
1079 switch (controlType)
1080 {
1081 case "Billboard":
1082 specialAttributes = null;
1083 notTabbable = true;
1084 disabled = true;
1085
1086 this.Core.EnsureTable(sourceLineNumbers, "Billboard");
1087 break;
1088 case "Bitmap":
1089 specialAttributes = BitmapControlAttributes;
1090 notTabbable = true;
1091 disabled = true;
1092 break;
1093 case "CheckBox":
1094 specialAttributes = CheckboxControlAttributes;
1095 break;
1096 case "ComboBox":
1097 specialAttributes = ComboboxControlAttributes;
1098 break;
1099 case "DirectoryCombo":
1100 specialAttributes = VolumeControlAttributes;
1101 break;
1102 case "DirectoryList":
1103 specialAttributes = null;
1104 break;
1105 case "Edit":
1106 specialAttributes = EditControlAttributes;
1107 break;
1108 case "GroupBox":
1109 specialAttributes = null;
1110 notTabbable = true;
1111 break;
1112 case "Hyperlink":
1113 specialAttributes = HyperlinkControlAttributes;
1114 break;
1115 case "Icon":
1116 specialAttributes = IconControlAttributes;
1117 notTabbable = true;
1118 disabled = true;
1119 break;
1120 case "Line":
1121 specialAttributes = null;
1122 notTabbable = true;
1123 disabled = true;
1124 break;
1125 case "ListBox":
1126 specialAttributes = ListboxControlAttributes;
1127 break;
1128 case "ListView":
1129 specialAttributes = ListviewControlAttributes;
1130 break;
1131 case "MaskedEdit":
1132 specialAttributes = EditControlAttributes;
1133 break;
1134 case "PathEdit":
1135 specialAttributes = EditControlAttributes;
1136 break;
1137 case "ProgressBar":
1138 specialAttributes = ProgressControlAttributes;
1139 notTabbable = true;
1140 disabled = true;
1141 break;
1142 case "PushButton":
1143 specialAttributes = ButtonControlAttributes;
1144 break;
1145 case "RadioButtonGroup":
1146 specialAttributes = RadioControlAttributes;
1147 break;
1148 case "ScrollableText":
1149 specialAttributes = null;
1150 break;
1151 case "SelectionTree":
1152 specialAttributes = null;
1153 break;
1154 case "Text":
1155 specialAttributes = TextControlAttributes;
1156 notTabbable = true;
1157 break;
1158 case "VolumeCostList":
1159 specialAttributes = VolumeControlAttributes;
1160 notTabbable = true;
1161 break;
1162 case "VolumeSelectCombo":
1163 specialAttributes = VolumeControlAttributes;
1164 break;
1165 default:
1166 specialAttributes = null;
1167 notTabbable = true;
1168 break;
1169 }
1170
1171 foreach (var attrib in node.Attributes())
1172 {
1173 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1174 {
1175 switch (attrib.Name.LocalName)
1176 {
1177 case "Id":
1178 controlId = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib);
1179 break;
1180 case "Type": // already processed
1181 break;
1182 case "Cancel":
1183 isCancel = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1184 break;
1185 case "CheckBoxPropertyRef":
1186 checkBoxPropertyRef = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1187 break;
1188 case "CheckBoxValue":
1189 checkboxValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1190 break;
1191 case "Default":
1192 isDefault = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1193 break;
1194 case "Height":
1195 height = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
1196 break;
1197 case "Help":
1198 help = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1199 break;
1200 case "IconSize":
1201 var iconSizeValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1202 if (null != specialAttributes)
1203 {
1204 switch (iconSizeValue)
1205 {
1206 case "16":
1207 this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16);
1208 break;
1209 case "32":
1210 this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16);
1211 break;
1212 case "48":
1213 this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16);
1214 this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16);
1215 break;
1216 case "":
1217 break;
1218 default:
1219 this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "16", "32", "48"));
1220 break;
1221 }
1222 //if (0 < iconSizeValue.Length)
1223 //{
1224 // var iconsSizeType = Wix.Control.ParseIconSizeType(iconSizeValue);
1225 // switch (iconsSizeType)
1226 // {
1227 // case Wix.Control.IconSizeType.Item16:
1228 // this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16);
1229 // break;
1230 // case Wix.Control.IconSizeType.Item32:
1231 // this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16);
1232 // break;
1233 // case Wix.Control.IconSizeType.Item48:
1234 // this.Core.TrySetBitFromName(specialAttributes, "Icon16", YesNoType.Yes, bits, 16);
1235 // this.Core.TrySetBitFromName(specialAttributes, "Icon32", YesNoType.Yes, bits, 16);
1236 // break;
1237 // default:
1238 // this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "16", "32", "48"));
1239 // break;
1240 // }
1241 //}
1242 }
1243 else
1244 {
1245 this.Core.Write(ErrorMessages.IllegalAttributeValueWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, iconSizeValue, "Type"));
1246 }
1247 break;
1248 case "Property":
1249 property = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1250 break;
1251 case "TabSkip":
1252 notTabbable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1253 break;
1254 case "Text":
1255 text = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1256 break;
1257 case "ToolTip":
1258 tooltip = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1259 break;
1260 case "Width":
1261 width = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
1262 break;
1263 case "X":
1264 x = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
1265 break;
1266 case "Y":
1267 y = this.Core.GetAttributeLocalizableIntegerValue(sourceLineNumbers, attrib, 0, Int16.MaxValue);
1268 break;
1269 case "Disabled":
1270 disabled = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1271 break;
1272 case "Hidden":
1273 hidden = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1274 break;
1275 case "Sunken":
1276 sunken = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1277 break;
1278 case "Indirect":
1279 indirect = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1280 break;
1281 case "Integer":
1282 integer = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1283 break;
1284 case "RightToLeft":
1285 rightToLeft = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1286 break;
1287 case "RightAligned":
1288 rightAligned = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1289 break;
1290 case "LeftScroll":
1291 leftScroll = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1292 break;
1293 default:
1294 var attribValue = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1295 if (null == specialAttributes || !this.Core.TrySetBitFromName(specialAttributes, attrib.Name.LocalName, attribValue, bits, 16))
1296 {
1297 this.Core.UnexpectedAttribute(node, attrib);
1298 }
1299 break;
1300 }
1301 }
1302 else
1303 {
1304 this.Core.ParseExtensionAttribute(node, attrib);
1305 }
1306 }
1307
1308 var attributes = this.Core.CreateIntegerFromBitArray(bits);
1309
1310 //if (disabled)
1311 //{
1312 // attributes |= WindowsInstallerConstants.MsidbControlAttributesEnabled; // bit will be inverted when stored
1313 //}
1314
1315 if (null == height)
1316 {
1317 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Height"));
1318 }
1319
1320 if (null == width)
1321 {
1322 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Width"));
1323 }
1324
1325 if (null == x)
1326 {
1327 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "X"));
1328 }
1329
1330 if (null == y)
1331 {
1332 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Y"));
1333 }
1334
1335 if (null == controlId)
1336 {
1337 controlId = this.Core.CreateIdentifier("ctl", dialog, x, y, height, width);
1338 }
1339
1340 if (isCancel)
1341 {
1342 cancelControl = controlId.Id;
1343 }
1344
1345 if (isDefault)
1346 {
1347 defaultControl = controlId.Id;
1348 }
1349
1350 foreach (var child in node.Elements())
1351 {
1352 if (CompilerCore.WixNamespace == child.Name.Namespace)
1353 {
1354 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
1355 switch (child.Name.LocalName)
1356 {
1357 case "Binary":
1358 this.ParseBinaryElement(child);
1359 break;
1360 case "ComboBox":
1361 this.ParseControlGroupElement(child, TupleDefinitionType.ComboBox, "ListItem");
1362 break;
1363 case "Condition":
1364 this.ParseConditionElement(child, node.Name.LocalName, controlId.Id, dialog);
1365 break;
1366 case "ListBox":
1367 this.ParseControlGroupElement(child, TupleDefinitionType.ListBox, "ListItem");
1368 break;
1369 case "ListView":
1370 this.ParseControlGroupElement(child, TupleDefinitionType.ListView, "ListItem");
1371 break;
1372 case "Property":
1373 this.ParsePropertyElement(child);
1374 break;
1375 case "Publish":
1376 this.ParsePublishElement(child, dialog ?? String.Empty, controlId.Id, ref publishOrder);
1377 break;
1378 case "RadioButtonGroup":
1379 radioButtonsType = this.ParseRadioButtonGroupElement(child, property, radioButtonsType);
1380 break;
1381 case "Subscribe":
1382 this.ParseSubscribeElement(child, dialog, controlId.Id);
1383 break;
1384 case "Text":
1385 foreach (var attrib in child.Attributes())
1386 {
1387 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1388 {
1389 switch (attrib.Name.LocalName)
1390 {
1391 case "SourceFile":
1392 sourceFile = this.Core.GetAttributeValue(childSourceLineNumbers, attrib);
1393 break;
1394 default:
1395 this.Core.UnexpectedAttribute(child, attrib);
1396 break;
1397 }
1398 }
1399 else
1400 {
1401 this.Core.ParseExtensionAttribute(child, attrib);
1402 }
1403 }
1404
1405 text = Common.GetInnerText(child);
1406 if (!String.IsNullOrEmpty(text) && null != sourceFile)
1407 {
1408 this.Core.Write(ErrorMessages.IllegalAttributeWithInnerText(childSourceLineNumbers, child.Name.LocalName, "SourceFile"));
1409 }
1410 break;
1411 default:
1412 this.Core.UnexpectedElement(node, child);
1413 break;
1414 }
1415 }
1416 else
1417 {
1418 this.Core.ParseExtensionElement(node, child);
1419 }
1420 }
1421
1422 // If the radio buttons have icons, then we need to add the icon attribute.
1423 switch (radioButtonsType)
1424 {
1425 case RadioButtonType.Bitmap:
1426 attributes |= WindowsInstallerConstants.MsidbControlAttributesBitmap;
1427 break;
1428 case RadioButtonType.Icon:
1429 attributes |= WindowsInstallerConstants.MsidbControlAttributesIcon;
1430 break;
1431 case RadioButtonType.Text:
1432 // Text is the default so nothing needs to be added bits
1433 break;
1434 }
1435
1436 // the logic for creating control rows is a little tricky because of the way tabable controls are set
1437 IntermediateTuple tuple = null;
1438 if (!this.Core.EncounteredError)
1439 {
1440 if ("CheckBox" == controlType)
1441 {
1442 if (String.IsNullOrEmpty(property) && String.IsNullOrEmpty(checkBoxPropertyRef))
1443 {
1444 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef", true));
1445 }
1446 else if (!String.IsNullOrEmpty(property) && !String.IsNullOrEmpty(checkBoxPropertyRef))
1447 {
1448 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Property", "CheckBoxPropertyRef"));
1449 }
1450 else if (!String.IsNullOrEmpty(property))
1451 {
1452 var checkBoxTuple = new CheckBoxTuple(sourceLineNumbers)
1453 {
1454 Property = property,
1455 Value = checkboxValue
1456 };
1457
1458 this.Core.AddTuple(checkBoxTuple);
1459 }
1460 else
1461 {
1462 this.Core.CreateSimpleReference(sourceLineNumbers, "CheckBox", checkBoxPropertyRef);
1463 }
1464 }
1465
1466 var id = new Identifier(controlId.Access, dialog, controlId.Id);
1467
1468 if (TupleDefinitionType.BBControl == tupleType)
1469 {
1470 var bbTuple = new BBControlTuple(sourceLineNumbers, id)
1471 {
1472 Billboard_ = dialog,
1473 BBControl = controlId.Id,
1474 Type = controlType,
1475 Attributes = attributes,
1476 Enabled = !disabled,
1477 Indirect = indirect,
1478 Integer = integer,
1479 LeftScroll = leftScroll,
1480 RightAligned = rightAligned,
1481 RightToLeft = rightToLeft,
1482 Sunken = sunken,
1483 Visible = !hidden,
1484 Text = text,
1485 SourceFile = sourceFile
1486 };
1487
1488 bbTuple.Set((int)BBControlTupleFields.X, x);
1489 bbTuple.Set((int)BBControlTupleFields.Y, y);
1490 bbTuple.Set((int)BBControlTupleFields.Width, width);
1491 bbTuple.Set((int)BBControlTupleFields.Height, height);
1492
1493 this.Core.AddTuple(bbTuple);
1494
1495 tuple = bbTuple;
1496 }
1497 else
1498 {
1499 var controlTuple = new ControlTuple(sourceLineNumbers, id)
1500 {
1501 Dialog_ = dialog,
1502 Control = controlId.Id,
1503 Type = controlType,
1504 Attributes = attributes,
1505 Enabled = !disabled,
1506 Indirect = indirect,
1507 Integer = integer,
1508 LeftScroll = leftScroll,
1509 RightAligned = rightAligned,
1510 RightToLeft = rightToLeft,
1511 Sunken = sunken,
1512 Visible = !hidden,
1513 Property = !String.IsNullOrEmpty(property) ? property : checkBoxPropertyRef,
1514 Text = text,
1515 Help = (null == tooltip && null == help) ? null : String.Concat(tooltip, "|", help), // Separator is required, even if only one is non-null.};
1516 SourceFile = sourceFile
1517 };
1518
1519 controlTuple.Set((int)BBControlTupleFields.X, x);
1520 controlTuple.Set((int)BBControlTupleFields.Y, y);
1521 controlTuple.Set((int)BBControlTupleFields.Width, width);
1522 controlTuple.Set((int)BBControlTupleFields.Height, height);
1523
1524 this.Core.AddTuple(controlTuple);
1525
1526 tuple = controlTuple;
1527 }
1528 }
1529
1530 if (!notTabbable)
1531 {
1532 if (TupleDefinitionType.BBControl == tupleType)
1533 {
1534 this.Core.Write(ErrorMessages.TabbableControlNotAllowedInBillboard(sourceLineNumbers, node.Name.LocalName, controlType));
1535 }
1536
1537 if (null == firstControl)
1538 {
1539 firstControl = controlId.Id;
1540 }
1541
1542 if (null != lastTabTuple)
1543 {
1544 lastTabTuple.Set(10, controlId.Id);
1545 }
1546 lastTabTuple = tuple;
1547 }
1548
1549 // bitmap and icon controls contain a foreign key into the binary table in the text column;
1550 // add a reference if the identifier of the binary entry is known during compilation
1551 if (("Bitmap" == controlType || "Icon" == controlType) && Common.IsIdentifier(text))
1552 {
1553 this.Core.CreateSimpleReference(sourceLineNumbers, "Binary", text);
1554 }
1555 }
1556
1557 /// <summary>
1558 /// Parses a publish control event element.
1559 /// </summary>
1560 /// <param name="node">Element to parse.</param>
1561 /// <param name="dialog">Identifier of parent dialog.</param>
1562 /// <param name="control">Identifier of parent control.</param>
1563 /// <param name="order">Relative order of controls.</param>
1564 private void ParsePublishElement(XElement node, string dialog, string control, ref int order)
1565 {
1566 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1567 string argument = null;
1568 string condition = null;
1569 string controlEvent = null;
1570 string property = null;
1571
1572 // give this control event a unique ordering
1573 order++;
1574
1575 foreach (var attrib in node.Attributes())
1576 {
1577 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1578 {
1579 switch (attrib.Name.LocalName)
1580 {
1581 case "Control":
1582 if (null != control)
1583 {
1584 this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName));
1585 }
1586 control = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1587 break;
1588 case "Dialog":
1589 if (null != dialog)
1590 {
1591 this.Core.Write(ErrorMessages.IllegalAttributeWhenNested(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, node.Parent.Name.LocalName));
1592 }
1593 dialog = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
1594 this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", dialog);
1595 break;
1596 case "Event":
1597 controlEvent = Compiler.UppercaseFirstChar(this.Core.GetAttributeValue(sourceLineNumbers, attrib));
1598 break;
1599 case "Order":
1600 order = this.Core.GetAttributeIntegerValue(sourceLineNumbers, attrib, 0, 2147483647);
1601 break;
1602 case "Property":
1603 property = String.Concat("[", this.Core.GetAttributeValue(sourceLineNumbers, attrib), "]");
1604 break;
1605 case "Value":
1606 argument = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
1607 break;
1608 default:
1609 this.Core.UnexpectedAttribute(node, attrib);
1610 break;
1611 }
1612 }
1613 else
1614 {
1615 this.Core.ParseExtensionAttribute(node, attrib);
1616 }
1617 }
1618
1619 condition = this.Core.GetConditionInnerText(node);
1620
1621 if (null == control)
1622 {
1623 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Control"));
1624 }
1625
1626 if (null == dialog)
1627 {
1628 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Dialog"));
1629 }
1630
1631 if (null == controlEvent && null == property) // need to specify at least one
1632 {
1633 this.Core.Write(ErrorMessages.ExpectedAttributes(sourceLineNumbers, node.Name.LocalName, "Event", "Property"));
1634 }
1635 else if (null != controlEvent && null != property) // cannot specify both
1636 {
1637 this.Core.Write(ErrorMessages.IllegalAttributeWithOtherAttribute(sourceLineNumbers, node.Name.LocalName, "Event", "Property"));
1638 }
1639
1640 if (null == argument)
1641 {
1642 if (null != controlEvent)
1643 {
1644 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Value", "Event"));
1645 }
1646 else if (null != property)
1647 {
1648 // if this is setting a property to null, put a special value in the argument column
1649 argument = "{}";
1650 }
1651 }
1652
1653 this.Core.ParseForExtensionElements(node);
1654
1655 if (!this.Core.EncounteredError)
1656 {
1657 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.ControlEvent);
1658 row.Set(0, dialog);
1659 row.Set(1, control);
1660 row.Set(2, (null != controlEvent ? controlEvent : property));
1661 row.Set(3, argument);
1662 row.Set(4, condition);
1663 row.Set(5, order);
1664 }
1665
1666 if ("DoAction" == controlEvent && null != argument)
1667 {
1668 // if we're not looking at a standard action or a formatted string then create a reference
1669 // to the custom action.
1670 if (!WindowsInstallerStandard.IsStandardAction(argument) && !Common.ContainsProperty(argument))
1671 {
1672 this.Core.CreateSimpleReference(sourceLineNumbers, "CustomAction", argument);
1673 }
1674 }
1675
1676 // if we're referring to a dialog but not through a property, add it to the references
1677 if (("NewDialog" == controlEvent || "SpawnDialog" == controlEvent || "SpawnWaitDialog" == controlEvent || "SelectionBrowse" == controlEvent) && Common.IsIdentifier(argument))
1678 {
1679 this.Core.CreateSimpleReference(sourceLineNumbers, "Dialog", argument);
1680 }
1681 }
1682
1683 /// <summary>
1684 /// Parses a control subscription element.
1685 /// </summary>
1686 /// <param name="node">Element to parse.</param>
1687 /// <param name="dialog">Identifier of dialog.</param>
1688 /// <param name="control">Identifier of control.</param>
1689 private void ParseSubscribeElement(XElement node, string dialog, string control)
1690 {
1691 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
1692 string controlAttribute = null;
1693 string eventMapping = null;
1694
1695 foreach (var attrib in node.Attributes())
1696 {
1697 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
1698 {
1699 switch (attrib.Name.LocalName)
1700 {
1701 case "Attribute":
1702 controlAttribute = Compiler.UppercaseFirstChar(this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib));
1703 break;
1704 case "Event":
1705 eventMapping = Compiler.UppercaseFirstChar(this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib));
1706 break;
1707 default:
1708 this.Core.UnexpectedAttribute(node, attrib);
1709 break;
1710 }
1711 }
1712 else
1713 {
1714 this.Core.ParseExtensionAttribute(node, attrib);
1715 }
1716 }
1717
1718 this.Core.ParseForExtensionElements(node);
1719
1720 if (!this.Core.EncounteredError)
1721 {
1722 var row = this.Core.CreateRow(sourceLineNumbers, TupleDefinitionType.EventMapping);
1723 row.Set(0, dialog);
1724 row.Set(1, control);
1725 row.Set(2, eventMapping);
1726 row.Set(3, controlAttribute);
1727 }
1728 }
1729 }
1730}