Esempio n. 1
0
        //=====================================================================

        /// <summary>
        /// Load a site map file for editing
        /// </summary>
        /// <param name="siteMapFile">The site map file item to load</param>
        public void LoadSiteMapFile(FileItem siteMapFile)
        {
            if (siteMapFile == null)
            {
                throw new ArgumentNullException("siteMapFile", "A site map file item must be specified");
            }

            topics = new TocEntryCollection(siteMapFile.ToContentFile());
            topics.Load();

            // This works around a legacy support issue related to object equality
            foreach (var t in topics.All())
            {
                t.UniqueId = Guid.NewGuid();
            }

            topics.ListChanged += new ListChangedEventHandler(topics_ListChanged);

            if (topics.Count != 0 && topics.Find(t => t.IsSelected, false).Count() == 0)
            {
                topics[0].IsSelected = true;
            }

            tvContent.ItemsSource = topics;

            this.topics_ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, -1));
        }
Esempio n. 2
0
        /// <summary>
        /// Load the tree view with the table of content nodes
        /// </summary>
        private void LoadTree()
        {
            TreeNode           node;
            TocEntryCollection toc = bp.TableOfContent;

            tvTOC.Nodes.Clear();
            defaultNode = null;

            if (toc != null && toc.Count != 0)
            {
                btnDefaultTopic.Enabled = btnMoveUp.Enabled =
                    btnMoveDown.Enabled = btnSave.Enabled = true;

                foreach (TocEntry te in bp.TableOfContent)
                {
                    node     = tvTOC.Nodes.Add(te.Title);
                    node.Tag = te;

                    if (te.IsDefaultTopic)
                    {
                        defaultNode = node;
                    }

                    if (te.Children.Count != 0)
                    {
                        this.AddChildren(te.Children, node);
                    }
                }

                if (defaultNode != null)
                {
                    defaultNode.ToolTipText = "Default topic";
                    defaultNode.ImageIndex  = defaultNode.SelectedImageIndex = 1;
                }
            }
            else
            {
                btnDefaultTopic.Enabled = btnMoveUp.Enabled =
                    btnMoveDown.Enabled = btnSave.Enabled = false;
            }

            if (tvTOC.Nodes.Count != 0)
            {
                tvTOC.ExpandAll();
            }
        }
