You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
451 lines
13 KiB
451 lines
13 KiB
// <file> |
|
// <copyright see="prj:///doc/copyright.txt"/> |
|
// <license see="prj:///doc/license.txt"/> |
|
// <owner name="Matthew Ward" email="mrward@users.sourceforge.net"/> |
|
// <version>$Revision$</version> |
|
// </file> |
|
|
|
using System; |
|
using System.IO; |
|
using System.Xml; |
|
|
|
using ICSharpCode.SharpDevelop.Project; |
|
|
|
namespace ICSharpCode.WixBinding |
|
{ |
|
/// <summary> |
|
/// Class that is responsible for editing the installer package files in the |
|
/// WiX source file. |
|
/// </summary> |
|
public class WixPackageFilesEditor |
|
{ |
|
IWixPackageFilesView view; |
|
ITextFileReader fileReader; |
|
IWixDocumentWriter documentWriter; |
|
IDirectoryReader directoryReader; |
|
static WixDocument document; |
|
WixSchemaCompletionData wixSchemaCompletionData; |
|
bool usingRootDirectoryRef; |
|
ExcludedNames excludedNames = new ExcludedNames(); |
|
|
|
/// <summary> |
|
/// Creates a new instance of the WixPackageFilesEditor. |
|
/// </summary> |
|
/// <param name="view">The UI for the package files editor.</param> |
|
/// <param name="fileReader">The file reader hides the file system and the |
|
/// workbench from the editor so the class can be easily tested.</param> |
|
/// <param name="documentWriter">The file writer hides the file system and the |
|
/// workbench from the editor.</param> |
|
/// <param name="directoryReader">The directory reader hides the file system |
|
/// from the editor.</param> |
|
public WixPackageFilesEditor(IWixPackageFilesView view, ITextFileReader fileReader, IWixDocumentWriter documentWriter, IDirectoryReader directoryReader) |
|
{ |
|
document = null; |
|
this.view = view; |
|
this.fileReader = fileReader; |
|
this.documentWriter = documentWriter; |
|
this.directoryReader = directoryReader; |
|
} |
|
|
|
/// <summary> |
|
/// Creates a new instance of the WixPackageFilesEditor which uses |
|
/// the default directory reader which just uses the Directory class. |
|
/// </summary> |
|
public WixPackageFilesEditor(IWixPackageFilesView view, ITextFileReader fileReader, IWixDocumentWriter documentWriter) |
|
: this(view, fileReader, documentWriter, new DirectoryReader()) |
|
{ |
|
} |
|
|
|
/// <summary> |
|
/// Displays the setup files for the specified WixProject. |
|
/// </summary> |
|
public void ShowFiles(WixProject project) |
|
{ |
|
// Look for Wix document containing root directory. |
|
document = null; |
|
if (project.WixSourceFiles.Count > 0) { |
|
bool errors = false; |
|
WixDocument currentDocument = null; |
|
view.ClearDirectories(); |
|
foreach (FileProjectItem item in project.WixSourceFiles) { |
|
try { |
|
currentDocument = CreateWixDocument(item.FileName); |
|
FindRootDirectoryResult result = FindRootDirectory(currentDocument); |
|
if (result == FindRootDirectoryResult.RootDirectoryRefFound) { |
|
break; |
|
} |
|
} catch (XmlException) { |
|
errors = true; |
|
} |
|
} |
|
if (errors) { |
|
view.ShowSourceFilesContainErrorsMessage(); |
|
} else if (document == null) { |
|
view.ShowNoSourceFileFoundMessage(project.Name); |
|
} else { |
|
SelectedElementChanged(); |
|
} |
|
} else { |
|
view.ShowNoSourceFileFoundMessage(project.Name); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Gets the Wix document containing the package files information. |
|
/// </summary> |
|
public WixDocument Document { |
|
get { |
|
return document; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Saves changes made to the document. |
|
/// </summary> |
|
public void Save() |
|
{ |
|
if (view.IsDirty) { |
|
documentWriter.Write(document); |
|
view.IsDirty = false; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// The item has been selected in the view. |
|
/// </summary> |
|
public void SelectedElementChanged() |
|
{ |
|
XmlElement element = view.SelectedElement; |
|
view.AllowedChildElements.Clear(); |
|
view.Attributes.Clear(); |
|
if (element != null) { |
|
view.Attributes.AddRange(WixSchemaCompletionData.GetAttributes(element)); |
|
view.AllowedChildElements.AddRange(WixSchemaCompletionData.GetChildElements(element.Name)); |
|
} else { |
|
view.AllowedChildElements.Add("Directory"); |
|
} |
|
view.AttributesChanged(); |
|
} |
|
|
|
/// <summary> |
|
/// The attribute value has changed. |
|
/// </summary> |
|
public void AttributeChanged() |
|
{ |
|
view.IsDirty = true; |
|
UpdateChangedAttributes(view.SelectedElement); |
|
} |
|
|
|
/// <summary> |
|
/// Adds a new element. |
|
/// </summary> |
|
public void AddElement(string name) |
|
{ |
|
XmlElement parentElement = view.SelectedElement; |
|
XmlElement element = null; |
|
switch (name) { |
|
case WixDirectoryElement.DirectoryElementName: |
|
element = AddDirectory(parentElement as WixDirectoryElement); |
|
break; |
|
case WixComponentElement.ComponentElementName: |
|
element = AddComponent(parentElement as WixDirectoryElement, "NewComponent"); |
|
break; |
|
default: |
|
element = AddElement(parentElement, name); |
|
break; |
|
} |
|
|
|
if (element != null) { |
|
AddElementToView(element); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Removes the selected element. |
|
/// </summary> |
|
public void RemoveElement() |
|
{ |
|
XmlElement element = view.SelectedElement; |
|
if (element != null) { |
|
XmlElement parentElement = (XmlElement)element.ParentNode; |
|
parentElement.RemoveChild(element); |
|
view.RemoveElement(element); |
|
view.IsDirty = true; |
|
SelectedElementChanged(); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Adds the specified files to the selected element. |
|
/// </summary> |
|
public void AddFiles(string[] fileNames) |
|
{ |
|
foreach (string fileName in fileNames) { |
|
AddFile(fileName); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Adds the specified directory to the selected element. This |
|
/// adds all the contained files and subdirectories recursively to the |
|
/// setup package. |
|
/// </summary> |
|
public void AddDirectory(string directory) |
|
{ |
|
WixDirectoryElement parentElement = (WixDirectoryElement)view.SelectedElement; |
|
|
|
// Add directory. |
|
string directoryName = WixDirectoryElement.GetLastDirectoryName(directory); |
|
WixDirectoryElement directoryElement = AddDirectory(parentElement, directoryName); |
|
AddFiles(directoryElement, directory); |
|
|
|
// Adds directory contents recursively. |
|
AddDirectoryContents(directoryElement, directory); |
|
|
|
AddElementToView(directoryElement); |
|
} |
|
|
|
/// <summary> |
|
/// List of files and directory names that will be excluded when |
|
/// adding a directory to the package. |
|
/// </summary> |
|
public ExcludedNames ExcludedItems { |
|
get { |
|
return excludedNames; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Works out any differences betweent the files specified in |
|
/// the Wix document and the files on the file system and |
|
/// shows the differences. |
|
/// </summary> |
|
public void ShowDiff() |
|
{ |
|
WixPackageFilesDiff diff = new WixPackageFilesDiff(directoryReader); |
|
diff.ExcludedFileNames.Add(excludedNames); |
|
|
|
WixDirectoryElementBase directoryElement = view.SelectedElement as WixDirectoryElementBase; |
|
if (directoryElement == null) { |
|
directoryElement = RootDirectoryElement; |
|
} |
|
|
|
// Directory element selected? |
|
if (directoryElement == null) { |
|
view.ShowNoDifferenceFoundMessage(); |
|
return; |
|
} |
|
|
|
// Show diff results |
|
WixPackageFilesDiffResult[] diffResults = diff.Compare(directoryElement); |
|
if (diffResults.Length > 0) { |
|
view.ShowDiffResults(diffResults); |
|
} else { |
|
view.ShowNoDifferenceFoundMessage(); |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Adds a single file to the selected component element. |
|
/// </summary> |
|
void AddFile(string fileName) |
|
{ |
|
WixComponentElement componentElement = view.SelectedElement as WixComponentElement; |
|
if (componentElement != null) { |
|
WixFileElement fileElement = AddFile(componentElement, fileName); |
|
view.AddElement(fileElement); |
|
view.IsDirty = true; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Adds a file to the specified component element. |
|
/// </summary> |
|
WixFileElement AddFile(WixComponentElement componentElement, string fileName) |
|
{ |
|
WixFileElement fileElement = componentElement.AddFile(fileName); |
|
if (!componentElement.HasDiskId) { |
|
componentElement.DiskId = "1"; |
|
} |
|
return fileElement; |
|
} |
|
|
|
/// <summary> |
|
/// Updates the attribute values for the element. |
|
/// </summary> |
|
void UpdateChangedAttributes(XmlElement changedElement) |
|
{ |
|
if (changedElement != null) { |
|
foreach (WixXmlAttribute attribute in view.Attributes) { |
|
if (String.IsNullOrEmpty(attribute.Value)) { |
|
changedElement.RemoveAttribute(attribute.Name); |
|
} else { |
|
changedElement.SetAttribute(attribute.Name, attribute.Value); |
|
} |
|
} |
|
} |
|
} |
|
|
|
WixDocument CreateWixDocument(string fileName) |
|
{ |
|
WixDocument doc = new WixDocument(); |
|
doc.Load(fileReader.Create(fileName)); |
|
doc.FileName = fileName; |
|
return doc; |
|
} |
|
|
|
/// <summary> |
|
/// Adds a new directory to the specified element. |
|
/// </summary> |
|
WixDirectoryElement AddDirectory(WixDirectoryElementBase parentElement) |
|
{ |
|
WixDirectoryElement directoryElement = AddDirectory(parentElement, String.Empty); |
|
directoryElement.Id = "NewDirectory"; |
|
return directoryElement; |
|
} |
|
|
|
/// <summary> |
|
/// Adds a new directory with the specified name. |
|
/// </summary> |
|
WixDirectoryElement AddDirectory(WixDirectoryElementBase parentElement, string name) |
|
{ |
|
if (parentElement == null) { |
|
parentElement = RootDirectoryElement; |
|
if (parentElement == null) { |
|
parentElement = document.AddRootDirectory(); |
|
} |
|
} |
|
return parentElement.AddDirectory(name); |
|
} |
|
|
|
/// <summary> |
|
/// Gets the root directory element being used in the document. |
|
/// Takes into account whether the WixDocument is using a |
|
/// DirectoryRef element. |
|
/// </summary> |
|
WixDirectoryElementBase RootDirectoryElement { |
|
get { |
|
if (usingRootDirectoryRef) { |
|
return document.RootDirectoryRef; |
|
} |
|
return document.RootDirectory; |
|
} |
|
} |
|
|
|
WixSchemaCompletionData WixSchemaCompletionData { |
|
get { |
|
if (wixSchemaCompletionData == null) { |
|
wixSchemaCompletionData = new WixSchemaCompletionData(); |
|
} |
|
return wixSchemaCompletionData; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Adds a new element to the specified parent. |
|
/// </summary> |
|
XmlElement AddElement(XmlElement parentElement, string name) |
|
{ |
|
if (parentElement != null) { |
|
XmlElement element = document.CreateWixElement(name); |
|
return (XmlElement)parentElement.AppendChild(element); |
|
} |
|
return null; |
|
} |
|
|
|
void AddElementToView(XmlElement element) |
|
{ |
|
view.AddElement(element); |
|
view.SelectedElement = element; |
|
view.IsDirty = true; |
|
SelectedElementChanged(); |
|
} |
|
|
|
/// <summary> |
|
/// Adds a new component element to the directory element. |
|
/// </summary> |
|
/// <param name="id">The id attribute the component element will have.</param> |
|
WixComponentElement AddComponent(WixDirectoryElement parentElement, string id) |
|
{ |
|
if (parentElement != null) { |
|
WixComponentElement element = parentElement.AddComponent(id); |
|
return element; |
|
} |
|
return null; |
|
} |
|
|
|
enum FindRootDirectoryResult |
|
{ |
|
NoMatch = 0, |
|
RootDirectoryFound = 1, |
|
RootDirectoryRefFound = 2 |
|
} |
|
|
|
/// <summary> |
|
/// Tries to find a root directory or root directory ref in the specified |
|
/// document. |
|
/// </summary> |
|
FindRootDirectoryResult FindRootDirectory(WixDocument currentDocument) |
|
{ |
|
if (currentDocument.IsProductDocument) { |
|
WixDirectoryElement rootDirectory = currentDocument.RootDirectory; |
|
if (rootDirectory != null) { |
|
view.AddDirectories(rootDirectory.GetDirectories()); |
|
} |
|
document = currentDocument; |
|
return FindRootDirectoryResult.RootDirectoryFound; |
|
} else { |
|
WixDirectoryRefElement rootDirectoryRef = currentDocument.RootDirectoryRef; |
|
if (rootDirectoryRef != null) { |
|
view.AddDirectories(rootDirectoryRef.GetDirectories()); |
|
document = currentDocument; |
|
usingRootDirectoryRef = true; |
|
return FindRootDirectoryResult.RootDirectoryRefFound; |
|
} |
|
} |
|
return FindRootDirectoryResult.NoMatch; |
|
} |
|
|
|
/// <summary> |
|
/// Adds the set of files to the specified directory element. Each file |
|
/// gets its own parent component element. |
|
/// </summary> |
|
void AddFiles(WixDirectoryElement directoryElement, string directory) |
|
{ |
|
foreach (string fileName in DirectoryReader.GetFiles(directory)) { |
|
if (!excludedNames.IsExcluded(fileName)) { |
|
string path = Path.Combine(directory, fileName); |
|
string id = WixComponentElement.GenerateIdFromFileName(document, path); |
|
WixComponentElement component = AddComponent(directoryElement, id); |
|
AddFile(component, path); |
|
} |
|
} |
|
} |
|
|
|
IDirectoryReader DirectoryReader { |
|
get { |
|
return directoryReader; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Adds any subdirectories and files to the directory element. |
|
/// </summary> |
|
/// <param name="directoryElement">The directory element to add |
|
/// the components and subdirectories to.</param> |
|
/// <param name="directory">The full path of the directory.</param> |
|
void AddDirectoryContents(WixDirectoryElement directoryElement, string directory) |
|
{ |
|
foreach (string subDirectory in DirectoryReader.GetDirectories(directory)) { |
|
string subDirectoryName = WixDirectoryElement.GetLastDirectoryName(subDirectory); |
|
if (!excludedNames.IsExcluded(subDirectoryName)) { |
|
WixDirectoryElement subDirectoryElement = AddDirectory(directoryElement, subDirectoryName); |
|
AddFiles(subDirectoryElement, subDirectory); |
|
|
|
// Add the subdirectory contents. |
|
AddDirectoryContents(subDirectoryElement, subDirectory); |
|
} |
|
} |
|
} |
|
} |
|
}
|
|
|