public static void ParseSmileys(MessageModel msg) { string simleyRegex; simleyRegex = @":-?(\(|\))"; Regex reg = new Regex(simleyRegex); // clone MessageParts IList<MessagePartModel> parts = new List<MessagePartModel>(msg.MessageParts); foreach (MessagePartModel part in parts) { if (!(part is TextMessagePartModel)) { continue; } TextMessagePartModel textPart = (TextMessagePartModel) part; Match simleyMatch = reg.Match(textPart.Text); // OPT: fast regex scan if (!simleyMatch.Success) { // no smileys in this MessagePart, nothing to do continue; } // found smiley(s) // remove current MessagePartModel as we need to split it int idx = msg.MessageParts.IndexOf(part); msg.MessageParts.RemoveAt(idx); string[] textPartParts = textPart.Text.Split(new char[] {' '}); for (int i = 0; i < textPartParts.Length; i++) { string textPartPart = textPartParts[i]; simleyMatch = reg.Match(textPartPart); if (simleyMatch.Success) { string filename = null; if (textPartPart == ":-)") { filename = "smile.png"; } ImageMessagePartModel imagePart = new ImageMessagePartModel( filename, textPartPart ); msg.MessageParts.Insert(idx++, imagePart); msg.MessageParts.Insert(idx++, new TextMessagePartModel(" ")); } else { // FIXME: we put each text part into it's own object, instead of combining them (the smart way) TextMessagePartModel notUrlPart = new TextMessagePartModel(textPartPart + " "); // restore formatting / colors from the original text part notUrlPart.IsHighlight = textPart.IsHighlight; notUrlPart.ForegroundColor = textPart.ForegroundColor; notUrlPart.BackgroundColor = textPart.BackgroundColor; notUrlPart.Bold = textPart.Bold; notUrlPart.Italic = textPart.Italic; notUrlPart.Underline = textPart.Underline; msg.MessageParts.Insert(idx++, notUrlPart); } } } }
public static IList <MessagePartModel> ParsePatterns(TextMessagePartModel textPart, List <MessagePatternModel> patterns) { if (textPart == null) { throw new ArgumentNullException("textPart"); } if (patterns == null) { throw new ArgumentNullException("patterns"); } var msgParts = new List <MessagePartModel>(); if (patterns.Count == 0) { // all patterns have been tried -> this text is PURE text msgParts.Add(textPart); return(msgParts); } var remainingPatterns = new List <MessagePatternModel>(patterns); var pattern = remainingPatterns.First(); remainingPatterns.Remove(pattern); var match = pattern.MessagePartPattern.Match(textPart.Text); if (!match.Success) { // no matches in this MessagePart, try other smartlinks return(ParsePatterns(textPart, remainingPatterns)); } int lastindex = 0; do { var groupValues = new string[match.Groups.Count]; int i = 0; foreach (Group @group in match.Groups) { groupValues[i++] = @group.Value; } string url; if (String.IsNullOrEmpty(pattern.LinkFormat)) { url = match.Value; } else { url = String.Format(pattern.LinkFormat, groupValues); } string text; if (String.IsNullOrEmpty(pattern.TextFormat)) { text = match.Value; } else { text = String.Format(pattern.TextFormat, groupValues); } if (lastindex != match.Index) { // there were some non-matching-chars before the match // copy that to a TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex, match.Index - lastindex); // and try other patterns on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } MessagePartModel msgPart; if (pattern.MessagePartType == typeof(UrlMessagePartModel)) { // no need to set URL and text if they are the same text = text == url ? null : text; msgPart = new UrlMessagePartModel(url, text); } else if (pattern.MessagePartType == typeof(ImageMessagePartModel)) { msgPart = new ImageMessagePartModel(url, text); } else { msgPart = new TextMessagePartModel(text); } msgParts.Add(msgPart); lastindex = match.Index + match.Length; match = match.NextMatch(); } while (match.Success); if (lastindex != textPart.Text.Length) { // there were some non-url-chars before this url // copy TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex); // and try other smartlinks on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } return(msgParts); }
static void AddAlternativeText(Gtk.TextBuffer buffer, ref Gtk.TextIter iter, ImageMessagePartModel imgPart) { if (!String.IsNullOrEmpty(imgPart.AlternativeText)) { buffer.Insert(ref iter, imgPart.AlternativeText); } }
void AddEmoji(Gtk.TextBuffer buffer, ref Gtk.TextIter iter, ImageMessagePartModel imgPart, string shortName) { var unicode = Emojione.ShortnameToUnicode(shortName); if (unicode == null) { AddAlternativeText(buffer, ref iter, imgPart); return; } int width, height; int widthPango, heightPango; int descent; using (var layout = CreatePangoLayout(null)) { layout.GetPixelSize(out width, out height); layout.GetSize(out widthPango, out heightPango); descent = layout.Context.GetMetrics(layout.FontDescription, null).Descent; } // A mark here serves two pusposes. One is to allow us to apply the // tag across the pixbuf. It also lets us know later where to put // the pixbuf if we need to load it from the network var mark = new Gtk.TextMark(null, true); buffer.AddMark(mark, iter); var emojiName = unicode + ".png"; string emojiPath; if (EmojiCache.TryGetIcon("emojione", emojiName, out emojiPath)) { var emojiFile = new FileInfo(emojiPath); if (emojiFile.Exists && emojiFile.Length > 0) { var pix = new Gdk.Pixbuf(emojiPath, -1, height); buffer.InsertPixbuf(ref iter, pix); var beforeIter = buffer.GetIterAtMark(mark); var imgTag = new EmojiTag(mark, emojiFile.FullName); imgTag.Rise = - descent; _MessageTextTagTable.Add(imgTag); buffer.ApplyTag(imgTag, beforeIter, iter); } else { AddAlternativeText(buffer, ref iter, imgPart); } return; } var emojiUrl = Emojione.UnicodeToUrl(unicode); EmojiCache.BeginDownloadFile("emojione", emojiName, emojiUrl, (path) => { GLib.Idle.Add(delegate { var afterIter = buffer.GetIterAtMark(mark); buffer.InsertPixbuf(ref afterIter, new Gdk.Pixbuf(path, -1, height)); var beforeIter = buffer.GetIterAtMark(mark); var emojiTag = new EmojiTag(mark, path); _MessageTextTagTable.Add(emojiTag); emojiTag.Rise = - descent; buffer.ApplyTag(emojiTag, beforeIter, afterIter); return false; }); }, (ex) => { GLib.Idle.Add(delegate { var markIter = buffer.GetIterAtMark(mark); buffer.DeleteMark(mark); AddAlternativeText(buffer, ref markIter, imgPart); return false; }); } ); }
private void InsertToBuffer(Gtk.TextBuffer buffer, ref Gtk.TextIter iter, ImageMessagePartModel imgpart) { Uri uri = null; string scheme = null; try { uri = new Uri(imgpart.ImageFileName); scheme = uri.Scheme; } catch (UriFormatException) { AddAlternativeText(buffer, ref iter, imgpart); } switch (scheme) { case "smuxi-emoji": var shortName = uri.Host; AddEmoji(buffer, ref iter, imgpart, shortName); break; default: AddAlternativeText(buffer, ref iter, imgpart); break; } }
public static IList<MessagePartModel> ParsePatterns(TextMessagePartModel textPart, List<MessagePatternModel> patterns) { if (textPart == null) { throw new ArgumentNullException("textPart"); } if (patterns == null) { throw new ArgumentNullException("patterns"); } var msgParts = new List<MessagePartModel>(); if (patterns.Count == 0) { // all patterns have been tried -> this text is PURE text msgParts.Add(textPart); return msgParts; } var remainingPatterns = new List<MessagePatternModel>(patterns); var pattern = remainingPatterns.First(); remainingPatterns.Remove(pattern); var match = pattern.MessagePartPattern.Match(textPart.Text); if (!match.Success) { // no matches in this MessagePart, try other smartlinks return ParsePatterns(textPart, remainingPatterns); } int lastindex = 0; do { var groupValues = new string[match.Groups.Count]; int i = 0; foreach (Group @group in match.Groups) { groupValues[i++] = @group.Value; } string url; if (String.IsNullOrEmpty(pattern.LinkFormat)) { url = match.Value; } else { url = String.Format(pattern.LinkFormat, groupValues); } string text; if (String.IsNullOrEmpty(pattern.TextFormat)) { text = match.Value; } else { text = String.Format(pattern.TextFormat, groupValues); } if (lastindex != match.Index) { // there were some non-matching-chars before the match // copy that to a TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex, match.Index - lastindex); // and try other patterns on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } MessagePartModel msgPart; if (pattern.MessagePartType == typeof(UrlMessagePartModel)) { // no need to set URL and text if they are the same text = text == url ? null : text; msgPart = new UrlMessagePartModel(url, text); } else if (pattern.MessagePartType == typeof(ImageMessagePartModel)) { msgPart = new ImageMessagePartModel(url, text); } else { msgPart = new TextMessagePartModel(text); } msgParts.Add(msgPart); lastindex = match.Index + match.Length; match = match.NextMatch(); } while (match.Success); if (lastindex != textPart.Text.Length) { // there were some non-url-chars before this url // copy TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex); // and try other smartlinks on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } return msgParts; }
public static IList <MessagePartModel> ParsePatterns(TextMessagePartModel textPart, List <MessagePatternModel> patterns) { if (textPart == null) { throw new ArgumentNullException("textPart"); } if (patterns == null) { throw new ArgumentNullException("patterns"); } var msgParts = new List <MessagePartModel>(); if (patterns.Count == 0) { // all patterns have been tried -> this text is PURE text msgParts.Add(textPart); return(msgParts); } var remainingPatterns = new List <MessagePatternModel>(patterns); var pattern = remainingPatterns.First(); remainingPatterns.Remove(pattern); var match = pattern.MessagePartPattern.Match(textPart.Text); if (!match.Success) { // no matches in this MessagePart, try other smartlinks return(ParsePatterns(textPart, remainingPatterns)); } int lastindex = 0; do { var startDelimiterLength = 0; var regexDelimiterForStartOfPatternValue = match.Groups[MessageBuilderSettings.StartDelimiterGroupName]; if (regexDelimiterForStartOfPatternValue != null) { startDelimiterLength = regexDelimiterForStartOfPatternValue.Value.Length; } var endDelimiterLength = 0; var regexDelimiterForEndOfPatternValue = match.Groups[MessageBuilderSettings.EndDelimiterGroupName]; if (regexDelimiterForEndOfPatternValue != null) { endDelimiterLength = regexDelimiterForEndOfPatternValue.Value.Length; } var groupValues = match.Groups.Cast <Group>() // don't get the delimiter because it only determines // the start or end of pattern, which is not part of the pattern .Where(g => g != regexDelimiterForStartOfPatternValue && g != regexDelimiterForEndOfPatternValue) .Select(g => g.Value).ToArray(); string url; if (String.IsNullOrEmpty(pattern.LinkFormat)) { url = match.Value; url = url.Substring(0 + startDelimiterLength, url.Length - (startDelimiterLength - endDelimiterLength)); } else { url = String.Format(pattern.LinkFormat, groupValues); } string text; if (String.IsNullOrEmpty(pattern.TextFormat)) { text = match.Value; } else { text = String.Format(pattern.TextFormat, groupValues); } text = text.Substring(0 + startDelimiterLength, text.Length - (startDelimiterLength + endDelimiterLength)); if (lastindex != match.Index) { // there were some non-matching-chars before the match // copy that to a TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex, match.Index + startDelimiterLength - lastindex); // and try other patterns on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } MessagePartModel msgPart; if (pattern.MessagePartType == typeof(UrlMessagePartModel)) { // no need to set URL and text if they are the same text = text == url ? null : text; msgPart = new UrlMessagePartModel(url, text); } else if (pattern.MessagePartType == typeof(ImageMessagePartModel)) { msgPart = new ImageMessagePartModel(url, text); } else { msgPart = new TextMessagePartModel(text); } msgParts.Add(msgPart); lastindex = match.Index + match.Length - endDelimiterLength; match = match.NextMatch(); } while (match.Success); if (lastindex != textPart.Text.Length) { // there were some non-matching-chars after the last match // copy TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex); // and try other smartlinks on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } return(msgParts); }
public static void ParseSmileys(MessageModel msg) { // clone MessageParts IList <MessagePartModel> parts = new List <MessagePartModel>(msg.MessageParts); foreach (MessagePartModel part in parts) { if (!(part is TextMessagePartModel)) { continue; } TextMessagePartModel textPart = (TextMessagePartModel)part; Match simleyMatch = SimleyRegex.Match(textPart.Text); // OPT: fast regex scan if (!simleyMatch.Success) { // no smileys in this MessagePart, nothing to do continue; } // found smiley(s) // remove current MessagePartModel as we need to split it int idx = msg.MessageParts.IndexOf(part); msg.MessageParts.RemoveAt(idx); string[] textPartParts = textPart.Text.Split(new char[] { ' ' }); for (int i = 0; i < textPartParts.Length; i++) { string textPartPart = textPartParts[i]; simleyMatch = SimleyRegex.Match(textPartPart); if (simleyMatch.Success) { string filename = null; if (textPartPart == ":-)") { filename = "smile.png"; } ImageMessagePartModel imagePart = new ImageMessagePartModel( filename, textPartPart ); msg.MessageParts.Insert(idx++, imagePart); msg.MessageParts.Insert(idx++, new TextMessagePartModel(" ")); } else { // FIXME: we put each text part into it's own object, instead of combining them (the smart way) TextMessagePartModel notUrlPart = new TextMessagePartModel(textPartPart + " "); // restore formatting / colors from the original text part notUrlPart.IsHighlight = textPart.IsHighlight; notUrlPart.ForegroundColor = textPart.ForegroundColor; notUrlPart.BackgroundColor = textPart.BackgroundColor; notUrlPart.Bold = textPart.Bold; notUrlPart.Italic = textPart.Italic; notUrlPart.Underline = textPart.Underline; msg.MessageParts.Insert(idx++, notUrlPart); } } } }
public static IList<MessagePartModel> ParsePatterns(TextMessagePartModel textPart, List<MessagePatternModel> patterns) { if (textPart == null) { throw new ArgumentNullException("textPart"); } if (patterns == null) { throw new ArgumentNullException("patterns"); } var msgParts = new List<MessagePartModel>(); if (patterns.Count == 0) { // all patterns have been tried -> this text is PURE text msgParts.Add(textPart); return msgParts; } var remainingPatterns = new List<MessagePatternModel>(patterns); var pattern = remainingPatterns.First(); remainingPatterns.Remove(pattern); var match = pattern.MessagePartPattern.Match(textPart.Text); if (!match.Success) { // no matches in this MessagePart, try other smartlinks return ParsePatterns(textPart, remainingPatterns); } int lastindex = 0; do { var delimiterLength = 0; var regexDelimiterForEndOfPatternValue = match.Groups[MessageBuilderSettings.EndDelimiterGroupName]; if (regexDelimiterForEndOfPatternValue != null) { delimiterLength = regexDelimiterForEndOfPatternValue.Value.Length; } var groupValues = match.Groups.Cast<Group>() // don't get the delimiter because it only determines // the end of pattern, which is not part of the pattern .Where(g => g != regexDelimiterForEndOfPatternValue) .Select(g => g.Value).ToArray(); string url; if (String.IsNullOrEmpty(pattern.LinkFormat)) { url = match.Value; } else { url = String.Format(pattern.LinkFormat, groupValues); } url = url.Substring(0, url.Length - delimiterLength); string text; if (String.IsNullOrEmpty(pattern.TextFormat)) { text = match.Value; } else { text = String.Format(pattern.TextFormat, groupValues); } text = text.Substring(0, text.Length - delimiterLength); if (lastindex != match.Index) { // there were some non-matching-chars before the match // copy that to a TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex, match.Index - lastindex); // and try other patterns on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } MessagePartModel msgPart; if (pattern.MessagePartType == typeof(UrlMessagePartModel)) { // no need to set URL and text if they are the same text = text == url ? null : text; msgPart = new UrlMessagePartModel(url, text); } else if (pattern.MessagePartType == typeof(ImageMessagePartModel)) { msgPart = new ImageMessagePartModel(url, text); } else { msgPart = new TextMessagePartModel(text); } msgParts.Add(msgPart); lastindex = match.Index + match.Length - delimiterLength; match = match.NextMatch(); } while (match.Success); if (lastindex != textPart.Text.Length) { // there were some non-url-chars before this url // copy TextMessagePartModel var notMatchPart = new TextMessagePartModel(textPart); // only take the proper chunk of text notMatchPart.Text = textPart.Text.Substring(lastindex); // and try other smartlinks on this part var parts = ParsePatterns(notMatchPart, remainingPatterns); foreach (var part in parts) { msgParts.Add(part); } } return msgParts; }