/// <summary> /// This method can be used by plug-ins to merge content from another Sandcastle Help File Builder /// project file. /// </summary> /// <param name="project">The project file from which to merge content</param> /// <remarks>Auto-generated content can be added to a temporary SHFB project and then added to the /// current project's content at build time using this method. Such content cannot always be added to /// the project being built as it may alter the underlying MSBuild project which is not wanted.</remarks> public void MergeContentFrom(SandcastleProject project) { var otherImageFiles = new ImageReferenceCollection(project); var otherCodeSnippetFiles = new FileItemCollection(project, BuildAction.CodeSnippets); var otherTokenFiles = new FileItemCollection(project, BuildAction.Tokens); var otherContentLayoutFiles = new FileItemCollection(project, BuildAction.ContentLayout); foreach (var image in otherImageFiles) { imageFiles.Add(image); } foreach (var snippets in otherCodeSnippetFiles) { codeSnippetFiles.Add(snippets); } foreach (var tokens in otherTokenFiles) { tokenFiles.Add(tokens); } foreach (FileItem file in otherContentLayoutFiles) { topics.Add(new TopicCollection(file)); } }
//===================================================================== /// <summary> /// This loads the tree view with token file entries from the project /// </summary> private void LoadTokenInfo() { TreeNode rootNode = null, node; TokenCollection tokens; tvEntities.ImageList = ilImages; tvEntities.Nodes.Clear(); if (tokenFiles == null) { tokenFiles = new FileItemCollection(currentProject, BuildAction.Tokens); } foreach (FileItem tokenFile in tokenFiles) { try { if (File.Exists(tokenFile.FullPath)) { rootNode = tvEntities.Nodes.Add(Path.GetFileName( tokenFile.FullPath)); rootNode.ImageIndex = rootNode.SelectedImageIndex = (int)EntityType.CodeEntities; tokens = new TokenCollection(tokenFile); tokens.Load(); foreach (Token t in tokens) { node = rootNode.Nodes.Add(t.TokenName); node.Name = t.TokenName; node.Tag = t; node.ImageIndex = node.SelectedImageIndex = (int)EntityType.Tokens; } } rootNode = null; } catch (Exception ex) { if (rootNode == null) { tvEntities.Nodes.Add("Unable to load file '" + tokenFile.FullPath + "'. Reason: " + ex.Message); } else { rootNode.Nodes.Add("Unable to load file: " + ex.Message); } } } txtFindName.Enabled = true; tvEntities.Enabled = true; tvEntities.ExpandAll(); }
//===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="project">The project from which to load the settings</param> public ConceptualContentSettings(SandcastleProject project) { imageFiles = new ImageReferenceCollection(project); codeSnippetFiles = new FileItemCollection(project, BuildAction.CodeSnippets); tokenFiles = new FileItemCollection(project, BuildAction.Tokens); contentLayoutFiles = new FileItemCollection(project, BuildAction.ContentLayout); topics = new Collection<TopicCollection>(); foreach(FileItem file in contentLayoutFiles) topics.Add(new TopicCollection(file)); }
public ImportForm(IDatabaseManager databaseManager) { this.InitializeComponent(); this.InitializeListViewEnhancements(); this.listViewWorker = this.InitializeListViewWorker(); this.processWorker = this.InitializeProcessWorker(); this.files = new FileItemCollection(); this.options = new FileOptions(); this.databaseManager = databaseManager; this.isValidDataTable = false; }
//===================================================================== /// <summary> /// Constructor /// </summary> /// <param name="project">The project from which to load the settings</param> public ConceptualContentSettings(SandcastleProject project) { imageFiles = new ImageReferenceCollection(project); codeSnippetFiles = new FileItemCollection(project, BuildAction.CodeSnippets); tokenFiles = new FileItemCollection(project, BuildAction.Tokens); contentLayoutFiles = new FileItemCollection(project, BuildAction.ContentLayout); topics = new Collection <TopicCollection>(); foreach (FileItem file in contentLayoutFiles) { topics.Add(new TopicCollection(file)); } }
public PackageClass() { Groups = new GroupItemCollection(); Sections = new SectionItemCollection(); GeneralInfo = new GeneralInfoItem(); UniqueFileList = new FileItemCollection(); Version = "2.0"; ZipProvider = new ZipProviderClass(); UnInstallInfo = new UnInstallInfoCollection(); Dependencies = new DependencyItemCollection(); PluginDependencies = new PluginDependencyItemCollection(); ProjectSettings = new ProjectSettings(); Silent = false; IsHiden = false; Parent = null; }
//===================================================================== /// <summary> /// This is called to copy the additional content files to the help format content folders /// </summary> private void CopyAdditionalContent() { FileItemCollection contentItems; string projectPath, source, filename, dirName; this.ReportProgress(BuildStep.CopyAdditionalContent, "Copying additional content files..."); if (!this.ExecutePlugIns(ExecutionBehaviors.InsteadOf)) { // Plug-ins might add or remove additional content so call them before checking to see if there // is anything to copy. this.ExecutePlugIns(ExecutionBehaviors.Before); if (!project.HasItems(BuildAction.Content)) { this.ReportProgress("No additional content to copy"); } else { // Now copy the content files contentItems = new FileItemCollection(project, BuildAction.Content); projectPath = FolderPath.TerminatePath(Path.GetDirectoryName(originalProjectName)); foreach (FileItem fileItem in contentItems) { source = fileItem.Include; dirName = Path.GetDirectoryName(fileItem.Link.ToString().Substring(projectPath.Length)); filename = Path.Combine(dirName, Path.GetFileName(source)); this.EnsureOutputFoldersExist(dirName); foreach (string baseFolder in this.HelpFormatOutputFolders) { this.ReportProgress("{0} -> {1}{2}", source, baseFolder, filename); // All attributes are turned off so that we can delete it later File.Copy(source, baseFolder + filename, true); File.SetAttributes(baseFolder + filename, FileAttributes.Normal); } } } this.ExecutePlugIns(ExecutionBehaviors.After); } }
private void btnStart_Click(object sender, RoutedEventArgs e) { if (!CanEnterState(State.Working)) { return; } var configuration = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); configuration.AppSettings.Settings["imageFinder.dir1"].Value = txtDir1.Text.Trim(); configuration.AppSettings.Settings["imageFinder.dir2"].Value = txtDir2.Text.Trim(); configuration.AppSettings.Settings["imageFinder.dir3"].Value = txtDir3.Text.Trim(); configuration.AppSettings.Settings["imageFinder.dir4"].Value = txtDir4.Text.Trim(); configuration.AppSettings.Settings["imageFinder.dir5"].Value = txtDir5.Text.Trim(); configuration.Save(); var dirs = new List <string>(); AddValidDir(dirs, txtDir1); AddValidDir(dirs, txtDir2); AddValidDir(dirs, txtDir3); AddValidDir(dirs, txtDir4); AddValidDir(dirs, txtDir5); if (dirs.Count > 0) { if (_files != null) { _files.SelectionChanged -= files_SelectionChanged; } _files = new FileItemCollection(); _files.SelectionChanged += files_SelectionChanged; fileList.ItemsSource = _files; _task = new FinderTask(this, dirs.ToArray()); _task.Start(); } else { MessageBox.Show("请输入目录"); } }
/// <summary> /// Refresh the currently displayed entity information /// </summary> /// <param name="sender">The sender of the event</param> /// <param name="e">The event arguments</param> private void tsbRefresh_Click(object sender, EventArgs e) { switch ((EntityType)cboContentType.SelectedIndex) { case EntityType.Tokens: tokenFiles = null; break; case EntityType.Images: images = null; break; case EntityType.CodeSnippets: codeSnippetFiles = null; break; default: codeEntities = null; break; } tvEntities.Nodes.Clear(); this.cboContentType_SelectedIndexChanged(sender, e); }
//===================================================================== /// <summary> /// This loads the tree view with table of contents file entries from the project /// </summary> private List <EntityReference> LoadTableOfContentsInfo() { FileItemCollection contentLayoutFiles, siteMapFiles; List <ITableOfContents> tocFiles; TopicCollection contentLayout; TocEntryCollection siteMap, mergedToc; EntityReference er; bool hasSelectedItem = false; if (tableOfContents != null) { return(tableOfContents); } tableOfContents = new List <EntityReference>(); // Get content from open file editors var args = new FileContentNeededEventArgs(FileContentNeededEvent, this); base.RaiseEvent(args); try { // Get the content layout and site map files currentProject.EnsureProjectIsCurrent(false); contentLayoutFiles = new FileItemCollection(currentProject, BuildAction.ContentLayout); siteMapFiles = new FileItemCollection(currentProject, BuildAction.SiteMap); tocFiles = new List <ITableOfContents>(); // Add the conceptual content layout files foreach (FileItem file in contentLayoutFiles) { // If open in an editor, use the edited values if (!args.ContentLayoutFiles.TryGetValue(file.FullPath, out contentLayout)) { contentLayout = new TopicCollection(file); contentLayout.Load(); } tocFiles.Add(contentLayout); } // Load all site maps and add them to the list foreach (FileItem fileItem in siteMapFiles) { // If open in an editor, use the edited values if (!args.SiteMapFiles.TryGetValue(fileItem.FullPath, out siteMap)) { siteMap = new TocEntryCollection(fileItem); siteMap.Load(); } tocFiles.Add(siteMap); } // Sort the files tocFiles.Sort((x, y) => { FileItem fx = x.ContentLayoutFile, fy = y.ContentLayoutFile; if (fx.SortOrder < fy.SortOrder) { return(-1); } if (fx.SortOrder > fy.SortOrder) { return(1); } return(String.Compare(fx.Name, fy.Name, StringComparison.OrdinalIgnoreCase)); }); // Create the merged TOC. For the purpose of adding links, we'll include everything // even topics marked as invisible. mergedToc = new TocEntryCollection(); foreach (ITableOfContents file in tocFiles) { file.GenerateTableOfContents(mergedToc, currentProject, true); } // Convert the TOC info to entity references foreach (var t in mergedToc) { er = new EntityReference { EntityType = EntityType.TocEntry, Id = t.Id, Label = (t.Title ?? t.Id ?? "(No title)"), ToolTip = String.Format(CultureInfo.CurrentCulture, "ID: {0}\nFile: {1}", (t.Id ?? t.Title ?? "(No ID)"), t.SourceFile), Tag = t, IsExpanded = t.IsExpanded, IsSelected = (t.IsSelected && !hasSelectedItem) }; // Only use the first selected item if (er.IsSelected) { hasSelectedItem = true; } tableOfContents.Add(er); if (t.Children.Count != 0) { hasSelectedItem = this.AddChildTocEntries(t, er, hasSelectedItem); } } } catch (Exception ex) { tableOfContents.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load TOC info: " + ex.Message, ToolTip = "Error" }); } if (!hasSelectedItem && tableOfContents.Count != 0) { tableOfContents[0].IsSelected = true; } return(tableOfContents); }
//===================================================================== /// <summary> /// This loads the tree view with token file entries from the project /// </summary> private List <EntityReference> LoadTokenInfo() { FileItemCollection tokenFiles; EntityReference tokenFileEntity = null; TokenCollection tokenColl; if (tokens != null) { return(tokens); } tokens = new List <EntityReference>(); currentProject.EnsureProjectIsCurrent(false); tokenFiles = new FileItemCollection(currentProject, BuildAction.Tokens); // Get content from open file editors var args = new FileContentNeededEventArgs(FileContentNeededEvent, this); base.RaiseEvent(args); foreach (FileItem tokenFile in tokenFiles) { try { if (File.Exists(tokenFile.FullPath)) { tokenFileEntity = new EntityReference { EntityType = EntityType.File, Id = tokenFile.FullPath, Label = Path.GetFileName(tokenFile.FullPath), ToolTip = tokenFile.FullPath }; tokens.Add(tokenFileEntity); // If open in an editor, use the edited values if (!args.TokenFiles.TryGetValue(tokenFile.FullPath, out tokenColl)) { tokenColl = new TokenCollection(tokenFile.FullPath); tokenColl.Load(); } foreach (Token t in tokenColl) { tokenFileEntity.SubEntities.Add(new EntityReference { EntityType = EntityType.Token, Id = t.TokenName, Label = t.TokenName, ToolTip = t.TokenName, Tag = t }); } } tokenFileEntity = null; } catch (Exception ex) { if (tokenFileEntity == null) { tokens.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file '" + tokenFile.FullPath + "'. Reason: " + ex.Message, ToolTip = "Error" }); } else { tokens.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file: " + ex.Message, ToolTip = "Error" }); } } } if (tokens.Count != 0) { tokens[0].IsSelected = true; if (tokens[0].SubEntities.Count != 0) { tokens[0].IsExpanded = true; } } return(tokens); }
/// <summary> /// This is called to copy the additional content files and build a /// list of them for the help file project. /// </summary> /// <remarks>Note that for wilcard content items, the folders are /// copied recursively.</remarks> protected void CopyAdditionalContent() { Dictionary<string, TocEntryCollection> tocItems = new Dictionary<string, TocEntryCollection>(); TocEntryCollection parentToc; TocEntry tocEntry, tocFolder; FileItemCollection contentItems; string projectPath, source, filename, dirName; string[] parts; int part; this.ReportProgress(BuildStep.CopyAdditionalContent, "Copying additional content files..."); if(this.ExecutePlugIns(ExecutionBehaviors.InsteadOf)) return; // A plug-in might add or remove additional content so call // them before checking to see if there is anything to copy. this.ExecutePlugIns(ExecutionBehaviors.Before); if(!project.HasItems(BuildAction.Content) && !project.HasItems(BuildAction.SiteMap)) { this.ReportProgress("No additional content to copy"); this.ExecutePlugIns(ExecutionBehaviors.After); return; } toc = new TocEntryCollection(); tocItems.Add(String.Empty, toc); // Now copy the content files contentItems = new FileItemCollection(project, BuildAction.Content); projectPath = FolderPath.TerminatePath(Path.GetDirectoryName(originalProjectName)); foreach(FileItem fileItem in contentItems) { source = fileItem.Include; dirName = Path.GetDirectoryName(fileItem.Link.ToString().Substring(projectPath.Length)); filename = Path.Combine(dirName, Path.GetFileName(source)); if(source.EndsWith(".htm", StringComparison.OrdinalIgnoreCase) || source.EndsWith(".html", StringComparison.OrdinalIgnoreCase) || source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) { tocEntry = BuildProcess.GetTocInfo(source); // Exclude the page if so indicated via the item metadata if(fileItem.ExcludeFromToc) tocEntry.IncludePage = false; // .topic files get transformed into .html files if(source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) filename = Path.ChangeExtension(filename, ".html"); tocEntry.SourceFile = new FilePath(source, project); tocEntry.DestinationFile = filename; // Figure out where to add the entry parts = tocEntry.DestinationFile.Split('\\'); pathToRoot = String.Empty; parentToc = toc; for(part = 0; part < parts.Length - 1; part++) { pathToRoot += parts[part] + @"\"; // Create place holders if necessary if(!tocItems.TryGetValue(pathToRoot, out parentToc)) { tocFolder = new TocEntry(project); tocFolder.Title = parts[part]; if(part == 0) toc.Add(tocFolder); else tocItems[String.Join(@"\", parts, 0, part) + @"\"].Add(tocFolder); parentToc = tocFolder.Children; tocItems.Add(pathToRoot, parentToc); } } parentToc.Add(tocEntry); if(tocEntry.IncludePage && tocEntry.IsDefaultTopic) defaultTopic = tocEntry.DestinationFile; } else tocEntry = null; this.EnsureOutputFoldersExist(dirName); foreach(string baseFolder in this.HelpFormatOutputFolders) { // If the file contains items that need to be resolved, // it is handled separately. if(tocEntry != null && (tocEntry.HasLinks || tocEntry.HasCodeBlocks || tocEntry.NeedsColorizing || tocEntry.HasProjectTags || source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))) { // Figure out the path to the root if needed parts = tocEntry.DestinationFile.Split('\\'); pathToRoot = String.Empty; for(part = 0; part < parts.Length - 1; part++) pathToRoot += "../"; this.ResolveLinksAndCopy(source, baseFolder + filename, tocEntry); } else { this.ReportProgress("{0} -> {1}{2}", source, baseFolder, filename); // All attributes are turned off so that we can delete it later File.Copy(source, baseFolder + filename, true); File.SetAttributes(baseFolder + filename, FileAttributes.Normal); } } } // Remove excluded nodes, merge folder item info into the root // nodes, and sort the items. If a site map isn't defined, this // will define the layout of the items. toc.RemoveExcludedNodes(null); toc.Sort(); codeColorizer = null; sharedContent = sharedBuilderContent = styleContent = null; this.ExecutePlugIns(ExecutionBehaviors.After); }
/// <summary> /// This is used to merge the conceptual content table of contents with /// any additional content table of contents information. /// </summary> /// <remarks>This will also split the table of contents if any entry /// has the "split" option. A split in the conceptual content will /// take precedence as additional content is always appended to /// the end of the conceptual content. Likewise, a default topic in /// the conceptual content will take precedence over a default topic /// in the additional content.</remarks> private void MergeConceptualAndAdditionalContentTocInfo() { FileItemCollection siteMapFiles; List <ITableOfContents> tocFiles; TocEntryCollection siteMap, mergedToc; TocEntry tocEntry; this.ReportProgress(BuildStep.MergeTablesOfContents, "Merging conceptual and additional tables of contents..."); if (this.ExecutePlugIns(ExecutionBehaviors.InsteadOf)) { return; } this.ExecutePlugIns(ExecutionBehaviors.Before); // Add the conceptual content layout files tocFiles = new List <ITableOfContents>(); foreach (TopicCollection topics in conceptualContent.Topics) { tocFiles.Add(topics); } // Load all site maps and add them to the list siteMapFiles = new FileItemCollection(project, BuildAction.SiteMap); foreach (FileItem fileItem in siteMapFiles) { this.ReportProgress(" Loading site map '{0}'", fileItem.FullPath); siteMap = new TocEntryCollection(fileItem); siteMap.Load(); // Merge destination file information into the site map foreach (TocEntry site in siteMap) { this.MergeTocInfo(site); } tocFiles.Add(siteMap); } // Sort the files tocFiles.Sort((x, y) => { FileItem fx = x.ContentLayoutFile, fy = y.ContentLayoutFile; if (fx.SortOrder < fy.SortOrder) { return(-1); } if (fx.SortOrder > fy.SortOrder) { return(1); } return(String.Compare(fx.Name, fy.Name, StringComparison.OrdinalIgnoreCase)); }); // Create the merged TOC. Invisible items are excluded. mergedToc = new TocEntryCollection(); foreach (ITableOfContents file in tocFiles) { file.GenerateTableOfContents(mergedToc, project, false); } // If there were no site maps, add items copied from the project. // Empty container nodes are ignored. if (siteMapFiles.Count == 0 && toc != null && toc.Count != 0) { foreach (TocEntry t in toc) { if (t.DestinationFile != null || t.Children.Count != 0) { mergedToc.Add(t); } } } toc = mergedToc; if (toc.Count != 0) { // Look for the default topic tocEntry = toc.FindDefaultTopic(); if (tocEntry != null) { defaultTopic = tocEntry.DestinationFile; } } this.ExecutePlugIns(ExecutionBehaviors.After); }
/// <summary> /// This is used to merge the conceptual content table of contents with /// any additional content table of contents information. /// </summary> /// <remarks>This will also split the table of contents if any entry /// has the "split" option. A split in the conceptual content will /// take precedence as additional content is always appended to /// the end of the conceptual content. Likewise, a default topic in /// the conceptual content will take precedence over a default topic /// in the additional content.</remarks> private void MergeConceptualAndAdditionalContentTocInfo() { FileItemCollection siteMapFiles; List<ITableOfContents> tocFiles; TocEntryCollection siteMap, mergedToc; TocEntry tocEntry; this.ReportProgress(BuildStep.MergeTablesOfContents, "Merging conceptual and additional tables of contents..."); if(this.ExecutePlugIns(ExecutionBehaviors.InsteadOf)) return; this.ExecutePlugIns(ExecutionBehaviors.Before); // Add the conceptual content layout files tocFiles = new List<ITableOfContents>(); foreach(TopicCollection topics in conceptualContent.Topics) tocFiles.Add(topics); // Load all site maps and add them to the list siteMapFiles = new FileItemCollection(project, BuildAction.SiteMap); foreach(FileItem fileItem in siteMapFiles) { this.ReportProgress(" Loading site map '{0}'", fileItem.FullPath); siteMap = new TocEntryCollection(fileItem); siteMap.Load(); // Merge destination file information into the site map foreach(TocEntry site in siteMap) this.MergeTocInfo(site); tocFiles.Add(siteMap); } // Sort the files tocFiles.Sort((x, y) => { FileItem fx = x.ContentLayoutFile, fy = y.ContentLayoutFile; if(fx.SortOrder < fy.SortOrder) return -1; if(fx.SortOrder > fy.SortOrder) return 1; return String.Compare(fx.Name, fy.Name, StringComparison.OrdinalIgnoreCase); }); // Create the merged TOC mergedToc = new TocEntryCollection(); foreach(ITableOfContents file in tocFiles) file.GenerateTableOfContents(mergedToc, project); // If there were no site maps, add items copied from the project. // Empty container nodes are ignored. if(siteMapFiles.Count == 0 && toc != null && toc.Count != 0) foreach(TocEntry t in toc) if(t.DestinationFile != null || t.Children.Count != 0) mergedToc.Add(t); toc = mergedToc; if(toc.Count != 0) { // Look for the default topic tocEntry = toc.FindDefaultTopic(); if(tocEntry != null) defaultTopic = tocEntry.DestinationFile; } this.ExecutePlugIns(ExecutionBehaviors.After); }
//===================================================================== /// <summary> /// This loads the tree view with token file entries from the project /// </summary> private void LoadTokenInfo() { TreeNode rootNode = null, node; TokenCollection tokens; tvEntities.ImageList = ilImages; tvEntities.Nodes.Clear(); if(tokenFiles == null) tokenFiles = new FileItemCollection(currentProject, BuildAction.Tokens); foreach(FileItem tokenFile in tokenFiles) try { if(File.Exists(tokenFile.FullPath)) { rootNode = tvEntities.Nodes.Add(Path.GetFileName( tokenFile.FullPath)); rootNode.ImageIndex = rootNode.SelectedImageIndex = (int)EntityType.CodeEntities; tokens = new TokenCollection(tokenFile); tokens.Load(); foreach(Token t in tokens) { node = rootNode.Nodes.Add(t.TokenName); node.Name = t.TokenName; node.Tag = t; node.ImageIndex = node.SelectedImageIndex = (int)EntityType.Tokens; } } rootNode = null; } catch(Exception ex) { if(rootNode == null) tvEntities.Nodes.Add("Unable to load file '" + tokenFile.FullPath + "'. Reason: " + ex.Message); else rootNode.Nodes.Add("Unable to load file: " + ex.Message); } txtFindName.Enabled = true; tvEntities.Enabled = true; tvEntities.ExpandAll(); }
//===================================================================== /// <summary> /// This loads the tree view with code snippet file entries from the project /// </summary> private List <EntityReference> LoadCodeSnippetInfo() { FileItemCollection codeSnippetFiles; EntityReference snippetFileEntity = null; XPathDocument snippets; XPathNavigator navSnippets; CodeReference cr; if (codeSnippets != null) { return(codeSnippets); } codeSnippets = new List <EntityReference>(); currentProject.EnsureProjectIsCurrent(false); codeSnippetFiles = new FileItemCollection(currentProject, BuildAction.CodeSnippets); foreach (FileItem snippetFile in codeSnippetFiles) { try { if (File.Exists(snippetFile.FullPath)) { snippetFileEntity = new EntityReference { EntityType = EntityType.File, Id = snippetFile.FullPath, Label = Path.GetFileName(snippetFile.FullPath), ToolTip = snippetFile.FullPath }; codeSnippets.Add(snippetFileEntity); snippets = new XPathDocument(snippetFile.FullPath); navSnippets = snippets.CreateNavigator(); foreach (XPathNavigator nav in navSnippets.Select("examples/item/@id")) { cr = new CodeReference(nav.Value); snippetFileEntity.SubEntities.Add(new EntityReference { EntityType = EntityType.CodeSnippet, Id = cr.Id, Label = cr.Id, ToolTip = cr.Id, Tag = cr }); } } snippetFileEntity = null; } catch (Exception ex) { if (snippetFileEntity == null) { codeSnippets.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file '" + snippetFile.FullPath + "'. Reason: " + ex.Message, ToolTip = "Error" }); } else { codeSnippets.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file: " + ex.Message, ToolTip = "Error" }); } } } if (codeSnippets.Count != 0) { codeSnippets[0].IsSelected = true; if (codeSnippets[0].SubEntities.Count != 0) { codeSnippets[0].IsExpanded = true; } } return(codeSnippets); }
//===================================================================== /// <summary> /// This loads the tree view with code snippet file entries from the project /// </summary> private List<EntityReference> LoadCodeSnippetInfo() { FileItemCollection codeSnippetFiles; EntityReference snippetFileEntity = null; XPathDocument snippets; XPathNavigator navSnippets; CodeReference cr; if(codeSnippets != null) return codeSnippets; codeSnippets = new List<EntityReference>(); currentProject.EnsureProjectIsCurrent(false); codeSnippetFiles = new FileItemCollection(currentProject, BuildAction.CodeSnippets); foreach(FileItem snippetFile in codeSnippetFiles) try { if(File.Exists(snippetFile.FullPath)) { snippetFileEntity = new EntityReference { EntityType = EntityType.File, Id = snippetFile.FullPath, Label = Path.GetFileName(snippetFile.FullPath), ToolTip = snippetFile.FullPath }; codeSnippets.Add(snippetFileEntity); snippets = new XPathDocument(snippetFile.FullPath); navSnippets = snippets.CreateNavigator(); foreach(XPathNavigator nav in navSnippets.Select("examples/item/@id")) { cr = new CodeReference(nav.Value); snippetFileEntity.SubEntities.Add(new EntityReference { EntityType = EntityType.CodeSnippet, Id = cr.Id, Label = cr.Id, ToolTip = cr.Id, Tag = cr }); } } snippetFileEntity = null; } catch(Exception ex) { if(snippetFileEntity == null) codeSnippets.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file '" + snippetFile.FullPath + "'. Reason: " + ex.Message, ToolTip = "Error" }); else codeSnippets.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file: " + ex.Message, ToolTip = "Error" }); } if(codeSnippets.Count != 0) { codeSnippets[0].IsSelected = true; if(codeSnippets[0].SubEntities.Count != 0) codeSnippets[0].IsExpanded = true; } return codeSnippets; }
//===================================================================== /// <summary> /// This loads the tree view with table of contents file entries from the project /// </summary> private List<EntityReference> LoadTableOfContentsInfo() { FileItemCollection contentLayoutFiles, siteMapFiles; List<ITableOfContents> tocFiles; TopicCollection contentLayout; TocEntryCollection siteMap, mergedToc; EntityReference er; bool hasSelectedItem = false; if(tableOfContents != null) return tableOfContents; tableOfContents = new List<EntityReference>(); // Get content from open file editors var args = new FileContentNeededEventArgs(FileContentNeededEvent, this); base.RaiseEvent(args); try { // Get the content layout and site map files currentProject.EnsureProjectIsCurrent(false); contentLayoutFiles = new FileItemCollection(currentProject, BuildAction.ContentLayout); siteMapFiles = new FileItemCollection(currentProject, BuildAction.SiteMap); tocFiles = new List<ITableOfContents>(); // Add the conceptual content layout files foreach(FileItem file in contentLayoutFiles) { // If open in an editor, use the edited values if(!args.ContentLayoutFiles.TryGetValue(file.FullPath, out contentLayout)) { contentLayout = new TopicCollection(file); contentLayout.Load(); } tocFiles.Add(contentLayout); } // Load all site maps and add them to the list foreach(FileItem fileItem in siteMapFiles) { // If open in an editor, use the edited values if(!args.SiteMapFiles.TryGetValue(fileItem.FullPath, out siteMap)) { siteMap = new TocEntryCollection(fileItem); siteMap.Load(); } tocFiles.Add(siteMap); } // Sort the files tocFiles.Sort((x, y) => { FileItem fx = x.ContentLayoutFile, fy = y.ContentLayoutFile; if(fx.SortOrder < fy.SortOrder) return -1; if(fx.SortOrder > fy.SortOrder) return 1; return String.Compare(fx.Name, fy.Name, StringComparison.OrdinalIgnoreCase); }); // Create the merged TOC. For the purpose of adding links, we'll include everything // even topics marked as invisible. mergedToc = new TocEntryCollection(); foreach(ITableOfContents file in tocFiles) file.GenerateTableOfContents(mergedToc, currentProject, true); // Convert the TOC info to entity references foreach(var t in mergedToc) { er = new EntityReference { EntityType = EntityType.TocEntry, Id = t.Id, Label = (t.Title ?? t.Id ?? "(No title)"), ToolTip = String.Format(CultureInfo.CurrentCulture, "ID: {0}\nFile: {1}", (t.Id ?? t.Title ?? "(No ID)"), t.SourceFile), Tag = t, IsExpanded = t.IsExpanded, IsSelected = (t.IsSelected && !hasSelectedItem) }; // Only use the first selected item if(er.IsSelected) hasSelectedItem = true; tableOfContents.Add(er); if(t.Children.Count != 0) hasSelectedItem = this.AddChildTocEntries(t, er, hasSelectedItem); } } catch(Exception ex) { tableOfContents.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load TOC info: " + ex.Message, ToolTip = "Error" }); } if(!hasSelectedItem && tableOfContents.Count != 0) tableOfContents[0].IsSelected = true; return tableOfContents; }
//===================================================================== /// <summary> /// This loads the tree view with token file entries from the project /// </summary> private List<EntityReference> LoadTokenInfo() { FileItemCollection tokenFiles; EntityReference tokenFileEntity = null; TokenCollection tokenColl; if(tokens != null) return tokens; tokens = new List<EntityReference>(); currentProject.EnsureProjectIsCurrent(false); tokenFiles = new FileItemCollection(currentProject, BuildAction.Tokens); // Get content from open file editors var args = new FileContentNeededEventArgs(FileContentNeededEvent, this); base.RaiseEvent(args); foreach(FileItem tokenFile in tokenFiles) try { if(File.Exists(tokenFile.FullPath)) { tokenFileEntity = new EntityReference { EntityType = EntityType.File, Id = tokenFile.FullPath, Label = Path.GetFileName(tokenFile.FullPath), ToolTip = tokenFile.FullPath }; tokens.Add(tokenFileEntity); // If open in an editor, use the edited values if(!args.TokenFiles.TryGetValue(tokenFile.FullPath, out tokenColl)) { tokenColl = new TokenCollection(tokenFile.FullPath); tokenColl.Load(); } foreach(Token t in tokenColl) tokenFileEntity.SubEntities.Add(new EntityReference { EntityType = EntityType.Token, Id = t.TokenName, Label = t.TokenName, ToolTip = t.TokenName, Tag = t }); } tokenFileEntity = null; } catch(Exception ex) { if(tokenFileEntity == null) tokens.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file '" + tokenFile.FullPath + "'. Reason: " + ex.Message, ToolTip = "Error" }); else tokens.Add(new EntityReference { EntityType = EntityType.File, Label = "Unable to load file: " + ex.Message, ToolTip = "Error" }); } if(tokens.Count != 0) { tokens[0].IsSelected = true; if(tokens[0].SubEntities.Count != 0) tokens[0].IsExpanded = true; } return tokens; }
/// <summary> /// Replace a field tag with a value from the project /// </summary> /// <param name="match">The match that was found</param> /// <returns>The string to use as the replacement</returns> private string OnFieldMatch(Match match) { ProjectProperty buildProp; FileItemCollection fileItems; StringBuilder sb; string replaceWith, fieldName; string[] parts; fieldName = match.Groups["Field"].Value.ToLowerInvariant(); switch(fieldName) { case "appdatafolder": // This folder should exist if used replaceWith = FolderPath.TerminatePath(Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), Constants.ProgramDataFolder)); break; case "localdatafolder": // This folder may not exist and we may need to create it replaceWith = FolderPath.TerminatePath(Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Constants.ProgramDataFolder)); if(!Directory.Exists(replaceWith)) Directory.CreateDirectory(replaceWith); break; case "shfbfolder": replaceWith = ComponentUtilities.ToolsFolder; break; case "componentsfolder": replaceWith = ComponentUtilities.ComponentsFolder; break; case "projectfolder": replaceWith = Path.GetDirectoryName(originalProjectName); if(replaceWith.Length == 0) replaceWith = Directory.GetCurrentDirectory(); replaceWith += @"\"; break; case "htmlencprojectfolder": replaceWith = HttpUtility.HtmlEncode(Path.GetDirectoryName(originalProjectName)); if(replaceWith.Length == 0) replaceWith = HttpUtility.HtmlEncode(Directory.GetCurrentDirectory()); replaceWith += @"\"; break; case "outputfolder": replaceWith = outputFolder; break; case "htmlencoutputfolder": replaceWith = HttpUtility.HtmlEncode(outputFolder); break; case "workingfolder": replaceWith = workingFolder; break; case "htmlencworkingfolder": replaceWith = HttpUtility.HtmlEncode(workingFolder); break; case "presentationpath": replaceWith = FolderPath.TerminatePath(this.PresentationStyleFolder); break; case "presentationstyle": replaceWith = project.PresentationStyle; break; case "docmodeltransformation": replaceWith = presentationStyle.ResolvePath( presentationStyle.DocumentModelTransformation.TransformationFilename); break; case "docmodeltransformationparameters": replaceWith = String.Join(";", presentationStyle.DocumentModelTransformation.Select(p => String.Format(CultureInfo.InvariantCulture, "{0}={1}", p.Key, p.Value))); break; case "namingmethod": replaceWith = project.NamingMethod.ToString(); break; case "toctransformation": replaceWith = presentationStyle.ResolvePath( presentationStyle.IntermediateTocTransformation.TransformationFilename); break; case "toctransformparameters": replaceWith = String.Join(";", presentationStyle.IntermediateTocTransformation.Select(p => String.Format(CultureInfo.InvariantCulture, "{0}={1}", p.Key, p.Value))); break; case "hhcpath": replaceWith = hhcFolder; break; case "hxcomppath": replaceWith = hxcompFolder; break; case "disablecodeblockcomponent": replaceWith = project.DisableCodeBlockComponent.ToString().ToLowerInvariant(); break; case "htmlhelpname": replaceWith = project.HtmlHelpName; break; case "htmlenchelpname": replaceWith = HttpUtility.HtmlEncode(project.HtmlHelpName); break; case "helpviewersetupname": // Help viewer setup names cannot contain periods so we'll replace them with underscores replaceWith = HttpUtility.HtmlEncode(project.HtmlHelpName.Replace('.', '_')); break; case "frameworkcommentlist": case "importframeworkcommentlist": replaceWith = this.FrameworkCommentList(fieldName); break; case "commentfilelist": replaceWith = commentsFiles.CommentFileList(workingFolder, false); break; case "inheritedcommentfilelist": replaceWith = commentsFiles.CommentFileList(workingFolder, true); break; case "helptitle": replaceWith = project.HelpTitle; break; case "htmlenchelptitle": replaceWith = HttpUtility.HtmlEncode(project.HelpTitle); break; case "scripthelptitle": // This is used when the title is passed as a parameter // to a JavaScript function. replaceWith = HttpUtility.HtmlEncode(project.HelpTitle).Replace("'", @"\'"); break; case "urlenchelptitle": // Just replace &, <, >, and " for now replaceWith = project.HelpTitle.Replace("&", "%26").Replace( "<", "%3C").Replace(">", "%3E").Replace("\"", "%22"); break; case "rootnamespacetitle": replaceWith = project.RootNamespaceTitle; if(replaceWith.Length == 0) replaceWith = "<include item=\"rootTopicTitleLocalized\"/>"; break; case "namespacegrouping": if(project.NamespaceGrouping && presentationStyle.SupportsNamespaceGrouping) replaceWith = "true"; else { replaceWith = "false"; if(project.NamespaceGrouping) this.ReportWarning("BE0027", "Namespace grouping was requested but the selected " + "presentation style does not support it. Option ignored."); } break; case "codesnippetgrouping": replaceWith = presentationStyle.SupportsCodeSnippetGrouping.ToString().ToLowerInvariant(); break; case "maximumgroupparts": replaceWith = project.MaximumGroupParts.ToString(CultureInfo.InvariantCulture); break; case "binarytoc": replaceWith = project.BinaryTOC ? "Yes" : "No"; break; case "windowoptions": // Currently, we use a default set of options and only // allow showing or hiding the Favorites tab. replaceWith = (project.IncludeFavorites) ? "0x63520" : "0x62520"; break; case "langid": replaceWith = language.LCID.ToString(CultureInfo.InvariantCulture); break; case "language": replaceWith = String.Format(CultureInfo.InvariantCulture, "0x{0:X} {1}", language.LCID, language.NativeName); break; case "resourceitemsfolder": replaceWith = FolderPath.TerminatePath(Path.Combine( presentationStyle.ResolvePath(presentationStyle.ResourceItemsPath), languageFolder)); break; case "locale": replaceWith = language.Name.ToLowerInvariant(); break; case "localemixedcase": replaceWith = language.Name; break; case "copyright": // Include copyright info if there is a copyright HREF or copyright text if(project.CopyrightHref.Length != 0 || project.CopyrightText.Length != 0) replaceWith = "<include item=\"copyright\"/>"; else replaceWith = String.Empty; break; case "copyrightinfo": if(project.CopyrightHref.Length == 0 && project.CopyrightText.Length == 0) replaceWith = String.Empty; else if(project.CopyrightHref.Length == 0) replaceWith = project.DecodedCopyrightText; else if(project.CopyrightText.Length == 0) replaceWith = project.CopyrightHref; else replaceWith = String.Format(CultureInfo.CurrentCulture, "{0} ({1})", project.DecodedCopyrightText, project.CopyrightHref); break; case "htmlenccopyrightinfo": if(project.CopyrightHref.Length == 0 && project.CopyrightText.Length == 0) replaceWith = String.Empty; else if(project.CopyrightHref.Length == 0) replaceWith = "<p>" + HttpUtility.HtmlEncode(project.DecodedCopyrightText) + "</p>"; else if(project.CopyrightText.Length == 0) replaceWith = String.Format(CultureInfo.CurrentCulture, "<p><a href='{0}' target='_blank'>{0}</a></p>", HttpUtility.HtmlEncode(project.CopyrightHref)); else replaceWith = String.Format(CultureInfo.CurrentCulture, "<p><a href='{0}' target='_blank'>{1}</a></p>", HttpUtility.HtmlEncode(project.CopyrightHref), HttpUtility.HtmlEncode(project.DecodedCopyrightText)); break; case "copyrighthref": replaceWith = project.CopyrightHref; break; case "htmlenccopyrighthref": if(project.CopyrightHref.Length == 0) replaceWith = String.Empty; else replaceWith = String.Format(CultureInfo.CurrentCulture, "<a href='{0}' target='_blank'>{0}</a>", HttpUtility.HtmlEncode(project.CopyrightHref)); break; case "copyrighttext": if(project.CopyrightText.Length == 0) replaceWith = String.Empty; else replaceWith = project.DecodedCopyrightText; break; case "htmlenccopyrighttext": if(project.CopyrightText.Length == 0) replaceWith = String.Empty; else replaceWith = HttpUtility.HtmlEncode(project.DecodedCopyrightText); break; case "comments": // Include "send comments" line if feedback e-mail address // is specified. if(project.FeedbackEMailAddress.Length != 0) replaceWith = "<include item=\"comments\"/>"; else replaceWith = String.Empty; break; case "feedbackemailaddress": replaceWith = project.FeedbackEMailAddress; break; case "feedbackemaillinktext": replaceWith = project.FeedbackEMailLinkText; break; case "urlencfeedbackemailaddress": if(project.FeedbackEMailAddress.Length == 0) replaceWith = String.Empty; else replaceWith = HttpUtility.UrlEncode(project.FeedbackEMailAddress); break; case "htmlencfeedbackemailaddress": // If link text is specified, it will be used instead if(project.FeedbackEMailAddress.Length == 0) replaceWith = String.Empty; else if(project.FeedbackEMailLinkText.Length == 0) replaceWith = HttpUtility.HtmlEncode(project.FeedbackEMailAddress); else replaceWith = HttpUtility.HtmlEncode(project.FeedbackEMailLinkText); break; case "headertext": replaceWith = project.HeaderText; break; case "footertext": replaceWith = project.FooterText; break; case "indenthtml": replaceWith = project.IndentHtml.ToString().ToLowerInvariant(); break; case "preliminary": // Include the "preliminary" warning in the header text if wanted if(project.Preliminary) replaceWith = "<include item=\"preliminary\"/>"; else replaceWith = String.Empty; break; case "defaulttopic": if(defaultTopic.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) replaceWith = Path.ChangeExtension(defaultTopic, ".html"); else replaceWith = defaultTopic; break; case "webdefaulttopic": if(defaultTopic.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) replaceWith = Path.ChangeExtension(defaultTopic, ".html").Replace('\\', '/'); else replaceWith = defaultTopic.Replace('\\', '/'); break; case "targetframeworkidentifier": replaceWith = frameworkSettings.Platform; break; case "frameworkversion": replaceWith = frameworkSettings.Version.ToString(); break; case "frameworkversionshort": replaceWith = frameworkSettings.Version.ToString(2); break; case "platformversion": // MRefBuilder legacy platform element support // This specifies the framework version for use by CCI in MRefBuilder. It is related to // the .NET Framework and is currently capped at 2.0. Using a higher value causes // MRefBuilder to throw an exception. if(frameworkSettings.Platform != PlatformType.DotNetFramework || frameworkSettings.Version.Major > 2) replaceWith = "2.0"; else replaceWith = frameworkSettings.Version.ToString(2); break; case "coreframeworkpath": // MRefBuilder legacy platform element support replaceWith = frameworkSettings.AssemblyLocations.First(l => l.IsCoreLocation).Path; break; case "help1xprojectfiles": replaceWith = this.HelpProjectFileList(String.Format(CultureInfo.InvariantCulture, @"{0}Output\{1}", workingFolder, HelpFileFormats.HtmlHelp1), HelpFileFormats.HtmlHelp1); break; case "help2xprojectfiles": replaceWith = this.HelpProjectFileList(String.Format(CultureInfo.InvariantCulture, @"{0}Output\{1}", workingFolder, HelpFileFormats.MSHelp2), HelpFileFormats.MSHelp2); break; case "htmlsdklinktype": replaceWith = project.HtmlSdkLinkType.ToString().ToLowerInvariant(); break; case "mshelp2sdklinktype": replaceWith = project.MSHelp2SdkLinkType.ToString().ToLowerInvariant(); break; case "mshelpviewersdklinktype": replaceWith = project.MSHelpViewerSdkLinkType.ToString().ToLowerInvariant(); break; case "websitesdklinktype": replaceWith = project.WebsiteSdkLinkType.ToString().ToLowerInvariant(); break; case "sdklinktarget": replaceWith = "_" + project.SdkLinkTarget.ToString().ToLowerInvariant(); break; case "htmltoc": replaceWith = this.GenerateHtmlToc(); break; case "syntaxfilters": replaceWith = ComponentUtilities.SyntaxFilterGeneratorsFrom(syntaxGenerators, project.SyntaxFilters); break; case "syntaxfiltersdropdown": // Note that we can't remove the dropdown box if only a single language is selected as // script still depends on it. replaceWith = ComponentUtilities.SyntaxFilterLanguagesFrom(syntaxGenerators, project.SyntaxFilters); break; case "autodocumentconstructors": replaceWith = project.AutoDocumentConstructors.ToString().ToLowerInvariant(); break; case "autodocumentdisposemethods": replaceWith = project.AutoDocumentDisposeMethods.ToString().ToLowerInvariant(); break; case "showmissingparams": replaceWith = project.ShowMissingParams.ToString().ToLowerInvariant(); break; case "showmissingremarks": replaceWith = project.ShowMissingRemarks.ToString().ToLowerInvariant(); break; case "showmissingreturns": replaceWith = project.ShowMissingReturns.ToString().ToLowerInvariant(); break; case "showmissingsummaries": replaceWith = project.ShowMissingSummaries.ToString().ToLowerInvariant(); break; case "showmissingtypeparams": replaceWith = project.ShowMissingTypeParams.ToString().ToLowerInvariant(); break; case "showmissingvalues": replaceWith = project.ShowMissingValues.ToString().ToLowerInvariant(); break; case "showmissingnamespaces": replaceWith = project.ShowMissingNamespaces.ToString().ToLowerInvariant(); break; case "showmissingincludetargets": replaceWith = project.ShowMissingIncludeTargets.ToString().ToLowerInvariant(); break; case "documentattributes": replaceWith = project.DocumentAttributes.ToString().ToLowerInvariant(); break; case "documentexplicitinterfaceimplementations": replaceWith = project.DocumentExplicitInterfaceImplementations.ToString().ToLowerInvariant(); break; case "documentinheritedmembers": replaceWith = project.DocumentInheritedMembers.ToString().ToLowerInvariant(); break; case "documentinheritedframeworkmembers": replaceWith = project.DocumentInheritedFrameworkMembers.ToString().ToLowerInvariant(); break; case "documentinheritedframeworkinternalmembers": replaceWith = project.DocumentInheritedFrameworkInternalMembers.ToString().ToLowerInvariant(); break; case "documentinheritedframeworkprivatemembers": replaceWith = project.DocumentInheritedFrameworkPrivateMembers.ToString().ToLowerInvariant(); break; case "documentinternals": replaceWith = project.DocumentInternals.ToString().ToLowerInvariant(); break; case "documentprivates": replaceWith = project.DocumentPrivates.ToString().ToLowerInvariant(); break; case "documentprivatefields": replaceWith = project.DocumentPrivateFields.ToString().ToLowerInvariant(); break; case "documentprotected": replaceWith = project.DocumentProtected.ToString().ToLowerInvariant(); break; case "documentsealedprotected": replaceWith = project.DocumentSealedProtected.ToString().ToLowerInvariant(); break; case "documentprotectedinternalasprotected": replaceWith = project.DocumentProtectedInternalAsProtected.ToString().ToLowerInvariant(); break; case "documentnopiatypes": replaceWith = project.DocumentNoPIATypes.ToString().ToLowerInvariant(); break; case "apifilter": // In a partial build used to get API info for the API filter designer, we won't apply the // filter. if(!this.SuppressApiFilter) replaceWith = apiFilter.ToString(); else replaceWith = String.Empty; break; case "builddate": // Apply a format specifier? if(match.Groups["Format"].Value.Length != 0) replaceWith = String.Format(CultureInfo.CurrentCulture, "{0:" + match.Groups["Format"].Value + "}", DateTime.Now); else replaceWith = DateTime.Now.ToString(CultureInfo.CurrentCulture); break; case "projectnodename": replaceWith = "R:Project_" + project.HtmlHelpName.Replace(" ", "_"); break; case "rootnamespacecontainer": replaceWith = project.RootNamespaceContainer.ToString().ToLowerInvariant(); break; case "projectnodeidoptional": if(project.RootNamespaceContainer) replaceWith = "Project_" + project.HtmlHelpName.Replace(" ", "_").Replace("&", "_"); else replaceWith = String.Empty; break; case "projectnodeidrequired": replaceWith = "Project_" + project.HtmlHelpName.Replace(" ", "_").Replace("&", "_"); break; case "help1folder": if((project.HelpFileFormat & HelpFileFormats.HtmlHelp1) != 0) replaceWith = @"Output\" + HelpFileFormats.HtmlHelp1.ToString(); else replaceWith = String.Empty; break; case "websitefolder": if((project.HelpFileFormat & HelpFileFormats.Website) != 0) replaceWith = @"Output\" + HelpFileFormats.Website.ToString(); else replaceWith = String.Empty; break; case "stopwordfile": if(project.IncludeStopWordList) replaceWith = "StopWordFile=\"StopWordList.txt\""; else replaceWith = String.Empty; break; case "stopwordlistfilename": if(project.IncludeStopWordList) replaceWith = "StopWordList.txt"; else replaceWith = String.Empty; break; case "collectiontocstyle": replaceWith = project.CollectionTocStyle.ToString(); break; case "helpfileversion": replaceWith = project.HelpFileVersion; break; case "h2regpluginentries": parts = project.PlugInNamespaces.Split(','); sb = new StringBuilder(1024); foreach(string ns in parts) { replaceWith = ns.Trim(); if(replaceWith.Length != 0) sb.AppendFormat("{0}|_DEFAULT|{1}|_DEFAULT\r\n", replaceWith, project.HtmlHelpName); } replaceWith = sb.ToString(); break; case "h2regmergenamespaces": parts = project.PlugInNamespaces.Split(','); sb = new StringBuilder(1024); foreach(string ns in parts) { replaceWith = ns.Trim(); if(replaceWith.Length != 0) sb.AppendFormat("{0}|AUTO\r\n", replaceWith); } replaceWith = sb.ToString(); break; case "helpattributes": replaceWith = project.HelpAttributes.ToConfigurationString(); break; case "tokenfiles": sb = new StringBuilder(1024); if(conceptualContent != null) fileItems = conceptualContent.TokenFiles; else fileItems = new FileItemCollection(project, BuildAction.Tokens); foreach(FileItem file in fileItems) sb.AppendFormat("<content file=\"{0}\" />\r\n", Path.GetFileName(file.FullPath)); replaceWith = sb.ToString(); break; case "codesnippetsfiles": sb = new StringBuilder(1024); if(conceptualContent != null) fileItems = conceptualContent.CodeSnippetFiles; else fileItems = new FileItemCollection(project, BuildAction.CodeSnippets); foreach(FileItem file in fileItems) sb.AppendFormat("<examples file=\"{0}\" />\r\n", file.FullPath); replaceWith = sb.ToString(); break; case "resourceitemfiles": sb = new StringBuilder(1024); fileItems = new FileItemCollection(project, BuildAction.ResourceItems); // Add syntax generator resource item files. All languages are included regardless of the // project filter settings since code examples can be in any language. Files are copied and // transformed as they may contain substitution tags foreach(string itemFile in ComponentUtilities.SyntaxGeneratorResourceItemFiles( componentContainer, project.Language)) { sb.AppendFormat("<content file=\"{0}\" />\r\n", Path.GetFileName(itemFile)); this.TransformTemplate(Path.GetFileName(itemFile), Path.GetDirectoryName(itemFile), workingFolder); } // Add project resource item files last so that they override all other files foreach(FileItem file in fileItems) { sb.AppendFormat("<content file=\"{0}\" />\r\n", Path.GetFileName(file.FullPath)); this.TransformTemplate(Path.GetFileName(file.FullPath), Path.GetDirectoryName(file.FullPath), workingFolder); } replaceWith = sb.ToString(); break; case "xamlconfigfiles": sb = new StringBuilder(1024); fileItems = new FileItemCollection(project, BuildAction.XamlConfiguration); foreach(FileItem file in fileItems) sb.AppendFormat("<filter files=\"{0}\" />\r\n", file.FullPath); replaceWith = sb.ToString(); break; case "buildassemblerverbosity": replaceWith = (project.BuildAssemblerVerbosity == BuildAssemblerVerbosity.AllMessages) ? "Info" : (project.BuildAssemblerVerbosity == BuildAssemblerVerbosity.OnlyWarningsAndErrors) ? "Warn" : "Error"; break; case "componentlocations": if(String.IsNullOrWhiteSpace(project.ComponentPath)) replaceWith = String.Empty; else replaceWith = String.Format(CultureInfo.InvariantCulture, "<location folder=\"{0}\" />\r\n", HttpUtility.HtmlEncode(project.ComponentPath)); replaceWith += String.Format(CultureInfo.InvariantCulture, "<location folder=\"{0}\" />", HttpUtility.HtmlEncode(Path.GetDirectoryName(project.Filename))); break; case "helpfileformat": replaceWith = project.HelpFileFormat.ToString(); break; case "helpformatoutputpaths": sb = new StringBuilder(1024); // Add one entry for each help file format being generated foreach(string baseFolder in this.HelpFormatOutputFolders) sb.AppendFormat("<path value=\"{0}\" />", baseFolder.Substring(workingFolder.Length)); replaceWith = sb.ToString(); break; case "catalogname": replaceWith = project.CatalogName; break; case "catalogproductid": replaceWith = project.CatalogProductId; break; case "catalogversion": replaceWith = project.CatalogVersion; break; case "vendorname": replaceWith = !String.IsNullOrEmpty(project.VendorName) ? project.VendorName : "Vendor Name"; break; case "htmlencvendorname": replaceWith = !String.IsNullOrEmpty(project.VendorName) ? HttpUtility.HtmlEncode(project.VendorName) : "Vendor Name"; break; case "producttitle": replaceWith = !String.IsNullOrEmpty(project.ProductTitle) ? project.ProductTitle : project.HelpTitle; break; case "htmlencproducttitle": replaceWith = !String.IsNullOrEmpty(project.ProductTitle) ? HttpUtility.HtmlEncode(project.ProductTitle) : HttpUtility.HtmlEncode(project.HelpTitle); break; case "topicversion": replaceWith = HttpUtility.HtmlEncode(project.TopicVersion); break; case "tocparentid": replaceWith = HttpUtility.HtmlEncode(project.TocParentId); break; case "tocparentversion": replaceWith = HttpUtility.HtmlEncode(project.TocParentVersion); break; case "apitocparentid": // If null, empty or it starts with '*', it's parented to the root node if(!String.IsNullOrEmpty(this.ApiTocParentId) && this.ApiTocParentId[0] != '*') { // Ensure that the ID is valid and visible in the TOC if(!conceptualContent.Topics.Any(t => t[this.ApiTocParentId] != null && t[this.ApiTocParentId].Visible)) throw new BuilderException("BE0022", String.Format(CultureInfo.CurrentCulture, "The project's ApiTocParent property value '{0}' must be associated with a topic in " + "your project's conceptual content and must have its Visible property set to True in " + "the content layout file.", this.ApiTocParentId)); replaceWith = HttpUtility.HtmlEncode(this.ApiTocParentId); } else if(!String.IsNullOrEmpty(this.RootContentContainerId)) replaceWith = HttpUtility.HtmlEncode(this.RootContentContainerId); else replaceWith = HttpUtility.HtmlEncode(project.TocParentId); break; case "addxamlsyntaxdata": // If the XAML syntax generator is present, add XAML syntax data to the reflection file if(ComponentUtilities.SyntaxFiltersFrom(syntaxGenerators, project.SyntaxFilters).Any( s => s.Id == "XAML Usage")) replaceWith = @";~\ProductionTransforms\AddXamlSyntaxData.xsl"; else replaceWith = String.Empty; break; case "transformcomponentarguments": sb = new StringBuilder(1024); foreach(var arg in project.TransformComponentArguments) if(arg.Value != null) sb.AppendFormat("<argument key=\"{0}\" value=\"{1}\" />\r\n", arg.Key, arg.Value); else sb.AppendFormat("<argument key=\"{0}\">{1}</argument>\r\n", arg.Key, arg.Content); replaceWith = sb.ToString(); break; case "referencelinknamespacefiles": sb = new StringBuilder(1024); foreach(string s in this.ReferencedNamespaces) sb.AppendFormat("<namespace file=\"{0}.xml\" />\r\n", s); replaceWith = sb.ToString(); break; case "uniqueid": // Get a unique ID for the project and current user replaceWith = Environment.GetEnvironmentVariable("USERNAME"); if(String.IsNullOrWhiteSpace(replaceWith)) replaceWith = "DefaultUser"; replaceWith = (project.Filename + "_" + replaceWith).GetHashCode().ToString("X", CultureInfo.InvariantCulture); break; case "sandcastlepath": // This is obsolete but will still appear in the older component and plug-in configurations. // Throw an exception that describes what to do to fix it. throw new BuilderException("BE0065", "One or more component or plug-in configurations in " + "this project contains an obsolete path setting. Please remove the custom components " + "and plug-ins and add them again so that their configurations are updated. See the " + "version release notes for information on breaking changes that require this update."); default: // Try for a custom project property. Use the last one since the original may be // in a parent project file or it may have been overridden from the command line. buildProp = project.MSBuildProject.AllEvaluatedProperties.LastOrDefault( p => p.Name.Equals(fieldName, StringComparison.OrdinalIgnoreCase)); if(buildProp != null) replaceWith = buildProp.EvaluatedValue; else { // If not there, try the global properties. If still not found, give up. string key = project.MSBuildProject.GlobalProperties.Keys.FirstOrDefault( k => k.Equals(fieldName, StringComparison.OrdinalIgnoreCase)); if(key == null || !project.MSBuildProject.GlobalProperties.TryGetValue(key, out replaceWith)) switch(fieldName) { case "referencepath": // Ignore these and use an empty string case "outdir": replaceWith = String.Empty; break; default: throw new BuilderException("BE0020", String.Format(CultureInfo.CurrentCulture, "Unknown field tag: '{0}'", match.Groups["Field"].Value)); } } break; } return replaceWith; }
/// <summary> /// This is used to transform a *.topic file into a *.html file using /// an XSLT transformation based on the presentation style. /// </summary> /// <param name="sourceFile">The source topic filename</param> private void XslTransform(string sourceFile) { TocEntry tocInfo; XmlReader reader = null; XmlWriter writer = null; XsltSettings settings; XmlReaderSettings readerSettings; XmlWriterSettings writerSettings; Encoding enc = Encoding.Default; FileItemCollection transforms; string content; string sourceStylesheet, destFile = Path.ChangeExtension(sourceFile, ".html"); try { readerSettings = new XmlReaderSettings(); readerSettings.ProhibitDtd = false; readerSettings.CloseInput = true; // Create the transform on first use if(xslTransform == null) { transforms = new FileItemCollection(project, BuildAction.TopicTransform); if(transforms.Count != 0) { if(transforms.Count > 1) this.ReportWarning("BE0011", "Multiple topic " + "transformations found. Using '{0}'", transforms[0].FullPath); sourceStylesheet = transforms[0].FullPath; } else sourceStylesheet = templateFolder + presentationParam + ".xsl"; xslStylesheet = workingFolder + Path.GetFileName(sourceStylesheet); tocInfo = BuildProcess.GetTocInfo(sourceStylesheet); // The stylesheet may contain shared content items so we // must resolve it this way rather than using // TransformTemplate. this.ResolveLinksAndCopy(sourceStylesheet, xslStylesheet, tocInfo); xslTransform = new XslCompiledTransform(); settings = new XsltSettings(true, true); xslArguments = new XsltArgumentList(); xslTransform.Load(XmlReader.Create(xslStylesheet, readerSettings), settings, new XmlUrlResolver()); } this.ReportProgress("Applying XSL transformation '{0}' to '{1}'.", xslStylesheet, sourceFile); reader = XmlReader.Create(sourceFile, readerSettings); writerSettings = xslTransform.OutputSettings.Clone(); writerSettings.CloseOutput = true; writerSettings.Indent = false; writer = XmlWriter.Create(destFile, writerSettings); xslArguments.Clear(); xslArguments.AddParam("pathToRoot", String.Empty, pathToRoot); xslTransform.Transform(reader, xslArguments, writer); } catch(Exception ex) { throw new BuilderException("BE0017", String.Format( CultureInfo.InvariantCulture, "Unexpected error " + "using '{0}' to transform additional content file '{1}' " + "to '{2}'. The error is: {3}\r\n{4}", xslStylesheet, sourceFile, destFile, ex.Message, (ex.InnerException == null) ? String.Empty : ex.InnerException.Message)); } finally { if(reader != null) reader.Close(); if(writer != null) { writer.Flush(); writer.Close(); } } // The source topic file is deleted as the transformed file // takes its place. File.Delete(sourceFile); // <span> and <script> tags cannot be self-closing if empty. // The template may contain them correctly but when written out // as XML, they get converted to self-closing tags which breaks // them. To fix them, convert them to full start and close tags. content = BuildProcess.ReadWithEncoding(destFile, ref enc); content = reSpanScript.Replace(content, "<$1$2></$1>"); // An XSL transform might have added tags and include items that // need replacing so run it through those options if needed. tocInfo = BuildProcess.GetTocInfo(destFile); // Expand <code> tags if necessary if(tocInfo.HasCodeBlocks) content = reCodeBlock.Replace(content, codeBlockMatchEval); // Colorize <pre> tags if necessary if(tocInfo.NeedsColorizing || tocInfo.HasCodeBlocks) { // Initialize code colorizer on first use if(codeColorizer == null) codeColorizer = new CodeColorizer(shfbFolder + @"Colorizer\highlight.xml", shfbFolder + @"Colorizer\highlight.xsl"); // Set the path the "Copy" image codeColorizer.CopyImageUrl = pathToRoot + "icons/CopyCode.gif"; // Colorize it and replace the "Copy" literal text with the // shared content include item so that it gets localized. content = codeColorizer.ProcessAndHighlightText(content); content = content.Replace(codeColorizer.CopyText + "</span", "<include item=\"copyCode\"/></span"); tocInfo.HasProjectTags = true; } // Use a regular expression to find and replace all tags with // cref attributes with a link to the help file content. This // needs to happen after the code block processing as they // may contain <see> tags that need to be resolved. if(tocInfo.HasLinks || tocInfo.HasCodeBlocks) content = reResolveLinks.Replace(content, linkMatchEval); // Replace project option tags with project option values if(tocInfo.HasProjectTags) { // Project tags can be nested while(reProjectTags.IsMatch(content)) content = reProjectTags.Replace(content, fieldMatchEval); // Shared content items can be nested while(reSharedContent.IsMatch(content)) content = reSharedContent.Replace(content, contentMatchEval); } // Write the file back out with the appropriate encoding using(StreamWriter sw = new StreamWriter(destFile, false, enc)) { sw.Write(content); } }
/// <summary> /// This is called to copy the additional content files and build a list of them for the help file /// project. /// </summary> /// <remarks>Note that for wildcard content items, the folders are copied recursively.</remarks> private void CopyAdditionalContent() { Dictionary <string, TocEntryCollection> tocItems = new Dictionary <string, TocEntryCollection>(); TocEntryCollection parentToc; TocEntry tocEntry, tocFolder; FileItemCollection contentItems; string projectPath, source, filename, dirName; string[] parts; int part; this.ReportProgress(BuildStep.CopyAdditionalContent, "Copying additional content files..."); if (this.ExecutePlugIns(ExecutionBehaviors.InsteadOf)) { return; } // A plug-in might add or remove additional content so call // them before checking to see if there is anything to copy. this.ExecutePlugIns(ExecutionBehaviors.Before); if (!project.HasItems(BuildAction.Content) && !project.HasItems(BuildAction.SiteMap)) { this.ReportProgress("No additional content to copy"); this.ExecutePlugIns(ExecutionBehaviors.After); return; } toc = new TocEntryCollection(); tocItems.Add(String.Empty, toc); // Now copy the content files contentItems = new FileItemCollection(project, BuildAction.Content); projectPath = FolderPath.TerminatePath(Path.GetDirectoryName(originalProjectName)); foreach (FileItem fileItem in contentItems) { source = fileItem.Include; dirName = Path.GetDirectoryName(fileItem.Link.ToString().Substring(projectPath.Length)); filename = Path.Combine(dirName, Path.GetFileName(source)); if (source.EndsWith(".htm", StringComparison.OrdinalIgnoreCase) || source.EndsWith(".html", StringComparison.OrdinalIgnoreCase) || source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) { tocEntry = BuildProcess.GetTocInfo(source); // Exclude the page if so indicated via the item metadata if (fileItem.ExcludeFromToc) { tocEntry.IncludePage = false; } // .topic files get transformed into .html files if (source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) { filename = Path.ChangeExtension(filename, ".html"); } tocEntry.SourceFile = new FilePath(source, project); tocEntry.DestinationFile = filename; // Figure out where to add the entry parts = tocEntry.DestinationFile.Split('\\'); pathToRoot = String.Empty; parentToc = toc; for (part = 0; part < parts.Length - 1; part++) { pathToRoot += parts[part] + @"\"; // Create place holders if necessary if (!tocItems.TryGetValue(pathToRoot, out parentToc)) { tocFolder = new TocEntry(project); tocFolder.Title = parts[part]; if (part == 0) { toc.Add(tocFolder); } else { tocItems[String.Join(@"\", parts, 0, part) + @"\"].Add(tocFolder); } parentToc = tocFolder.Children; tocItems.Add(pathToRoot, parentToc); } } parentToc.Add(tocEntry); if (tocEntry.IncludePage && tocEntry.IsDefaultTopic) { defaultTopic = tocEntry.DestinationFile; } } else { tocEntry = null; } this.EnsureOutputFoldersExist(dirName); foreach (string baseFolder in this.HelpFormatOutputFolders) { // If the file contains items that need to be resolved, // it is handled separately. if (tocEntry != null && (tocEntry.HasLinks || tocEntry.HasCodeBlocks || tocEntry.NeedsColorizing || tocEntry.HasProjectTags || source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))) { // Figure out the path to the root if needed parts = tocEntry.DestinationFile.Split('\\'); pathToRoot = String.Empty; for (part = 0; part < parts.Length - 1; part++) { pathToRoot += "../"; } this.ResolveLinksAndCopy(source, baseFolder + filename, tocEntry); } else { this.ReportProgress("{0} -> {1}{2}", source, baseFolder, filename); // All attributes are turned off so that we can delete it later File.Copy(source, baseFolder + filename, true); File.SetAttributes(baseFolder + filename, FileAttributes.Normal); } } } // Remove excluded nodes, merge folder item info into the root // nodes, and sort the items. If a site map isn't defined, this // will define the layout of the items. toc.RemoveExcludedNodes(null); toc.Sort(); codeColorizer = null; sharedContent = null; this.ExecutePlugIns(ExecutionBehaviors.After); }
/// <summary> /// This method can be used by plug-ins to merge content from another Sandcastle Help File Builder /// project file. /// </summary> /// <param name="project">The project file from which to merge content</param> /// <remarks>Auto-generated content can be added to a temporary SHFB project and then added to the /// current project's content at build time using this method. Such content cannot always be added to /// the project being built as it may alter the underlying MSBuild project which is not wanted.</remarks> public void MergeContentFrom(SandcastleProject project) { var otherImageFiles = new ImageReferenceCollection(project); var otherCodeSnippetFiles = new FileItemCollection(project, BuildAction.CodeSnippets); var otherTokenFiles = new FileItemCollection(project, BuildAction.Tokens); var otherContentLayoutFiles = new FileItemCollection(project, BuildAction.ContentLayout); foreach(var image in otherImageFiles) imageFiles.Add(image); foreach(var snippets in otherCodeSnippetFiles) codeSnippetFiles.Add(snippets); foreach(var tokens in otherTokenFiles) tokenFiles.Add(tokens); foreach(FileItem file in otherContentLayoutFiles) topics.Add(new TopicCollection(file)); }
/// <summary> /// This is used to transform a *.topic file into a *.html file using an XSLT transformation based on the /// presentation style. /// </summary> /// <param name="sourceFile">The source topic filename</param> private void XslTransform(string sourceFile) { TocEntry tocInfo; XmlReader reader = null; XmlWriter writer = null; XsltSettings settings; XmlReaderSettings readerSettings; XmlWriterSettings writerSettings; Encoding enc = Encoding.Default; FileItemCollection transforms; string content; string sourceStylesheet, destFile = Path.ChangeExtension(sourceFile, ".html"); try { readerSettings = new XmlReaderSettings(); readerSettings.CloseInput = true; readerSettings.DtdProcessing = DtdProcessing.Parse; // Create the transform on first use if (xslTransform == null) { transforms = new FileItemCollection(project, BuildAction.TopicTransform); if (transforms.Count != 0) { if (transforms.Count > 1) { this.ReportWarning("BE0011", "Multiple topic transformations found. Using '{0}'", transforms[0].FullPath); } sourceStylesheet = transforms[0].FullPath; } else { sourceStylesheet = templateFolder + project.PresentationStyle + ".xsl"; } xslStylesheet = workingFolder + Path.GetFileName(sourceStylesheet); tocInfo = BuildProcess.GetTocInfo(sourceStylesheet); // The style sheet may contain shared content items so we must resolve it this way rather // than using TransformTemplate. this.ResolveLinksAndCopy(sourceStylesheet, xslStylesheet, tocInfo); xslTransform = new XslCompiledTransform(); settings = new XsltSettings(true, true); xslArguments = new XsltArgumentList(); xslTransform.Load(XmlReader.Create(xslStylesheet, readerSettings), settings, new XmlUrlResolver()); } this.ReportProgress("Applying XSL transformation '{0}' to '{1}'.", xslStylesheet, sourceFile); reader = XmlReader.Create(sourceFile, readerSettings); writerSettings = xslTransform.OutputSettings.Clone(); writerSettings.CloseOutput = true; writerSettings.Indent = false; writer = XmlWriter.Create(destFile, writerSettings); xslArguments.Clear(); xslArguments.AddParam("pathToRoot", String.Empty, pathToRoot); xslTransform.Transform(reader, xslArguments, writer); } catch (Exception ex) { throw new BuilderException("BE0017", String.Format(CultureInfo.CurrentCulture, "Unexpected error using '{0}' to transform additional content file '{1}' to '{2}'. The " + "error is: {3}\r\n{4}", xslStylesheet, sourceFile, destFile, ex.Message, (ex.InnerException == null) ? String.Empty : ex.InnerException.Message)); } finally { if (reader != null) { reader.Close(); } if (writer != null) { writer.Flush(); writer.Close(); } } // The source topic file is deleted as the transformed file takes its place File.Delete(sourceFile); // <span> and <script> tags cannot be self-closing if empty. The template may contain them correctly // but when written out as XML, they get converted to self-closing tags which breaks them. To fix // them, convert them to full start and close tags. content = BuildProcess.ReadWithEncoding(destFile, ref enc); content = reSpanScript.Replace(content, "<$1$2></$1>"); // An XSL transform might have added tags and include items that need replacing so run it through // those options if needed. tocInfo = BuildProcess.GetTocInfo(destFile); // Expand <code> tags if necessary if (tocInfo.HasCodeBlocks) { content = reCodeBlock.Replace(content, codeBlockMatchEval); } // Colorize <pre> tags if necessary if (tocInfo.NeedsColorizing || tocInfo.HasCodeBlocks) { // Initialize code colorizer on first use if (codeColorizer == null) { codeColorizer = new CodeColorizer(ComponentUtilities.ToolsFolder + @"PresentationStyles\Colorizer\highlight.xml", ComponentUtilities.ToolsFolder + @"PresentationStyles\Colorizer\highlight.xsl"); } // Set the path the "Copy" image codeColorizer.CopyImageUrl = pathToRoot + "icons/CopyCode.gif"; // Colorize it and replace the "Copy" literal text with the shared content include item so that // it gets localized. content = codeColorizer.ProcessAndHighlightText(content); content = content.Replace(codeColorizer.CopyText + "</span", "<include item=\"copyCode\"/></span"); tocInfo.HasProjectTags = true; } // Use a regular expression to find and replace all tags with cref attributes with a link to the help // file content. This needs to happen after the code block processing as they may contain <see> tags // that need to be resolved. if (tocInfo.HasLinks || tocInfo.HasCodeBlocks) { content = reResolveLinks.Replace(content, linkMatchEval); } // Replace project option tags with project option values if (tocInfo.HasProjectTags) { // Project tags can be nested while (reProjectTags.IsMatch(content)) { content = reProjectTags.Replace(content, fieldMatchEval); } // Shared content items can be nested while (reSharedContent.IsMatch(content)) { content = reSharedContent.Replace(content, contentMatchEval); } } // Write the file back out with the appropriate encoding using (StreamWriter sw = new StreamWriter(destFile, false, enc)) { sw.Write(content); } }
public void GenerateUniqueFileList() { FileItemCollection copy = new FileItemCollection(); foreach (FileItem item in UniqueFileList.Items) copy.Add(item); UniqueFileList.Items.Clear(); foreach (GroupItem groupItem in Groups.Items) { foreach (FileItem fileItem in groupItem.Files.Items) { if (!UniqueFileList.ExistLocalFileName(fileItem)) UniqueFileList.Add(new FileItem(fileItem)); } } foreach (SectionItem sectionItem in Sections.Items) { foreach (SectionParam sectionParam in sectionItem.Params.Items) { if (sectionParam.ValueType == ValueTypeEnum.File && !string.IsNullOrEmpty(sectionParam.Value)) { if (!UniqueFileList.ExistLocalFileName(sectionParam.Value)) { FileItem existingItem = copy.GetByLocalFileName(sectionParam.Value); if (existingItem != null) UniqueFileList.Add(existingItem); else UniqueFileList.Add(new FileItem(sectionParam.Value, true)); } else UniqueFileList.GetByLocalFileName(sectionParam.Value).SystemFile = true; } } foreach (ActionItem actionItem in sectionItem.Actions.Items) { foreach (SectionParam sectionParam in actionItem.Params.Items) { if (sectionParam.ValueType == ValueTypeEnum.File && !string.IsNullOrEmpty(sectionParam.Value)) { if (!UniqueFileList.ExistLocalFileName(sectionParam.Value)) { FileItem existingItem = copy.GetByLocalFileName(sectionParam.Value); if (existingItem != null) UniqueFileList.Add(existingItem); else UniqueFileList.Add(new FileItem(sectionParam.Value, true)); } else UniqueFileList.GetByLocalFileName(sectionParam.Value).SystemFile = true; } } } } foreach (SectionParam sectionParam in GeneralInfo.Params.Items) { if (sectionParam.ValueType == ValueTypeEnum.File && !string.IsNullOrEmpty(sectionParam.Value)) { if (!UniqueFileList.ExistLocalFileName(sectionParam.Value)) { FileItem existingItem = copy.GetByLocalFileName(sectionParam.Value); if (existingItem != null) UniqueFileList.Add(existingItem); else UniqueFileList.Add(new FileItem(sectionParam.Value, true)); } else UniqueFileList.GetByLocalFileName(sectionParam.Value).SystemFile = true; } } }
/// <summary> /// This loads the tree view with table of contents file entries from the project /// </summary> /// <remarks>Token information is also loaded here and passed on to the converter.</remarks> private void LoadTableOfContentsInfo() { FileItemCollection imageFiles, tokenFiles, contentLayoutFiles; List <ITableOfContents> tocFiles; TopicCollection contentLayout; TokenCollection tokens; tvContent.ItemsSource = null; tableOfContents = null; lblCurrentProject.Text = null; browserHistory.Clear(); historyLocation = -1; if (currentProject == null) { lblCurrentProject.Text = "None - Select a help file builder project in the Solution Explorer"; return; } // Make sure the base path is set for imported code blocks this.SetImportedCodeBasePath(); // Get content from open file editors var args = new FileContentNeededEventArgs(FileContentNeededEvent, this); base.RaiseEvent(args); currentProject.EnsureProjectIsCurrent(false); lblCurrentProject.Text = currentProject.Filename; browserHistory.Clear(); historyLocation = -1; tableOfContents = new TocEntryCollection(); try { converter.MediaFiles.Clear(); // Get the image files. This information is used to resolve media link elements in the // topic files. imageFiles = new FileItemCollection(currentProject, BuildAction.Image); foreach (FileItem file in imageFiles) { if (!String.IsNullOrEmpty(file.ImageId)) { converter.MediaFiles[file.ImageId] = new KeyValuePair <string, string>(file.FullPath, file.AlternateText); } } } catch (Exception ex) { tableOfContents.Add(new TocEntry(currentProject) { Title = "ERROR: Unable to load media info: " + ex.Message }); } try { converter.Tokens.Clear(); // Get the token files. This information is used to resolve token elements in the // topic files. tokenFiles = new FileItemCollection(currentProject, BuildAction.Tokens); foreach (FileItem file in tokenFiles) { // If open in an editor, use the edited values if (!args.TokenFiles.TryGetValue(file.FullPath, out tokens)) { tokens = new TokenCollection(file.FullPath); tokens.Load(); } // Store the tokens as XElements so that they can be parsed inline with the topic foreach (var t in tokens) { converter.Tokens.Add(t.TokenName, XElement.Parse("<token>" + t.TokenValue + "</token>")); } } } catch (Exception ex) { tableOfContents.Add(new TocEntry(currentProject) { Title = "ERROR: Unable to load token info: " + ex.Message }); } try { converter.TopicTitles.Clear(); // Get the content layout files. Site maps are ignored. We don't support rendering them. contentLayoutFiles = new FileItemCollection(currentProject, BuildAction.ContentLayout); tocFiles = new List <ITableOfContents>(); // Add the conceptual content layout files foreach (FileItem file in contentLayoutFiles) { // If open in an editor, use the edited values if (!args.ContentLayoutFiles.TryGetValue(file.FullPath, out contentLayout)) { contentLayout = new TopicCollection(file); contentLayout.Load(); } tocFiles.Add(contentLayout); } // Sort the files tocFiles.Sort((x, y) => { FileItem fx = x.ContentLayoutFile, fy = y.ContentLayoutFile; if (fx.SortOrder < fy.SortOrder) { return(-1); } if (fx.SortOrder > fy.SortOrder) { return(1); } return(String.Compare(fx.Name, fy.Name, StringComparison.OrdinalIgnoreCase)); }); // Create the merged TOC. For the purpose of adding links, we'll include everything // even topics marked as invisible. foreach (ITableOfContents file in tocFiles) { file.GenerateTableOfContents(tableOfContents, currentProject, true); } // Pass the topic IDs and titles on to the converter for use in hyperlinks foreach (var t in tableOfContents.All()) { if (!String.IsNullOrEmpty(t.Id)) { converter.TopicTitles[t.Id] = t.LinkText; } } } catch (Exception ex) { tableOfContents.Add(new TocEntry(currentProject) { Title = "ERROR: Unable to load TOC info: " + ex.Message }); } if (tableOfContents.Count != 0) { foreach (var t in tableOfContents.All()) { t.IsSelected = false; } tableOfContents[0].IsSelected = true; } tvContent.ItemsSource = tableOfContents; }
//===================================================================== private void LoadCodeSnippetInfo() { TreeNode rootNode = null, node; XPathDocument snippets; XPathNavigator navSnippets; CodeReference cr; tvEntities.ImageList = ilImages; tvEntities.Nodes.Clear(); if(codeSnippetFiles == null) codeSnippetFiles = new FileItemCollection(currentProject, BuildAction.CodeSnippets); foreach(FileItem snippetFile in codeSnippetFiles) try { if(File.Exists(snippetFile.FullPath)) { rootNode = tvEntities.Nodes.Add(Path.GetFileName( snippetFile.FullPath)); rootNode.ImageIndex = rootNode.SelectedImageIndex = (int)EntityType.CodeEntities; snippets = new XPathDocument(snippetFile.FullPath); navSnippets = snippets.CreateNavigator(); foreach(XPathNavigator nav in navSnippets.Select( "examples/item/@id")) { cr = new CodeReference(nav.Value); node = rootNode.Nodes.Add(cr.Id); node.Name = cr.Id; node.Tag = cr; node.ImageIndex = node.SelectedImageIndex = (int)EntityType.CodeSnippets; } } rootNode = null; } catch(Exception ex) { if(rootNode == null) tvEntities.Nodes.Add("Unable to load file '" + snippetFile.FullPath + "'. Reason: " + ex.Message); else rootNode.Nodes.Add("Unable to load file: " + ex.Message); } txtFindName.Enabled = true; tvEntities.Enabled = true; tvEntities.ExpandAll(); }
//===================================================================== private void LoadCodeSnippetInfo() { TreeNode rootNode = null, node; XPathDocument snippets; XPathNavigator navSnippets; CodeReference cr; tvEntities.ImageList = ilImages; tvEntities.Nodes.Clear(); if (codeSnippetFiles == null) { codeSnippetFiles = new FileItemCollection(currentProject, BuildAction.CodeSnippets); } foreach (FileItem snippetFile in codeSnippetFiles) { try { if (File.Exists(snippetFile.FullPath)) { rootNode = tvEntities.Nodes.Add(Path.GetFileName( snippetFile.FullPath)); rootNode.ImageIndex = rootNode.SelectedImageIndex = (int)EntityType.CodeEntities; snippets = new XPathDocument(snippetFile.FullPath); navSnippets = snippets.CreateNavigator(); foreach (XPathNavigator nav in navSnippets.Select( "examples/item/@id")) { cr = new CodeReference(nav.Value); node = rootNode.Nodes.Add(cr.Id); node.Name = cr.Id; node.Tag = cr; node.ImageIndex = node.SelectedImageIndex = (int)EntityType.CodeSnippets; } } rootNode = null; } catch (Exception ex) { if (rootNode == null) { tvEntities.Nodes.Add("Unable to load file '" + snippetFile.FullPath + "'. Reason: " + ex.Message); } else { rootNode.Nodes.Add("Unable to load file: " + ex.Message); } } } txtFindName.Enabled = true; tvEntities.Enabled = true; tvEntities.ExpandAll(); }
/// <summary> /// Refresh the currently displayed entity information /// </summary> /// <param name="sender">The sender of the event</param> /// <param name="e">The event arguments</param> private void tsbRefresh_Click(object sender, EventArgs e) { switch((EntityType)cboContentType.SelectedIndex) { case EntityType.Tokens: tokenFiles = null; break; case EntityType.Images: images = null; break; case EntityType.CodeSnippets: codeSnippetFiles = null; break; default: codeEntities = null; break; } tvEntities.Nodes.Clear(); this.cboContentType_SelectedIndexChanged(sender, e); }
/// <summary> /// Replace a field tag with a value from the project /// </summary> /// <param name="match">The match that was found</param> /// <returns>The string to use as the replacement</returns> private string OnFieldMatch(Match match) { BuildProperty buildProp; FileItemCollection fileItems; StringBuilder sb; string replaceWith, fieldName; string[] parts; fieldName = match.Groups["Field"].Value.ToLower(CultureInfo.InvariantCulture); switch(fieldName) { case "appdatafolder": // This folder should exist if used replaceWith = FolderPath.TerminatePath(Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), Constants.ProgramDataFolder)); break; case "localdatafolder": // This folder may not exist and we may need to create it replaceWith = FolderPath.TerminatePath(Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), Constants.ProgramDataFolder)); if(!Directory.Exists(replaceWith)) Directory.CreateDirectory(replaceWith); break; case "shfbfolder": replaceWith = shfbFolder; break; case "componentsfolder": replaceWith = BuildComponentManager.BuildComponentsFolder; break; case "projectfolder": replaceWith = Path.GetDirectoryName(originalProjectName); if(replaceWith.Length == 0) replaceWith = Directory.GetCurrentDirectory(); replaceWith += @"\"; break; case "htmlencprojectfolder": replaceWith = HttpUtility.HtmlEncode(Path.GetDirectoryName(originalProjectName)); if(replaceWith.Length == 0) replaceWith = HttpUtility.HtmlEncode( Directory.GetCurrentDirectory()); replaceWith += @"\"; break; case "outputfolder": replaceWith = outputFolder; break; case "htmlencoutputfolder": replaceWith = HttpUtility.HtmlEncode(outputFolder); break; case "workingfolder": replaceWith = workingFolder; break; case "htmlencworkingfolder": replaceWith = HttpUtility.HtmlEncode(workingFolder); break; case "sandcastlepath": replaceWith = sandcastleFolder; break; case "presentationpath": replaceWith = presentationFolder; break; case "presentationstyle": replaceWith = project.PresentationStyle; break; case "presentationparam": replaceWith = presentationParam; break; case "hhcpath": replaceWith = hhcFolder; break; case "hxcomppath": replaceWith = hxcompFolder; break; case "docinternals": if(project.DocumentInternals || project.DocumentPrivates) replaceWith = "true"; else replaceWith = "false"; break; case "htmlhelpname": replaceWith = project.HtmlHelpName; break; case "htmlenchelpname": replaceWith = HttpUtility.HtmlEncode(project.HtmlHelpName); break; case "helpviewersetupname": // Help viewer setup names cannot contain periods so we'll replace them with underscores replaceWith = HttpUtility.HtmlEncode(project.HtmlHelpName.Replace('.', '_')); break; case "frameworkcommentlist": case "cachedframeworkcommentlist": case "importframeworkcommentlist": replaceWith = this.FrameworkCommentList(match.Groups["Field"].Value.ToLower( CultureInfo.InvariantCulture)); break; case "commentfilelist": replaceWith = commentsFiles.CommentFileList(workingFolder, false); break; case "inheritedcommentfilelist": replaceWith = commentsFiles.CommentFileList(workingFolder, true); break; case "helptitle": replaceWith = project.HelpTitle; break; case "htmlenchelptitle": replaceWith = HttpUtility.HtmlEncode(project.HelpTitle); break; case "scripthelptitle": // This is used when the title is passed as a parameter // to a JavaScript function. replaceWith = HttpUtility.HtmlEncode(project.HelpTitle).Replace("'", @"\'"); break; case "urlenchelptitle": // Just replace &, <, >, and " for now replaceWith = project.HelpTitle.Replace("&", "%26").Replace( "<", "%3C").Replace(">", "%3E").Replace("\"", "%22"); break; case "rootnamespacetitle": replaceWith = project.RootNamespaceTitle; if(replaceWith.Length == 0) replaceWith = "<include item=\"rootTopicTitleLocalized\"/>"; break; case "binarytoc": replaceWith = project.BinaryTOC ? "Yes" : "No"; break; case "windowoptions": // Currently, we use a default set of options and only // allow showing or hiding the Favorites tab. replaceWith = (project.IncludeFavorites) ? "0x63520" : "0x62520"; break; case "langid": replaceWith = language.LCID.ToString(CultureInfo.InvariantCulture); break; case "language": replaceWith = String.Format(CultureInfo.InvariantCulture, "0x{0:X} {1}", language.LCID, language.NativeName); break; case "languagefolder": replaceWith = languageFolder; break; case "locale": replaceWith = language.Name.ToLower(CultureInfo.InvariantCulture); break; case "copyright": // Include copyright info if there is a copyright HREF or // copyright text. if(project.CopyrightHref.Length != 0 || project.CopyrightText.Length != 0) replaceWith = "<include item=\"copyright\"/>"; else replaceWith = String.Empty; break; case "copyrightinfo": if(project.CopyrightHref.Length == 0 && project.CopyrightText.Length == 0) replaceWith = String.Empty; else if(project.CopyrightHref.Length == 0) replaceWith = project.DecodedCopyrightText; else if(project.CopyrightText.Length == 0) replaceWith = project.CopyrightHref; else replaceWith = String.Format(CultureInfo.CurrentCulture, "{0} ({1})", project.DecodedCopyrightText, project.CopyrightHref); break; case "htmlenccopyrightinfo": if(project.CopyrightHref.Length == 0 && project.CopyrightText.Length == 0) replaceWith = String.Empty; else if(project.CopyrightHref.Length == 0) replaceWith = "<p/>" + HttpUtility.HtmlEncode(project.DecodedCopyrightText); else if(project.CopyrightText.Length == 0) replaceWith = String.Format(CultureInfo.CurrentCulture, "<p/><a href='{0}' target='_blank'>{0}</a>", HttpUtility.HtmlEncode(project.CopyrightHref)); else replaceWith = String.Format(CultureInfo.CurrentCulture, "<p/><a href='{0}' target='_blank'>{1}</a>", HttpUtility.HtmlEncode(project.CopyrightHref), HttpUtility.HtmlEncode(project.DecodedCopyrightText)); break; case "copyrighthref": replaceWith = project.CopyrightHref; break; case "htmlenccopyrighthref": if(project.CopyrightHref.Length == 0) replaceWith = String.Empty; else replaceWith = String.Format(CultureInfo.CurrentCulture, "<a href='{0}' target='_blank'>{0}</a>", HttpUtility.HtmlEncode(project.CopyrightHref)); break; case "copyrighttext": if(project.CopyrightText.Length == 0) replaceWith = String.Empty; else replaceWith = project.DecodedCopyrightText; break; case "htmlenccopyrighttext": if(project.CopyrightText.Length == 0) replaceWith = String.Empty; else replaceWith = HttpUtility.HtmlEncode(project.DecodedCopyrightText); break; case "comments": // Include "send comments" line if feedback e-mail address // is specified. if(project.FeedbackEMailAddress.Length != 0) replaceWith = "<include item=\"comments\"/>"; else replaceWith = String.Empty; break; case "feedbackemailaddress": replaceWith = project.FeedbackEMailAddress; break; case "feedbackemaillinktext": replaceWith = project.FeedbackEMailLinkText; break; case "urlencfeedbackemailaddress": if(project.FeedbackEMailAddress.Length == 0) replaceWith = String.Empty; else replaceWith = HttpUtility.UrlEncode(project.FeedbackEMailAddress); break; case "htmlencfeedbackemailaddress": // If link text is specified, it will be used instead if(project.FeedbackEMailAddress.Length == 0) replaceWith = String.Empty; else if(project.FeedbackEMailLinkText.Length == 0) replaceWith = HttpUtility.HtmlEncode(project.FeedbackEMailAddress); else replaceWith = HttpUtility.HtmlEncode(project.FeedbackEMailLinkText); break; case "headertext": replaceWith = project.HeaderText; break; case "footertext": replaceWith = project.FooterText; break; case "indenthtml": replaceWith = project.IndentHtml.ToString().ToLower(CultureInfo.InvariantCulture); break; case "preliminary": // Include the "preliminary" warning in the header text if wanted if(project.Preliminary) replaceWith = "<include item=\"preliminary\"/>"; else replaceWith = String.Empty; break; case "defaulttopic": if(defaultTopic.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) replaceWith = Path.ChangeExtension(defaultTopic, ".html"); else replaceWith = defaultTopic; break; case "webdefaulttopic": if(defaultTopic.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)) replaceWith = Path.ChangeExtension(defaultTopic, ".html").Replace('\\', '/'); else replaceWith = defaultTopic.Replace('\\', '/'); break; case "frameworkversion": replaceWith = project.FrameworkVersion; break; case "frameworkversionshort": replaceWith = project.FrameworkVersion.Substring(0, 3); break; case "mrefframeworkversion": replaceWith = project.FrameworkVersion; // For .NET 3.0 or higher, Microsoft says to use the .NET 2.0 // framework files. if(replaceWith[0] >= '3') replaceWith = FrameworkVersionTypeConverter.LatestMatching("2.0"); break; case "mrefframeworkversionshort": replaceWith = project.FrameworkVersion.Substring(0, 3); // For .NET 3.0 or higher, Microsoft says to use the .NET 2.0 // framework files. if(replaceWith[0] >= '3') replaceWith = "2.0"; break; case "help1xprojectfiles": replaceWith = this.HelpProjectFileList(String.Format(CultureInfo.InvariantCulture, @"{0}Output\{1}", workingFolder, HelpFileFormat.HtmlHelp1), HelpFileFormat.HtmlHelp1); break; case "help2xprojectfiles": replaceWith = this.HelpProjectFileList(String.Format(CultureInfo.InvariantCulture, @"{0}Output\{1}", workingFolder, HelpFileFormat.MSHelp2), HelpFileFormat.MSHelp2); break; case "htmlsdklinktype": replaceWith = project.HtmlSdkLinkType.ToString().ToLower(CultureInfo.InvariantCulture); break; case "mshelp2sdklinktype": replaceWith = project.MSHelp2SdkLinkType.ToString().ToLower(CultureInfo.InvariantCulture); break; case "mshelpviewersdklinktype": replaceWith = project.MSHelpViewerSdkLinkType.ToString().ToLower(CultureInfo.InvariantCulture); break; case "websitesdklinktype": replaceWith = project.WebsiteSdkLinkType.ToString().ToLower(CultureInfo.InvariantCulture); break; case "sdklinktarget": replaceWith = "_" + project.SdkLinkTarget.ToString().ToLower(CultureInfo.InvariantCulture); break; case "htmltoc": replaceWith = this.GenerateHtmlToc(); break; case "syntaxfilters": replaceWith = BuildComponentManager.SyntaxFilterGeneratorsFrom(project.SyntaxFilters); break; case "syntaxfiltersdropdown": // Note that we can't remove the dropdown box if only a single // language is selected as script still depends on it. replaceWith = BuildComponentManager.SyntaxFilterLanguagesFrom(project.SyntaxFilters); break; case "autodocumentconstructors": replaceWith = project.AutoDocumentConstructors.ToString().ToLower(CultureInfo.InvariantCulture); break; case "autodocumentdisposemethods": replaceWith = project.AutoDocumentDisposeMethods.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingparams": replaceWith = project.ShowMissingParams.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingremarks": replaceWith = project.ShowMissingRemarks.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingreturns": replaceWith = project.ShowMissingReturns.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingsummaries": replaceWith = project.ShowMissingSummaries.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingtypeparams": replaceWith = project.ShowMissingTypeParams.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingvalues": replaceWith = project.ShowMissingValues.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingnamespaces": replaceWith = project.ShowMissingNamespaces.ToString().ToLower(CultureInfo.InvariantCulture); break; case "showmissingincludetargets": replaceWith = project.ShowMissingIncludeTargets.ToString().ToLower(CultureInfo.InvariantCulture); break; case "apifilter": // In a partial build used to get API info for the API // filter designer, we won't apply the filter. if(!suppressApiFilter) replaceWith = apiFilter.ToString(); else replaceWith = String.Empty; break; case "builddate": // Apply a format specifier? if(match.Groups["Format"].Value.Length != 0) replaceWith = String.Format(CultureInfo.CurrentCulture, "{0:" + match.Groups["Format"].Value + "}", DateTime.Now); else replaceWith = DateTime.Now.ToString(CultureInfo.CurrentCulture); break; case "includeprojectnode": if(project.RootNamespaceContainer) replaceWith = "project=Project"; else replaceWith = String.Empty; break; case "help1folder": if((project.HelpFileFormat & HelpFileFormat.HtmlHelp1) != 0) replaceWith = @"Output\" + HelpFileFormat.HtmlHelp1.ToString(); else replaceWith = String.Empty; break; case "websitefolder": if((project.HelpFileFormat & HelpFileFormat.Website) != 0) replaceWith = @"Output\" + HelpFileFormat.Website.ToString(); else replaceWith = String.Empty; break; case "stopwordfile": if(project.IncludeStopWordList) replaceWith = "StopWordFile=\"StopWordList.txt\""; else replaceWith = String.Empty; break; case "stopwordlistfilename": if(project.IncludeStopWordList) replaceWith = "StopWordList.txt"; else replaceWith = String.Empty; break; case "collectiontocstyle": replaceWith = project.CollectionTocStyle.ToString(); break; case "helpfileversion": replaceWith = project.HelpFileVersion; break; case "h2regpluginentries": parts = project.PlugInNamespaces.Split(','); sb = new StringBuilder(1024); foreach(string ns in parts) { replaceWith = ns.Trim(); if(replaceWith.Length != 0) sb.AppendFormat("{0}|_DEFAULT|{1}|_DEFAULT\r\n", replaceWith, project.HtmlHelpName); } replaceWith = sb.ToString(); break; case "h2regmergenamespaces": parts = project.PlugInNamespaces.Split(','); sb = new StringBuilder(1024); foreach(string ns in parts) { replaceWith = ns.Trim(); if(replaceWith.Length != 0) sb.AppendFormat("{0}|AUTO\r\n", replaceWith); } replaceWith = sb.ToString(); break; case "helpattributes": replaceWith = project.HelpAttributes.ToConfigurationString(); break; case "tokenfiles": sb = new StringBuilder(1024); if(conceptualContent != null) fileItems = conceptualContent.TokenFiles; else fileItems = new FileItemCollection(project, BuildAction.Tokens); foreach(FileItem file in fileItems) sb.AppendFormat("<content file=\"{0}\" />\r\n", Path.GetFileName(file.FullPath)); replaceWith = sb.ToString(); break; case "codesnippetsfiles": sb = new StringBuilder(1024); if(conceptualContent != null) fileItems = conceptualContent.CodeSnippetFiles; else fileItems = new FileItemCollection(project, BuildAction.CodeSnippets); foreach(FileItem file in fileItems) sb.AppendFormat("<examples file=\"{0}\" />\r\n", file.FullPath); replaceWith = sb.ToString(); break; case "resourceitemfiles": sb = new StringBuilder(1024); fileItems = new FileItemCollection(project, BuildAction.ResourceItems); // Files are copied and transformed as they may contain // substitution tags. foreach(FileItem file in fileItems) { sb.AppendFormat("<content file=\"{0}\" />\r\n", Path.GetFileName(file.FullPath)); this.TransformTemplate(Path.GetFileName(file.FullPath), Path.GetDirectoryName(file.FullPath), workingFolder); } replaceWith = sb.ToString(); break; case "helpfileformat": replaceWith = project.HelpFileFormat.ToString(); break; case "helpformatoutputpaths": sb = new StringBuilder(1024); // Add one entry for each help file format being generated foreach(string baseFolder in this.HelpFormatOutputFolders) sb.AppendFormat("<path value=\"{0}\" />", baseFolder.Substring(workingFolder.Length)); replaceWith = sb.ToString(); break; case "catalogproductid": replaceWith = project.CatalogProductId; break; case "catalogversion": replaceWith = project.CatalogVersion; break; case "vendorname": replaceWith = !String.IsNullOrEmpty(project.VendorName) ? project.VendorName : "Vendor Name"; break; case "htmlencvendorname": replaceWith = !String.IsNullOrEmpty(project.VendorName) ? HttpUtility.HtmlEncode(project.VendorName) : "Vendor Name"; break; case "producttitle": replaceWith = !String.IsNullOrEmpty(project.ProductTitle) ? project.ProductTitle : project.HelpTitle; break; case "htmlencproducttitle": replaceWith = !String.IsNullOrEmpty(project.ProductTitle) ? HttpUtility.HtmlEncode(project.ProductTitle) : HttpUtility.HtmlEncode(project.HelpTitle); break; case "selfbranded": replaceWith = project.SelfBranded.ToString().ToLower(CultureInfo.InvariantCulture); break; case "topicversion": replaceWith = HttpUtility.HtmlEncode(project.TopicVersion); break; case "tocparentid": replaceWith = HttpUtility.HtmlEncode(project.TocParentId); break; case "tocparentversion": replaceWith = HttpUtility.HtmlEncode(project.TocParentVersion); break; case "apitocparentid": // If null, empty or it starts with '*', it's parented to the root node if(!String.IsNullOrEmpty(this.ApiTocParentId) && this.ApiTocParentId[0] != '*') { // Ensure that the ID is valid and visible in the TOC if(!conceptualContent.Topics.Any(t => t[this.ApiTocParentId] != null && t[this.ApiTocParentId].Visible)) throw new BuilderException("BE0022", String.Format(CultureInfo.CurrentCulture, "The project's ApiTocParent property value '{0}' must be associated with a topic in " + "your project's conceptual content and must have its Visible property set to True in " + "the content layout file.", this.ApiTocParentId)); replaceWith = HttpUtility.HtmlEncode(this.ApiTocParentId); } else if(!String.IsNullOrEmpty(this.RootContentContainerId)) replaceWith = HttpUtility.HtmlEncode(this.RootContentContainerId); else replaceWith = HttpUtility.HtmlEncode(project.TocParentId); break; default: // Try for a custom project property buildProp = project.MSBuildProject.EvaluatedProperties[fieldName]; // If not there, try the global properties if(buildProp == null) buildProp = project.MSBuildProject.GlobalProperties[fieldName]; // If not there, give up if(buildProp == null) throw new BuilderException("BE0020", String.Format(CultureInfo.CurrentCulture, "Unknown field tag: '{0}'", match.Groups["Field"].Value)); replaceWith = buildProp.FinalValue; break; } return replaceWith; }
/// <summary> /// This loads the tree view with table of contents file entries from the project /// </summary> /// <remarks>Token information is also loaded here and passed on to the converter.</remarks> private void LoadTableOfContentsInfo() { FileItemCollection imageFiles, tokenFiles, contentLayoutFiles; List<ITableOfContents> tocFiles; TopicCollection contentLayout; TokenCollection tokens; tvContent.ItemsSource = null; tableOfContents = null; lblCurrentProject.Text = null; browserHistory.Clear(); historyLocation = -1; if(currentProject == null) { lblCurrentProject.Text = "None - Select a help file builder project in the Solution Explorer"; return; } // Make sure the base path is set for imported code blocks this.SetImportedCodeBasePath(); // Get content from open file editors var args = new FileContentNeededEventArgs(FileContentNeededEvent, this); base.RaiseEvent(args); currentProject.EnsureProjectIsCurrent(false); lblCurrentProject.Text = currentProject.Filename; browserHistory.Clear(); historyLocation = -1; tableOfContents = new TocEntryCollection(); try { converter.MediaFiles.Clear(); // Get the image files. This information is used to resolve media link elements in the // topic files. imageFiles = new FileItemCollection(currentProject, BuildAction.Image); foreach(FileItem file in imageFiles) if(!String.IsNullOrEmpty(file.ImageId)) converter.MediaFiles[file.ImageId] = new KeyValuePair<string, string>(file.FullPath, file.AlternateText); } catch(Exception ex) { tableOfContents.Add(new TocEntry(currentProject) { Title = "ERROR: Unable to load media info: " + ex.Message }); } try { converter.Tokens.Clear(); // Get the token files. This information is used to resolve token elements in the // topic files. tokenFiles = new FileItemCollection(currentProject, BuildAction.Tokens); foreach(FileItem file in tokenFiles) { // If open in an editor, use the edited values if(!args.TokenFiles.TryGetValue(file.FullPath, out tokens)) { tokens = new TokenCollection(file.FullPath); tokens.Load(); } // Store the tokens as XElements so that they can be parsed inline with the topic foreach(var t in tokens) converter.Tokens.Add(t.TokenName, XElement.Parse("<token>" + t.TokenValue + "</token>")); } } catch(Exception ex) { tableOfContents.Add(new TocEntry(currentProject) { Title = "ERROR: Unable to load token info: " + ex.Message }); } try { converter.TopicTitles.Clear(); // Get the content layout files. Site maps are ignored. We don't support rendering them. contentLayoutFiles = new FileItemCollection(currentProject, BuildAction.ContentLayout); tocFiles = new List<ITableOfContents>(); // Add the conceptual content layout files foreach(FileItem file in contentLayoutFiles) { // If open in an editor, use the edited values if(!args.ContentLayoutFiles.TryGetValue(file.FullPath, out contentLayout)) { contentLayout = new TopicCollection(file); contentLayout.Load(); } tocFiles.Add(contentLayout); } // Sort the files tocFiles.Sort((x, y) => { FileItem fx = x.ContentLayoutFile, fy = y.ContentLayoutFile; if(fx.SortOrder < fy.SortOrder) return -1; if(fx.SortOrder > fy.SortOrder) return 1; return String.Compare(fx.Name, fy.Name, StringComparison.OrdinalIgnoreCase); }); // Create the merged TOC. For the purpose of adding links, we'll include everything // even topics marked as invisible. foreach(ITableOfContents file in tocFiles) file.GenerateTableOfContents(tableOfContents, currentProject, true); // Pass the topic IDs and titles on to the converter for use in hyperlinks foreach(var t in tableOfContents.All()) if(!String.IsNullOrEmpty(t.Id)) converter.TopicTitles[t.Id] = t.LinkText; } catch(Exception ex) { tableOfContents.Add(new TocEntry(currentProject) { Title = "ERROR: Unable to load TOC info: " + ex.Message }); } if(tableOfContents.Count != 0) { foreach(var t in tableOfContents.All()) t.IsSelected = false; tableOfContents[0].IsSelected = true; } tvContent.ItemsSource = tableOfContents; }