#At file:///C:/src/bzr.mysql/wex/installer/ based on revid:iggy@stripped
375 Iggy Galarza 2011-03-21 [merge]
Auto-Merge.
modified:
WexInstaller.Core/Package.cs
WexInstaller.Core/Product.cs
WexInstaller.Core/ProductFeature.cs
WexInstaller.Core/ProductManager.cs
WexInstaller/Controls/FeatureBox.cs
WexInstaller/Controls/FeatureTreeView.cs
WexInstaller/InstallWizard/InstallProgressPanel.cs
=== modified file 'WexInstaller.Core/Package.cs'
--- a/WexInstaller.Core/Package.cs 2011-03-18 10:29:04 +0000
+++ b/WexInstaller.Core/Package.cs 2011-03-21 10:34:56 +0000
@@ -4,394 +4,398 @@ using System.Diagnostics;
using System.IO;
using System.Text;
using System.Xml.Serialization;
+
using Microsoft.Win32;
namespace WexInstaller.Core
{
- public class Package
- {
- private string packageCode;
- private FileVersionInfo msiVersion;
-
- [XmlAttribute("type")]
- public PackageType Type { get; set; }
+ public class Package
+ {
+ private string packageCode;
+ private FileVersionInfo msiVersion;
+
+ [XmlAttribute("type")]
+ public PackageType Type { get; set; }
- [XmlAttribute("arch")]
- public PackageArchitecture Architecture { get; set; }
+ [XmlAttribute("arch")]
+ public PackageArchitecture Architecture { get; set; }
- [XmlAttribute("filename")]
- public string FileName { get; set; }
+ [XmlAttribute("filename")]
+ public string FileName { get; set; }
- [XmlAttribute("id")]
- public string Id
- {
- get { return packageCode; }
- set { packageCode = value; UpdateOptionalParameters(); }
- }
+ [XmlAttribute("id")]
+ public string Id
+ {
+ get { return packageCode; }
+ set { packageCode = value; UpdateOptionalParameters(); }
+ }
- [XmlAttribute("thisVersion")]
- public string ThisVersion { get; set; }
+ [XmlAttribute("thisVersion")]
+ public string ThisVersion { get; set; }
- [XmlElement("Feature")]
- public List<ProductFeature> Features { get; set; }
+ [XmlElement("Feature")]
+ public List<ProductFeature> Features { get; set; }
- [XmlIgnore]
- public string UrlBase { get; set; }
+ [XmlIgnore]
+ public string UrlBase { get; set; }
- [XmlIgnore]
- public string FullPath { get { return InstallerConfiguration.ProductCachePath + FileName; } }
+ [XmlIgnore]
+ public string FullPath { get { return InstallerConfiguration.ProductCachePath + FileName; } }
- [XmlIgnore]
- public string RemotePath
+ [XmlIgnore]
+ public string RemotePath
+ {
+ get
+ {
+ string remoteURL = String.Empty;
+ if (String.IsNullOrEmpty(UrlBase) == false)
{
- get
- {
- string remoteURL = String.Empty;
- if (String.IsNullOrEmpty(UrlBase) == false)
- {
- if (UrlBase.Contains("http:"))
- {
- remoteURL = String.Format("{0}/{1}", UrlBase, FileName);
- }
- else
- {
- remoteURL = String.Format("http://downloads.mysql.com/archives/{0}", UrlBase);
- if (!remoteURL.EndsWith("/"))
- {
- remoteURL += "/";
- }
- remoteURL += FileName;
- }
- }
- return remoteURL;
- }
+ if (UrlBase.Contains("http:"))
+ remoteURL = String.Format("{0}/{1}", UrlBase, FileName);
+ else
+ {
+ remoteURL = String.Format("http://downloads.mysql.com/archives/{0}", UrlBase);
+ if (!remoteURL.EndsWith("/"))
+ remoteURL += "/";
+ remoteURL += FileName;
+ }
}
+ return remoteURL;
+ }
+ }
- [XmlIgnore]
- public string TempFileName { get { return String.Format("{0}.temp", FullPath); } }
+ [XmlIgnore]
+ public string TempFileName { get { return String.Format("{0}.temp", FullPath); } }
- [XmlIgnore]
- public string DisplayName { get; set; }
+ [XmlIgnore]
+ public string DisplayName { get; set; }
- [XmlIgnore]
- public string Publisher { get; set; }
+ [XmlIgnore]
+ public string Publisher { get; set; }
- [XmlIgnore]
- public string MSICache { get; set; }
+ [XmlIgnore]
+ public string MSICache { get; set; }
- [XmlIgnore]
- public bool Installed { get { return (DisplayName != String.Empty); } }
+ [XmlIgnore]
+ public bool Installed { get { return (DisplayName != String.Empty); } }
- [XmlIgnore]
- public bool FoundLocal { get { return File.Exists(FullPath); } }
+ [XmlIgnore]
+ public bool FoundLocal { get { return File.Exists(FullPath); } }
- [XmlIgnore]
- public Dictionary<string, string> RegistryEntries { get; set; }
+ [XmlIgnore]
+ public Dictionary<string, string> RegistryEntries { get; set; }
- [XmlIgnore]
- public int FeatureCount
+ [XmlIgnore]
+ public int FeatureCount
+ {
+ get
+ {
+ int count = 0;
+ foreach (ProductFeature f in Features)
{
- get
- {
- int count = 0;
- foreach (ProductFeature f in Features)
- {
- count++;
- count += f.FeatureCount;
- }
- return count;
- }
+ count++; // TODO: Does the package itself count as feature?
+ count += f.FeatureCount;
}
+ return count;
+ }
+ }
- public Package()
- {
- RegistryEntries = new Dictionary<string, string>();
- Features = new List<ProductFeature>();
- DisplayName = String.Empty;
- Publisher = String.Empty;
- MSICache = String.Empty;
- msiVersion = FileVersionInfo.GetVersionInfo(Environment.SystemDirectory + "\\msi.dll");
- }
+ /// <summary>
+ /// Returns all child and grand child features.
+ /// </summary>
+ [XmlIgnore]
+ public List<ProductFeature> AllFeatures
+ {
+ get
+ {
+ List<ProductFeature> result = new List<ProductFeature>();
+ foreach (ProductFeature feature in Features)
+ result.AddRange(feature.AllFeatures);
+ return result;
+ }
+ }
- private string GetMSIProductInfo(string propertyName)
- {
- int productInfoLength = 512;
- StringBuilder productInfo = new StringBuilder(productInfoLength);
- MSIEnumError status = MsiInterop.MsiGetProductInfo(Id, propertyName, productInfo, ref productInfoLength);
+ public Package()
+ {
+ RegistryEntries = new Dictionary<string, string>();
+ Features = new List<ProductFeature>();
+ DisplayName = String.Empty;
+ Publisher = String.Empty;
+ MSICache = String.Empty;
+ msiVersion = FileVersionInfo.GetVersionInfo(Environment.SystemDirectory + "\\msi.dll");
+ }
- return (status == MSIEnumError.Success) ? productInfo.ToString() : String.Empty;
- }
+ private string GetMSIProductInfo(string propertyName)
+ {
+ int productInfoLength = 512;
+ StringBuilder productInfo = new StringBuilder(productInfoLength);
+ MSIEnumError status = MsiInterop.MsiGetProductInfo(Id, propertyName, productInfo, ref productInfoLength);
- public bool UpdateOptionalParameters()
- {
- bool success = false;
+ return (status == MSIEnumError.Success) ? productInfo.ToString() : String.Empty;
+ }
- if (Id != String.Empty)
- {
- DisplayName = GetMSIProductInfo("ProductName");
- Publisher = GetMSIProductInfo("Publisher");
- MSICache = GetMSIProductInfo("LocalPackage");
- if (ThisVersion == null)
- ThisVersion = GetMSIProductInfo("VersionString");
- if (FileName == null)
- FileName = GetMSIProductInfo("PackageName");
+ public bool UpdateOptionalParameters()
+ {
+ bool success = false;
- if (DisplayName != String.Empty && Publisher != String.Empty)
- {
- if (RegistryEntries.Count > 0)
- RegistryEntries.Clear();
+ if (Id != String.Empty)
+ {
+ DisplayName = GetMSIProductInfo("ProductName");
+ Publisher = GetMSIProductInfo("Publisher");
+ MSICache = GetMSIProductInfo("LocalPackage");
+ if (ThisVersion == null)
+ ThisVersion = GetMSIProductInfo("VersionString");
+ if (FileName == null)
+ FileName = GetMSIProductInfo("PackageName");
- // Open registry and fetch all the keys and their values into a local dictionary.
- RegistryKey packageKey = Registry.LocalMachine;
- packageKey = packageKey.OpenSubKey("SOFTWARE\\");
- if (Architecture == PackageArchitecture.X86)
- {
- // Try to open the 32-bit Subkey.
- try
- {
- RegistryKey tempKey = packageKey.OpenSubKey("Wow6432Node\\");
- if (tempKey != null)
- packageKey = tempKey;
- }
- catch
- {
- // This fails when running on a 32 bit machine or OS version < Vista
- }
- }
-
- RegistryKey publisherKey = packageKey.OpenSubKey(String.Format("{0}\\{1}", Publisher, DisplayName), false);
- if (publisherKey != null)
- {
- packageKey = publisherKey;
- }
- else
- {
- packageKey = packageKey.OpenSubKey(String.Format("{0}\\{1}", "MySQL AB", DisplayName), false);
- if (packageKey != null)
- Publisher = "MySQL AB";
- }
-
- if (packageKey != null)
- {
- foreach (string valuename in packageKey.GetValueNames())
- {
- RegistryEntries.Add(valuename, packageKey.GetValue(valuename).ToString());
- }
- packageKey.Close();
- }
- }
+ if (DisplayName != String.Empty && Publisher != String.Empty)
+ {
+ if (RegistryEntries.Count > 0)
+ RegistryEntries.Clear();
+
+ // Open registry and fetch all the keys and their values into a local dictionary.
+ RegistryKey packageKey = Registry.LocalMachine;
+ packageKey = packageKey.OpenSubKey("SOFTWARE\\");
+ if (Architecture == PackageArchitecture.X86)
+ {
+ // Try to open the 32-bit Subkey.
+ try
+ {
+ RegistryKey tempKey = packageKey.OpenSubKey("Wow6432Node\\");
+ if (tempKey != null)
+ packageKey = tempKey;
}
- else
+ catch
{
- DisplayName = String.Empty;
+ // This fails when running on a 32 bit machine or OS version < Vista
}
+ }
- return success;
+ RegistryKey publisherKey = packageKey.OpenSubKey(String.Format("{0}\\{1}", Publisher, DisplayName), false);
+ if (publisherKey != null)
+ packageKey = publisherKey;
+ else
+ {
+ packageKey = packageKey.OpenSubKey(String.Format("{0}\\{1}", "MySQL AB", DisplayName), false);
+ if (packageKey != null)
+ Publisher = "MySQL AB";
+ }
+
+ if (packageKey != null)
+ {
+ foreach (string valuename in packageKey.GetValueNames())
+ RegistryEntries.Add(valuename, packageKey.GetValue(valuename).ToString());
+ packageKey.Close();
+ }
}
+ }
+ else
+ DisplayName = String.Empty;
- public long GetInstallationSizeEstimate()
- {
- long defaultBase = 0;
-
- if (FoundLocal)
- {
- // Disable MSI UI.
- InstallUILevel internalUILevel = InstallUILevel.None;
-
- if (msiVersion.FileMajorPart >= 5)
- {
- // Allow to installer to elevate, even in silent mode
- internalUILevel |= InstallUILevel.UACOnly;
- }
- MsiInterop.MsiSetInternalUI(internalUILevel, IntPtr.Zero);
-
- UIntPtr packageHandle = UIntPtr.Zero;
- uint retVal = MsiInterop.MsiOpenPackage(FullPath, ref packageHandle);
+ return success;
+ }
- if (retVal == 0)
- {
- uint results = 0;
- results += MsiInterop.MsiDoAction(packageHandle, "CostInitialize");
- results += MsiInterop.MsiDoAction(packageHandle, "FileCost");
- results += MsiInterop.MsiDoAction(packageHandle, "CostFinalize");
- results += MsiInterop.MsiDoAction(packageHandle, "InstallValidate");
- // The EstimateSize is not available until after the InstallValidate action is complete.
-
- if (results == 0)
- {
- // Now, you can find the estimated size per feature.
- foreach (ProductFeature f in Features)
- {
- int cost = 0;
- if (MsiInterop.MsiGetFeatureCost(packageHandle, f.Name, MSICostTree.Self, InstallState.Source, out cost) == 0)
- if (cost != -2147483648) // Null value returned when EstimateSize is uninitialized.
- f.SizeEstimate = cost * 512 * 1024; // Number of bytes
- defaultBase += f.SizeEstimate;
-
- foreach (ProductFeature f1 in f.Features)
- {
- int cost1 = 0;
- if (MsiInterop.MsiGetFeatureCost(packageHandle, f1.Name, MSICostTree.Self, InstallState.Source, out cost1) == 0)
- if (cost != -2147483648)
- f1.SizeEstimate = cost1 * 512 * 1024; // Number of bytes
- defaultBase += f1.SizeEstimate;
- }
- }
- }
- else
- {
- // Invalid package.
- }
- }
+ public long GetInstallationSizeEstimate()
+ {
+ long defaultBase = 0;
- MsiInterop.MsiCloseHandle(packageHandle);
- }
+ if (FoundLocal)
+ {
+ // Disable MSI UI.
+ InstallUILevel internalUILevel = InstallUILevel.None;
- return defaultBase;
+ if (msiVersion.FileMajorPart >= 5)
+ {
+ // Allow to installer to elevate, even in silent mode
+ internalUILevel |= InstallUILevel.UACOnly;
}
+ MsiInterop.MsiSetInternalUI(internalUILevel, IntPtr.Zero);
+
+ UIntPtr packageHandle = UIntPtr.Zero;
+ uint retVal = MsiInterop.MsiOpenPackage(FullPath, ref packageHandle);
- private void ProcessFeatures(List<ProductFeature> toAdd, List<ProductFeature> toRemove)
+ if (retVal == 0)
{
+ uint results = 0;
+ results += MsiInterop.MsiDoAction(packageHandle, "CostInitialize");
+ results += MsiInterop.MsiDoAction(packageHandle, "FileCost");
+ results += MsiInterop.MsiDoAction(packageHandle, "CostFinalize");
+ results += MsiInterop.MsiDoAction(packageHandle, "InstallValidate");
+ // The EstimateSize is not available until after the InstallValidate action is complete.
+
+ if (results == 0)
+ {
+ // Now, you can find the estimated size per feature.
foreach (ProductFeature f in Features)
{
- if (f.Installed != f.ProposedInstalled)
- {
- if (!f.Installed) toAdd.Add(f);
- else toRemove.Add(f);
- }
- f.ProcessFeatures(toAdd, toRemove);
+ int cost = 0;
+ if (MsiInterop.MsiGetFeatureCost(packageHandle, f.Name, MSICostTree.Self, InstallState.Source, out cost) == 0)
+ if (cost != -2147483648) // Null value returned when EstimateSize is uninitialized.
+ f.SizeEstimate = cost * 512 * 1024; // Number of bytes
+ defaultBase += f.SizeEstimate;
+
+ foreach (ProductFeature f1 in f.Features)
+ {
+ int cost1 = 0;
+ if (MsiInterop.MsiGetFeatureCost(packageHandle, f1.Name, MSICostTree.Self, InstallState.Source, out cost1) == 0)
+ if (cost != -2147483648)
+ f1.SizeEstimate = cost1 * 512 * 1024; // Number of bytes
+ defaultBase += f1.SizeEstimate;
+ }
}
+ }
+ else
+ {
+ // Invalid package.
+ }
}
- public string GetCommandLine()
- {
- List<ProductFeature> toAdd = new List<ProductFeature>();
- List<ProductFeature> toRemove = new List<ProductFeature>();
+ MsiInterop.MsiCloseHandle(packageHandle);
+ }
- ProcessFeatures(toAdd, toRemove);
- if (toAdd.Count == FeatureCount && toRemove.Count == 0)
- return "ADDLOCAL=ALL";
- else if (toAdd.Count == 0 && toRemove.Count == FeatureCount)
- return "REMOVE=ALL";
- else
- {
- StringBuilder cmdLine = new StringBuilder();
- if (toAdd.Count > 0)
- {
- cmdLine.Append("ADDLOCAL=");
- string delimiter = "";
- foreach (ProductFeature f in toAdd)
- {
- cmdLine.AppendFormat("{0}{1}", delimiter, f.Name);
- delimiter = ",";
- }
- cmdLine.Append(" ");
- }
- if (toRemove.Count > 0)
- {
- cmdLine.Append("REMOVE=");
- string delimiter = "";
- foreach (ProductFeature f in toRemove)
- {
- cmdLine.AppendFormat("{0}{1}", delimiter, f.Name);
- delimiter = ",";
- }
- }
- return cmdLine.ToString();
- }
- }
+ return defaultBase;
+ }
- public void PostInitialize()
+ private void ProcessFeatures(List<ProductFeature> toAdd, List<ProductFeature> toRemove)
+ {
+ foreach (ProductFeature f in Features)
+ {
+ if (f.Installed != f.ProposedInstalled)
{
- if (String.IsNullOrEmpty(Id) == false) // Valid Package.
- {
- // Synchronize Installed Feature state.
- StringBuilder FeatureCode = new StringBuilder(256);
- StringBuilder ParentCode = new StringBuilder(256);
- MSIEnumError rc = MSIEnumError.Success;
- uint CurrentIndex = 0;
-
- do
- {
- if (FeatureCode.Length > 0)
- {
- foreach (ProductFeature pf in Features)
- {
- if (pf.Name == FeatureCode.ToString())
- {
- InstallState currentState = MsiInterop.MsiQueryFeatureState(Id, FeatureCode.ToString());
- pf.Installed = (currentState == InstallState.Local);
- pf.ProposedInstalled = pf.Installed;
- break;
- }
-
- if (ParentCode.Length > 0)
- {
- if (pf.Name == ParentCode.ToString())
- {
- foreach (ProductFeature cf in pf.Features)
- {
- if (cf.Name == FeatureCode.ToString())
- {
- InstallState currentState = MsiInterop.MsiQueryFeatureState(Id, FeatureCode.ToString());
- cf.Installed = (currentState == InstallState.Local);
- cf.ProposedInstalled = cf.Installed;
- break;
- }
- }
- }
- }
- }
- ParentCode.Remove(0, ParentCode.Length);
- FeatureCode.Remove(0, FeatureCode.Length);
- }
-
-
- try
- {
- rc = (MSIEnumError)MsiInterop.MsiEnumFeatures(Id, CurrentIndex++, FeatureCode, ParentCode);
- }
- catch (Exception e)
- {
- Logger.LogException(e);
- }
- }
- while (rc == MSIEnumError.Success);
-
- if (rc != MSIEnumError.NoMoreItems)
- {
- // Record the real error.
- Logger.LogError(String.Format("Found error: {0}", rc.ToString()));
- }
- }
+ if (!f.Installed)
+ toAdd.Add(f);
+ else
+ toRemove.Add(f);
}
+ f.ProcessFeatures(toAdd, toRemove);
+ }
}
- public enum PackageType
+ public string GetCommandLine()
{
- MSI
- }
+ List<ProductFeature> toAdd = new List<ProductFeature>();
+ List<ProductFeature> toRemove = new List<ProductFeature>();
- public enum PackageArchitecture
- {
- X86,
- X64,
- Any
+ ProcessFeatures(toAdd, toRemove);
+ if (toAdd.Count == FeatureCount && toRemove.Count == 0)
+ return "ADDLOCAL=ALL";
+ else if (toAdd.Count == 0 && toRemove.Count == FeatureCount)
+ return "REMOVE=ALL";
+ else
+ {
+ StringBuilder cmdLine = new StringBuilder();
+ if (toAdd.Count > 0)
+ {
+ cmdLine.Append("ADDLOCAL=");
+ string delimiter = "";
+ foreach (ProductFeature f in toAdd)
+ {
+ cmdLine.AppendFormat("{0}{1}", delimiter, f.Name);
+ delimiter = ",";
+ }
+ cmdLine.Append(" ");
+ }
+ if (toRemove.Count > 0)
+ {
+ cmdLine.Append("REMOVE=");
+ string delimiter = "";
+ foreach (ProductFeature f in toRemove)
+ {
+ cmdLine.AppendFormat("{0}{1}", delimiter, f.Name);
+ delimiter = ",";
+ }
+ }
+ return cmdLine.ToString();
+ }
}
- public enum PackagePlatform
+ public void PostInitialize()
{
- Windows,
- Any
- }
+ if (String.IsNullOrEmpty(Id) == false) // Valid Package.
+ {
+ // Synchronize Installed Feature state.
+ StringBuilder FeatureCode = new StringBuilder(256);
+ StringBuilder ParentCode = new StringBuilder(256);
+ MSIEnumError rc = MSIEnumError.Success;
+ uint CurrentIndex = 0;
- public enum PackageMaturity
- {
- CTP,
- Alpha,
- Beta,
- RC,
- GA
+ do
+ {
+ if (FeatureCode.Length > 0)
+ {
+ foreach (ProductFeature pf in Features)
+ {
+ if (pf.Name == FeatureCode.ToString())
+ {
+ InstallState currentState = MsiInterop.MsiQueryFeatureState(Id, FeatureCode.ToString());
+ pf.Installed = (currentState == InstallState.Local);
+ pf.ProposedInstalled = pf.Installed;
+ break;
+ }
+
+ if (ParentCode.Length > 0 && (pf.Name == ParentCode.ToString()))
+ {
+ foreach (ProductFeature cf in pf.Features)
+ {
+ if (cf.Name == FeatureCode.ToString())
+ {
+ InstallState currentState = MsiInterop.MsiQueryFeatureState(Id, FeatureCode.ToString());
+ cf.Installed = (currentState == InstallState.Local);
+ cf.ProposedInstalled = cf.Installed;
+ break;
+ }
+ }
+ }
+ }
+ ParentCode.Remove(0, ParentCode.Length);
+ FeatureCode.Remove(0, FeatureCode.Length);
+ }
+
+ try
+ {
+ rc = (MSIEnumError)MsiInterop.MsiEnumFeatures(Id, CurrentIndex++, FeatureCode, ParentCode);
+ }
+ catch (Exception e)
+ {
+ Logger.LogException(e);
+ }
+ }
+ while (rc == MSIEnumError.Success);
+
+ if (rc != MSIEnumError.NoMoreItems)
+ {
+ // Record the real error.
+ Logger.LogError(String.Format("Found error: {0}", rc.ToString()));
+ }
+ }
}
+ }
+
+ public enum PackageType
+ {
+ MSI
+ }
+
+ public enum PackageArchitecture
+ {
+ X86,
+ X64,
+ Any
+ }
+
+ public enum PackagePlatform
+ {
+ Windows,
+ Any
+ }
+
+ public enum PackageMaturity
+ {
+ CTP,
+ Alpha,
+ Beta,
+ RC,
+ GA
+ }
}
=== modified file 'WexInstaller.Core/Product.cs'
--- a/WexInstaller.Core/Product.cs 2011-03-18 10:29:04 +0000
+++ b/WexInstaller.Core/Product.cs 2011-03-21 12:59:48 +0000
@@ -229,7 +229,7 @@ namespace WexInstaller.Core
{
bool hasChanges;
hasChanges = Installed != ProposedInstalled;
- foreach (ProductFeature feature in GetPackage().Features)
+ foreach (ProductFeature feature in GetPackage().AllFeatures)
hasChanges |= feature.HasChanges();
return hasChanges;
}
@@ -251,12 +251,24 @@ namespace WexInstaller.Core
return keyValue;
}
+ /// <summary>
+ /// Returns all direct features of a product.
+ /// </summary>
public List<ProductFeature> GetProductFeatures()
{
Package pack = GetPackage();
return pack.Features;
}
+ /// <summary>
+ /// Returns all features for a product, including their sub-features.
+ /// </summary>
+ public List<ProductFeature> GetAllProductFeatures()
+ {
+ Package pack = GetPackage();
+ return pack.AllFeatures;
+ }
+
// MSI Installation in a background worker thread.
private void ChainedInstallerUpdated(object sender, ChainedInstallerEventArgs c)
{
@@ -480,16 +492,58 @@ namespace WexInstaller.Core
return;
}
+ private enum ChangeType { Unknown, Installation, Update, Removal }
+
+ /// <summary>
+ /// Applies all the changes the user has selected.
+ /// Note: only one type of change can be processed at a time (update, installation, removal).
+ /// </summary>
public void MakeChanges()
{
- if (Installed && ProposedInstalled)
- Update();
- else
- if (!Installed && ProposedInstalled)
- Install();
+ ChangeType type = ChangeType.Unknown;
+
+ // First check the product as a whole for the change type.
+ if (Installed || ProposedInstalled)
+ {
+ if (Installed)
+ if (ProposedInstalled)
+ type = ChangeType.Update;
+ else
+ type = ChangeType.Removal;
else
- if (Installed && !ProposedInstalled)
- Remove();
+ type = ChangeType.Installation;
+ }
+
+ // If there was no change for the product as such go through the features to find changes.
+ if (type == ChangeType.Unknown)
+ {
+ foreach (ProductFeature feature in GetAllProductFeatures())
+ if (feature.Installed || feature.ProposedInstalled)
+ {
+ // We only look for the first change in the feature list, whatever it is and
+ // determine our next action from that.
+ if (feature.Installed)
+ if (feature.ProposedInstalled)
+ type = ChangeType.Update;
+ else
+ type = ChangeType.Removal;
+ else
+ type = ChangeType.Installation;
+ }
+ }
+
+ switch (type)
+ {
+ case ChangeType.Installation:
+ Install();
+ break;
+ case ChangeType.Removal:
+ Remove();
+ break;
+ case ChangeType.Update:
+ Update();
+ break;
+ }
}
public long GetInstallationSizeEstimate()
=== modified file 'WexInstaller.Core/ProductFeature.cs'
--- a/WexInstaller.Core/ProductFeature.cs 2011-03-18 10:29:04 +0000
+++ b/WexInstaller.Core/ProductFeature.cs 2011-03-21 10:34:56 +0000
@@ -125,6 +125,22 @@ namespace WexInstaller.Core
}
}
+ /// <summary>
+ /// Returns all child and grand child features.
+ /// </summary>
+ [XmlIgnore]
+ public List<ProductFeature> AllFeatures
+ {
+ get
+ {
+ List<ProductFeature> result = new List<ProductFeature>();
+ result.Add(this);
+ foreach (ProductFeature feature in Features)
+ result.AddRange(feature.AllFeatures);
+ return result;
+ }
+ }
+
public ProductFeature()
{
Features = new List<ProductFeature>();
=== modified file 'WexInstaller.Core/ProductManager.cs'
--- a/WexInstaller.Core/ProductManager.cs 2011-03-18 18:08:07 +0000
+++ b/WexInstaller.Core/ProductManager.cs 2011-03-21 15:29:28 +0000
@@ -82,6 +82,8 @@ namespace WexInstaller.Core
{
p.PostInitialize(true);
p.SetParent(pc);
+ foreach (ProductFeature feature in p.GetProductFeatures())
+ feature.SetParent(p);
// Initialize the controller if there are any
if (p.Controller != null)
=== modified file 'WexInstaller/Controls/FeatureBox.cs'
--- a/WexInstaller/Controls/FeatureBox.cs 2011-03-18 17:04:52 +0000
+++ b/WexInstaller/Controls/FeatureBox.cs 2011-03-21 10:02:47 +0000
@@ -34,7 +34,20 @@ namespace WexInstaller.Controls
#region Properties
- internal FeatureTreeView FeatureTree { get; set; }
+ private FeatureTreeView featureTreeview = null;
+ internal FeatureTreeView FeatureTree
+ {
+ get { return featureTreeview; }
+ set
+ {
+ if (featureTreeview != null)
+ featureTreeview.ProductInstallationProposalChanged -= featureTreeview_ProductInstallationProposalChanged;
+ featureTreeview = value;
+ if (featureTreeview != null)
+ featureTreeview.ProductInstallationProposalChanged +=
+ new EventHandler<FeatureTreeView.ProductChangedEventArgs>(featureTreeview_ProductInstallationProposalChanged);
+ }
+ }
public ProductElement SelectedObject
{
@@ -173,7 +186,7 @@ namespace WexInstaller.Controls
}
}
- // No iterate over all categories and their products and see if any of the products matches
+ // Now iterate over all categories and their products and see if any of the products matches
// any of the products in the reference catalog(s).
Dictionary<string, Product> products = new Dictionary<string, Product>();
foreach (Product p in category.Products)
@@ -190,6 +203,17 @@ namespace WexInstaller.Controls
return result;
}
+ private void InvalidateCheckbox(TreeNode child)
+ {
+ // The checkbox place is before the text centered in an area twice as wide as
+ // the checkbox itself.
+ Rectangle checkBoxRectangle = new Rectangle();
+ checkBoxRectangle.Location = new Point(CBGlyphSize.Width / 2,
+ child.Bounds.Top + ((featureList.ItemHeight - CBGlyphSize.Height) / 2));
+ checkBoxRectangle.Size = CBGlyphSize;
+ featureList.Invalidate(checkBoxRectangle);
+ }
+
#endregion
#region Drawing
@@ -225,33 +249,6 @@ namespace WexInstaller.Controls
g.DrawString(SelectedObject.Description, smallFont, blackBrush, textPt);
}
- #endregion
-
- #region Event handling
-
- private void featureList_AfterCheck(object sender, TreeViewEventArgs e)
- {
- Product p = e.Node.Tag as Product;
- if (p != null)
- {
- if (p.Installed)
- return;
- p.ProposedInstalled = !p.ProposedInstalled;
-
- List<ProductFeature> productFeatures = p.GetProductFeatures();
- foreach (ProductFeature pf in productFeatures)
- pf.ProposedInstalled = p.ProposedInstalled;
- }
- else
- {
- ProductFeature pf = e.Node.Tag as ProductFeature;
- pf.ProposedInstalled = !pf.ProposedInstalled;
- }
- featureList.Refresh();
- if (FeatureTree != null)
- FeatureTree.Refresh();
- }
-
private void featureList_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
if (e.Bounds.Width <= 0 || e.Bounds.Height <= 0)
@@ -287,5 +284,60 @@ namespace WexInstaller.Controls
#endregion
+ #region Event handling
+
+ private void featureList_AfterCheck(object sender, TreeViewEventArgs e)
+ {
+ Product p = e.Node.Tag as Product;
+ if (p != null)
+ {
+ if (p.Installed)
+ return;
+ p.ProposedInstalled = !p.ProposedInstalled;
+
+ List<ProductFeature> productFeatures = p.GetProductFeatures();
+ foreach (ProductFeature pf in productFeatures)
+ pf.ProposedInstalled = p.ProposedInstalled;
+
+ InvalidateCheckbox(e.Node); // Redraw only the single node whose state was changed.
+ }
+ else
+ {
+ ProductFeature pf = e.Node.Tag as ProductFeature;
+ pf.ProposedInstalled = !pf.ProposedInstalled;
+
+ // Check if at least one (visible) product feature for the owning product is proposed for installation.
+ // If so set also all invisible features too. Otherwise remove invisible features from the
+ // installation list so that the entire product is set to no-installation.
+ ProductElement element = pf;
+ do
+ {
+ element = element.Parent;
+ } while (element != null && !(element is Product));
+
+ if (element is Product)
+ {
+ Product product = element as Product;
+ bool anyFeatureInstalled = false;
+ foreach (TreeNode node in featureList.Nodes)
+ anyFeatureInstalled |= (node.Tag as ProductFeature).ProposedInstalled;
+ foreach (ProductFeature feature in product.GetProductFeatures())
+ if (feature.Display == "0") // Invisible feature.
+ feature.ProposedInstalled = anyFeatureInstalled;
+ }
+
+ featureList.Invalidate(); // There can be sub features that changed state too, so redraw everything.
+ }
+ if (FeatureTree != null)
+ FeatureTree.Invalidate();
+ }
+
+ void featureTreeview_ProductInstallationProposalChanged(object sender, FeatureTreeView.ProductChangedEventArgs e)
+ {
+ featureList.Invalidate();
+ }
+
+ #endregion
+
}
}
=== modified file 'WexInstaller/Controls/FeatureTreeView.cs'
--- a/WexInstaller/Controls/FeatureTreeView.cs 2011-03-18 17:04:52 +0000
+++ b/WexInstaller/Controls/FeatureTreeView.cs 2011-03-21 10:34:56 +0000
@@ -1,4 +1,5 @@
-using System.Collections.Generic;
+using System;
+using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.VisualStyles;
@@ -19,6 +20,16 @@ namespace WexInstaller.Controls
public CatalogArchitecture Architecture { get; set; }
+ public class ProductChangedEventArgs : EventArgs
+ {
+ public ProductChangedEventArgs(Product product)
+ {
+ this.Product = product;
+ }
+
+ public Product Product{ get; set; }
+ }
+
#endregion
#region Construction and setup
@@ -127,6 +138,8 @@ namespace WexInstaller.Controls
foreach (ProductFeature pf in productFeatures)
pf.ProposedInstalled = doInstall;
+
+ OnProductInstallationProposalChanged(p);
}
private CheckBoxState GetNodeCheckboxState(TreeNode node)
@@ -162,7 +175,7 @@ namespace WexInstaller.Controls
private CheckBoxState GetStateForProduct(Product p)
{
- List<ProductFeature> productFeatures = p.GetProductFeatures();
+ List<ProductFeature> productFeatures = p.GetAllProductFeatures();
CheckBoxState state;
if (productFeatures.Count > 0)
state = GetStateFromFeatureList(productFeatures);
@@ -382,6 +395,16 @@ namespace WexInstaller.Controls
base.OnNodeMouseClick(e);
}
+ public event EventHandler<ProductChangedEventArgs> ProductInstallationProposalChanged;
+ protected internal void OnProductInstallationProposalChanged(Product product)
+ {
+ if (ProductInstallationProposalChanged != null)
+ {
+ ProductChangedEventArgs args = new ProductChangedEventArgs(product);
+ ProductInstallationProposalChanged(this, args);
+ }
+ }
+
#endregion
private void InitializeComponent()
=== modified file 'WexInstaller/InstallWizard/InstallProgressPanel.cs'
--- a/WexInstaller/InstallWizard/InstallProgressPanel.cs 2011-03-10 18:30:35 +0000
+++ b/WexInstaller/InstallWizard/InstallProgressPanel.cs 2011-03-21 12:59:48 +0000
@@ -59,7 +59,6 @@ namespace WexInstaller
if (!finished)
{
started = false;
- nextOk = true;
progressLevels.Clear();
NextButton.Text = Properties.Resources.NextButtonExecuteText;
}
@@ -72,7 +71,8 @@ namespace WexInstaller
{
foreach (Product p in pc.Products)
{
- if (p.IsUpgrade || (p.ProposedInstalled && p.HasChanges()))
+ //if (p.IsUpgrade || (p.ProposedInstalled && p.HasChanges()))
+ if (p.IsUpgrade || p.HasChanges())
{
if (!p.FoundLocal)
leftToDownload++;
@@ -95,6 +95,8 @@ namespace WexInstaller
}
leftToInstall = productList.Items.Count;
+ nextOk = leftToInstall > 0;
+
base.Activate();
}
@@ -319,7 +321,20 @@ namespace WexInstaller
Resources.ContinueAfterDownloadErrorText, Resources.ConfirmContinueTitle,
MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation);
if (answer == DialogResult.Yes)
+ {
+ // Disable all try-again links before starting the installation.
+ foreach (ListViewItem item in productList.Items)
+ {
+ Product product = item.Tag as Product;
+ if ((product.CurrentState == ProductState.DownloadError) ||
+ (product.CurrentState == ProductState.DownloadCancelled) ||
+ (product.CurrentState == ProductState.DownloadNoMirror))
+ {
+ item.SubItems[3].Text = "--";
+ }
+ }
BeginInvoke(new MethodInvoker(InstallNextPackage));
+ }
}
}
}
Attachment: [text/bzr-bundle] bzr/iggy@mysql.com-20110321152928-bwc47fymydaeyb78.bundle
| Thread |
|---|
| • bzr commit into wex-installer-1.0 branch (iggy:375) | Iggy Galarza | 21 Mar |