Ejemplo n.º 1
0
        /// <summary>
        /// Open the selected file for editing
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdEdit_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntry t = ucTopicPreviewer.CurrentTopic;

            if (t.SourceFile.Exists)
            {
                string fullName = t.SourceFile;

                // If the document is already open, just activate it
                foreach (IDockContent content in this.DockPanel.Documents)
                {
                    if (String.Equals(content.DockHandler.ToolTipText, fullName, StringComparison.OrdinalIgnoreCase))
                    {
                        content.DockHandler.Activate();
                        return;
                    }
                }

                if (File.Exists(fullName))
                {
                    TopicEditorWindow editor = new TopicEditorWindow(fullName);
                    editor.Show(this.DockPanel);
                }
                else
                {
                    WinFormsMessageBox.Show("File does not exist: " + fullName, Constants.AppName,
                                            MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
            else
            {
                WinFormsMessageBox.Show("No file is associated with this topic", Constants.AppName,
                                        MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        /// <summary>
        /// This is used to copy site map files to the help format output folders including those for any child
        /// site map entries.
        /// </summary>
        /// <param name="site">The site entry containing the files to copy</param>
        private void CopySiteMapFiles(TocEntry site)
        {
            if (site.SourceFile.Path.Length != 0)
            {
                // Set the destination filename which will always match the source filename for site map files.
                site.DestinationFile = site.SourceFile.PersistablePath;

                foreach (string baseFolder in this.HelpFormatOutputFolders)
                {
                    if (!File.Exists(baseFolder + site.DestinationFile))
                    {
                        this.ReportProgress("{0} -> {1}{2}", site.SourceFile, baseFolder, site.DestinationFile);

                        // All attributes are turned off so that we can delete it later
                        File.Copy(site.SourceFile, baseFolder + site.DestinationFile, true);
                        File.SetAttributes(baseFolder + site.DestinationFile, FileAttributes.Normal);
                    }
                }
            }

            if (site.Children.Count != 0)
            {
                foreach (TocEntry entry in site.Children)
                {
                    this.CopySiteMapFiles(entry);
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Edit the selected file for editing
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdEdit_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            // If the sender is a topic, use that instead.  Due to the way the WPF tree view works, the
            // selected topic isn't always the one we just added when it's the first child of a parent topic.
            TocEntry t = sender as TocEntry;

            if (t == null)
            {
                t = base.UIControl.CurrentTopic;
            }

            if (t.SourceFile.Path.Length != 0)
            {
                string fullName = t.SourceFile;

                if (File.Exists(fullName))
                {
                    VsShellUtilities.OpenDocument(this, fullName);
                }
                else
                {
                    Utility.ShowMessageBox(OLEMSGICON.OLEMSGICON_INFO, "File does not exist: " + fullName);
                }
            }
            else
            {
                Utility.ShowMessageBox(OLEMSGICON.OLEMSGICON_INFO, "No file is associated with this topic");
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Paste the selected topic as a sibling or child of the selected topic
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdPaste_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntry targetTopic = this.CurrentTopic, newTopic = clipboardTopic;

            if (newTopic != null)
            {
                // Don't allow pasting multiple copies of the same item in here as the IDs must be unique
                clipboardTopic = null;

                if (targetTopic == null)
                {
                    topics.Add(newTopic);
                }
                else
                {
                    if (e.Command == EditorCommands.PasteAsChild)
                    {
                        targetTopic.Children.Add(newTopic);
                        targetTopic.IsExpanded = true;
                    }
                    else
                    {
                        targetTopic.Parent.Insert(targetTopic.Parent.IndexOf(targetTopic) + 1, newTopic);
                    }
                }

                newTopic.IsSelected = true;
                tvContent.Focus();
            }
        }
Ejemplo n.º 5
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;
        }
 internal RTUpdate GetRtUpdate(Guid tocKey)
 {
     if (this.toc.ContainsKey(tocKey))
     {
         TocEntry entry = (TocEntry)toc[tocKey];
         if (entry.DeckType == DeckTypeEnum.QuickPoll)
         {
             Debug.WriteLine("");
         }
         if (!UpdateAssociation(entry))
         {
             //If we failed to map a student submission to a deck it could be because the SS is on
             // a whiteboard page, or it could be that we don't yet have a TOC entry for the
             // original slide.  For now, just treat both cases as if
             // they were whiteboard.
             // P2: Make a way to mark the message as SS and leave the deck association empty, and
             // have that be understood as a SS on a WB.  I think this requires an update to WebViewer?
             RTUpdate rtu = entry.ToRtUpdate();
             rtu.DeckType = (int)DeckTypeEnum.Whiteboard;
             return(rtu);
         }
         return(entry.ToRtUpdate());
     }
     return(null);
 }
        internal object UpdateZoomAndColorForSlide(CP3Msgs.SlideInformationMessage sim, out string warning)
        {
            Guid  slideId = (Guid)sim.TargetId;
            float zoom    = sim.Zoom;
            Color color   = sim.SlideBackgroundColor;

            warning = "";
            if (!this.tocBySlideId.ContainsKey(slideId))
            {
                return(null);
            }
            TocEntry entry = (TocEntry)this.tocBySlideId[slideId];

            if ((entry.SlideSize != zoom) ||
                (!entry.BackgroundColor.Equals(color)))
            {
                if (!entry.BackgroundColor.Equals(color))
                {
                    Debug.WriteLine("*****Update to slide background color.");
                }
                entry.SlideSize       = zoom;
                entry.BackgroundColor = color;
                if (!UpdateAssociation(entry))
                {
                    return(null);
                }


                return(entry.ToRtUpdate());
            }
            return(null);
        }
        /// <summary>
        /// for the given Toc key, find the entry and if the entry is for a Student Submission slide, and
        /// the slide and deck association are missing, attempt to resolve and update them.
        /// Return false if the assocation needs updating, but the update failed.  Return true in all
        /// other cases.
        /// </summary>
        /// <param name="tocKey"></param>
        /// <returns></returns>
        private bool UpdateAssociation(TocEntry entry)
        {
            /// StudentSubmission and QuickPoll entries should have valid deck associations.
            /// A valid association includes a deck Guid, a slide index and a association deck typ
            /// that is a presentation or whiteboard.
            if (((entry.DeckType == DeckTypeEnum.StudentSubmission) ||
                 (entry.DeckType == DeckTypeEnum.QuickPoll)) &&
                ((entry.DeckAssociation == Guid.Empty) ||
                 (entry.SlideAssociation < 0) ||
                 (entry.DeckTypeAssociation == DeckTypeEnum.QuickPoll) ||
                 (entry.DeckTypeAssociation == DeckTypeEnum.StudentSubmission) ||
                 (entry.DeckTypeAssociation == DeckTypeEnum.Undefined)))
            {
                TocEntry associationEntry = FindAssociation(entry);

                if (associationEntry != null)
                {
                    entry.DeckAssociation     = associationEntry.DeckId;
                    entry.SlideAssociation    = associationEntry.SlideIndex;
                    entry.DeckTypeAssociation = associationEntry.DeckType;
                }
                else
                {
                    return(false);
                }
            }
            return(true);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Add a new topic from an existing file
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdAddExistingFile_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            FileNode thisNode    = this.FileNode;
            TocEntry t           = base.UIControl.CurrentTopic;
            string   projectPath = Path.GetDirectoryName(siteMapFile.ProjectElement.Project.Filename);

            using (WinFormsOpenFileDialog dlg = new WinFormsOpenFileDialog())
            {
                dlg.Title            = "Select the conceptual topic file(s)";
                dlg.Filter           = "HTML Files (*.htm, *.html)|*.htm;*.html|All files (*.*)|*.*";
                dlg.DefaultExt       = "html";
                dlg.InitialDirectory = (t != null && t.SourceFile.Path.Length != 0) ?
                                       Path.GetDirectoryName(t.SourceFile) : projectPath;
                dlg.Multiselect = true;

                // If selected, add the new file(s).  Filenames that are already in the collection are ignored.
                if (dlg.ShowDialog() == WinFormsDialogResult.OK)
                {
                    foreach (string filename in dlg.FileNames)
                    {
                        this.AddTopicFile(filename, e.Parameter != null);

                        if (t != null)
                        {
                            t.IsSelected = true;
                        }
                    }

                    if (thisNode != null)
                    {
                        thisNode.ProjectManager.RefreshProject();
                    }
                }
            }
        }
        /// <summary>
        /// This is used to recursively add child TOC entries to the entity reference collection
        /// </summary>
        /// <param name="t">The TOC entry</param>
        /// <param name="er">The parent entity reference</param>
        /// <param name="hasSelectedItem">The selected item state.  Only first selected item found is
        /// marked as the selected item.</param>
        private bool AddChildTocEntries(TocEntry t, EntityReference er, bool hasSelectedItem)
        {
            EntityReference subEnt;

            foreach (var child in t.Children)
            {
                subEnt = new EntityReference
                {
                    EntityType = EntityType.TocEntry,
                    Id         = child.Id,
                    Label      = (child.Title ?? child.Id ?? "(No title)"),
                    ToolTip    = String.Format(CultureInfo.CurrentCulture, "ID: {0}\nFile: {1}",
                                               (child.Id ?? child.Title ?? "(No ID)"), child.SourceFile),
                    Tag        = child,
                    IsExpanded = child.IsExpanded,
                    IsSelected = (child.IsSelected && !hasSelectedItem)
                };

                if (subEnt.IsSelected)
                {
                    hasSelectedItem = true;
                }

                er.SubEntities.Add(subEnt);

                if (child.Children.Count != 0)
                {
                    hasSelectedItem = this.AddChildTocEntries(child, subEnt, hasSelectedItem);
                }
            }

            return(hasSelectedItem);
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Insert a link to a site map table of contents entry (HTML only)
        /// </summary>
        /// <param name="extension">The extension of the file in which the
        /// link is being inserted.</param>
        /// <param name="tocEntry">The TOC entry for which to create a link</param>
        /// <remarks>If dropped inside some selected text, the link will
        /// wrap the selected text.</remarks>
        private void InsertTocLink(string extension, TocEntry tocEntry)
        {
            TextArea textArea = editor.ActiveTextAreaControl.TextArea;
            int      offset   = textArea.Caret.Offset;
            string   selectedText;

            if (textArea.SelectionManager.HasSomethingSelected &&
                textArea.SelectionManager.SelectionCollection[0].ContainsOffset(offset))
            {
                selectedText = textArea.SelectionManager.SelectionCollection[0].SelectedText;
            }
            else
            {
                selectedText = String.Empty;
            }

            if (extension == ".htm" || extension == ".html")
            {
                ContentEditorControl.InsertString(textArea,
                                                  tocEntry.ToAnchor(selectedText));
            }
            else
            {
                ContentEditorControl.InsertString(textArea,
                                                  tocEntry.Title); // Not supported in MAML topics
            }
        }
Ejemplo n.º 12
0
        //=====================================================================

        /// <summary>
        /// This is used to mark the file as dirty when the collection changes
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        void topics_ListChanged(object sender, ListChangedEventArgs e)
        {
            TocEntry selectedTopic = tvContent.SelectedItem as TocEntry;

            if (e.PropertyDescriptor != null)
            {
                switch (e.PropertyDescriptor.Name)
                {
                case "IsExpanded":
                case "IsSelected":
                    // We don't care about changes to these properties as they are for the
                    // editor and don't affect the state of the topic collection.
                    return;

                case "ApiParentMode":
                    // There can be only one API content parent
                    if (selectedTopic != null && selectedTopic.ApiParentMode != ApiParentMode.None)
                    {
                        foreach (var match in topics.Find(
                                     t => t.ApiParentMode != ApiParentMode.None && t != selectedTopic, false))
                        {
                            match.ApiParentMode = ApiParentMode.None;
                        }
                    }
                    break;

                case "IsDefaultTopic":
                    // There can be only one default topic
                    if (selectedTopic != null && selectedTopic.IsDefaultTopic)
                    {
                        foreach (var match in topics.Find(t => t.IsDefaultTopic && t != selectedTopic, false))
                        {
                            match.IsDefaultTopic = false;
                        }
                    }
                    break;

                default:
                    break;
                }
            }

            if (sender != this)
            {
                base.RaiseEvent(new RoutedEventArgs(ContentModifiedEvent, this));
            }

            // Update control state based on the collection content
            tvContent.IsEnabled = expTopicProps.IsEnabled = (topics != null && topics.Count != 0);

            CommandManager.InvalidateRequerySuggested();

            // We must clear the enumerator or it may throw an exception due to collection changes
            if (matchEnumerator != null)
            {
                matchEnumerator.Dispose();
                matchEnumerator = null;
            }
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Update the file related to the specified tree node with its new
        /// sort order and/or default topic indicator.
        /// </summary>
        /// <param name="tn">The tree node containing the TOC entry</param>
        /// <param name="sortOrder">The new sort order</param>
        private void UpdateTocEntry(TreeNode tn, int sortOrder)
        {
            Encoding enc;
            string   content;

            TocEntry toc = (TocEntry)tn.Tag;

            if (toc.SortOrder != sortOrder || (toc.IsDefaultTopic &&
                                               defaultNode != tn) || (!toc.IsDefaultTopic &&
                                                                      defaultNode == tn))
            {
                enc = Encoding.Default;

                if (toc.SourceFile.EndsWith(@"\"))
                {
                    toc.SourceFile += toc.Title + ".html";

                    // Exclude the new folder file if we create it
                    content = "<!-- @TOCExclude -->";
                }
                else
                {
                    content = BuildProcess.ReadWithEncoding(
                        toc.SourceFile, ref enc);
                }

                // Add or remove the default topic indicator
                if (defaultNode != tn)
                {
                    content = BuildProcess.reIsDefaultTopic.Replace(content,
                                                                    String.Empty);
                }
                else
                if (!BuildProcess.reIsDefaultTopic.IsMatch(content))
                {
                    content += "<!-- @DefaultTopic -->";
                }

                // Add or update the sort order
                if (BuildProcess.reSortOrder.IsMatch(content))
                {
                    content = BuildProcess.reSortOrder.Replace(content,
                                                               String.Format(CultureInfo.InvariantCulture,
                                                                             "<!-- @SortOrder {0} -->", sortOrder));
                }
                else
                {
                    content += String.Format(CultureInfo.InvariantCulture,
                                             "<!-- @SortOrder {0} -->", sortOrder);
                }

                using (StreamWriter sw = new StreamWriter(toc.SourceFile, false,
                                                          enc))
                {
                    sw.Write(content);
                }
            }
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Load the topic and display it when selected
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void tvContent_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e)
        {
            TocEntry t = tvContent.SelectedItem as TocEntry;

            if (t != null)
            {
                try
                {
                    Mouse.OverrideCursor = Cursors.Wait;

                    // If the file is open in an editor, use its current content
                    var args = new TopicContentNeededEventArgs(TopicContentNeededEvent, this, t.SourceFile);

                    if (!String.IsNullOrEmpty(t.SourceFile))
                    {
                        base.RaiseEvent(args);
                    }

                    txtTitle.Text     = t.PreviewerTitle;
                    fdViewer.Document = converter.ToFlowDocument(t.SourceFile, args.TopicContent);

                    this.AdjustPageWidth();

                    // Scroll to the top if not the first time shown
                    DependencyObject child = fdViewer;

                    if (VisualTreeHelper.GetChildrenCount(child) != 0)
                    {
                        while (!(child is ScrollViewer))
                        {
                            child = VisualTreeHelper.GetChild(child as Visual, 0);
                        }

                        ((ScrollViewer)child).ScrollToHome();
                    }
                }
                catch (Exception ex)
                {
                    // If we get here, something went really wrong
                    MessageBox.Show("Unable to convert topic.  Possible converter error.  Reason: " +
                                    ex.Message, Constants.AppName, MessageBoxButton.OK, MessageBoxImage.Error);
                }
                finally
                {
                    Mouse.OverrideCursor = null;
                }

                if (!isNavigating && !String.IsNullOrEmpty(t.Id))
                {
                    this.RecordHistory(new Uri("link://" + t.Id));
                }
            }
            else
            {
                txtTitle.Text     = null;
                fdViewer.Document = null;
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Cut the selected topic to the internal clipboard
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdCut_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            clipboardTopic = this.CurrentTopic;

            if (clipboardTopic != null)
            {
                clipboardTopic.Parent.Remove(clipboardTopic);
                tvContent.Focus();
            }
        }
Ejemplo n.º 16
0
        public BBeB ParseHTML(HtmlDocument doc, BindingParams bindingParams, TocEntry tocEntries)
        {
            m_Book = new BBeB();

            byte[] thumb = File.ReadAllBytes(bindingParams.IconFile);
            setHeaderValues(thumb.Length);
            m_Book.MetaData      = bindingParams.MetaData;
            m_Book.ThumbnailData = thumb;

            // Create our default Attribute objects
            createDefaultAttributeObjects(BBeB.ReaderPageWidth, BBeB.ReaderPageHeight);

            // cover page works, but it's ugly
            createCoverPage();

            m_CurrentPage = createPage();

            PageObject firstBookPage = m_CurrentPage;

            m_StartReadingBlock = null;
            m_StartReadingPage  = null;

            addBookPage(m_CurrentPage);

            IHTMLDocument2             dom      = (IHTMLDocument2)doc.DomDocument;
            IHTMLDOMNode               domNode  = (IHTMLDOMNode)dom.body;
            IHTMLDOMChildrenCollection children = (IHTMLDOMChildrenCollection)domNode.childNodes;

            TextBlockBuilder tbBuilder = new TextBlockBuilder(GetNextObjId(), m_CharMapper);

            foreach (IHTMLDOMNode child in children)
            {
                tbBuilder = ParseDomNode(child, tbBuilder);
            }

            PrintHTMLElementChildren(children);

            // If we have any text left then add it
            FlushTextToBlock(m_CurrentPage, tbBuilder, m_MainBodyTextAttr);

            finalizePage(m_CurrentPage);

            // Create the table of contents
            createTocPage(firstBookPage, tocEntries);

            m_TocObject.AddEntry(m_StartReadingPage.ID, m_StartReadingBlock.ID, "Start Reading");

            // Also serialize the table of contents object
            m_TocObject.Serialize();

            finalizeBook();

            return(m_Book);
        }
Ejemplo n.º 17
0
        private void AddTocViewNodes(TocEntry tocEntry, TreeNodeCollection nodes)
        {
            TreeNode node = new TreeNode(tocEntry.Title);

            node.Tag = tocEntry;
            nodes.Add(node);

            foreach (TocEntry child in tocEntry.Children)
            {
                AddTocViewNodes(child, node.Nodes);
            }
        }
Ejemplo n.º 18
0
        /// <summary>
        /// Delete the selected topic and all of its children
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdDelete_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntry t = tvContent.SelectedItem as TocEntry;

            if (t != null && MessageBox.Show(String.Format(CultureInfo.CurrentCulture, "Are you sure you " +
                                                           "want to delete the topic '{0}' and all of its sub-topics?", t.Title), Constants.AppName,
                                             MessageBoxButton.YesNo, MessageBoxImage.Question, MessageBoxResult.No) == MessageBoxResult.Yes)
            {
                t.Parent.Remove(t);
                tvContent.Focus();
            }
        }
Ejemplo n.º 19
0
        private void TocTree_AfterSelect(object sender, TreeViewEventArgs e)
        {
            if (m_TocTree.SelectedNode == null)
            {
                return;
            }

            TocEntry    itemTocEntry    = (TocEntry)m_TocTree.SelectedNode.Tag;
            HtmlElement selectedElement = (HtmlElement)itemTocEntry.Tag;

            selectedElement.ScrollIntoView(true);
        }
        internal object GetRtUpdateForSlideId(Guid guid)
        {
            if (guid.Equals(Guid.Empty))
            {
                return(null);
            }
            TocEntry entry = this.LookupBySlideId(guid);

            if (entry == null)
            {
                return(null);
            }
            return(entry.ToRtUpdate());
        }
Ejemplo n.º 21
0
        /// <summary>
        /// Clear the topic associated with the selected node
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void btnClearTopic_Click(object sender, RoutedEventArgs e)
        {
            TocEntry t = tvContent.SelectedItem as TocEntry;

            if (t != null && MessageBox.Show("Do you want to clear the file associated with this topic?",
                                             "Site Map Editor", MessageBoxButton.YesNo, MessageBoxImage.Question,
                                             MessageBoxResult.No) == MessageBoxResult.Yes)
            {
                t.SourceFile = null;

                txtTopicFilename.GetBindingExpression(TextBox.TextProperty).UpdateTarget();

                this.topics_ListChanged(tvContent, new ListChangedEventArgs(ListChangedType.Reset, -1));
            }
        }
Ejemplo n.º 22
0
        //=====================================================================

        /// <summary>
        /// Refresh the table of contents and the current topic to show any changes made to them
        /// </summary>
        /// <param name="reloadLastTopic">True to reload the last topic, false to ignore it</param>
        public void Refresh(bool reloadLastTopic)
        {
            TocEntry t = this.CurrentTopic;

            if (t != null)
            {
                this.LoadTableOfContentsInfo();

                // Go back to the last selected topic if it is still there and wanted
                if (reloadLastTopic)
                {
                    this.FindAndDisplay(t.SourceFile);
                }
            }
        }
Ejemplo n.º 23
0
        public void RoundTripTocEntry()
        {
            XDocument doc = Utils.ReadXmlResource("UnitTestMergeWebToEpub.TestData.toc.ncx");
            var       e1  = doc.Root.Element(Epub.ncxNs + "navMap")
                            .Element(Epub.ncxNs + "navPoint");

            string ncxPath   = "OEPBS/content.opf";
            string ncxFolder = ncxPath.GetZipPath();
            var    api       = Utils.FakeAbsolutePathIndex(doc, ncxPath);
            var    tocEntry  = new TocEntry(e1, ncxFolder, api);
            int    playOrder = 0;
            var    e2        = tocEntry.ToNavPoint(ref playOrder, ncxFolder);

            Assert.IsTrue(XNode.DeepEquals(e1, e2));
        }
        /// <summary>
        /// This is used to extract table of contents information from a file
        /// that will appear in the help file's table of contents.
        /// </summary>
        /// <param name="filename">The file from which to extract the
        /// information</param>
        /// <returns>The table of contents entry</returns>
        internal static TocEntry GetTocInfo(string filename)
        {
            TocEntry tocEntry;
            Encoding enc = Encoding.Default;
            string   content;

            content = BuildProcess.ReadWithEncoding(filename, ref enc);

            tocEntry                = new TocEntry(null);
            tocEntry.IncludePage    = !reTocExclude.IsMatch(content);
            tocEntry.IsDefaultTopic = reIsDefaultTopic.IsMatch(content);

            if (reSplitToc.IsMatch(content))
            {
                tocEntry.ApiParentMode = ApiParentMode.InsertAfter;
            }

            Match m = reSortOrder.Match(content);

            if (m.Success)
            {
                tocEntry.SortOrder = Convert.ToInt32(m.Groups["SortOrder"].Value, CultureInfo.InvariantCulture);
            }

            // Get the page title if possible.  If not found, use the filename
            // without the path or extension as the page title.
            m = rePageTitle.Match(content);
            if (!m.Success)
            {
                tocEntry.Title = Path.GetFileNameWithoutExtension(filename);
            }
            else
            {
                tocEntry.Title = HttpUtility.HtmlDecode(m.Groups["Title"].Value).Replace(
                    "\r", String.Empty).Replace("\n", String.Empty);
            }

            // Since we've got the file loaded, see if there are links
            // that need to be resolved when the file is copied, if it
            // contains <pre> blocks that should be colorized, or if it
            // contains tags or shared content items that need replacing.
            tocEntry.HasLinks        = reResolveLinks.IsMatch(content);
            tocEntry.HasCodeBlocks   = reCodeBlock.IsMatch(content);
            tocEntry.NeedsColorizing = reColorizeCheck.IsMatch(content);
            tocEntry.HasProjectTags  = (reProjectTags.IsMatch(content) || reSharedContent.IsMatch(content));

            return(tocEntry);
        }
Ejemplo n.º 25
0
        /// <summary>
        /// Get the text to copy as a link to the clipboard
        /// </summary>
        /// <returns>The string to copy to the clipboard or null if there is nothing to copy</returns>
        private string GetTextToCopy()
        {
            TocEntry t = tvContent.SelectedItem as TocEntry;
            string   textToCopy;

            if (t != null)
            {
                textToCopy = t.ToAnchor(!String.IsNullOrEmpty(t.Title) ? t.Title : "(No title)");
            }
            else
            {
                textToCopy = null;
            }

            return(textToCopy);
        }
Ejemplo n.º 26
0
        /// <summary>
        /// Move the selected topic down within its parent collection
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdMoveDown_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntry           t = tvContent.SelectedItem as TocEntry;
            TocEntryCollection parent;
            int idx;

            if (t != null)
            {
                parent = t.Parent;
                idx    = parent.IndexOf(t);

                parent.Remove(t);
                parent.Insert(idx + 1, t);
                t.IsSelected = true;
                tvContent.Focus();
            }
        }
        /// <summary>
        /// Associate a QuickPollId in the TOC with the given SlideId, so that when we get QuickPoll results later
        /// we can look up the TOC entry by this ID.
        /// </summary>
        /// <param name="slideId"></param>
        /// <param name="quickPollId"></param>
        internal void AddQuickPollIdForSlide(Guid slideId, Guid quickPollId)
        {
            //First make sure the SlideId exists in the TOC
            TocEntry entry = this.LookupBySlideId(slideId);

            if (entry == null)
            {
                Debug.WriteLine("!!!Failed to find slide to which to add QuickPoll ID!!!");
                return;
            }
            //Remove existing mapping if any.
            if (QuickPollIdToSlideId.ContainsKey(quickPollId))
            {
                QuickPollIdToSlideId.Remove(quickPollId);
            }
            //Add mapping
            QuickPollIdToSlideId.Add(quickPollId, slideId);
        }
Ejemplo n.º 28
0
        /// <summary>
        /// Fill the table of contents tree view.
        /// </summary>
        private void FillTocView()
        {
            TocEntry toc = CreateTableOfContents();

            // The top entry is a fake entry to contain the others.

            if (m_TocEntryRoot == null || !m_TocEntryRoot.Equals(toc))
            {
                m_TocTree.Nodes.Clear();
                foreach (TocEntry entry in toc.Children)
                {
                    AddTocViewNodes(entry, m_TocTree.Nodes);
                }
                m_TocTree.ExpandAll();

                m_TocEntryRoot = toc;
            }
        }
Ejemplo n.º 29
0
        public static void Regenerate(string directory)
        {
            var allMetadata = Directory
                              .GetFiles(directory, "*.yml")
                              .Where(file => Path.GetFileName(file) != "toc.yml")
                              .SelectMany(file => MetadataFile.LoadYaml(file).Items)
                              .ToDictionary(item => item.Uid);
            var assemblies = allMetadata.Values
                             .SelectMany(item => item.Assemblies)
                             .Distinct()
                             .OrderBy(assembly => assembly, StringComparer.Ordinal)
                             .ToList();

            var tocEntries = assemblies.Select(assembly => CreateTocEntryForAssembly(assembly, allMetadata)).ToList();
            var tocText    = TocEntry.CreateToc(tocEntries);

            File.WriteAllText(Path.Combine(directory, "toc.yml"), tocText);
        }
Ejemplo n.º 30
0
        /// <summary>
        /// Associate a project file with the current topic
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void ucSiteMapEditor_AssociateTopic(object sender, RoutedEventArgs e)
        {
            FileNode thisNode = this.FileNode;
            TocEntry t = base.UIControl.CurrentTopic;
            string   newPath, projectPath = Path.GetDirectoryName(
                siteMapFile.ProjectElement.Project.Filename);

            if (t != null)
            {
                using (WinFormsOpenFileDialog dlg = new WinFormsOpenFileDialog())
                {
                    dlg.Title  = "Select the additional content topic file";
                    dlg.Filter = "Additional Content Topics (*.htm, *.html)|*.htm;*.html|" +
                                 "All files (*.*)|*.*";
                    dlg.DefaultExt       = "html";
                    dlg.InitialDirectory = projectPath;
                    dlg.CheckFileExists  = true;

                    if (dlg.ShowDialog() == WinFormsDialogResult.OK)
                    {
                        // The file must reside under the project path
                        newPath = dlg.FileName;

                        if (!Path.GetDirectoryName(newPath).StartsWith(projectPath, StringComparison.OrdinalIgnoreCase))
                        {
                            newPath = Path.Combine(projectPath, Path.GetFileName(newPath));
                        }

                        // Add the file to the project if not already there
                        siteMapFile.ProjectElement.Project.AddFileToProject(dlg.FileName, newPath);

                        t.SourceFile = new FilePath(newPath, siteMapFile.ProjectElement.Project);

                        // Let the caller know we associated a file with the topic
                        e.Handled = true;

                        if (thisNode != null)
                        {
                            thisNode.ProjectManager.RefreshProject();
                        }
                    }
                }
            }
        }
        /// <summary>
        /// This is used to copy site map files to the help format output folders including those for any child
        /// site map entries.
        /// </summary>
        /// <param name="site">The site entry containing the files to copy</param>
        private void CopySiteMapFiles(TocEntry site)
        {
            if(site.SourceFile.Path.Length != 0)
            {
                // Set the destination filename which will always match the source filename for site map files.
                site.DestinationFile = site.SourceFile.PersistablePath;

                foreach(string baseFolder in this.HelpFormatOutputFolders)
                    if(!File.Exists(baseFolder + site.DestinationFile))
                    {
                        this.ReportProgress("{0} -> {1}{2}", site.SourceFile, baseFolder, site.DestinationFile);

                        // All attributes are turned off so that we can delete it later
                        File.Copy(site.SourceFile, baseFolder + site.DestinationFile, true);
                        File.SetAttributes(baseFolder + site.DestinationFile, FileAttributes.Normal);
                    }
            }

            if(site.Children.Count != 0)
                foreach(TocEntry entry in site.Children)
                    this.CopySiteMapFiles(entry);
        }
        /// <summary>
        /// This is called to copy the additional content files and build a
        /// list of them for the help file project.
        /// </summary>
        /// <remarks>Note that for wilcard content items, the folders are
        /// copied recursively.</remarks>
        protected void CopyAdditionalContent()
        {
            Dictionary<string, TocEntryCollection> tocItems =
                new Dictionary<string, TocEntryCollection>();
            TocEntryCollection parentToc;
            TocEntry tocEntry, tocFolder;
            FileItemCollection contentItems;
            string projectPath, source, filename, dirName;
            string[] parts;
            int part;

            this.ReportProgress(BuildStep.CopyAdditionalContent, "Copying additional content files...");

            if(this.ExecutePlugIns(ExecutionBehaviors.InsteadOf))
                return;

            // A plug-in might add or remove additional content so call
            // them before checking to see if there is anything to copy.
            this.ExecutePlugIns(ExecutionBehaviors.Before);

            if(!project.HasItems(BuildAction.Content) && !project.HasItems(BuildAction.SiteMap))
            {
                this.ReportProgress("No additional content to copy");
                this.ExecutePlugIns(ExecutionBehaviors.After);
                return;
            }

            toc = new TocEntryCollection();
            tocItems.Add(String.Empty, toc);

            // Now copy the content files
            contentItems = new FileItemCollection(project, BuildAction.Content);
            projectPath = FolderPath.TerminatePath(Path.GetDirectoryName(originalProjectName));

            foreach(FileItem fileItem in contentItems)
            {
                source = fileItem.Include;
                dirName = Path.GetDirectoryName(fileItem.Link.ToString().Substring(projectPath.Length));
                filename = Path.Combine(dirName, Path.GetFileName(source));

                if(source.EndsWith(".htm", StringComparison.OrdinalIgnoreCase) ||
                  source.EndsWith(".html", StringComparison.OrdinalIgnoreCase) ||
                  source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))
                {
                    tocEntry = BuildProcess.GetTocInfo(source);

                    // Exclude the page if so indicated via the item metadata
                    if(fileItem.ExcludeFromToc)
                        tocEntry.IncludePage = false;

                    // .topic files get transformed into .html files
                    if(source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))
                        filename = Path.ChangeExtension(filename, ".html");

                    tocEntry.SourceFile = new FilePath(source, project);
                    tocEntry.DestinationFile = filename;

                    // Figure out where to add the entry
                    parts = tocEntry.DestinationFile.Split('\\');
                    pathToRoot = String.Empty;
                    parentToc = toc;

                    for(part = 0; part < parts.Length - 1; part++)
                    {
                        pathToRoot += parts[part] + @"\";

                        // Create place holders if necessary
                        if(!tocItems.TryGetValue(pathToRoot, out parentToc))
                        {
                            tocFolder = new TocEntry(project);
                            tocFolder.Title = parts[part];

                            if(part == 0)
                                toc.Add(tocFolder);
                            else
                                tocItems[String.Join(@"\", parts, 0, part) + @"\"].Add(tocFolder);

                            parentToc = tocFolder.Children;
                            tocItems.Add(pathToRoot, parentToc);
                        }
                    }

                    parentToc.Add(tocEntry);

                    if(tocEntry.IncludePage && tocEntry.IsDefaultTopic)
                        defaultTopic = tocEntry.DestinationFile;
                }
                else
                    tocEntry = null;

                this.EnsureOutputFoldersExist(dirName);

                foreach(string baseFolder in this.HelpFormatOutputFolders)
                {
                    // If the file contains items that need to be resolved,
                    // it is handled separately.
                    if(tocEntry != null &&
                      (tocEntry.HasLinks || tocEntry.HasCodeBlocks ||
                      tocEntry.NeedsColorizing || tocEntry.HasProjectTags ||
                      source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)))
                    {
                        // Figure out the path to the root if needed
                        parts = tocEntry.DestinationFile.Split('\\');
                        pathToRoot = String.Empty;

                        for(part = 0; part < parts.Length - 1; part++)
                            pathToRoot += "../";

                        this.ResolveLinksAndCopy(source, baseFolder + filename, tocEntry);
                    }
                    else
                    {
                        this.ReportProgress("{0} -> {1}{2}", source, baseFolder, filename);

                        // All attributes are turned off so that we can delete it later
                        File.Copy(source, baseFolder + filename, true);
                        File.SetAttributes(baseFolder + filename, FileAttributes.Normal);
                    }
                }
            }

            // Remove excluded nodes, merge folder item info into the root
            // nodes, and sort the items.  If a site map isn't defined, this
            // will define the layout of the items.
            toc.RemoveExcludedNodes(null);
            toc.Sort();

            codeColorizer = null;
            sharedContent = sharedBuilderContent = styleContent = null;

            this.ExecutePlugIns(ExecutionBehaviors.After);
        }
        /// <summary>
        /// This is used to merge destination file information into the site
        /// map TOC.
        /// </summary>
        /// <param name="site">The site entry to update</param>
        /// <remarks>In addition, files in the site map that do not exist in
        /// the TOC built from the defined content will be processed and
        /// copied to the root folder.</remarks>
        private void MergeTocInfo(TocEntry site)
        {
            TocEntry match;
            string source, filename;

            if(site.SourceFile.Path.Length != 0)
            {
                match = toc.Find(site.SourceFile);

                if(match != null)
                    site.DestinationFile = match.DestinationFile;
                else
                {
                    source = site.SourceFile;
                    site.DestinationFile = Path.GetFileName(source);
                    filename = site.DestinationFile;

                    // .topic files get transformed into .html files
                    if(source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))
                        site.DestinationFile = Path.ChangeExtension(site.DestinationFile, ".html");

                    // Check to see if anything needs resolving
                    if(source.EndsWith(".htm", StringComparison.OrdinalIgnoreCase) ||
                      source.EndsWith(".html", StringComparison.OrdinalIgnoreCase) ||
                      source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))
                        match = BuildProcess.GetTocInfo(source);

                    foreach(string baseFolder in this.HelpFormatOutputFolders)
                    {
                        // If the file contains items that need to be resolved, it is handled separately
                        if(match != null && (match.HasLinks || match.HasCodeBlocks ||
                          match.NeedsColorizing || match.HasProjectTags ||
                          source.EndsWith(".topic", StringComparison.OrdinalIgnoreCase)))
                        {
                            // Files are always copied to the root
                            pathToRoot = String.Empty;

                            this.ResolveLinksAndCopy(source, baseFolder + filename, match);
                        }
                        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);
                        }
                    }
                }
            }

            if(site.Children.Count != 0)
                foreach(TocEntry entry in site.Children)
                    this.MergeTocInfo(entry);
        }
Ejemplo n.º 34
0
        /// <summary>
        /// Add a new topic file
        /// </summary>
        /// <param name="filename">The filename of the topic to add</param>
        /// <param name="addAsChild">True to add as a child of the selected
        /// node or false to add it as a sibling.</param>
        private void AddTopicFile(string filename, bool addAsChild)
        {
            TocEntry topic, parentTopic;
            TreeNode tnNew, tnParent;
            string newPath = filename, projectPath = Path.GetDirectoryName(
                topics.FileItem.ProjectElement.Project.Filename);

            // The file must reside under the project path
            if(!Path.GetDirectoryName(filename).StartsWith(projectPath,
              StringComparison.OrdinalIgnoreCase))
                newPath = Path.Combine(projectPath, Path.GetFileName(filename));

            // Add the file to the project
            topics.FileItem.ProjectElement.Project.AddFileToProject(filename,
                newPath);
            topic = new TocEntry(topics.FileItem.ProjectElement.Project);
            topic.SourceFile = new FilePath(newPath, topic.BasePathProvider);
            topic.Title = Path.GetFileNameWithoutExtension(newPath);

            tnNew = new TreeNode(topic.Title);
            tnNew.Name = topic.SourceFile;
            tnNew.Tag = topic;

            if(addAsChild)
            {
                tvContent.SelectedNode.Nodes.Add(tnNew);
                parentTopic = (TocEntry)tvContent.SelectedNode.Tag;
                parentTopic.Children.Add(topic);
            }
            else
                if(tvContent.SelectedNode == null)
                {
                    tvContent.Nodes.Add(tnNew);
                    topics.Add(topic);
                }
                else
                {
                    if(tvContent.SelectedNode.Parent == null)
                        tvContent.Nodes.Insert(tvContent.Nodes.IndexOf(
                            tvContent.SelectedNode) + 1, tnNew);
                    else
                    {
                        tnParent = tvContent.SelectedNode.Parent;
                        tnParent.Nodes.Insert(tnParent.Nodes.IndexOf(
                            tvContent.SelectedNode) + 1, tnNew);
                    }

                    parentTopic = (TocEntry)tvContent.SelectedNode.Tag;
                    parentTopic.Parent.Insert(
                        parentTopic.Parent.IndexOf(parentTopic) + 1,
                        topic);
                }

            tvContent.SelectedNode = tnNew;
        }
Ejemplo n.º 35
0
        /// <summary>
        /// Load the tree view with the topics and set the form up to edit them
        /// </summary>
        /// <param name="selectedEntry">If not null, the node containing the
        /// specified entry is set as the selected node.  If null, the first
        /// node is selected.</param>
        private void LoadTopics(TocEntry selectedEntry)
        {
            TreeNode node;

            try
            {
                tvContent.SuspendLayout();
                tvContent.Nodes.Clear();

                defaultNode = splitTocNode = firstNode = null;
                firstSelection = selectedEntry;

                if(topics.Count != 0)
                {
                    foreach(TocEntry t in topics)
                    {
                        node = tvContent.Nodes.Add(t.Title);
                        node.Name = t.SourceFile;
                        node.Tag = t;

                        if(t.IsDefaultTopic)
                            defaultNode = node;

                        // This is only valid at the root level
                        if(t.ApiParentMode != ApiParentMode.None)
                            splitTocNode = node;

                        if(t == firstSelection)
                            firstNode = node;

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

                    if(defaultNode != null)
                    {
                        defaultNode.ToolTipText = "Default topic";
                        defaultNode.ImageIndex = defaultNode.SelectedImageIndex = 1;
                    }

                    if(splitTocNode != null)
                    {
                        splitTocNode.ToolTipText = "Split Table of Contents";
                        splitTocNode.ImageIndex = splitTocNode.SelectedImageIndex = 10;
                    }

                    if(defaultNode != null && defaultNode == splitTocNode)
                    {
                        defaultNode.ToolTipText = "Default topic/Split TOC";
                        defaultNode.ImageIndex = defaultNode.SelectedImageIndex = 11;
                    }

                    tvContent.ExpandAll();

                    if(firstNode != null)
                    {
                        tvContent.SelectedNode = firstNode;
                        firstNode.EnsureVisible();
                    }
                    else
                    {
                        tvContent.SelectedNode = tvContent.Nodes[0];
                        tvContent.SelectedNode.EnsureVisible();
                    }
                }
                else
                    this.UpdateControlStatus();
            }
            finally
            {
                tvContent.ResumeLayout();
            }
        }
Ejemplo n.º 36
0
        /// <summary>
        /// Add an empty container node that is not associated with any topic
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void tsbAddTopic_ButtonClick(object sender, EventArgs e)
        {
            ToolStripItem tiAdd = (ToolStripItem)sender;
            TocEntry topic, parentTopic;
            TreeNode tnNew, tnParent;

            topic = new TocEntry(topics.FileItem.ProjectElement.Project);
            topic.Title = "Table of Contents Container";
            tnNew = new TreeNode(topic.Title);
            tnNew.Name = topic.SourceFile;
            tnNew.Tag = topic;

            if(tiAdd == tsbAddChildTopic || tiAdd.Owner == cmsNewChildTopic)
            {
                tvContent.SelectedNode.Nodes.Add(tnNew);
                parentTopic = (TocEntry)tvContent.SelectedNode.Tag;
                parentTopic.Children.Add(topic);
            }
            else
                if(tvContent.SelectedNode == null)
                {
                    tvContent.Nodes.Add(tnNew);
                    topics.Add(topic);
                }
                else
                {
                    if(tvContent.SelectedNode.Parent == null)
                        tvContent.Nodes.Insert(tvContent.Nodes.IndexOf(
                            tvContent.SelectedNode) + 1, tnNew);
                    else
                    {
                        tnParent = tvContent.SelectedNode.Parent;
                        tnParent.Nodes.Insert(tnParent.Nodes.IndexOf(
                            tvContent.SelectedNode) + 1, tnNew);
                    }

                    parentTopic = (TocEntry)tvContent.SelectedNode.Tag;
                    parentTopic.Parent.Insert(
                        parentTopic.Parent.IndexOf(parentTopic) + 1,
                        topic);
                }

            tvContent.SelectedNode = tnNew;
        }
Ejemplo n.º 37
0
        /// <summary>
        /// Insert a link to a site map table of contents entry (HTML only)
        /// </summary>
        /// <param name="extension">The extension of the file in which the
        /// link is being inserted.</param>
        /// <param name="tocEntry">The TOC entry for which to create a link</param>
        /// <remarks>If dropped inside some selected text, the link will
        /// wrap the selected text.</remarks>
        private void InsertTocLink(string extension, TocEntry tocEntry)
        {
            TextArea textArea = editor.ActiveTextAreaControl.TextArea;
            int offset = textArea.Caret.Offset;
            string selectedText;

            if(textArea.SelectionManager.HasSomethingSelected &&
              textArea.SelectionManager.SelectionCollection[0].ContainsOffset(offset))
                selectedText = textArea.SelectionManager.SelectionCollection[0].SelectedText;
            else
                selectedText = String.Empty;

            if(extension == ".htm" || extension == ".html")
                ContentEditorControl.InsertString(textArea, tocEntry.ToAnchor(selectedText));
            else
                ContentEditorControl.InsertString(textArea, tocEntry.Title);    // Not supported in MAML topics
        }
        //=====================================================================

        /// <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>
        /// Paste the selected topic as a sibling or child of the selected topic
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdPaste_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            TocEntry targetTopic = this.CurrentTopic, newTopic = clipboardTopic;

            if(newTopic != null)
            {
                // Don't allow pasting multiple copies of the same item in here as the IDs must be unique
                clipboardTopic = null;

                if(targetTopic == null)
                    topics.Add(newTopic);
                else
                {
                    if(e.Command == EditorCommands.PasteAsChild)
                    {
                        targetTopic.Children.Add(newTopic);
                        targetTopic.IsExpanded = true;
                    }
                    else
                        targetTopic.Parent.Insert(targetTopic.Parent.IndexOf(targetTopic) + 1, newTopic);
                }

                newTopic.IsSelected = true;
                tvContent.Focus();
            }
        }
        /// <summary>
        /// This is called to load an additional content file, resolve links
        /// to namespace content and copy it to the output folder.
        /// </summary>
        /// <param name="sourceFile">The source filename to copy</param>
        /// <param name="destFile">The destination filename</param>
        /// <param name="entry">The entry being resolved.</param>
        internal void ResolveLinksAndCopy(string sourceFile, string destFile,
          TocEntry entry)
        {
            Encoding enc = Encoding.Default;
            string content, script, syntaxFile;
            int pos;

            // For topics, change the extenstion back to ".topic".  It's
            // ".html" in the TOC as that's what it ends up as after
            // transformation.
            if(sourceFile.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))
                destFile = Path.ChangeExtension(destFile, ".topic");

            this.ReportProgress("{0} -> {1}", sourceFile, destFile);

            // When reading the file, use the default encoding but detect the
            // encoding if byte order marks are present.
            content = BuildProcess.ReadWithEncoding(sourceFile, ref enc);

            // Expand <code> tags if necessary
            if(entry.HasCodeBlocks)
                content = reCodeBlock.Replace(content, codeBlockMatchEval);

            // Colorize <pre> tags if necessary
            if(entry.NeedsColorizing || entry.HasCodeBlocks)
            {
                // Initialize code colorizer on first use
                if(codeColorizer == null)
                    codeColorizer = new CodeColorizer(shfbFolder + @"Colorizer\highlight.xml",
                        shfbFolder + @"Colorizer\highlight.xsl");

                // Set the path the "Copy" image
                codeColorizer.CopyImageUrl = pathToRoot + "icons/CopyCode.gif";

                // Colorize it and replace the "Copy" literal text with the
                // shared content include item so that it gets localized.
                content = codeColorizer.ProcessAndHighlightText(content);
                content = content.Replace(codeColorizer.CopyText + "</span",
                    "<include item=\"copyCode\"/></span");
                entry.HasProjectTags = true;

                // Add the links to the colorizer stylesheet and script files
                // unless it's going to be transformed.  In which case, the
                // links should be in the XSL stylesheet.
                if(!sourceFile.EndsWith(".topic", StringComparison.OrdinalIgnoreCase) &&
                  !sourceFile.EndsWith(".xsl", StringComparison.OrdinalIgnoreCase))
                {
                    script = String.Format(CultureInfo.InvariantCulture,
                        "<link type='text/css' rel='stylesheet' href='{0}styles/highlight.css' />" +
                        "<script type='text/javascript' src='{0}scripts/highlight.js'></script>", pathToRoot);

                    pos = content.IndexOf("</head>", StringComparison.Ordinal);

                    // Create a <head> section if one doesn't exist
                    if(pos == -1)
                    {
                        script = "<head>" + script + "</head>";
                        pos = content.IndexOf("<html>", StringComparison.Ordinal);

                        if(pos != -1)
                            pos += 6;
                        else
                            pos = 0;
                    }

                    content = content.Insert(pos, script);
                }

                // Copy the colorizer files if not already there
                this.EnsureOutputFoldersExist("icons");
                this.EnsureOutputFoldersExist("styles");
                this.EnsureOutputFoldersExist("scripts");

                foreach(string baseFolder in this.HelpFormatOutputFolders)
                    if(!File.Exists(baseFolder + @"styles\highlight.css"))
                    {
                        syntaxFile = baseFolder + @"styles\highlight.css";
                        File.Copy(shfbFolder + @"Colorizer\highlight.css", syntaxFile);
                        File.SetAttributes(syntaxFile, FileAttributes.Normal);

                        syntaxFile = baseFolder + @"scripts\highlight.js";
                        File.Copy(shfbFolder + @"Colorizer\highlight.js", syntaxFile);
                        File.SetAttributes(syntaxFile, FileAttributes.Normal);

                        // Always copy the image files, they may be different.  Also, delete the
                        // destination file first if it exists as the filename casing may be different.
                        syntaxFile = baseFolder + @"icons\CopyCode.gif";

                        if(File.Exists(syntaxFile))
                        {
                            File.SetAttributes(syntaxFile, FileAttributes.Normal);
                            File.Delete(syntaxFile);
                        }

                        File.Copy(shfbFolder + @"Colorizer\CopyCode.gif", syntaxFile);
                        File.SetAttributes(syntaxFile, FileAttributes.Normal);

                        syntaxFile = baseFolder + @"icons\CopyCode_h.gif";

                        if(File.Exists(syntaxFile))
                        {
                            File.SetAttributes(syntaxFile, FileAttributes.Normal);
                            File.Delete(syntaxFile);
                        }

                        File.Copy(shfbFolder + @"Colorizer\CopyCode_h.gif", syntaxFile);
                        File.SetAttributes(syntaxFile, FileAttributes.Normal);
                    }
            }

            // Use a regular expression to find and replace all tags with
            // cref attributes with a link to the help file content.  This
            // needs to happen after the code block processing as they
            // may contain <see> tags that need to be resolved.
            if(entry.HasLinks || entry.HasCodeBlocks)
                content = reResolveLinks.Replace(content, linkMatchEval);

            // Replace project option tags with project option values
            if(entry.HasProjectTags)
            {
                // Project tags can be nested
                while(reProjectTags.IsMatch(content))
                    content = reProjectTags.Replace(content, fieldMatchEval);

                // Shared content items can be nested
                while(reSharedContent.IsMatch(content))
                    content = reSharedContent.Replace(content, contentMatchEval);
            }

            // Write the file back out with the appropriate encoding
            using(StreamWriter sw = new StreamWriter(destFile, false, enc))
            {
                sw.Write(content);
            }

            // Transform .topic files into .html files
            if(sourceFile.EndsWith(".topic", StringComparison.OrdinalIgnoreCase))
                this.XslTransform(destFile);
        }
        /// <summary>
        /// Cut the selected topic to the internal clipboard
        /// </summary>
        /// <param name="sender">The sender of the event</param>
        /// <param name="e">The event arguments</param>
        private void cmdCut_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            clipboardTopic = this.CurrentTopic;

            if(clipboardTopic != null)
            {
                clipboardTopic.Parent.Remove(clipboardTopic);
                tvContent.Focus();
            }
        }
Ejemplo n.º 42
0
        /// <summary>
        /// Add a new topic file to the project and the editor
        /// </summary>
        /// <param name="filename">The filename of the topic to add</param>
        /// <param name="addAsChild">True to add as a child of the selected
        /// topic or false to add it as a sibling.</param>
        /// <returns>The topic that was just added</returns>
        private TocEntry AddTopicFile(string filename, bool addAsChild)
        {
            TocEntry newTopic, currentTopic = ucSiteMapEditor.CurrentTopic;
            string newPath = filename, projectPath = Path.GetDirectoryName(
                siteMapFile.Project.Filename);

            // The file must reside under the project path
            if(!Path.GetDirectoryName(filename).StartsWith(projectPath, StringComparison.OrdinalIgnoreCase))
                newPath = Path.Combine(projectPath, Path.GetFileName(filename));

            // Add the file to the project if not already there
            siteMapFile.Project.AddFileToProject(filename, newPath);

            // Add the topic to the editor's collection
            newTopic = new TocEntry(siteMapFile.Project)
            {
                SourceFile = new FilePath(newPath, siteMapFile.Project),
                Title = Path.GetFileNameWithoutExtension(newPath)
            };

            if(addAsChild && currentTopic != null)
            {
                currentTopic.Children.Add(newTopic);
                currentTopic.IsExpanded = true;
            }
            else
                if(currentTopic == null)
                    ucSiteMapEditor.Topics.Add(newTopic);
                else
                    currentTopic.Parent.Insert(currentTopic.Parent.IndexOf(currentTopic) + 1, newTopic);

            newTopic.IsSelected = true;

            return newTopic;
        }
        /// <summary>
        /// This is used to recursively add child TOC entries to the entity reference collection
        /// </summary>
        /// <param name="t">The TOC entry</param>
        /// <param name="er">The parent entity reference</param>
        /// <param name="hasSelectedItem">The selected item state.  Only first selected item found is
        /// marked as the selected item.</param>
        private bool AddChildTocEntries(TocEntry t, EntityReference er, bool hasSelectedItem)
        {
            EntityReference subEnt;

            foreach(var child in t.Children)
            {
                subEnt = new EntityReference
                {
                    EntityType = EntityType.TocEntry,
                    Id = child.Id,
                    Label = (child.Title ?? child.Id ?? "(No title)"),
                    ToolTip = String.Format(CultureInfo.CurrentCulture, "ID: {0}\nFile: {1}",
                        (child.Id ?? child.Title ?? "(No ID)"), child.SourceFile),
                    Tag = child,
                    IsExpanded = child.IsExpanded,
                    IsSelected = (child.IsSelected && !hasSelectedItem)
                };

                if(subEnt.IsSelected)
                    hasSelectedItem = true;

                er.SubEntities.Add(subEnt);

                if(child.Children.Count != 0)
                    hasSelectedItem = this.AddChildTocEntries(child, subEnt, hasSelectedItem);
            }

            return hasSelectedItem;
        }
        /// <summary>
        /// This is used to extract table of contents information from a file
        /// that will appear in the help file's table of contents.
        /// </summary>
        /// <param name="filename">The file from which to extract the 
        /// information</param>
        /// <returns>The table of contents entry</returns>
        internal static TocEntry GetTocInfo(string filename)
        {
            TocEntry tocEntry;
            Encoding enc = Encoding.Default;
            string content;

            content = BuildProcess.ReadWithEncoding(filename, ref enc);

            tocEntry = new TocEntry(null);
            tocEntry.IncludePage = !reTocExclude.IsMatch(content);
            tocEntry.IsDefaultTopic = reIsDefaultTopic.IsMatch(content);

            if(reSplitToc.IsMatch(content))
                tocEntry.ApiParentMode = ApiParentMode.InsertAfter;

            Match m = reSortOrder.Match(content);
            if(m.Success)
                tocEntry.SortOrder = Convert.ToInt32(m.Groups["SortOrder"].Value, CultureInfo.InvariantCulture);

            // Get the page title if possible.  If not found, use the filename
            // without the path or extension as the page title.
            m = rePageTitle.Match(content);
            if(!m.Success)
                tocEntry.Title = Path.GetFileNameWithoutExtension(filename);
            else
                tocEntry.Title = HttpUtility.HtmlDecode(m.Groups["Title"].Value).Replace(
                    "\r", String.Empty).Replace("\n", String.Empty);

            // Since we've got the file loaded, see if there are links
            // that need to be resolved when the file is copied, if it
            // contains <pre> blocks that should be colorized, or if it
            // contains tags or shared content items that need replacing.
            tocEntry.HasLinks = reResolveLinks.IsMatch(content);
            tocEntry.HasCodeBlocks = reCodeBlock.IsMatch(content);
            tocEntry.NeedsColorizing = reColorizeCheck.IsMatch(content);
            tocEntry.HasProjectTags = (reProjectTags.IsMatch(content) || reSharedContent.IsMatch(content));

            return tocEntry;
        }