[msitools: 6/11] wixl: parse nodes from user interface dialog files




commit 7bb9eec1f45c0c4ed8a97b3105ac8a78f5c3799a
Author: Brendon Jones <brendon jones gmail com>
Date:   Sun Sep 19 23:25:42 2021 +1200

    wixl: parse nodes from user interface dialog files

 tools/wixl/builder.vala | 458 +++++++++++++++++++++++++++++++++++++++++++++++-
 tools/wixl/wix.vala     | 277 +++++++++++++++++++++++++++++
 2 files changed, 726 insertions(+), 9 deletions(-)
---
diff --git a/tools/wixl/builder.vala b/tools/wixl/builder.vala
index 4ef9b4d..35e532f 100644
--- a/tools/wixl/builder.vala
+++ b/tools/wixl/builder.vala
@@ -18,6 +18,20 @@ namespace Wixl {
         public static Extension from_string(string s) throws GLib.Error {
             return enum_from_string<Extension> (s);
         }
+
+        public string get_dir () {
+            switch (this) {
+                case UI: return "ui";
+                default: return "";
+            };
+        }
+
+        public string to_string () {
+            switch (this) {
+                case UI: return "ui";
+                default: return "";
+            };
+        }
     }
 
     class WixBuilder: WixNodeVisitor, WixResolver {
@@ -70,6 +84,14 @@ namespace Wixl {
             }
         }
 
