public static void AddNewMessageRow(this FlowDocument document, Tox tox, MessageData data, bool sameUser) { document.IsEnabled = true; //Make a new row TableRow newTableRow = new TableRow(); newTableRow.Tag = data; //Make a new cell and create a paragraph in it TableCell usernameTableCell = new TableCell(); usernameTableCell.Name = "usernameTableCell"; usernameTableCell.Padding = new Thickness(10, 0, 0, 0); Paragraph usernameParagraph = new Paragraph(); usernameParagraph.TextAlignment = data.IsAction ? TextAlignment.Right : TextAlignment.Left; usernameParagraph.Foreground = new SolidColorBrush(Color.FromRgb(164, 164, 164)); if (data.Username != tox.Name.Replace("\n", "").Replace("\r", "")) usernameParagraph.SetResourceReference(Paragraph.ForegroundProperty, "AccentColorBrush"); if(!sameUser) usernameParagraph.Inlines.Add(data.Username); usernameTableCell.Blocks.Add(usernameParagraph); //Make a new cell and create a paragraph in it TableCell messageTableCell = new TableCell(); Paragraph messageParagraph = new Paragraph(); messageParagraph.TextAlignment = TextAlignment.Left; if (!data.IsGroupMsg && data.IsSelf) messageParagraph.Foreground = Brushes.LightGray; bool isHighlight = data.IsGroupMsg && !data.IsSelf && data.Message.ToLower().Contains(tox.Name.ToLower()); ProcessMessage(data, messageParagraph, false, isHighlight); messageTableCell.Blocks.Add(messageParagraph); TableCell timestampTableCell = new TableCell(); Paragraph timestampParagraph = new Paragraph(); timestampParagraph.Foreground = Brushes.LightGray; timestampTableCell.TextAlignment = TextAlignment.Right; timestampParagraph.Inlines.Add(data.Timestamp.ToShortTimeString()); timestampTableCell.Blocks.Add(timestampParagraph); //Add the two cells to the row we made before newTableRow.Cells.Add(usernameTableCell); newTableRow.Cells.Add(messageTableCell); newTableRow.Cells.Add(timestampTableCell); //Adds row to the Table > TableRowGroup TableRowGroup MessageRows = (TableRowGroup)document.FindName("MessageRows"); MessageRows.Rows.Add(newTableRow); }
public static Paragraph Present(IConferenceMessage message) { Paragraph paragraph = new Paragraph(); paragraph.SetResourceReference(Paragraph.StyleProperty, "parentRowStyle"); // at first, textInlines will contains only one inline - raw text List<Inline> textInlines = new List<Inline>(); // applying custom decorators DecoratorsRegistry.GetDecorators().ForEach(i => textInlines = i.Decorate(message, textInlines)); paragraph.Inlines.AddRange(textInlines); return paragraph; }
public static void AddNewMessageRow(this FlowDocument document, Tox tox, MessageData data, EmojiProvider emojiProvider) { document.IsEnabled = true; //Make a new row TableRow newTableRow = new TableRow(); //Make a new cell and create a paragraph in it TableCell usernameTableCell = new TableCell(); usernameTableCell.Name = "usernameTableCell"; usernameTableCell.Padding = new Thickness(10, 0, 0, 0); Paragraph usernameParagraph = new Paragraph(); usernameParagraph.TextAlignment = data.IsAction ? TextAlignment.Right : TextAlignment.Left; usernameParagraph.Foreground = new SolidColorBrush(Color.FromRgb(164, 164, 164)); if (data.Username != tox.GetSelfName()) usernameParagraph.SetResourceReference(Paragraph.ForegroundProperty, "AccentColorBrush"); usernameParagraph.Inlines.Add(data.Username); usernameTableCell.Blocks.Add(usernameParagraph); //Make a new cell and create a paragraph in it TableCell messageTableCell = new TableCell(); Paragraph messageParagraph = new Paragraph(); messageParagraph.TextAlignment = TextAlignment.Left; ProcessMessage(data, messageParagraph, false, emojiProvider); //messageParagraph.Inlines.Add(fakeHyperlink); messageTableCell.Blocks.Add(messageParagraph); TableCell timestampTableCell = new TableCell(); Paragraph timestamParagraph = new Paragraph(); timestampTableCell.TextAlignment = TextAlignment.Right; timestamParagraph.Inlines.Add(DateTime.Now.ToShortTimeString()); timestampTableCell.Blocks.Add(timestamParagraph); timestamParagraph.Foreground = new SolidColorBrush(Color.FromRgb(164, 164, 164)); //Add the two cells to the row we made before newTableRow.Cells.Add(usernameTableCell); newTableRow.Cells.Add(messageTableCell); newTableRow.Cells.Add(timestampTableCell); //Adds row to the Table > TableRowGroup TableRowGroup MessageRows = (TableRowGroup)document.FindName("MessageRows"); MessageRows.Rows.Add(newTableRow); }
//===================================================================== /// <summary> /// Handle table elements /// </summary> /// <param name="props">The element properties</param> private static void TableElement(ElementProperties props) { // If there is a title element, add a title using its content right before the table. The title // element handler will ignore it since it will have this table as its parent. XElement title = props.Element.Element(ddue + "title"); if(title != null) { Paragraph p = new Paragraph(new Run(reCondenseWhitespace.Replace(title.Value.Trim(), " "))); props.Converter.AddNonParentToBlockContainer(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.TableTitle); } props.Converter.AddToBlockContainer(new Table()); }
/// <summary> /// This is used to add the related topic links /// </summary> /// <param name="converter">The converter used to add the elements</param> /// <param name="s">The section used to contain the links</param> /// <param name="links">The list of links to add</param> /// <param name="sectionTitle">The section title</param> private static void AddRelatedTopicLinks(MamlToFlowDocumentConverter converter, Section s, List<XElement> links, string sectionTitle) { Paragraph p; bool isFirst = true; if(links.Count != 0) { p = new Paragraph(new Run(sectionTitle)); s.Blocks.Add(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.RelatedTopicTitle); p = new Paragraph(); s.Blocks.Add(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.NoTopMargin); foreach(var link in links) { if(isFirst) isFirst = false; else p.Inlines.Add(new LineBreak()); converter.ParseChildren(p, new[] { link }); } } }
/// <summary> /// Handle related topics elements /// </summary> /// <param name="props">The element properties</param> /// <remarks>If empty, the related topics section is omitted</remarks> private static void RelatedTopicsElement(ElementProperties props) { List<XElement> tasks = new List<XElement>(), reference = new List<XElement>(), concepts = new List<XElement>(), otherResources = new List<XElement>(), tokenContent = new List<XElement>(); XElement token; XAttribute attribute; Guid topicId, href; string linkType; if(!props.ParseChildren || !props.Element.HasElements) { props.ParseChildren = props.ReturnToParent = false; return; } // All links are handled here props.ParseChildren = false; // A name is added here for use by autoOutline elements Section s = new Section { Name = ToElementName("seeAlsoSection") }; props.Converter.AddToBlockContainer(s); // Add the section title Paragraph p = new Paragraph(new Run(NamedSectionTitles[props.Element.Name.LocalName])); s.Blocks.Add(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.Title); // Expand tokens first foreach(var link in props.Element.Nodes().OfType<XElement>().Where(n => n.Name.LocalName == "token")) if(props.Converter.Tokens.TryGetValue(link.Value.Trim(), out token)) tokenContent.AddRange(token.Nodes().OfType<XElement>()); // Group the elements by type or topic ID foreach(var link in props.Element.Nodes().OfType<XElement>().Concat(tokenContent)) { linkType = link.Name.LocalName; attribute = link.Attribute("topicType_id"); if(attribute == null || !Guid.TryParse(attribute.Value, out topicId)) topicId = Guid.Empty; attribute = link.Attribute(xlink + "href"); if(attribute == null || !Guid.TryParse(attribute.Value, out href)) href = Guid.Empty; if(href != Guid.Empty && (linkType == "link" || linkType == "legacyLink") && ( topicId == HowToId || topicId == WalkthroughId || topicId == SampleId || topicId == TroubleshootingId)) { tasks.Add(link); } else if(linkType == "codeEntityReference" || ((linkType == "link" || linkType == "legacyLink") && ( href == Guid.Empty || topicId == ReferenceWithoutSyntaxId || topicId == ReferenceWithSyntaxId || topicId == XmlReferenceId || topicId == ErrorMessageId || topicId == UIReferenceId))) { reference.Add(link); } else if(href != Guid.Empty && (linkType == "link" || linkType == "legacyLink") && ( topicId == ConceptualId || topicId == SdkTechnologyOverviewArchitectureId || topicId == SdkTechnologyOverviewCodeDirectoryId || topicId == SdkTechnologyOverviewScenariosId || topicId == SdkTechnologyOverviewTechnologySummaryId)) concepts.Add(link); else if(linkType == "externalLink" || ((linkType == "link" || linkType == "legacyLink") && href != Guid.Empty && (topicId == Guid.Empty || topicId == OrientationId || topicId == WhitePaperId || topicId == CodeEntityId || topicId == GlossaryId || topicId == SDKTechnologyOverviewOrientationId))) otherResources.Add(link); } // Add each set AddRelatedTopicLinks(props.Converter, s, tasks, "Tasks"); AddRelatedTopicLinks(props.Converter, s, reference, "Reference"); AddRelatedTopicLinks(props.Converter, s, concepts, "Concepts"); AddRelatedTopicLinks(props.Converter, s, otherResources, "Other Resources"); }
//===================================================================== /// <summary> /// Handle defined term elements /// </summary> /// <param name="props">The element properties</param> private static void DefinedTermElement(ElementProperties props) { Paragraph p = new Paragraph(); props.Converter.AddToBlockContainer(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.DefinedTerm); }
/// <summary> /// Handle title elements /// </summary> /// <param name="props">The element properties</param> /// <remarks>If the title element is inside a table, it is skipped as the table will already have /// added it outside of itself.</remarks> private static void TitleElement(ElementProperties props) { if(props.Converter.CurrentBlockElement is Table) props.ReturnToParent = false; else { Paragraph p = new Paragraph(new Run(reCondenseWhitespace.Replace( props.Element.Value.Trim(), " "))); props.Converter.AddToBlockContainer(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.Title); } props.ParseChildren = false; }
/// <summary> /// Handle general and named section elements /// </summary> /// <param name="props">The element properties</param> /// <remarks>If the section is empty, it will be omitted</remarks> private static void SectionElement(ElementProperties props) { if(props.ParseChildren && props.Element.HasElements) { Section s = new Section(); string title; // If this is a named section, add the standard title if(NamedSectionTitles.TryGetValue(props.Element.Name.LocalName, out title)) { Paragraph p = new Paragraph(new Run(title)); s.Blocks.Add(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.Title); } props.Converter.AddToBlockContainer(s); } else props.ParseChildren = props.ReturnToParent = false; }
//===================================================================== /// <summary> /// Handle alert elements /// </summary> /// <param name="props">The element properties</param> private static void AlertElement(ElementProperties props) { XAttribute attribute; string title = null, icon = null; // Map the class name to a title attribute = props.Element.Attribute("class"); if(attribute == null || !AlertTitles.TryGetValue(attribute.Value, out title)) title = "Note"; if(attribute == null || !AlertIcons.TryGetValue(attribute.Value, out icon)) icon = "AlertNote"; Section alert = new Section(); props.Converter.AddToBlockContainer(alert); Paragraph p = new Paragraph(); alert.Blocks.Add(p); // Set the icon based on the alert type var iconImage = (ImageSource)props.Converter.Document.Resources[icon]; p.Inlines.Add(new InlineUIContainer(new Image { Source = iconImage, Height = iconImage.Height / 2, Width = iconImage.Width / 2, ToolTip = title, Margin = new Thickness(0, 0, 5, 0), VerticalAlignment = VerticalAlignment.Center })); p.Inlines.Add(new Run(title)); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.AlertTitle); Section alertBody = new Section(); alert.Blocks.Add(alertBody); // We want the body section to be the current parent here rather than the containing section props.Converter.CurrentBlockElement = alertBody; alertBody.SetResourceReference(Section.StyleProperty, NamedStyle.AlertBody); }
/// <summary> /// This is used to render a glossary division /// </summary> /// <param name="d">The root glossary division element</param> /// <param name="divisionId">The division ID used as a prefix for each letter section in the division</param> /// <param name="entries">An enumerable list of all glossary entries</param> /// <param name="converter">The converter to which the glossary elements will be added</param> /// <returns>An enumerable list of blocks that define the glossary division in the document</returns> private static void RenderGlossaryDivision(XElement d, string divisionId, IEnumerable<GlossaryEntry> entries, MamlToFlowDocumentConverter converter) { Section s; Paragraph p = new Paragraph(); bool isFirst = true; // Group all entries in this division by the first letter of the first term var groupLetters = entries.Where(g => g.Parent == d).GroupBy( g => Char.ToUpperInvariant(g.Terms.First().Key[0])).OrderBy(g => g.Key); // Generate the letter bar for the division for(char ch = 'A'; ch <= 'Z'; ch++) { if(isFirst) isFirst = false; else p.Inlines.Add(new Run(" | ")); if(!groupLetters.Any(g => g.Key == ch)) p.Inlines.Add(new Bold(new Run(ch.ToString()))); else p.Inlines.Add(new Hyperlink(new Run(ch.ToString())) { NavigateUri = new Uri("link://#" + divisionId + "_" + ch.ToString()) }); } converter.AddNonParentToBlockContainer(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.GlossaryLetterBar); foreach(var g in groupLetters) { p = new Paragraph(new Run(g.Key.ToString()) { Name = ToElementName(divisionId + "_" + g.Key.ToString()) }); converter.AddNonParentToBlockContainer(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.GlossaryLetterTitle); foreach(var entry in g) { s = new Section(); converter.AddNonParentToBlockContainer(s); s.SetResourceReference(Section.StyleProperty, NamedStyle.GlossaryDefinition); p = new Paragraph(); isFirst = true; foreach(var t in entry.Terms) { if(isFirst) isFirst = false; else p.Inlines.Add(new Run(", ")); p.Inlines.Add(new Bold(new Run(t.Key)) { Name = (t.Value == null) ? String.Empty : ToElementName(t.Value) }); } s.Blocks.Add(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.NoMargin); converter.ParseChildren(s, entry.Definition.Nodes()); if(entry.RelatedEntries.Count != 0) { p = new Paragraph(); p.Inlines.Add(new Run("See also: ")); isFirst = true; foreach(var r in entry.RelatedEntries) { if(isFirst) isFirst = false; else p.Inlines.Add(new Run(", ")); var related = entries.SelectMany(e => e.Terms).FirstOrDefault(t => t.Value == r); if(related.Key != null) p.Inlines.Add(new Hyperlink(new Run(related.Key)) { NavigateUri = new Uri("link://#" + r) }); } p.Inlines.Add(new LineBreak()); s.Blocks.Add(p); } } } }
//===================================================================== /// <summary> /// Handle all aspects of glossary element and sub-element formatting /// </summary> /// <param name="props">The element properties</param> private static void GlossaryElement(ElementProperties props) { Section glossary = new Section(); Paragraph p = null; XElement titleElement; XAttribute addressAttr; List<XElement> divisions; Dictionary<XElement, Tuple<string, string>> divisionIds = new Dictionary<XElement, Tuple<string, string>>(); List<GlossaryEntry> entries = new List<GlossaryEntry>(); string address, id, title; bool isFirst = true; int autoId = 1; // All elements are handled here props.ParseChildren = false; props.Converter.AddToBlockContainer(glossary); // If there is a title element, add a title using its content titleElement = props.Element.Element(ddue + "title"); if(titleElement != null) { p = new Paragraph(new Run(reCondenseWhitespace.Replace(titleElement.Value.Trim(), " "))); glossary.Blocks.Add(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.Title); } // See if there are divisions. If so, add one section for each division. If not, lump all entries // into one untitled division. divisions = props.Element.Descendants(ddue + "glossaryDiv").ToList(); // If there are multiple divisions, add a link to each one provided we have an address and a title if(divisions.Count == 0) { divisions = new List<XElement>() { props.Element }; divisionIds.Add(props.Element, Tuple.Create<string, string>(null, null)); } else { foreach(var d in divisions) { addressAttr = d.Attribute("address"); titleElement = d.Element(ddue + "title"); if(addressAttr != null) { address = addressAttr.Value; id = ToElementName(address); } else address = id = null; if(titleElement != null) title = reCondenseWhitespace.Replace(titleElement.Value.Trim(), " "); else title = null; divisionIds.Add(d, Tuple.Create(id, title)); if(!String.IsNullOrEmpty(title)) { if(isFirst) { p = new Paragraph(); glossary.Blocks.Add(p); isFirst = false; } else p.Inlines.Add(new Run(" | ")); if(!String.IsNullOrEmpty(address)) p.Inlines.Add(new Hyperlink(new Run(title)) { NavigateUri = new Uri("link://#" + address) }); else p.Inlines.Add(new Bold(new Run(title))); } } p.Inlines.Add(new LineBreak()); } // Extract all glossary entries for use in creating the divisions. Entries may refer to related // entries in other divisions so we need to get them all up front. entries.AddRange(props.Element.Descendants( MamlToFlowDocumentConverter.ddue + "glossaryEntry").Select(g => new GlossaryEntry(g))); // Render each division foreach(var d in divisions) { var titleAndId = divisionIds[d]; // Add a title if there is one if(!String.IsNullOrEmpty(titleAndId.Item2)) { id = titleAndId.Item1; p = new Paragraph(new Run(titleAndId.Item2)) { Name = id }; glossary.Blocks.Add(p); p.SetResourceReference(Paragraph.StyleProperty, NamedStyle.GlossaryDivisionTitle); } else { id = "__GlossaryDiv" + autoId.ToString(CultureInfo.InvariantCulture); autoId++; } RenderGlossaryDivision(d, id, entries, props.Converter); glossary.Blocks.Add(new Paragraph()); } }
private Paragraph ParseChatNodesIntoParagraph(ChatNode[] nodes) { Paragraph fullElement = new Paragraph(); foreach (ChatNode node in nodes) { Inline child = RenderNode(node); fullElement.Inlines.Add(child); } fullElement.Style = display.Resources["Paragraphs"] as Style; fullElement.SetResourceReference(FrameworkContentElement.StyleProperty, "Paragraphs"); return fullElement; }