/// <inheritdoc /> protected override void OnInitialize() { IConfigurationElement[] configurationElements = ExtensionService.Instance.GetConfigurationElements(DataViewExtensionPointId); if (configurationElements.Length == 0) { _log.Warning("No data view has been contributed by any extension point!"); return; } _log.Debug($"{configurationElements.Length} data view contributions has been found"); for (int i = -1; ++i != configurationElements.Length;) { IConfigurationElement configurationElement = configurationElements[i]; string id = configurationElement["id"]; string cls = configurationElement["class"]; string label = configurationElement["label"]; if (string.IsNullOrEmpty(label)) { label = id; } _log.Debug($"Registering contribution {{id: '{id}', cls: '{cls}', label: '{label}'}}"); if (string.IsNullOrWhiteSpace(id)) { _log.Error("Id attribute of data view extension contribution is null or empty!"); continue; } if (string.IsNullOrWhiteSpace(cls)) { _log.Error($"Class attribute of data view extension contribution is null or empty!. Contribution id: '{id}'"); continue; } IBundle providingBundle = ExtensionService.Instance.GetProvidingBundle(configurationElement); try { Type dataViewType = TypeLoader.TypeForName(providingBundle, cls); // NLS support label = NLS.Localize(label, dataViewType); DataViewContribution dataViewContribution = new DataViewContribution { DataViewId = id, DataViewType = dataViewType, DataViewLabel = label }; iRegisteredDataViews.Add(dataViewContribution); _log.Info($"Data view contribution '{id}' registered."); } catch (Exception ex) { _log.Error($"Error loading type '{cls}'.", ex); } } }
/// <summary> Resolves all registered menus and items and tells the main window to handle it. </summary> /// <param name="mainWindow">Main window</param> public static void AddExtensionPointMenuItems(IMainWindow mainWindow) { IConfigurationElement[] configurationElements = ExtensionService.Instance.GetConfigurationElements(ExtensionPointIdMenuItems); List <IConfigurationElement> menuElementCollection = new List <IConfigurationElement>(30); List <IConfigurationElement> menuItemElementsCollection = new List <IConfigurationElement>(30); List <IConfigurationElement> menuItemSeparatorsCollection = new List <IConfigurationElement>(30); Func <string, ICollection <IConfigurationElement> > getCollection = prefix => { if (prefix == "menu") { return(menuElementCollection); } if (prefix == "menuItem") { return(menuItemElementsCollection); } if (prefix == "separator") { return(menuItemSeparatorsCollection); } return(null); }; // Sort elements into corresponding collections for (int i = -1; ++i != configurationElements.Length;) { IConfigurationElement element = configurationElements[i]; string prefix = element.Prefix; ICollection <IConfigurationElement> collection = getCollection(prefix); collection?.Add(element); } // Process registered menus using (IEnumerator <IConfigurationElement> itr = menuElementCollection.GetEnumerator()) { while (itr.MoveNext()) { IConfigurationElement element = itr.Current; string id = element["id"]; string label = element["label"]; // NLS support if (label.StartsWith("%")) { string nlsKey = label.Substring(1); string assemblyName = ExtensionService.Instance.GetProvidingBundle(element).Name; // We cannot use the AppDomain here, because the assembly must not have been loaded yet Assembly assembly = Assembly.Load(assemblyName); // TODO Check if this may be an issue string localizationId = NLS.GetLocalizationId(assembly); label = NLS.GetText(localizationId, nlsKey); } MenuContribution menu = new MenuContribution(id, label); _idToMenuMap.Add(id, menu); } } // Collection of all opened streams LinkedList <Stream> streamList = new LinkedList <Stream>(); // Process registered menu items using (IEnumerator <IConfigurationElement> itr = menuItemElementsCollection.GetEnumerator()) { while (itr.MoveNext()) { IConfigurationElement element = itr.Current; string id = element["id"]; string menu = element["menu"]; string label = element["label"]; string handler = element["handler"]; string shortcut = element["shortcut"]; string image = element["image"]; IBundle providingBundle = ExtensionService.Instance.GetProvidingBundle(element); IActionHandler actionHandler = null; if (!string.IsNullOrEmpty(handler)) { Type handlerType = TypeLoader.TypeForName(providingBundle, handler); actionHandler = handlerType.NewInstance <IActionHandler>(); } Stream imageStream = null; if (!string.IsNullOrEmpty(image)) { imageStream = providingBundle.GetAssemblyResourceAsStream(image); streamList.AddLast(imageStream); } // NLS support label = NLS.Localize(label, actionHandler); MenuItemContribution menuItem = new MenuItemContribution(id, label, menu, actionHandler, shortcut, imageStream); if (_idToMenuMap.TryGetValue(menu, out MenuContribution menuInstance)) { menuInstance.MenuItems.Add(menuItem); } } } int findIndex(IList <MenuItemContribution> set, string itemRef) { for (int i = -1; ++i != set.Count;) { MenuItemContribution mic = set[i]; if (mic.Id == itemRef) { return(i); } } return(-1); } // Process registered separators using (IEnumerator <IConfigurationElement> itr = menuItemSeparatorsCollection.GetEnumerator()) { while (itr.MoveNext()) { IConfigurationElement element = itr.Current; string id = element["id"]; string menu = element["menu"]; string insertBefore = element["insertBefore"]; string insertAfter = element["insertAfter"]; MenuItemContribution menuItem = new MenuItemContribution(id, string.Empty, menu, null, null, null) { IsSeparator = true }; if (!_idToMenuMap.TryGetValue(menu, out MenuContribution menuContribution)) { continue; } bool useInsertBefore = !string.IsNullOrEmpty(insertBefore); string itemReference = useInsertBefore ? insertBefore : insertAfter; IList <MenuItemContribution> menuItemCollection = menuContribution.MenuItems; int referenceIndex = findIndex(menuItemCollection, itemReference); if (referenceIndex == -1) { continue; } int insertIndex = useInsertBefore ? referenceIndex : referenceIndex + 1; menuItemCollection.Insert(insertIndex, menuItem); } } // Support custom menu configurer ICustomMenuConfigurer customMenuConfigurer = GetCustomMenuConfigurer(); MenuContribution[] menuContributions = _idToMenuMap.Values.ToArray(); MenuContribution[] customMenuContributions = customMenuConfigurer != null ? customMenuConfigurer.Configure(menuContributions) : menuContributions; // Add each contributed menu to the main window Array.ForEach(customMenuContributions, mainWindow.AddMenu); // Disposing all opened streams using (LinkedList <Stream> .Enumerator enmtor = streamList.GetEnumerator()) { while (enmtor.MoveNext()) { Stream stream = enmtor.Current; stream?.Dispose(); } } }
/// <summary> Resolves all registered menus and items and tells the main window to handle it. </summary> /// <param name="mainWindow">Main window</param> public static void AddExtensionPointToolbarItems(IMainWindow mainWindow) { IConfigurationElement[] configurationElements = ExtensionService.Instance.GetConfigurationElements(ExtensionPointId); IConfigurationElement[] groupElements = configurationElements.Where(x => x.Prefix == "toolbarGroup").ToArray(); IConfigurationElement[] groupItemElements = configurationElements.Where(x => x.Prefix == "toolbarItem").ToArray(); for (int i = -1; ++i < groupElements.Length;) { IConfigurationElement element = groupElements[i]; string id = element["id"]; ToolbarGroupContribution menu = new ToolbarGroupContribution(id); _idToMenuMap.Add(id, menu); } // Collection of all opened streams List <Stream> streamList = new List <Stream>(20); for (int i = -1; ++i < groupItemElements.Length;) { IConfigurationElement element = groupItemElements[i]; string id = element["id"]; string group = element["group"]; string handler = element["handler"]; string image = element["image"]; string label = element["label"]; IBundle providingBundle = ExtensionService.Instance.GetProvidingBundle(element); IActionHandler actionHandler = null; if (!string.IsNullOrEmpty(handler)) { Type handlerType = TypeLoader.TypeForName(providingBundle, handler); actionHandler = handlerType.NewInstance <IActionHandler>(); } Stream imageStream = null; if (!string.IsNullOrEmpty(image)) { imageStream = providingBundle.GetAssemblyResourceAsStream(image); streamList.Add(imageStream); } // NLS support label = NLS.Localize(label, actionHandler); ToolbarItemContribution menuItem = new ToolbarItemContribution(id, group, actionHandler, label, imageStream); ToolbarGroupContribution menuInstance; if (_idToMenuMap.TryGetValue(group, out menuInstance)) { menuInstance.GroupItems.Add(menuItem); } } using (IEnumerator <ToolbarGroupContribution> itr = _idToMenuMap.Values.GetEnumerator()) { while (itr.MoveNext()) { ToolbarGroupContribution contribution = itr.Current; mainWindow.AddToolbarGroup(contribution); } } // Disposing all opened streams using (IEnumerator <Stream> itr = streamList.GetEnumerator()) { while (itr.MoveNext()) { Stream stream = itr.Current; stream?.Dispose(); } } }
/// <inheritdoc /> protected override void OnInitialize() { IConfigurationElement[] configurationElements = ExtensionService.Instance.GetConfigurationElements(ExtensionPointId); IConfigurationElement[] categories = configurationElements.Where(el => el.Prefix == "category").ToArray(); IConfigurationElement[] wizards = configurationElements.Where(el => el.Prefix == "wizard").ToArray(); IDictionary <string, CategoryContribution> idToCategoryMap = new Dictionary <string, CategoryContribution>(categories.Length); // Processing categories for (int i = -1; ++i < categories.Length;) { IConfigurationElement category = categories[i]; string id = category["id"]; string label = category["label"]; // NLS support if (label.StartsWith("%")) { string nlsKey = label.Substring(1); string assemblyName = ExtensionService.Instance.GetProvidingBundle(category).Name; // We cannot use the AppDomain here, because the assembly must not have been loaded yet Assembly assembly = Assembly.Load(assemblyName); // TODO Check if this may be an issue string localizationId = NLS.GetLocalizationId(assembly); label = NLS.GetText(localizationId, nlsKey); } CategoryContribution contribution = new CategoryContribution { Id = id, Label = label }; idToCategoryMap.Add(id, contribution); _contributions.Add(contribution); } // Processing wizards for (int i = -1; ++i < wizards.Length;) { IConfigurationElement wizard = wizards[i]; string id = wizard["id"]; string category = wizard["category"]; string label = wizard["label"]; string className = wizard["class"]; string imagePath = wizard["image"]; if (string.IsNullOrEmpty(className)) { continue; } IWizard wizardImpl; try { IBundle providingBundle = ExtensionService.Instance.GetProvidingBundle(wizard); Type wizardType = TypeLoader.TypeForName(providingBundle, className); wizardImpl = wizardType.NewInstance <IWizard>(); } catch (Exception ex) { _log.Error($"Error on creating wizard of type '{className}'.", ex); continue; } ImageDescriptor imageDescriptor = null; if (!string.IsNullOrEmpty(imagePath)) { try { imageDescriptor = ImageDescriptor.Create($"image.{id}", wizardImpl.GetType().Assembly, imagePath); } catch (Exception ex) { _log.Error($"Error on resolving image of wizard '{id}'.", ex); } } // NLS support label = NLS.Localize(label, wizardImpl); WizardContribution contribution = new WizardContribution { Id = id, Label = label, Category = category, Wizard = wizardImpl, Image = imageDescriptor }; // Is it a categorized item? if (!string.IsNullOrEmpty(category)) { if (idToCategoryMap.TryGetValue(category, out CategoryContribution categoryContr)) { categoryContr.Wizards.Add(contribution); continue; } } _contributions.Add(contribution); } }