Esempio n. 3
0
        /// <summary>
        /// Add a root node and its children to the tree view recursively
        /// </summary>
        /// <param name="children">The collection of entries to add</param>
        /// <param name="root">The root to which they are added</param>
        private void AddChildren(TocEntryCollection children, TreeNode root)
        {
            TreeNode node;

            foreach (TocEntry te in children)
            {
                node     = root.Nodes.Add(te.Title);
                node.Tag = te;

                if (te.IsDefaultTopic)
                {
                    defaultNode = node;
                }

                if (te.Children.Count != 0)
                {
                    this.AddChildren(te.Children, node);
                }
            }
        }
        //=====================================================================

        /// <summary>
        /// This loads the tree view with table of contents file entries from the project
        /// </summary>
        private List <EntityReference> LoadTableOfContentsInfo()
        {
            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
            {
                tocFiles = new List <ITableOfContents>();

                // Load all content layout files and add them to the list
                foreach (var contentFile in currentProject.ContentFiles(BuildAction.ContentLayout))
                {
                    // If open in an editor, use the edited values
                    if (!args.ContentLayoutFiles.TryGetValue(contentFile.FullPath, out contentLayout))
                    {
                        contentLayout = new TopicCollection(contentFile);
                        contentLayout.Load();
                    }

                    tocFiles.Add(contentLayout);
                }

                // Load all site maps and add them to the list
                foreach (var contentFile in currentProject.ContentFiles(BuildAction.SiteMap))
                {
                    // If open in an editor, use the edited values
                    if (!args.SiteMapFiles.TryGetValue(contentFile.FullPath, out siteMap))
                    {
                        siteMap = new TocEntryCollection(contentFile);
                        siteMap.Load();
                    }

                    tocFiles.Add(siteMap);
                }

                tocFiles.Sort((x, y) =>
                {
                    ContentFile fx = x.ContentLayoutFile, fy = y.ContentLayoutFile;

                    if (fx.SortOrder < fy.SortOrder)
                    {
                        return(-1);
                    }

                    if (fx.SortOrder > fy.SortOrder)
                    {
                        return(1);
                    }

                    return(String.Compare(fx.Filename, fy.Filename, 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, 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);
        }
Esempio n. 5
0
        /// <summary>
        /// Add new topics from all files in a selected folder
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdAddAllFromFolder_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            FileNode           thisNode = this.FileNode;
            TocEntryCollection parent, newTopics = new TocEntryCollection(null);
            TocEntry           selectedTopic = base.UIControl.CurrentTopic;
            string             projectPath   = Path.GetDirectoryName(siteMapFile.ProjectElement.Project.Filename);
            int idx;

            using (WinFormsFolderBrowserDialog dlg = new WinFormsFolderBrowserDialog())
            {
                dlg.Description  = "Select a folder to add all of its content";
                dlg.SelectedPath = (selectedTopic != null && selectedTopic.SourceFile.Path.Length != 0) ?
                                   Path.GetDirectoryName(selectedTopic.SourceFile) : projectPath;

                if (dlg.ShowDialog() == WinFormsDialogResult.OK)
                {
                    Utility.GetServiceFromPackage <IVsUIShell, SVsUIShell>(true).SetWaitCursor();

                    newTopics.AddTopicsFromFolder(dlg.SelectedPath, dlg.SelectedPath,
                                                  siteMapFile.ProjectElement.Project);

                    if (thisNode != null)
                    {
                        thisNode.ProjectManager.RefreshProject();
                    }
                }

                if (newTopics.Count != 0)
                {
                    if (e.Parameter == null || selectedTopic == null)
                    {
                        // Insert as siblings
                        if (selectedTopic == null)
                        {
                            parent = base.UIControl.Topics;
                            idx    = 0;
                        }
                        else
                        {
                            parent = selectedTopic.Parent;
                            idx    = parent.IndexOf(selectedTopic) + 1;
                        }

                        foreach (TocEntry t in newTopics)
                        {
                            parent.Insert(idx++, t);
                        }
                    }
                    else
                    {
                        // Insert as children
                        parent = selectedTopic.Children;

                        foreach (TocEntry t in newTopics)
                        {
                            parent.Add(t);
                        }

                        selectedTopic.IsExpanded = true;
                    }
                }
            }
        }
Esempio n. 6
0
        /// <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;
        }
        /// <summary>
        /// This is used to merge the conceptual content table of contents with any additional content table of
        /// contents information.
        /// </summary>
        private void MergeConceptualAndAdditionalContentTocInfo()
        {
            List <ITableOfContents> tocFiles;
            TocEntryCollection      siteMap;
            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 this.ConceptualContent.Topics)
            {
                tocFiles.Add(topics);
            }

            // Load all site maps and add them to the list
            foreach (var contentFile in project.ContentFiles(BuildAction.SiteMap))
            {
                this.ReportProgress("    Loading site map '{0}'", contentFile.FullPath);
                siteMap = new TocEntryCollection(contentFile);
                siteMap.Load();

                // Copy site map files to the help format folders
                foreach (TocEntry site in siteMap)
                {
                    this.CopySiteMapFiles(site);
                }

                tocFiles.Add(siteMap);
            }

            // Sort the files
            tocFiles.Sort((x, y) =>
            {
                ContentFile fx = x.ContentLayoutFile, fy = y.ContentLayoutFile;

                if (fx.SortOrder < fy.SortOrder)
                {
                    return(-1);
                }

                if (fx.SortOrder > fy.SortOrder)
                {
                    return(1);
                }

                return(String.Compare(fx.Filename, fy.Filename, StringComparison.OrdinalIgnoreCase));
            });

            // Create the merged TOC.  Invisible items are excluded.
            toc = new TocEntryCollection();

            foreach (ITableOfContents file in tocFiles)
            {
                file.GenerateTableOfContents(toc, false);
            }

            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>
        /// Load a site map file for editing
        /// </summary>
        /// <param name="siteMapFile">The site map file item to load</param>
        public void LoadSiteMapFile(FileItem siteMapFile)
        {
            if(siteMapFile == null)
                throw new ArgumentNullException("siteMapFile", "A site map file item must be specified");

            topics = new TocEntryCollection(siteMapFile.ToContentFile());
            topics.Load();

            // This works around a legacy support issue related to object equality
            foreach(var t in topics.All())
                t.UniqueId = Guid.NewGuid();

            topics.ListChanged += new ListChangedEventHandler(topics_ListChanged);

            if(topics.Count != 0 && topics.Find(t => t.IsSelected, false).Count() == 0)
                topics[0].IsSelected = true;

            tvContent.ItemsSource = topics;

            this.topics_ListChanged(this, new ListChangedEventArgs(ListChangedType.Reset, -1));
        }
        /// <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 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>
        /// Constructor
        /// </summary>
        /// <param name="fileItem">The project file item to edit</param>
        public SiteMapEditorWindow(FileItem fileItem)
        {
            EventHandler onClick = new EventHandler(templateFile_OnClick);
            ToolStripMenuItem miTemplate;
            Image itemImage;
            string name;

            InitializeComponent();

            sbStatusBarText.InstanceStatusBar = MainForm.Host.StatusBarTextLabel;

            // Look for custom templates in the local application data folder
            name = Path.Combine(Environment.GetFolderPath(
                Environment.SpecialFolder.LocalApplicationData),
                Constants.ItemTemplates);

            if(!Directory.Exists(name))
                miCustomSibling.Enabled = miCustomChild.Enabled = false;
            else
            {
                string[] files = Directory.GetFiles(name, "*.htm?");

                if(files.Length == 0)
                    miCustomSibling.Enabled = miCustomChild.Enabled = false;
                else
                    foreach(string file in files)
                    {
                        name = Path.GetFileNameWithoutExtension(file);
                        itemImage = null;

                        miTemplate = new ToolStripMenuItem(name, null, onClick);
                        miTemplate.Image = itemImage;
                        miTemplate.Tag = file;
                        sbStatusBarText.SetStatusBarText(miTemplate,
                            "Add new '" + name + "' topic");
                        miCustomSibling.DropDownItems.Add(miTemplate);

                        miTemplate = new ToolStripMenuItem(name, null, onClick);
                        miTemplate.Image = itemImage;
                        miTemplate.Tag = file;
                        sbStatusBarText.SetStatusBarText(miTemplate,
                            "Add new '" + name + "' topic");
                        miCustomChild.DropDownItems.Add(miTemplate);
                    }
            }

            topics = new TocEntryCollection(fileItem);
            topics.Load();
            topics.ListChanged += new ListChangedEventHandler(topics_ListChanged);

            this.Text = Path.GetFileName(fileItem.FullPath);
            this.ToolTipText = fileItem.FullPath;
            this.LoadTopics(null);
        }
        /// <summary>
        /// Add child nodes to the tree view recursively
        /// </summary>
        /// <param name="children">The collection of entries to add</param>
        /// <param name="root">The root to which they are added</param>
        private void AddChildren(TocEntryCollection children, TreeNode root)
        {
            TreeNode node;

            foreach(TocEntry t in children)
            {
                node = root.Nodes.Add(t.Title);
                node.Name = t.SourceFile;
                node.Tag = t;

                if(t.IsDefaultTopic)
                    defaultNode = node;

                if(t == firstSelection)
                    firstNode = node;

                if(t.Children.Count != 0)
                    this.AddChildren(t.Children, node);
            }
        }
        /// <summary>
        /// Add all topic files found in the selected folder
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void AddAllTopicsInFolder_Click(object sender, EventArgs e)
        {
            ToolStripItem tiAdd = (ToolStripItem)sender;
            TocEntryCollection parent, newTopics = new TocEntryCollection(null);
            TocEntry selectedTopic;
            int idx;

            using(FolderBrowserDialog dlg = new FolderBrowserDialog())
            {
                dlg.Description = "Select a folder to add all of its content";
                dlg.SelectedPath = Directory.GetCurrentDirectory();

                if(dlg.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        Cursor.Current = Cursors.WaitCursor;
                        newTopics.AddTopicsFromFolder(dlg.SelectedPath,
                            dlg.SelectedPath, topics.FileItem.ProjectElement.Project);
                        MainForm.Host.ProjectExplorer.RefreshProject();
                    }
                    finally
                    {
                        Cursor.Current = Cursors.Default;
                    }
                }

                if(newTopics.Count != 0)
                {
                    if(tiAdd.Owner != cmsNewChildTopic)
                    {
                        // Insert as siblings
                        if(tvContent.SelectedNode == null)
                        {
                            parent = topics;
                            idx = 0;
                        }
                        else
                        {
                            selectedTopic = (TocEntry)tvContent.SelectedNode.Tag;
                            parent = selectedTopic.Parent;
                            idx = parent.IndexOf(selectedTopic) + 1;
                        }

                        foreach(TocEntry t in newTopics)
                        {
                            parent.Insert(idx, t);
                            idx++;
                        }
                    }
                    else    // Insert as children
                    {
                        parent = ((TocEntry)tvContent.SelectedNode.Tag).Children;

                        foreach(TocEntry t in newTopics)
                            parent.Add(t);
                    }

                    // Take the easy way out and reload the tree
                    this.LoadTopics(newTopics[0]);
                }
            }
        }
        /// <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()
        {
            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);

            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.
                foreach(var file in currentProject.ImagesReferences)
                    converter.MediaFiles[file.Id] = 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.
                foreach(var file in currentProject.ContentFiles(BuildAction.Tokens).OrderBy(f => f.LinkPath))
                {
                    // 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();

                // Load the content layout files.  Site maps are ignored as we don't support rendering them.
                tocFiles = new List<ITableOfContents>();

                foreach(var contentFile in currentProject.ContentFiles(BuildAction.ContentLayout))
                {
                    // If open in an editor, use the edited values
                    if(!args.ContentLayoutFiles.TryGetValue(contentFile.FullPath, out contentLayout))
                    {
                        contentLayout = new TopicCollection(contentFile);
                        contentLayout.Load();
                    }

                    tocFiles.Add(contentLayout);
                }

                tocFiles.Sort((x, y) =>
                {
                    ContentFile fx = x.ContentLayoutFile, fy = y.ContentLayoutFile;

                    if(fx.SortOrder < fy.SortOrder)
                        return -1;

                    if(fx.SortOrder > fy.SortOrder)
                        return 1;

                    return String.Compare(fx.Filename, fy.Filename, 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, 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;
        }
Esempio n. 16
0
        /// <summary>
        /// Add new topics from all files in a selected folder
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdAddAllFromFolder_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntryCollection parent, newTopics = new TocEntryCollection(null);
            TocEntry selectedTopic = ucSiteMapEditor.CurrentTopic;
            string projectPath = Path.GetDirectoryName(siteMapFile.Project.Filename);
            int idx;

            using(FolderBrowserDialog dlg = new FolderBrowserDialog())
            {
                dlg.Description = "Select a folder to add all of its content";
                dlg.SelectedPath = (selectedTopic != null && selectedTopic.SourceFile.Path.Length != 0) ?
                    Path.GetDirectoryName(selectedTopic.SourceFile) : projectPath;

                if(dlg.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        MouseCursor.Current = MouseCursors.WaitCursor;

                        newTopics.AddTopicsFromFolder(dlg.SelectedPath, dlg.SelectedPath,
                            siteMapFile.Project);

                        MainForm.Host.ProjectExplorer.RefreshProject();
                    }
                    finally
                    {
                        MouseCursor.Current = MouseCursors.Default;
                    }
                }

                if(newTopics.Count != 0)
                    if(e.Parameter == null || selectedTopic == null)
                    {
                        // Insert as siblings
                        if(selectedTopic == null)
                        {
                            parent = ucSiteMapEditor.Topics;
                            idx = 0;
                        }
                        else
                        {
                            parent = selectedTopic.Parent;
                            idx = parent.IndexOf(selectedTopic) + 1;
                        }

                        foreach(TocEntry t in newTopics)
                            parent.Insert(idx++, t);
                    }
                    else
                    {
                        // Insert as children
                        parent = selectedTopic.Children;

                        foreach(TocEntry t in newTopics)
                            parent.Add(t);

                        selectedTopic.IsExpanded = true;
                    }
            }
        }
        /// <summary>
        /// This is used to merge the conceptual content table of contents with any additional content table of
        /// contents information.
        /// </summary>
        private void MergeConceptualAndAdditionalContentTocInfo()
        {
            List<ITableOfContents> tocFiles;
            TocEntryCollection siteMap;
            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 this.ConceptualContent.Topics)
                tocFiles.Add(topics);

            // Load all site maps and add them to the list
            foreach(var contentFile in project.ContentFiles(BuildAction.SiteMap))
            {
                this.ReportProgress("    Loading site map '{0}'", contentFile.FullPath);
                siteMap = new TocEntryCollection(contentFile);
                siteMap.Load();

                // Copy site map files to the help format folders
                foreach(TocEntry site in siteMap)
                    this.CopySiteMapFiles(site);

                tocFiles.Add(siteMap);
            }

            // Sort the files
            tocFiles.Sort((x, y) =>
            {
                ContentFile fx = x.ContentLayoutFile, fy = y.ContentLayoutFile;

                if(fx.SortOrder < fy.SortOrder)
                    return -1;

                if(fx.SortOrder > fy.SortOrder)
                    return 1;

                return String.Compare(fx.Filename, fy.Filename, StringComparison.OrdinalIgnoreCase);
            });

            // Create the merged TOC.  Invisible items are excluded.
            toc = new TocEntryCollection();

            foreach(ITableOfContents file in tocFiles)
                file.GenerateTableOfContents(toc, false);

            if(toc.Count != 0)
            {
                // Look for the default topic
                tocEntry = toc.FindDefaultTopic();

                if(tocEntry != null)
                    defaultTopic = tocEntry.DestinationFile;
            }

            this.ExecutePlugIns(ExecutionBehaviors.After);
        }
Esempio n. 18
0
        /// <summary>
        /// Add new topics from all files in a selected folder
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdAddAllFromFolder_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntryCollection parent, newTopics = new TocEntryCollection(null);
            TocEntry           selectedTopic = ucSiteMapEditor.CurrentTopic;
            string             projectPath   = Path.GetDirectoryName(siteMapFile.Project.Filename);
            int idx;

            using (FolderBrowserDialog dlg = new FolderBrowserDialog())
            {
                dlg.Description  = "Select a folder to add all of its content";
                dlg.SelectedPath = (selectedTopic != null && selectedTopic.SourceFile.Path.Length != 0) ?
                                   Path.GetDirectoryName(selectedTopic.SourceFile) : projectPath;

                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    try
                    {
                        MouseCursor.Current = MouseCursors.WaitCursor;

                        newTopics.AddTopicsFromFolder(dlg.SelectedPath, dlg.SelectedPath,
                                                      siteMapFile.Project);

                        MainForm.Host.ProjectExplorer.RefreshProject();
                    }
                    finally
                    {
                        MouseCursor.Current = MouseCursors.Default;
                    }
                }

                if (newTopics.Count != 0)
                {
                    if (e.Parameter == null || selectedTopic == null)
                    {
                        // Insert as siblings
                        if (selectedTopic == null)
                        {
                            parent = ucSiteMapEditor.Topics;
                            idx    = 0;
                        }
                        else
                        {
                            parent = selectedTopic.Parent;
                            idx    = parent.IndexOf(selectedTopic) + 1;
                        }

                        foreach (TocEntry t in newTopics)
                        {
                            parent.Insert(idx++, t);
                        }
                    }
                    else
                    {
                        // Insert as children
                        parent = selectedTopic.Children;

                        foreach (TocEntry t in newTopics)
                        {
                            parent.Add(t);
                        }

                        selectedTopic.IsExpanded = true;
                    }
                }
            }
        }
        //=====================================================================

        /// <summary>
        /// This loads the tree view with table of contents file entries from the project
        /// </summary>
        private List<EntityReference> LoadTableOfContentsInfo()
        {
            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
            {
                tocFiles = new List<ITableOfContents>();

                // Load all content layout files and add them to the list
                foreach(var contentFile in currentProject.ContentFiles(BuildAction.ContentLayout))
                {
                    // If open in an editor, use the edited values
                    if(!args.ContentLayoutFiles.TryGetValue(contentFile.FullPath, out contentLayout))
                    {
                        contentLayout = new TopicCollection(contentFile);
                        contentLayout.Load();
                    }

                    tocFiles.Add(contentLayout);
                }

                // Load all site maps and add them to the list
                foreach(var contentFile in currentProject.ContentFiles(BuildAction.SiteMap))
                {
                    // If open in an editor, use the edited values
                    if(!args.SiteMapFiles.TryGetValue(contentFile.FullPath, out siteMap))
                    {
                        siteMap = new TocEntryCollection(contentFile);
                        siteMap.Load();
                    }

                    tocFiles.Add(siteMap);
                }

                tocFiles.Sort((x, y) =>
                {
                    ContentFile fx = x.ContentLayoutFile, fy = y.ContentLayoutFile;

                    if(fx.SortOrder < fy.SortOrder)
                        return -1;

                    if(fx.SortOrder > fy.SortOrder)
                        return 1;

                    return String.Compare(fx.Filename, fy.Filename, 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, 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 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);
        }