+        public void load_extension_file(Extension ext, string name) throws GLib.Error {
+            if (ext in extensions) {
+                load_file(File.new_build_filename (extdir, ext.get_dir(), name + ".wxs"));
+            } else {
+                throw new Wixl.Error.FAILED ("Can't load '%s': extension '%s' isn't enabled", name, 
ext.to_string());
+            }
+        }
+
         public void load_file (File file, bool preproc_only = false) throws GLib.Error {
             string data;
             FileUtils.get_contents (file.get_path (), out data);
@@ -797,23 +819,41 @@ namespace Wixl {
 
             if (action.name == "Custom")
                 action.name = action.Action;
+            if (action.name == "Show")
+                action.name = action.Dialog;
 
             var node = table.get_action (action.name);
-            warn_if_fail (node.action == null);
+
+            if ( node.action != null ) {
+                return;
+            }
+
             node.action = action;
 
-            if (action.Sequence != null)
-                node.sequence = int.parse (action.Sequence);
+            if (action.OnExit != null) {
+                if (action.OnExit == "success") node.sequence = -1;
+                if (action.OnExit == "cancel") node.sequence = -2;
+                if (action.OnExit == "error") node.sequence = -3;
+                if (action.OnExit == "suspend") node.sequence = -4;
+            } else {
+                if (action.Sequence != null) {
+                    node.sequence = int.parse (action.Sequence);
+                }
 
-            if (action.After != null)
-                node.add_dep (table.get_action (action.After));
+                if (action.After != null) {
+                    node.add_dep (table.get_action (action.After));
+                }
 
-            if (action.Before != null) {
-                var before = table.get_action (action.Before);
-                before.add_dep (node);
+                if (action.Before != null) {
+                    var before = table.get_action (action.Before);
+                    before.add_dep (node);
+                }
             }
 
-            if (action.children.length () > 0) {
+            // set condition from either an attribute or inner text
+            if (action.Condition != null) {
+                node.condition = action.Condition;
+            } else if (action.children.length () > 0) {
                 return_if_fail (action.children.length () == 1);
                 var text = action.children.first ().data as WixText;
                 node.condition = text.Text;
@@ -1183,6 +1223,406 @@ namespace Wixl {
             media.Id = "1";
             visit_media (media);
         }
+
+        public override void visit_ui_ref (WixUIRef ref) throws GLib.Error {
+            if (find_element<WixUI>(@ref.Id) == null) {
+                load_extension_file(Extension.UI, @ref.Id);
+            }
+        }
+
+        public override void visit_ui_text (WixUIText text) throws GLib.Error {
+            db.table_ui_text.add (text.Id, text.Value);
+        }
+
+        public override void visit_text_element (WixTextElement text) throws GLib.Error {
+            // set the Text value of the parent control
+            var control = text.parent as WixControl;
+
+            if (text.SourceFile != null) {
+                // use the contents of the given file
+                string data;
+                File file = find_file (text.SourceFile, null);
+                FileUtils.get_contents (file.get_path (), out data);
+                control.Text = data;
+            } else if (text.children.length () > 0) {
+                // use the inner text from this element
+                return_if_fail (text.children.length () == 1);
+                var node = text.children.first ().data as WixText;
+                control.Text = node.Text;
+            }
+        }
+
+        [Flags]
+        enum TextStyleBits {
+            BOLD = 1 << 0,
+            ITALIC = 1 << 1,
+            UNDERLINE = 1 << 2,
+            STRIKE = 1 << 3,
+        }
+
+        public override void visit_text_style (WixTextStyle style) throws GLib.Error {
+            int? color = null;
+            TextStyleBits bits = 0;
+
+            if (style.Blue != null || style.Green != null ||
+                    style.Red != null) {
+
+                color = 0;
+
+                if (style.Blue != null)
+                    color += 65536 * int.parse (style.Blue);
+                if (style.Green != null)
+                    color += 256 * int.parse (style.Green);
+                if (style.Red != null)
+                    color += int.parse (style.Red);
+            }
+
+            if (parse_yesno (style.Bold))
+                bits |= TextStyleBits.BOLD;
+            if (parse_yesno (style.Italic))
+                bits |= TextStyleBits.ITALIC;
+            if (parse_yesno (style.Underline))
+                bits |= TextStyleBits.UNDERLINE;
+            if (parse_yesno (style.Strike))
+                bits |= TextStyleBits.STRIKE;
+
+            db.table_text_style.add (style.Id, style.FaceName,
+                    int.parse (style.Size), color, bits);
+        }
+
+        [Flags]
+        enum DialogStyleBits {
+            VISIBLE = 1 << 0,
+            MODAL = 1 << 1,
+            MINIMIZE = 1 << 2,
+            SYS_MODAL = 1 << 3,
+            KEEP_MODELESS = 1 << 4,
+            TRACK_DISK_SPACE = 1 << 5,
+            USE_CUSTOM_PALETTE = 1 << 6,
+            RTLRO = 1 << 7,
+            RIGHT_ALIGNED = 1 << 8,
+            LEFT_SCROLL = 1 << 9,
+            BIDI = RTLRO | RIGHT_ALIGNED | LEFT_SCROLL,
+            ERROR = 1 << 16,
+        }
+
+        public override void visit_dialog (WixDialog dialog) throws GLib.Error {
+            int hcenter = 50;
+            int vcenter = 50;
+            int attributes = 0;
+            int width = int.parse (dialog.Width);
+            int height = int.parse (dialog.Height);
+
+            if (!parse_yesno (dialog.Hidden))
+                attributes |= DialogStyleBits.VISIBLE;
+            if (!parse_yesno (dialog.Modeless))
+                attributes |= DialogStyleBits.MODAL;
+            if (!parse_yesno (dialog.NoMinimize))
+                attributes |= DialogStyleBits.MINIMIZE;
+            if (parse_yesno (dialog.KeepModeless))
+                attributes |= DialogStyleBits.KEEP_MODELESS;
+            if (parse_yesno (dialog.TrackDiskSpace))
+                attributes |= DialogStyleBits.TRACK_DISK_SPACE;
+            if (parse_yesno (dialog.CustomPalette))
+                attributes |= DialogStyleBits.USE_CUSTOM_PALETTE;
+            if (parse_yesno (dialog.RightToLeft))
+                attributes |= DialogStyleBits.RTLRO;
+            if (parse_yesno (dialog.RightAligned))
+                attributes |= DialogStyleBits.RIGHT_ALIGNED;
+            if (parse_yesno (dialog.LeftScroll))
+                attributes |= DialogStyleBits.LEFT_SCROLL;
+            if (parse_yesno (dialog.ErrorDialog))
+                attributes |= DialogStyleBits.ERROR;
+
+            WixControl first = dialog.children.first().data as WixControl;
+
+            db.table_dialog.add (dialog.Id, hcenter, vcenter, width, height,
+                    attributes, dialog.Title, first.Id,
+                    dialog.Default, dialog.Cancel);
+
+            // do this after we know what all the children are, which means
+            // keeping a reference to the record so it can be updated in place
+
+            // loop over all the children and update the tab selection order
+            // of the controls, ignoring some controls
+            WixControl? firsttab = null;
+            WixControl? prevtab = null;
+
+            foreach (var child in dialog.children) {
+                var control = child as WixControl;
+
+                if (control.Type != "Bitmap" && control.Type != "CheckBox" &&
+                        control.Type != "PushButton" &&
+                        control.Type != "RadioButtonGroup") {
+                    continue;
+                }
+
+                if (control.TabSkip != null && parse_yesno (control.TabSkip)) {
+                    continue;
+                }
+
+                if (firsttab == null) {
+                    firsttab = control;
+                }
+
+                if (prevtab != null) {
+                    db.table_control.set_next_control (prevtab.record, control.Id);
+                }
+
+                prevtab = control;
+            }
+
+            if (prevtab != null && firsttab != null && prevtab != firsttab) {
+                db.table_control.set_next_control (prevtab.record, firsttab.Id);
+            }
+        }
+
+        public override void visit_dialog_ref (WixDialogRef ref) throws GLib.Error {
+            if (find_element<WixDialog>(@ref.Id) == null) {
+                load_extension_file(Extension.UI, @ref.Id);
+            }
+        }
+
+        [Flags]
+        enum ControlAttributes {
+            BIDI = 0xE0,
+            ENABLED = 0x02,
+            INDIRECT = 0x08,
+            INTEGER_CONTROL = 0x10,
+            LEFT_SCROLL = 0x80,
+            RIGHT_ALIGNED = 0x40,
+            RTLRO = 0x20,
+            SUNKEN = 0x04,
+            VISIBLE = 0x01,
+            // Text
+            FORMAT_SIZE = 0x080000,
+            NO_PREFIX = 0x020000,
+            NO_WRAP = 0x040000,
+            PASSWORD = 0x200000,
+            TRANSPARENT = 0x010000,
+            USERS_LANGUAGE = 0x100000,
+            // ProgressBar
+            PROGRESS_95 = 0x010000,
+            // Volume and Directory
+            FIXED_VOLUME = 0x020000,
+            REMOTE_VOLUME = 0x040000,
+            // PictureButton
+            BITMAP = 0x040000,
+            FIXED_SIZE = 0x100000,
+            ICON = 0x080000,
+            ICON_SIZE_16 = 0x200000,
+            ICON_SIZE_32 = 0x400000,
+            ICON_SIZE_48 = 0x600000,
+            // PushButton
+            ELEVATION_SHIELD = 0x800000,
+            // VolumeCostList
+            SHOW_ROLLBACK_COST = 0x00400000,
+        }
+
+        public override void visit_control (WixControl control) throws GLib.Error {
+            int attributes = 0;
+            int x = 100;
+            int y = 100;
+            int width = 500;
+            int height = 500;
+            string? filename = null;
+            string help;
+
+            if (!(control.parent is WixDialog)) {
+                error ("unhandled parent type %s", control.parent.name);
+            }
+
+            // static controls don't need to be enabled
+            if (control.Type != "Line" && control.Type != "Bitmap" &&
+                    control.Type != "Icon") {
+                if (!parse_yesno (control.Disabled))
+                    attributes |= ControlAttributes.ENABLED;
+            }
+            if (parse_yesno (control.Sunken))
+                attributes |= ControlAttributes.SUNKEN;
+            if (!parse_yesno (control.Hidden))
+                attributes |= ControlAttributes.VISIBLE;
+
+            // Text
+            if (parse_yesno (control.NoPrefix))
+                attributes |= ControlAttributes.NO_PREFIX;
+            if (parse_yesno (control.Transparent))
+                attributes |= ControlAttributes.TRANSPARENT;
+
+            // ProgressBar
+            if (parse_yesno (control.ProgressBlocks))
+                attributes |= ControlAttributes.PROGRESS_95;
+
+            // Volume and Directory
+            if (parse_yesno (control.Fixed))
+                attributes |= ControlAttributes.FIXED_VOLUME;
+
+            // PictureButton
+            if (control.IconSize != null) {
+                if (control.IconSize == "16") {
+                    attributes |= ControlAttributes.ICON_SIZE_16;
+                } else if (control.IconSize == "32") {
+                    attributes |= ControlAttributes.ICON_SIZE_32;
+                } else if (control.IconSize == "48") {
+                    attributes |= ControlAttributes.ICON_SIZE_48;
+                }
+            }
+            if (parse_yesno (control.FixedSize))
+                attributes |= ControlAttributes.FIXED_SIZE;
+
+            // PushButton
+            if (parse_yesno (control.ElevationShield))
+                attributes |= ControlAttributes.ELEVATION_SHIELD;
+
+            // VolumeCostList
+            if (parse_yesno (control.ShowRollbackCost))
+                attributes |= ControlAttributes.SHOW_ROLLBACK_COST;
+
+            if (control.X != null)
+                x = int.parse (control.X);
+            if (control.Y != null)
+                y = int.parse (control.Y);
+
+            if (control.Width != null)
+                width = int.parse (control.Width);
+            if (control.Height != null)
+                height = int.parse (control.Height);
+
+            help = control.ToolTip + "|";
+
+            if ( control.file != null ) {
+                filename = control.file.get_path();
+            }
+
+            if (control.Default != null && parse_yesno (control.Default)) {
+                if (control.parent is WixDialog) {
+                    var parent = control.parent as WixDialog;
+                    parent.Default = control.Id;
+                }
+            }
+
+            if (control.Cancel != null && parse_yesno (control.Cancel)) {
+                if (control.parent is WixDialog) {
+                    var parent = control.parent as WixDialog;
+                    parent.Cancel = control.Id;
+                }
+            }
+
+            if (control.DefaultCondition != null) {
+                var parent = control.parent as WixDialog;
+                db.table_control_condition.add (parent.Id, control.Id,
+                        "Default", control.DefaultCondition);
+            }
+
+            if (control.DisableCondition != null) {
+                var parent = control.parent as WixDialog;
+                db.table_control_condition.add (parent.Id, control.Id,
+                        "Disable", control.DisableCondition);
+            }
+
+            if (control.EnableCondition != null) {
+                var parent = control.parent as WixDialog;
+                db.table_control_condition.add (parent.Id, control.Id,
+                        "Enable", control.EnableCondition);
+            }
+
+            if (control.HideCondition != null) {
+                var parent = control.parent as WixDialog;
+                db.table_control_condition.add (parent.Id, control.Id,
+                        "Hide", control.HideCondition);
+            }
+
+            if (control.ShowCondition != null) {
+                var parent = control.parent as WixDialog;
+                db.table_control_condition.add (parent.Id, control.Id,
+                        "Show", control.ShowCondition);
+            }
+
+            var rec = db.table_control.add (control.parent.Id, control.Id,
+                    control.Type, x, y, width, height, attributes,
+                    control.Property, control.Text, filename, null);
+
+            // save the record so we can update the control tab order later
+            control.record = rec;
+
+            // also attach the property to the relevant control table
+            if ( control.Type == "CheckBox" ) {
+                db.table_check_box.add (control.Property, control.CheckBoxValue);
+            }
+        }
+
+        public override void visit_publish (WixPublish publish) throws GLib.Error {
+            int order;
+            string control;
+            string dialog;
+            string event;
+            string argument = null;
+            string condition = "1";
+
+            if (publish.parent is WixUI) {
+                control = publish.Control;
+                dialog = publish.Dialog;
+
+                if (find_element<WixDialog>(dialog) == null) {
+                    load_extension_file(Extension.UI, dialog);
+                }
+            } else {
+                control = (publish.parent as WixControl).Id;
+                dialog = (publish.parent.parent as WixDialog).Id;
+            }
+
+            if (publish.Property != null) {
+                event = "[%s]".printf (publish.Property);
+                if (publish.Value != null) {
+                    argument = publish.Value;
+                } else {
+                    argument = "{}";
+                }
+            } else {
+                event = publish.Event;
+                argument = publish.Value;
+            }
+
+            if (publish.Condition != null) {
+                condition = publish.Condition;
+            }
+
+            if (publish.Order != null) {
+                // use the next integer if nested under control
+                order = int.parse (publish.Order);
+                WixPublish.order = order + 1;
+            } else {
+                // use the given value and update the next value
+                order = WixPublish.order++;
+            }
+
+            db.table_control_event.add (dialog, control, event, argument,
+                    condition, order);
+        }
+
+        public override void visit_radio_button (WixRadioButton radio) throws GLib.Error {
+            string property;
+            int order;
+
+            property = (radio.parent as WixRadioButtonGroup).Property;
+            order = (radio.parent as WixRadioButtonGroup).order++;
+
+            db.table_radio_button.add (property, order, radio.Value,
+                    int.parse (radio.X), int.parse (radio.Y),
+                    int.parse (radio.Width), int.parse (radio.Height),
+                    radio.Text, radio.Help);
+        }
+
+        public override void visit_subscribe (WixSubscribe subscribe) throws GLib.Error {
+            string control;
+            string dialog;
+
+            dialog = (subscribe.parent.parent as WixDialog).Id;
+            control = (subscribe.parent as WixControl).Id;
+
+            db.table_event_mapping.add (dialog, control,
+                    subscribe.Event, subscribe.Attribute);
+        }
     }
 
 } // Wixl
diff --git a/tools/wixl/wix.vala b/tools/wixl/wix.vala
index 6f28254..9df8623 100644
--- a/tools/wixl/wix.vala
+++ b/tools/wixl/wix.vala
@@ -66,6 +66,16 @@ namespace Wixl {
         public abstract void visit_binary (WixBinary binary) throws GLib.Error;
         public abstract void visit_major_upgrade (WixMajorUpgrade major) throws GLib.Error;
         public abstract void visit_media_template (WixMediaTemplate media) throws GLib.Error;
+        public abstract void visit_ui_ref (WixUIRef ref) throws GLib.Error;
+        public abstract void visit_ui_text (WixUIText text) throws GLib.Error;
+        public abstract void visit_text_element (WixTextElement text) throws GLib.Error;
+        public abstract void visit_text_style (WixTextStyle style) throws GLib.Error;
+        public abstract void visit_dialog (WixDialog dialog) throws GLib.Error;
+        public abstract void visit_dialog_ref (WixDialogRef ref) throws GLib.Error;
+        public abstract void visit_control (WixControl control) throws GLib.Error;
+        public abstract void visit_publish (WixPublish publish) throws GLib.Error;
+        public abstract void visit_radio_button (WixRadioButton radio) throws GLib.Error;
+        public abstract void visit_subscribe (WixSubscribe subscribe) throws GLib.Error;
     }
 
     public abstract class WixNode: Object {
@@ -280,6 +290,10 @@ namespace Wixl {
                 typeof (WixDirectory),
                 typeof (WixDirectoryRef),
                 typeof (WixComponentGroup),
+                typeof (WixBinary),
+                typeof (WixUI),
+                typeof (WixUIRef),
+                typeof (WixInstallUISequence),
             });
         }
 
@@ -315,6 +329,7 @@ namespace Wixl {
         }
 
         public string Value { get; set; }
+        public string Secure { get; set; }
 
         public override void accept (WixNodeVisitor visitor) throws GLib.Error {
             base.accept (visitor);
@@ -690,6 +705,11 @@ namespace Wixl {
         public string Sequence { get; set; }
         public string Suppress { get; set; }
         public string Action { get; set; }
+        public string Dialog { get; set; }
+        public string OnExit { get; set; }
+
+        // not in the specification, but used by layouts?
+        public string Condition { get; set; }
 
         public override void load (Xml.Node *node) throws Wixl.Error {
             base.load (node);
@@ -1012,6 +1032,7 @@ namespace Wixl {
                 typeof (WixBinary),
                 typeof (WixMajorUpgrade),
                 typeof (WixMediaTemplate),
+                typeof (WixUIRef),
             });
         }
 
@@ -1158,6 +1179,262 @@ namespace Wixl {
         }
     }
 
+    public class WixUI: WixElement {
+        static construct {
+            name = "UI";
+
+            add_child_types (child_types, {
+                typeof (WixBinary),
+                typeof (WixDialog),
+                typeof (WixDialogRef),
+                typeof (WixProperty),
+                typeof (WixPublish),
+                typeof (WixTextStyle),
+                typeof (WixUIRef),
+                typeof (WixUIText),
+                typeof (WixAdminUISequence),
+                typeof (WixInstallUISequence),
+            });
+        }
+    }
+
+    public class WixUIRef: WixElementRef<WixUI> {
+        static construct {
+            name = "UIRef";
+            ref_type = typeof (WixUI);
+        }
+
+        public override string full_path (WixResolver r) throws GLib.Error {
+            return ((WixElement)r.resolve<WixUI> (this)).full_path (r);
+        }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_ui_ref (this);
+        }
+    }
+
+    public class WixUIText: WixElement {
+        static construct {
+            name = "UIText";
+        }
+
+        public string Value { get; set; }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_ui_text (this);
+        }
+    }
+
+    // note that this is different to the WixText node type
+    public class WixTextElement: WixElement {
+        static construct {
+            name = "Text";
+        }
+
+        public string SourceFile { get; set; }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_text_element (this);
+        }
+    }
+
+    public class WixTextStyle: WixElement {
+        static construct {
+            name = "TextStyle";
+        }
+
+        public string Blue { get; set; }
+        public string Bold { get; set; }
+        public string FaceName { get; set; }
+        public string Green { get; set; }
+        public string Italic { get; set; }
+        public string Red { get; set; }
+        public string Size { get; set; }
+        public string Strike { get; set; }
+        public string Underline { get; set; }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_text_style (this);
+        }
+    }
+
+    public class WixDialog: WixElement {
+        static construct {
+            name = "Dialog";
+
+            add_child_types (child_types, {
+                typeof (WixControl),
+            });
+        }
+
+        public string CustomPalette { get; set; }
+        public string ErrorDialog { get; set; }
+        public string Height { get; set; }
+        public string Hidden { get; set; }
+        public string KeepModeless { get; set; }
+        public string LeftScroll { get; set; }
+        public string Modeless { get; set; }
+        public string NoMinimize { get; set; }
+        public string RightAligned { get; set; }
+        public string RightToLeft { get; set; }
+        public string Title { get; set; }
+        public string TrackDiskSpace { get; set; }
+        public string Width { get; set; }
+
+        // child controls can set themselves as the default or cancel action
+        public string Default;
+        public string Cancel;
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            base.accept (visitor);
+            visitor.visit_dialog (this);
+        }
+    }
+
+    public class WixDialogRef: WixElementRef<WixDialog> {
+        static construct {
+            name = "DialogRef";
+            ref_type = typeof (WixDialog);
+        }
+
+        public override string full_path (WixResolver r) throws GLib.Error {
+            return ((WixElement)r.resolve<WixDialog> (this)).full_path (r);
+        }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_dialog_ref (this);
+        }
+    }
+
+    public class WixControl: WixElement {
+        static construct {
+            name = "Control";
+
+            add_child_types (child_types, {
+                typeof (WixPublish),
+                typeof (WixRadioButtonGroup),
+                typeof (WixSubscribe),
+                typeof (WixTextElement),
+            });
+        }
+
+        public string Bitmap { get; set; }
+        public string Cancel { get; set; }
+        public string CheckBoxValue { get; set; }
+        public string Default { get; set; }
+        public string Disabled { get; set; }
+        public string ElevationShield { get; set; }
+        public string Fixed { get; set; }
+        public string FixedSize { get; set; }
+        public string Height { get; set; }
+        public string Hidden { get; set; }
+        public string IconSize { get; set; }
+        public string NoPrefix { get; set; }
+        public string ProgressBlocks { get; set; }
+        public string Property { get; set; }
+        public string Remote { get; set; }
+        public string ShowRollbackCost { get; set; }
+        public string Sunken { get; set; }
+        public string TabSkip { get; set; }
+        public string Text { get; set; }
+        public string ToolTip { get; set; }
+        public string Transparent { get; set; }
+        public string Type { get; set; }
+        public string Width { get; set; }
+        public string X { get; set; }
+        public string Y { get; set; }
+
+        // the specification suggests these should be in a child <Condition>
+        // element but they are used as attributes in all the layouts
+        public string DefaultCondition { get; set; }
+        public string DisableCondition { get; set; }
+        public string EnableCondition { get; set; }
+        public string HideCondition { get; set; }
+        public string ShowCondition { get; set; }
+
+        // the text attribute can be populated from a child <Text>, which
+        // itself could come from a file
+        public File file;
+
+        // updating the tab order involves a later pass through all the
+        // controls, so keep a reference to the record so it can be updated
+        public Libmsi.Record record;
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            base.accept (visitor);
+            visitor.visit_control (this);
+        }
+    }
+
+    public class WixPublish: WixElement {
+        static construct {
+            name = "Publish";
+        }
+
+        // if it isn't set then the default value should be one greater than
+        // any previous <Publish> element's order, so keep track
+        public static int order = 1;
+
+        public string Control { get; set; }
+        public string Dialog { get; set; }
+        public string Event { get; set; }
+        public string Order { get; set; }
+        public string Property { get; set; }
+        public string Value { get; set; }
+
+        // the specification suggests this should be the inner text but it's
+        // also used as an attribute in some of the layouts
+        public string Condition { get; set; }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_publish (this);
+        }
+    }
+
+    public class WixRadioButtonGroup: WixElement {
+        static construct {
+            name = "RadioButtonGroup";
+
+            add_child_types (child_types, {
+                typeof (WixRadioButton),
+            });
+        }
+
+        public string Property { get; set; }
+        public int order = 1;
+    }
+
+    public class WixRadioButton: WixElement {
+        static construct {
+            name = "RadioButton";
+        }
+
+        public string Height { get; set; }
+        public string Help { get; set; }
+        public string Text { get; set; }
+        public string Value { get; set; }
+        public string Width { get; set; }
+        public string X { get; set; }
+        public string Y { get; set; }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_radio_button (this);
+        }
+    }
+
+    public class WixSubscribe: WixElement {
+        static construct {
+            name = "Subscribe";
+        }
+
+        public string Attribute { get; set; }
+        public string Event { get; set; }
+
+        public override void accept (WixNodeVisitor visitor) throws GLib.Error {
+            visitor.visit_subscribe (this);
+        }
+    }
+
     class WixRoot: WixElement {
         static construct {
             name = "Wix";


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]