Melhorias atributos tag "pack":
 - criado atributo "readonly" para a difinição dos pacotes;
 - suporte a valores variáveis (IzPack variable ou conditional) para
   os atributos de pacote "required", "preselected" e "readonly".

--- a/izpack-api/src/main/java/com/izforge/izpack/api/data/Pack.java
+++ b/izpack-api/src/main/java/com/izforge/izpack/api/data/Pack.java
@@ -110,6 +110,19 @@ public class Pack implements Serializable
     private boolean required;

     /**
+     * Original value for attribute "required" from "install-script.xml".
+     *
+     * How it works:
+     * Every time a panel is switched, the boolean value "required" will be revaluated based on this String original definition:
+     * <ul>
+     *      <li>if "yes"/"true" or "no"/"false", it will be converted to a boolean (it's a constant);</li>
+     *      <li>if starts with $ or ${}, it will be evaluated as a IzPack variable;</li>
+     *      <li>otherwise, it will be evaluated as a IzPack condition.</li>
+     * </ul>
+     */
+    private String requiredExpr;
+
+    /**
      * The size of the pack. This may include reserved space, independent of the size of the files.
      */
     private long size;
@@ -125,6 +138,37 @@ public class Pack implements Serializable
     private boolean preselected;

     /**
+     * Original value for attribute "preselected" from "install-script.xml".
+     *
+     * How it works:
+     * Every time a panel is switched, the boolean value "preselected" will be revaluated based on this String original definition:
+     * <ul>
+     *      <li>if "yes"/"true" or "no"/"false", it will be converted to a boolean (it's a constant);</li>
+     *      <li>if starts with $ or ${}, it will be evaluated as a IzPack variable;</li>
+     *      <li>otherwise, it will be evaluated as a IzPack condition.</li>
+     * </ul>
+     */
+    private String preselectedExpr;
+
+    /**
+     * Determines if the pack should be read only.
+     */
+    private boolean readonly;
+
+    /**
+     * Original value for attribute "readonly" from "install-script.xml".
+     *
+     * How it works:
+     * Every time a panel is switched, the boolean value "readonly" will be revaluated based on this String original definition:
+     * <ul>
+     *      <li>if "yes"/"true" or "no"/"false", it will be converted to a boolean (it's a constant);</li>
+     *      <li>if starts with $ or ${}, it will be evaluated as a IzPack variable;</li>
+     *      <li>otherwise, it will be evaluated as a IzPack condition.</li>
+     * </ul>
+     */
+    private String readonlyExpr;
+
+    /**
      * Parent pack name. May be {@code null}
      */
     private String parent;
@@ -336,6 +380,15 @@ public class Pack implements Serializable
         return required;
     }

