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

        /// <summary>
        /// Add an empty container topic to the collection that is not associated with any file
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdAddItem_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntry currentTopic = this.CurrentTopic,
                     newTopic     = new TocEntry(topics.ContentLayoutFile.BasePathProvider)
            {
                Title    = "Table of Contents Container",
                UniqueId = Guid.NewGuid()
            };

            // If the command parameter is null, add it as a sibling.  If not, add it as a child.
            if (e.Parameter == null || currentTopic == null)
            {
                if (currentTopic == null || topics.Count == 0)
                {
                    topics.Add(newTopic);
                }
                else
                {
                    currentTopic.Parent.Insert(currentTopic.Parent.IndexOf(currentTopic) + 1, newTopic);
                }
            }
            else
            {
                currentTopic.Children.Add(newTopic);
                currentTopic.IsExpanded = true;
            }

            newTopic.IsSelected = 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()
        {
            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. 3
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>
        /// <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>
        /// 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 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);
        }