//
//
//
//
// $Revision: 3671 $
//
using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
namespace ICSharpCode.Core
{
public sealed class AddIn
{
Properties properties = new Properties();
List runtimes = new List();
List bitmapResources = new List();
List stringResources = new List();
internal string addInFileName = null;
AddInManifest manifest = new AddInManifest();
Dictionary paths = new Dictionary();
AddInAction action = AddInAction.Disable;
bool enabled;
static bool hasShownErrorMessage = false;
public object CreateObject(string className)
{
LoadDependencies();
foreach (Runtime runtime in runtimes) {
object o = runtime.CreateInstance(className);
if (o != null) {
return o;
}
}
if (hasShownErrorMessage) {
LoggingService.Error("Cannot create object: " + className);
} else {
hasShownErrorMessage = true;
MessageService.ShowError("Cannot create object: " + className + "\nFuture missing objects will not cause an error message.");
}
return null;
}
public void LoadRuntimeAssemblies()
{
LoadDependencies();
foreach (Runtime runtime in runtimes) {
runtime.Load();
}
}
bool dependenciesLoaded;
void LoadDependencies()
{
if (!dependenciesLoaded) {
dependenciesLoaded = true;
foreach (AddInReference r in manifest.Dependencies) {
if (r.RequirePreload) {
bool found = false;
foreach (AddIn addIn in AddInTree.AddIns) {
if (addIn.Manifest.Identities.ContainsKey(r.Name)) {
found = true;
addIn.LoadRuntimeAssemblies();
}
}
if (!found) {
throw new AddInLoadException("Cannot load run-time dependency for " + r.ToString());
}
}
}
}
}
public override string ToString()
{
return "[AddIn: " + Name + "]";
}
string customErrorMessage;
///
/// Gets the message of a custom load error. Used only when AddInAction is set to CustomError.
/// Settings this property to a non-null value causes Enabled to be set to false and
/// Action to be set to AddInAction.CustomError.
///
public string CustomErrorMessage {
get {
return customErrorMessage;
}
internal set {
if (value != null) {
Enabled = false;
Action = AddInAction.CustomError;
}
customErrorMessage = value;
}
}
///
/// Action to execute when the application is restarted.
///
public AddInAction Action {
get {
return action;
}
set {
action = value;
}
}
public List Runtimes {
get {
return runtimes;
}
}
public Version Version {
get {
return manifest.PrimaryVersion;
}
}
public string FileName {
get {
return addInFileName;
}
}
public string Name {
get {
return properties["name"];
}
}
public AddInManifest Manifest {
get {
return manifest;
}
}
public Dictionary Paths {
get {
return paths;
}
}
public Properties Properties {
get {
return properties;
}
}
public List BitmapResources {
get {
return bitmapResources;
}
set {
bitmapResources = value;
}
}
public List StringResources {
get {
return stringResources;
}
set {
stringResources = value;
}
}
public bool Enabled {
get {
return enabled;
}
set {
enabled = value;
this.Action = value ? AddInAction.Enable : AddInAction.Disable;
}
}
internal AddIn()
{
}
static void SetupAddIn(XmlReader reader, AddIn addIn, string hintPath)
{
while (reader.Read()) {
if (reader.NodeType == XmlNodeType.Element && reader.IsStartElement()) {
switch (reader.LocalName) {
case "StringResources":
case "BitmapResources":
if (reader.AttributeCount != 1) {
throw new AddInLoadException("BitmapResources requires ONE attribute.");
}
string filename = StringParser.Parse(reader.GetAttribute("file"));
if(reader.LocalName == "BitmapResources")
{
addIn.BitmapResources.Add(filename);
}
else
{
addIn.StringResources.Add(filename);
}
break;
case "Runtime":
if (!reader.IsEmptyElement) {
Runtime.ReadSection(reader, addIn, hintPath);
}
break;
case "Include":
if (reader.AttributeCount != 1) {
throw new AddInLoadException("Include requires ONE attribute.");
}
if (!reader.IsEmptyElement) {
throw new AddInLoadException("Include nodes must be empty!");
}
if (hintPath == null) {
throw new AddInLoadException("Cannot use include nodes when hintPath was not specified (e.g. when AddInManager reads a .addin file)!");
}
string fileName = Path.Combine(hintPath, reader.GetAttribute(0));
XmlReaderSettings xrs = new XmlReaderSettings();
xrs.ConformanceLevel = ConformanceLevel.Fragment;
using (XmlReader includeReader = XmlTextReader.Create(fileName, xrs)) {
SetupAddIn(includeReader, addIn, Path.GetDirectoryName(fileName));
}
break;
case "Path":
if (reader.AttributeCount != 1) {
throw new AddInLoadException("Import node requires ONE attribute.");
}
string pathName = reader.GetAttribute(0);
ExtensionPath extensionPath = addIn.GetExtensionPath(pathName);
if (!reader.IsEmptyElement) {
ExtensionPath.SetUp(extensionPath, reader, "Path");
}
break;
case "Manifest":
addIn.Manifest.ReadManifestSection(reader, hintPath);
break;
default:
throw new AddInLoadException("Unknown root path node:" + reader.LocalName);
}
}
}
}
public ExtensionPath GetExtensionPath(string pathName)
{
if (!paths.ContainsKey(pathName)) {
return paths[pathName] = new ExtensionPath(pathName, this);
}
return paths[pathName];
}
public static AddIn Load(TextReader textReader)
{
return Load(textReader, null);
}
public static AddIn Load(TextReader textReader, string hintPath)
{
AddIn addIn = new AddIn();
using (XmlTextReader reader = new XmlTextReader(textReader)) {
while (reader.Read()){
if (reader.IsStartElement()) {
switch (reader.LocalName) {
case "AddIn":
addIn.properties = Properties.ReadFromAttributes(reader);
SetupAddIn(reader, addIn, hintPath);
break;
default:
throw new AddInLoadException("Unknown add-in file.");
}
}
}
}
return addIn;
}
public static AddIn Load(string fileName)
{
try {
using (TextReader textReader = File.OpenText(fileName)) {
AddIn addIn = Load(textReader, Path.GetDirectoryName(fileName));
addIn.addInFileName = fileName;
return addIn;
}
} catch (Exception e) {
throw new AddInLoadException("Can't load " + fileName, e);
}
}
}
}