+    public String getRequiredExpr()
+    {
+        return requiredExpr;
+    }
+
+    public void setRequired(boolean required) {
+        this.required = required;
+    }
+
     /**
      * Determines if the pack should be preselected for installation.
      *
@@ -346,6 +399,17 @@ public class Pack implements Serializable
         this.preselected = preselected;
     }

+
+    /**
+     * Determines if the pack should be read only.
+     *
+     * @param preselected if {@code true}, the pack should be read only
+     */
+    public void setReadonly(boolean readonly)
+    {
+        this.readonly = readonly;
+    }
+
     /**
      * Determines if the pack should be preselected for installation.
      *
@@ -356,6 +420,26 @@ public class Pack implements Serializable
         return preselected;
     }

+    public String getPreselectedExpr()
+    {
+        return preselectedExpr;
+    }
+
+    /**
+     * Determines if the pack should be read only.
+     *
+     * @return {@code true} if the pack should be read only
+     */
+    public boolean isReadonly()
+    {
+        return readonly;
+    }
+
+    public String getReadonlyExpr()
+    {
+        return readonlyExpr;
+    }
+
     /**
      * Determines if pack files are stored outside of the installation packages.
      *
@@ -640,4 +724,16 @@ public class Pack implements Serializable
         }
     }

+    public void setRequiredExpr(String requiredExpr) {
+        this.requiredExpr = requiredExpr;
+    }
+
+    public void setPreselectedExpr(String preselectedExpr) {
+        this.preselectedExpr = preselectedExpr;
+    }
+
+    public void setReadonlyExpr(String readonlyExpr) {
+        this.readonlyExpr = readonlyExpr;
+    }
+
 }

--- a/izpack-compiler/src/main/java/com/izforge/izpack/compiler/CompilerConfig.java
+++ b/izpack-compiler/src/main/java/com/izforge/izpack/compiler/CompilerConfig.java
@@ -743,10 +743,13 @@ public class CompilerConfig extends Thread

             boolean loose = Boolean.parseBoolean(packElement.getAttribute("loose", "false"));
             String description = xmlCompilerHelper.requireChildNamed(packElement, "description").getContent();
-            boolean required = xmlCompilerHelper.requireYesNoAttribute(packElement, "required");
+            boolean required = xmlCompilerHelper.requireYesNoAttributeDynamic(packElement, "required");
             String group = packElement.getAttribute("group");
             String installGroups = packElement.getAttribute("installGroups");
             String excludeGroup = packElement.getAttribute("excludeGroup");
+            String requiredExpr = packElement.getAttribute("required");
+            String preselectedExpr = packElement.getAttribute("preselected");
+            String readonlyExpr = packElement.getAttribute("readonly");
             boolean uninstall = "yes".equalsIgnoreCase(packElement.getAttribute("uninstall", "yes"));
             long size = xmlCompilerHelper.getLong(packElement, "size", 0);
             String parent = packElement.getAttribute("parent");
@@ -830,6 +833,10 @@ public class CompilerConfig extends Thread
                 pack.addValidator(type.getName());
             }

+            pack.setRequiredExpr(requiredExpr);
+            pack.setPreselectedExpr(preselectedExpr);
+            pack.setReadonlyExpr(readonlyExpr);
+
             // We add the pack
             packager.addPack(pack);
         }

--- a/izpack-compiler/src/main/java/com/izforge/izpack/compiler/helper/XmlCompilerHelper.java
+++ b/izpack-compiler/src/main/java/com/izforge/izpack/compiler/helper/XmlCompilerHelper.java
@@ -133,6 +133,12 @@ public class XmlCompilerHelper
         return validateYesNoAttribute(element, attribute, null);
     }

+    public boolean requireYesNoAttributeDynamic(IXMLElement element, String attribute)
+            throws CompilerException
+    {
+        return validateYesNoAttribute(element, attribute, false);
+    }
+
     /**
      * Call getAttribute on an element, producing a meaningful warning if not "yes" or "no". If the
      * 'element' or 'attribute' are null, the default value is returned.

--- a/izpack-installer/src/main/java/com/izforge/izpack/installer/console/ConsoleInstallAction.java
+++ b/izpack-installer/src/main/java/com/izforge/izpack/installer/console/ConsoleInstallAction.java
@@ -23,6 +23,7 @@ package com.izforge.izpack.installer.console;

 import com.izforge.izpack.api.data.InstallData;
 import com.izforge.izpack.installer.data.UninstallDataWriter;
+import com.izforge.izpack.installer.gui.InstallerFrame;
 import com.izforge.izpack.util.Console;

 /**
@@ -61,6 +62,7 @@ public class ConsoleInstallAction extends AbstractInstallAction
     public boolean run(ConsolePanelView panel)
     {
         ConsolePanel view = panel.getView();
+        InstallerFrame.revaluateDynamicAttributes(getInstallData());
         return view.run(getInstallData(), console);
     }

--- a/izpack-installer/src/main/java/com/izforge/izpack/installer/console/ConsoleInstaller.java
+++ b/izpack-installer/src/main/java/com/izforge/izpack/installer/console/ConsoleInstaller.java
@@ -35,6 +35,7 @@ import com.izforge.izpack.api.exception.IzPackException;
 import com.izforge.izpack.installer.base.InstallerBase;
 import com.izforge.izpack.installer.bootstrap.Installer;
 import com.izforge.izpack.installer.data.UninstallDataWriter;
+import com.izforge.izpack.installer.gui.InstallerFrame;
 import com.izforge.izpack.installer.requirement.RequirementsChecker;
 import com.izforge.izpack.util.Console;
 import com.izforge.izpack.util.Housekeeper;

--- a/izpack-installer/src/main/java/com/izforge/izpack/installer/gui/InstallerFrame.java
+++ b/izpack-installer/src/main/java/com/izforge/izpack/installer/gui/InstallerFrame.java
@@ -68,7 +68,9 @@ import com.izforge.izpack.api.adaptator.IXMLElement;
 import com.izforge.izpack.api.adaptator.IXMLWriter;
 import com.izforge.izpack.api.adaptator.impl.XMLWriter;
 import com.izforge.izpack.api.data.Info;
+import com.izforge.izpack.api.data.InstallData;
 import com.izforge.izpack.api.data.LocaleDatabase;
+import com.izforge.izpack.api.data.Pack;
 import com.izforge.izpack.api.data.Panel;
 import com.izforge.izpack.api.data.Variables;
 import com.izforge.izpack.api.event.ProgressListener;
@@ -535,6 +537,9 @@ public class InstallerFrame extends JFrame implements InstallerView
      */
     protected void switchPanel(IzPanelView newPanel, IzPanelView oldPanel)
     {
+
+        revaluateDynamicAttributes(newPanel.getInstallData());
+
         int oldIndex = (oldPanel != null) ? oldPanel.getIndex() : -1;
         logger.fine("Switching panel, old index is " + oldIndex);

@@ -629,6 +634,37 @@ public class InstallerFrame extends JFrame implements InstallerView
         }
     }

