/// <summary> /// This combines the conceptual and API intermediate TOC files into one file ready for transformation to /// the help format-specific TOC file formats and, if necessary, determines the default topic. /// </summary> private void CombineIntermediateTocFiles() { XmlAttribute attr; XmlDocument conceptualXml = null, tocXml; XmlElement docElement; XmlNodeList allNodes; XmlNode node, parent; int insertionPoint; this.ReportProgress(BuildStep.CombiningIntermediateTocFiles, "Combining conceptual and API intermediate TOC files..."); if (!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf)) { this.ExecutePlugIns(ExecutionBehaviors.Before); // Load the TOC files if (toc != null && toc.Count != 0) { conceptualXml = new XmlDocument(); conceptualXml.Load(Path.Combine(workingFolder, "_ConceptualTOC_.xml")); } tocXml = new XmlDocument(); tocXml.Load(Path.Combine(workingFolder, "toc.xml")); // Merge the conceptual and API TOCs into one? if (conceptualXml != null) { // Remove the root content container if present as we don't need it for the other formats if ((project.HelpFileFormat & HelpFileFormats.MSHelpViewer) != 0 && !String.IsNullOrEmpty(this.RootContentContainerId)) { docElement = conceptualXml.DocumentElement; node = docElement.FirstChild; allNodes = node.SelectNodes("topic"); foreach (XmlNode n in allNodes) { n.ParentNode.RemoveChild(n); docElement.AppendChild(n); } node.ParentNode.RemoveChild(node); } if (String.IsNullOrEmpty(this.ApiTocParentId)) { // If not parented, the API content is placed above or below the conceptual content based // on the project's ContentPlacement setting. if (project.ContentPlacement == ContentPlacement.AboveNamespaces) { docElement = conceptualXml.DocumentElement; foreach (XmlNode n in tocXml.SelectNodes("topics/topic")) { node = conceptualXml.ImportNode(n, true); docElement.AppendChild(node); } tocXml = conceptualXml; } else { docElement = tocXml.DocumentElement; foreach (XmlNode n in conceptualXml.SelectNodes("topics/topic")) { node = tocXml.ImportNode(n, true); docElement.AppendChild(node); } } } else { // Parent the API content to a conceptual topic parent = conceptualXml.SelectSingleNode("//topic[@id='" + this.ApiTocParentId + "']"); // If not found, parent it to the root if (parent == null) { parent = conceptualXml.DocumentElement; } insertionPoint = this.ApiTocOrder; if (insertionPoint == -1 || insertionPoint >= parent.ChildNodes.Count) { insertionPoint = parent.ChildNodes.Count; } foreach (XmlNode n in tocXml.SelectNodes("topics/topic")) { node = conceptualXml.ImportNode(n, true); if (insertionPoint >= parent.ChildNodes.Count) { parent.AppendChild(node); } else { parent.InsertBefore(node, parent.ChildNodes[insertionPoint]); } insertionPoint++; } tocXml = conceptualXml; } // Fix up empty container nodes by removing the file attribute and setting the ID attribute to // the title attribute value. foreach (XmlNode n in tocXml.SelectNodes("//topic[@title]")) { attr = n.Attributes["file"]; if (attr != null) { n.Attributes.Remove(attr); } attr = n.Attributes["id"]; if (attr != null) { attr.Value = n.Attributes["title"].Value; } } tocXml.Save(Path.Combine(workingFolder, "toc.xml")); } this.ExecutePlugIns(ExecutionBehaviors.After); } // Determine the default topic for Help 1, website, and markdown output if one was not specified in a // site map or content layout file. if (defaultTopic == null && (project.HelpFileFormat & (HelpFileFormats.HtmlHelp1 | HelpFileFormats.Website | HelpFileFormats.Markdown)) != 0) { var defTopic = ComponentUtilities.XmlStreamAxis(Path.Combine(workingFolder, "toc.xml"), "topic").FirstOrDefault( t => t.Attribute("file") != null); if (defTopic != null) { // Find the file. Could be .htm, .html, or .md so just look for any file with the given name. defaultTopic = Directory.EnumerateFiles(workingFolder + "Output", defTopic.Attribute("file").Value + ".*", SearchOption.AllDirectories).FirstOrDefault(); if (defaultTopic != null) { defaultTopic = defaultTopic.Substring(workingFolder.Length + 7); if (defaultTopic.IndexOf('\\') != -1) { defaultTopic = defaultTopic.Substring(defaultTopic.IndexOf('\\') + 1); } } } // This shouldn't happen anymore, but just in case... if (defaultTopic == null) { throw new BuilderException("BE0026", "Unable to determine default topic in toc.xml. Mark " + "one as the default topic manually in the content layout file."); } } }
//===================================================================== /// <summary> /// This is called to generate the namespace summary file /// </summary> private void GenerateNamespaceSummaries() { XmlNode member; NamespaceSummaryItem nsi; string nsName = null, summaryText; bool isDocumented; this.ReportProgress(BuildStep.GenerateNamespaceSummaries, "Generating namespace summary information..."); // Add a dummy file if there are no comments files specified. This will contain the project and // namespace summaries. if (commentsFiles.Count == 0) { nsName = workingFolder + "_ProjNS_.xml"; using (StreamWriter sw = new StreamWriter(nsName, false, Encoding.UTF8)) { sw.Write("<?xml version=\"1.0\"?>\r\n<doc>\r\n" + "<assembly>\r\n<name>_ProjNS_</name>\r\n" + "</assembly>\r\n<members/>\r\n</doc>\r\n"); } commentsFiles.Add(new XmlCommentsFile(nsName)); } // Replace any "NamespaceDoc" and "NamespaceGroupDoc" class IDs with their containing namespace. // The comments in these then become the comments for the namespaces and namespace groups. commentsFiles.ReplaceNamespaceDocEntries(); if (this.ExecutePlugIns(ExecutionBehaviors.InsteadOf)) { return; } this.ExecutePlugIns(ExecutionBehaviors.Before); // XML comments do not support summaries on namespace elements by default. However, if Sandcastle // finds them, it will add them to the help file. The same holds true for project comments on the // root namespaces page (R:Project_[HtmlHelpName]). We can accomplish this by adding elements to // the first comments file or by supplying them in an external XML comments file. try { // Add the project comments if specified if (project.ProjectSummary.Length != 0) { // Set the name in case it isn't valid nsName = "R:Project_" + this.ResolvedHtmlHelpName.Replace(" ", "_"); member = commentsFiles.FindMember(nsName); this.AddNamespaceComments(member, project.ProjectSummary); } // Get all the namespace and namespace group nodes from the reflection information file var nsElements = ComponentUtilities.XmlStreamAxis(reflectionFile, "api").Where(el => { string id = el.Attribute("id").Value; return(id.Length > 1 && id[1] == ':' && (id[0] == 'N' || id[0] == 'G') && el.Element("topicdata").Attribute("group").Value != "rootGroup"); }).Select(el => el.Attribute("id").Value); // Add the namespace summaries foreach (var n in nsElements) { nsName = n; nsi = project.NamespaceSummaries[nsName.StartsWith("N:", StringComparison.Ordinal) ? nsName.Substring(2) : nsName.Substring(2) + " (Group)"]; if (nsi != null) { isDocumented = nsi.IsDocumented; summaryText = nsi.Summary; } else { // The global namespace is not documented by default isDocumented = (nsName != "N:"); summaryText = String.Empty; } if (isDocumented) { // If documented, add the summary text member = commentsFiles.FindMember(nsName); this.AddNamespaceComments(member, summaryText); } } } catch (Exception ex) { // Eat the error in a partial build so that the user can get into the namespace comments editor // to fix it. if (this.PartialBuildType != PartialBuildType.None) { throw new BuilderException("BE0012", String.Format(CultureInfo.CurrentCulture, "Error generating namespace summaries (Namespace = {0}): {1}", nsName, ex.Message), ex); } } this.ExecutePlugIns(ExecutionBehaviors.After); }
//===================================================================== /// <summary> /// Try to load information about all available plug-ins so that they can be added to the project /// </summary> /// <returns>True on success, false on failure or if no project is loaded</returns> private void LoadAvailablePlugInMetadata() { SandcastleProject currentProject = null; HashSet <string> plugInIds = new HashSet <string>(); try { Cursor.Current = Cursors.WaitCursor; if (componentContainer != null) { componentContainer.Dispose(); componentContainer = null; availablePlugIns = null; } #if !STANDALONEGUI if (base.ProjectMgr != null) { currentProject = ((SandcastleBuilderProjectNode)base.ProjectMgr).SandcastleProject; } #else currentProject = base.CurrentProject; #endif lastProjectName = currentProject == null ? null : currentProject.Filename; if (currentProject != null) { componentContainer = ComponentUtilities.CreateComponentContainer(new[] { currentProject.ComponentPath, Path.GetDirectoryName(currentProject.Filename) }); } else { componentContainer = ComponentUtilities.CreateComponentContainer(new string[] { }); } lbProjectPlugIns.Items.Clear(); availablePlugIns = componentContainer.GetExports <IPlugIn, IPlugInMetadata>().ToList(); // There may be duplicate component IDs across the assemblies found. See // BuildComponentManger.GetComponentContainer() for the folder search precedence. Only the first // component for a unique ID will be used. We also ignore hidden plug-ins. foreach (var plugIn in availablePlugIns) { if (!plugIn.Metadata.IsHidden && !plugInIds.Contains(plugIn.Metadata.Id)) { lbAvailablePlugIns.Items.Add(plugIn.Metadata.Id); plugInIds.Add(plugIn.Metadata.Id); } } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); MessageBox.Show("Unexpected error loading plug-ins: " + ex.Message, messageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { Cursor.Current = Cursors.Default; } if (lbAvailablePlugIns.Items.Count != 0) { lbAvailablePlugIns.SelectedIndex = 0; gbAvailablePlugIns.Enabled = gbProjectAddIns.Enabled = true; } else { MessageBox.Show("No valid plug-ins found", messageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); gbAvailablePlugIns.Enabled = gbProjectAddIns.Enabled = false; } }
/// <summary> /// This is called when the component cache has finished being loaded and is available for use /// </summary> /// <param name="sender">The sender of the event</param> /// <param name="e">The event arguments</param> private void componentCache_ComponentContainerLoaded(object sender, EventArgs e) { BuildPropertiesNeededEventArgs projectSettings = new BuildPropertiesNeededEventArgs(); this.BuildPropertiesNeeded?.Invoke(this, projectSettings); HashSet <string> generatorIds = new HashSet <string>(), presentationStyleIds = new HashSet <string>(); try { Mouse.OverrideCursor = Cursors.Wait; isBinding = true; cboPresentationStyle.IsEnabled = lbSyntaxFilters.IsEnabled = lbHelpFileFormat.IsEnabled = true; cboPresentationStyle.ItemsSource = lbHelpFileFormat.ItemsSource = lbSyntaxFilters.ItemsSource = null; if (cboPresentationStyle.Items.Count != 0) { cboPresentationStyle.Items.Clear(); } if (lbHelpFileFormat.Items.Count != 0) { lbHelpFileFormat.Items.Clear(); } if (lbSyntaxFilters.Items.Count != 0) { lbSyntaxFilters.Items.Clear(); } syntaxGenerators = new List <ISyntaxGeneratorMetadata>(); presentationStyles = new List <IPresentationStyleMetadata>(); var generators = componentCache.ComponentContainer.GetExports <ISyntaxGeneratorFactory, ISyntaxGeneratorMetadata>().Select(g => g.Metadata).ToList(); // There may be duplicate generator IDs across the assemblies found. See // BuildComponentManger.GetComponentContainer() for the folder search precedence. Only the // first component for a unique ID will be used. foreach (var generator in generators) { if (!generatorIds.Contains(generator.Id)) { syntaxGenerators.Add(generator); generatorIds.Add(generator.Id); } } var styles = componentCache.ComponentContainer.GetExports <PresentationStyleSettings, IPresentationStyleMetadata>().Select(g => g.Metadata).ToList(); // As above for duplicates foreach (var style in styles) { if (!presentationStyleIds.Contains(style.Id)) { presentationStyles.Add(style); presentationStyleIds.Add(style.Id); } } allSyntaxFilters = new List <SyntaxFilterItem>(); foreach (var filter in syntaxGenerators.OrderBy(f => f.Id)) { allSyntaxFilters.Add(new SyntaxFilterItem { Id = filter.Id }); } lbSyntaxFilters.ItemsSource = allSyntaxFilters; cboPresentationStyle.ItemsSource = presentationStyles.OrderBy(s => s.IsDeprecated ? 1 : 0).ThenBy( s => s.Id).ToList(); cboPresentationStyle.SelectedValue = Constants.DefaultPresentationStyle; if (lbSyntaxFilters.Items.Count != 0) { lbSyntaxFilters.SelectedIndex = 0; } else { MessageBox.Show("No valid syntax generators found", Constants.AppName, MessageBoxButton.OK, MessageBoxImage.Information); } if (cboPresentationStyle.Items.Count == 0) { MessageBox.Show("No valid presentation styles found", Constants.AppName, MessageBoxButton.OK, MessageBoxImage.Information); } if (projectSettings.ProjectLoaded) { if (!String.IsNullOrWhiteSpace(projectSettings.PresentationStyle)) { var match = cboPresentationStyle.Items.Cast <IPresentationStyleMetadata>().FirstOrDefault(p => p.Id.Equals(projectSettings.PresentationStyle, StringComparison.OrdinalIgnoreCase)); if (match != null) { cboPresentationStyle.SelectedValue = match.Id; } } if (!String.IsNullOrWhiteSpace(projectSettings.SyntaxFilters)) { foreach (string filter in ComponentUtilities.SyntaxFiltersFrom(syntaxGenerators, projectSettings.SyntaxFilters).Select(f => f.Id)) { var match = allSyntaxFilters.FirstOrDefault(f => f.Id == filter); if (match != null) { match.IsSelected = true; } } } } } catch (Exception ex) { Debug.WriteLine(ex.ToString()); MessageBox.Show("Unexpected error loading syntax generators and presentation styles: " + ex.Message, Constants.AppName, MessageBoxButton.OK, MessageBoxImage.Error); } finally { Mouse.OverrideCursor = null; isBinding = false; } }
//===================================================================== /// <summary> /// Load a resource items file for editing /// </summary> /// <param name="resourceItemsFile">The resource items file to load</param> /// <param name="project">The current Sandcastle Builder project</param> public void LoadResourceItemsFile(string resourceItemsFile, SandcastleProject project) { PresentationStyleSettings pss = null; string presentationStylePath, shfbStyleContent; List <string> syntaxGeneratorFiles = new List <string>(); if (resourceItemsFile == null) { throw new ArgumentNullException("resourceItemsFile", "A resource items file name must be specified"); } try { Mouse.OverrideCursor = Cursors.Wait; resourceItemFilename = resourceItemsFile; using (var container = ComponentUtilities.CreateComponentContainer(new[] { project.ComponentPath, Path.GetDirectoryName(project.Filename) })) { var presentationStyles = container.GetExports <PresentationStyleSettings, IPresentationStyleMetadata>(); var style = presentationStyles.FirstOrDefault(s => s.Metadata.Id.Equals( project.PresentationStyle, StringComparison.OrdinalIgnoreCase)); if (style == null) { style = presentationStyles.FirstOrDefault(s => s.Metadata.Id.Equals( Constants.DefaultPresentationStyle, StringComparison.OrdinalIgnoreCase)); } if (style != null) { pss = style.Value; } else { MessageBox.Show("Unable to locate the presentation style ID " + project.PresentationStyle, "Resource Item Editor", MessageBoxButton.OK, MessageBoxImage.Error); return; } syntaxGeneratorFiles.AddRange(ComponentUtilities.SyntaxGeneratorResourceItemFiles(container, null)); } // Get the presentation style folders presentationStylePath = pss.ResolvePath(pss.ResourceItemsPath); shfbStyleContent = pss.ResolvePath(pss.ToolResourceItemsPath); // Use the language-specific files if they are present if (Directory.Exists(Path.Combine(presentationStylePath, project.Language.Name))) { presentationStylePath = Path.Combine(presentationStylePath, project.Language.Name); } if (File.Exists(Path.Combine(shfbStyleContent, project.Language.Name + ".xml"))) { shfbStyleContent = Path.Combine(shfbStyleContent, project.Language.Name + ".xml"); } else { shfbStyleContent = Path.Combine(shfbStyleContent, "en-US.xml"); } // Load the presentation style content files first followed by the syntax generator files, the // help file builder content items, and then the user's resource item file. foreach (string file in Directory.EnumerateFiles(presentationStylePath, "*.xml")) { this.LoadItemFile(file, false); } foreach (string file in syntaxGeneratorFiles) { this.LoadItemFile(file, false); } if (File.Exists(shfbStyleContent)) { this.LoadItemFile(shfbStyleContent, false); } this.LoadItemFile(resourceItemFilename, true); // Load everything into the list box resourceItems = new BindingList <ResourceItem>(allItems.Values.ToArray()); resourceItems.ListChanged += resourceItems_ListChanged; if (resourceItems.Count != 0) { resourceItems[0].IsSelected = true; } lbResourceItems.ItemsSource = resourceItems; this.resourceItems_ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, -1)); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); MessageBox.Show("Unable to load resource item files: " + ex.Message, "Resource Item Editor", MessageBoxButton.OK, MessageBoxImage.Error); } finally { Mouse.OverrideCursor = null; } }
/// <summary> /// This is used to get an enumerable list of unique namespaces referenced in the XML comments files /// </summary> /// <param name="validNamespaces">An enumerable list of valid namespaces</param> /// <returns>An enumerable list of unique namespaces referenced in the XML comments files</returns> public IEnumerable <string> GetReferencedNamespaces(IEnumerable <string> validNamespaces) { HashSet <string> seenNamespaces = new HashSet <string>(); string ns; foreach (XmlCommentsFile f in this) { // Find all comments elements with a reference. XML comments files may be ill-formed so // ignore any elements without a cref attribute. IEnumerable <string> crefs; try { crefs = ComponentUtilities.XmlStreamAxis(f.SourcePath, new[] { "event", "exception", "inheritdoc", "permission", "see", "seealso" }).Select( el => (string)el.Attribute("cref")).Where(c => c != null).ToList(); } catch (XmlException) { yield break; } foreach (string refId in crefs) { if (refId.Length > 2 && refId[1] == ':' && refId.IndexOfAny(new[] { '.', '(' }) != -1) { ns = refId.Trim(); // Strip off member name? if (!ns.StartsWith("R:", StringComparison.OrdinalIgnoreCase) && !ns.StartsWith("G:", StringComparison.OrdinalIgnoreCase) && !ns.StartsWith("N:", StringComparison.OrdinalIgnoreCase) && !ns.StartsWith("T:", StringComparison.OrdinalIgnoreCase)) { if (ns.IndexOf('(') != -1) { ns = ns.Substring(0, ns.IndexOf('(')); } if (ns.IndexOf('.') != -1) { ns = ns.Substring(0, ns.LastIndexOf('.')); } } if (ns.IndexOf('.') != -1) { ns = ns.Substring(2, ns.LastIndexOf('.') - 2); } else { ns = ns.Substring(2); } if (validNamespaces.Contains(ns) && !seenNamespaces.Contains(ns)) { seenNamespaces.Add(ns); yield return(ns); } } } } }
/// <inheritdoc /> protected override bool BindControlValue(Control control) { ProjectProperty projProp = null; List <string> allFilters; int idx; #if !STANDALONEGUI if (this.ProjectMgr == null) { return(false); } #else if (this.CurrentProject == null) { return(false); } #endif // Add the project's selected language to the list if it is not there if (control.Name == "cboLanguage") { #if !STANDALONEGUI projProp = this.ProjectMgr.BuildProject.GetProperty("Language"); #else projProp = this.CurrentProject.MSBuildProject.GetProperty("Language"); #endif if (projProp != null) { cboLanguage.SelectedItem = this.AddLanguage(projProp.UnevaluatedValue ?? "en-US"); } else { cboLanguage.SelectedItem = LanguageResourceConverter.StandardValues.First( c => c.Name.Equals("en-US", StringComparison.OrdinalIgnoreCase)); } return(true); } // Set the selected syntax filters if (control.Name == "cblSyntaxFilters") { for (idx = 0; idx < cblSyntaxFilters.Items.Count; idx++) { cblSyntaxFilters.SetItemChecked(idx, false); } #if !STANDALONEGUI SandcastleProject currentProject = null; if (base.ProjectMgr != null) { currentProject = ((SandcastleBuilderProjectNode)base.ProjectMgr).SandcastleProject; } if (syntaxGenerators == null || presentationStyles == null || currentProject == null || currentProject.Filename != lastProjectName) { this.LoadAvailableSyntaxGeneratorsAndPresentationStyles(); } if (base.ProjectMgr != null) { projProp = base.ProjectMgr.BuildProject.GetProperty("SyntaxFilters"); } #else if (syntaxGenerators == null || presentationStyles == null || base.CurrentProject == null || base.CurrentProject.Filename != lastProjectName) { this.LoadAvailableSyntaxGeneratorsAndPresentationStyles(); } if (base.CurrentProject != null) { projProp = base.CurrentProject.MSBuildProject.GetProperty("SyntaxFilters"); } #endif if (projProp != null) { allFilters = ComponentUtilities.SyntaxFiltersFrom(syntaxGenerators, projProp.UnevaluatedValue).Select(f => f.Id).ToList(); } else { allFilters = ComponentUtilities.SyntaxFiltersFrom(syntaxGenerators, "Standard").Select( f => f.Id).ToList(); } foreach (string s in allFilters) { idx = cblSyntaxFilters.FindStringExact(s); if (idx != -1) { cblSyntaxFilters.SetItemChecked(idx, true); } } return(true); } return(false); }
//===================================================================== /// <summary> /// Try to load information about all available syntax generators so that they can be selected for use /// in the project. /// </summary> /// <returns>True on success, false on failure or if no project is loaded</returns> private void LoadAvailableSyntaxGeneratorsAndPresentationStyles() { SandcastleProject currentProject = null; HashSet <string> generatorIds = new HashSet <string>(), presentationStyleIds = new HashSet <string>(); string[] searchFolders; try { Cursor.Current = Cursors.WaitCursor; syntaxGenerators = new List <ISyntaxGeneratorMetadata>(); presentationStyles = new List <IPresentationStyleMetadata>(); #if !STANDALONEGUI if (base.ProjectMgr != null) { currentProject = ((SandcastleBuilderProjectNode)base.ProjectMgr).SandcastleProject; } #else currentProject = base.CurrentProject; #endif lastProjectName = currentProject == null ? null : currentProject.Filename; if (currentProject != null) { searchFolders = new[] { currentProject.ComponentPath, Path.GetDirectoryName(currentProject.Filename) } } ; else { searchFolders = new string[] { } }; using (var componentContainer = ComponentUtilities.CreateComponentContainer(searchFolders)) { cblSyntaxFilters.Items.Clear(); var generators = componentContainer.GetExports <ISyntaxGeneratorFactory, ISyntaxGeneratorMetadata>().Select(g => g.Metadata).ToList(); // There may be duplicate generator IDs across the assemblies found. See // BuildComponentManger.GetComponentContainer() for the folder search precedence. Only the // first component for a unique ID will be used. foreach (var generator in generators) { if (!generatorIds.Contains(generator.Id)) { syntaxGenerators.Add(generator); generatorIds.Add(generator.Id); } } cboPresentationStyle.DataSource = null; var styles = componentContainer.GetExports <PresentationStyleSettings, IPresentationStyleMetadata>().Select(g => g.Metadata).ToList(); // As above for duplicates foreach (var style in styles) { if (!presentationStyleIds.Contains(style.Id)) { presentationStyles.Add(style); presentationStyleIds.Add(style.Id); } } } cblSyntaxFilters.Items.AddRange(syntaxGenerators.Select(f => f.Id).OrderBy(f => f).ToArray()); cboPresentationStyle.DataSource = presentationStyles.OrderBy(s => s.IsDeprecated ? 1 : 0).ThenBy( s => s.Id).ToList(); cboPresentationStyle.SelectedValue = Constants.DefaultPresentationStyle; // Resize the syntax filter columns to the widest entry int width, maxWidth = 0; foreach (string s in cblSyntaxFilters.Items) { width = TextRenderer.MeasureText(s, this.Font).Width; if (width > maxWidth) { maxWidth = width; } } cblSyntaxFilters.ColumnWidth = maxWidth + 20; } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.ToString()); MessageBox.Show("Unexpected error loading syntax generators and presentation styles: " + ex.Message, messageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Error); } finally { Cursor.Current = Cursors.Default; } if (cblSyntaxFilters.Items.Count != 0) { cblSyntaxFilters.SelectedIndex = 0; } else { MessageBox.Show("No valid syntax generators found", messageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); } if (cboPresentationStyle.Items.Count == 0) { MessageBox.Show("No valid presentation styles found", messageBoxTitle, MessageBoxButtons.OK, MessageBoxIcon.Information); } }