using System; using System.Diagnostics; using System.Reflection; using System.Text.RegularExpressions; using System.Windows; using System.Windows.Documents; using System.Windows.Media; using GUIControls.RichText; using JetBrains.Annotations; using JetBrains.Omea.Base; using JetBrains.Omea.OpenAPI; using JetBrains.Util; namespace OmniaMea { /// /// Static information about a plugin. /// public class PluginDescription { #region Data /// /// The generic icon for a plugin for which an icon is not [yet] available. /// [NotNull] public static readonly ImageSource GenericPluginIcon = Utils.LoadResourceImage("Icons/PluginGenericIcon.png"); private static readonly Regex _regexPluginClassLocalName = new Regex("Plugin$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline); #endregion #region Attributes /// /// Gets or sets the name of the plugin vendor. This could be a company name or a name of the plugin developer. Should not contain anything but the name; the contact and copyright information should go to the larger section. /// public string Author { get; set; } /// /// Gets or sets the freehand description for the plugin. /// public FlowDocument Description { get; set; } /// /// Gets or sets the for the plugin icon, a raster or vector image that will be primarily rendered 16x16. /// public ImageSource Icon { get; set; } /// /// Gets or sets the user-friendly short title of the plugin. /// This can be an empty string, in which case the local name of the plugin class should be considered. /// The assembly name is not used as a plugin name because there might be more than one plugin in an assembly. However, the enable/disable feature works per-assembly, not per plugin class, and the Plugin Options page lists assemblies, not plugins. /// public string Title { get; set; } #endregion /// /// Extracts plugin description from the given plugin type. /// [NotNull] public static PluginDescription CreateFromPluginType([NotNull] Type plugintype) { if(plugintype == null) throw new ArgumentNullException("plugintype"); return new PluginDescription {Title = GetPluginTitle(plugintype), Author = GetPluginAuthor(plugintype), Description = GetPluginDesriptionDocument(plugintype), Icon = GetPluginIcon(plugintype)}; } #region Operations /// /// Retrieves the plugin author name, or the default text if the name is not specified. /// /// The type that implements a plugin. /// A non-empty string with the author name or some stub text. public static string GetPluginAuthor([NotNull] Type plugintype) { if(plugintype == null) throw new ArgumentNullException("plugintype"); PluginDescriptionAttribute attr; try { attr = TryGetPluginDescriptionAttribute(plugintype); } catch(Exception ex) { Trace.WriteLine(ex.ToString()); return Stringtable.PluginAuthorUnavailableText; } if(attr == null) return Stringtable.PluginAuthorUnavailableText; return !string.IsNullOrEmpty(attr.Author) ? attr.Author : Stringtable.PluginAuthorUnavailableText; } /// /// Retrieves the plugin description text, or the default text if the description is not specified. /// /// The type that implements a plugin. /// A non-empty string with the author name or some stub text. public static FlowDocument GetPluginDesriptionDocument([NotNull] Type plugintype) { if(plugintype == null) throw new ArgumentNullException("plugintype"); try { // Descriptor PluginDescriptionAttribute attr = TryGetPluginDescriptionAttribute(plugintype); // No data? if((attr == null) || (attr.Description.IsEmpty())) return new FlowDocument(new Paragraph(new Italic(new Run(Stringtable.PluginDescriptionUnavailableText))) {TextAlignment = TextAlignment.Center}); // Render switch(attr.DescriptionFormat) { case PluginDescriptionFormat.PlainText: return RichContentConverter.DocumentFromPlainText(attr.Description); case PluginDescriptionFormat.Rtf: return RichContentConverter.DocumentFromRtf(attr.Description); case PluginDescriptionFormat.XamlInline: return RichContentConverter.DocumentFromInlineXaml(attr.Description); case PluginDescriptionFormat.XamlFlowDocumentPackUri: return RichContentConverter.DocumentFromResource(attr.Description, plugintype.Assembly); default: throw new InvalidOperationException(string.Format("The Description Format value {0} is unsupported.", attr.DescriptionFormat)); } } catch(Exception ex) { Core.ReportBackgroundException(ex); return RichContentConverter.DocumentFromException(ex); } } /// /// Retrieves the plugin icon as an image source, or returns the default plugin icon if not available. /// /// The type that implements a plugin. [NotNull] public static ImageSource GetPluginIcon([NotNull] Type plugintype) { if(plugintype == null) throw new ArgumentNullException("plugintype"); try { PluginDescriptionAttribute attr = TryGetPluginDescriptionAttribute(plugintype); if((attr != null) && (!attr.IconSrc.IsEmpty())) { var uri = new Uri(attr.IconSrc, UriKind.RelativeOrAbsolute); if(!uri.IsAbsoluteUri) uri = Utils.MakeResourceUri(attr.IconSrc, plugintype.Assembly); return Utils.LoadResourceImage(uri); } } catch(Exception ex) { Core.ReportBackgroundException(ex); } return GenericPluginIcon; } /// /// Retrieves the plugin user-friendly title text, or the plugin class local name if not specified. /// /// The type that implements a plugin. /// A non-empty string with the title. public static string GetPluginTitle([NotNull] Type plugintype) { if(plugintype == null) throw new ArgumentNullException("plugintype"); // See if we can get a meaningful title from the plugin try { PluginDescriptionAttribute attr = TryGetPluginDescriptionAttribute(plugintype); if((attr != null) && (!attr.Title.IsEmpty())) return attr.Title; } catch(Exception ex) { Core.ReportBackgroundException(ex); } // Use the local class name (remove the common “Plugin” suffix) return _regexPluginClassLocalName.Replace(plugintype.Name, ""); } #endregion #region Implementation /// /// By the plugin type, looks up the attribute. /// Throws on errors, returns Null if there're no attributes. /// [CanBeNull] private static PluginDescriptionAttribute TryGetPluginDescriptionAttribute([NotNull] ICustomAttributeProvider plugintype) { if(plugintype == null) throw new ArgumentNullException("plugintype"); foreach(PluginDescriptionAttribute attr in plugintype.GetCustomAttributes(typeof(PluginDescriptionAttribute), true)) return attr; return null; } #endregion } }