+    public static void revaluateDynamicAttributes(InstallData installData) {
+        List<Pack> packs = installData.getAllPacks();
+        // System.out.println("\nswitchPanel new: " + newPanel.getPanel().getClassName() + " ("+packs.size() + " packs) [");
+        if (packs != null) {
+            for (Pack pack : packs) {
+                // System.out.println(String.format("\tpack: %1$-25s req? %2$-25s pre? %3$-25s", pack.getLangPackId(), pack.isRequired(), pack.isPreselected()));
+                pack.setRequired(parseYesNoDynamic(pack.getRequiredExpr(), installData));
+                if (pack.getExcludeGroup() == null) {
+                    pack.setPreselected(parseYesNoDynamic(pack.getPreselectedExpr(), installData));
+                }
+                pack.setReadonly(parseYesNoDynamic(pack.getReadonlyExpr(), installData));
+                // System.out.println(String.format("\t      %1$-20s orig req? %2$-20s orig pre? %3$-25s", "", pack.getRequiredExpr(), pack.getPreselectedExpr()));
+                // System.out.println(String.format("\t      %1$-20s  new req? %2$-20s  new pre? %3$-25s", "", pack.isRequired(), pack.isPreselected()));
+            }
+        }
+        // System.out.println("]");
+    }
+
+    private static boolean parseYesNoDynamic(String expr, InstallData installData) {
+        if (expr == null) {
+            return false;
+        } else if (expr.equalsIgnoreCase("yes") || expr.equalsIgnoreCase("true")) {
+            return true;
+        } else if (expr.equalsIgnoreCase("no") || expr.equalsIgnoreCase("false")) {
+            return false;
+        } else if (expr.startsWith("${") && expr.endsWith("}")) {
+            return Boolean.parseBoolean(installData.getVariable(expr).substring(2, expr.length() - 1));
+        } else if (expr.startsWith("$")) {
+            return Boolean.parseBoolean(installData.getVariable(expr).substring(1));
+        }
+        return installData.getRules().getCondition(expr).isTrue();
+    }
+
     /**
      * Centers a window on screen.
      *

--- a/izpack-installer/src/main/java/com/izforge/izpack/installer/panel/AbstractPanelView.java
+++ b/izpack-installer/src/main/java/com/izforge/izpack/installer/panel/AbstractPanelView.java
@@ -537,4 +537,8 @@ public abstract class AbstractPanelView<T> implements PanelView<T>
         return message;
     }

+    public InstallData getInstallData() {
+        return this.installData;
+    }
+
 }
\ No newline at end of file

index 465e7c0..341800e 100755
--- a/izpack-panel/src/main/java/com/izforge/izpack/panels/packs/PacksPanelBase.java
+++ b/izpack-panel/src/main/java/com/izforge/izpack/panels/packs/PacksPanelBase.java
@@ -961,7 +961,7 @@ public abstract class PacksPanelBase extends IzPanel implements PacksPanelInterf
      *
      * @param row the row
      */
-    private void togglePack(int row)
+    protected void togglePack(int row)
     {
         Integer checked = (Integer) packsModel.getValueAt(row, 0);
         checked = (checked <= 0) ? 1 : 0;

--- a/izpack-util/src/main/java/com/izforge/izpack/data/PackInfo.java
+++ b/izpack-util/src/main/java/com/izforge/izpack/data/PackInfo.java
@@ -363,4 +363,17 @@ public class PackInfo implements Serializable
     {
         pack.addValidator(validatorClassName);
     }
+
+    public void setRequiredExpr(String requiredExpr) {
+        pack.setRequiredExpr(requiredExpr);
+    }
+
+    public void setPreselectedExpr(String preselectedExpr) {
+        pack.setPreselectedExpr(preselectedExpr);
+    }
+
+    public void setReadonlyExpr(String readonlyExpr) {
+        pack.setReadonlyExpr(readonlyExpr);
+    }
+
 }