using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Xml; using TradeIdeas.TIProData; using TradeIdeas.XML; namespace TradeIdeas.TIProGUI { /// /// Stores all annotations. Knows how to save to and restore from XML. /// public class ChartAnnotationCache { public ChartAnnotationCache() { } /// /// Adds an annotation to the cache. /// /// /// public void AddAnnotation(CacheableAnnotation annotation, string symbol) { List annotations = new List(); if (_annotations.ContainsKey(symbol)) annotations = _annotations[symbol]; annotations.Add(annotation); _annotations[symbol] = annotations; } /// /// Gets all annotations from the cache that correspond to the symbol and timeframe. Horizontal lines span all timeframes but all other /// annotation types are specific to a timeframe. /// /// /// /// public List GetAnnotations(string symbol, ChartTimeframe timeframe) { List annotations = new List(); if (_annotations.ContainsKey(symbol)) annotations = _annotations[symbol]; List toReturn = new List(); foreach (CacheableAnnotation annotation in annotations) { if (annotation.AnnotationType == AnnotationType.HorizontalLine) toReturn.Add(annotation); else if (annotation.ChartTimeframe == timeframe) toReturn.Add(annotation); } return toReturn; } /// /// Returns CacheableAnnotation by looking up the original id used when it was created. /// /// /// /// CacheableAnnotation object. public CacheableAnnotation GetAnnotation(string id, string symbol) { if (_annotations.ContainsKey(symbol)) { List annotations = _annotations[symbol].Where(x => x.Id == id).ToList(); if (annotations.Count > 0) return annotations.First(); } return null; } /// /// Removes annotation from cache by first looking it up by id and symbol. If it can't be found this does nothing. /// /// /// public void RemoveAnnotation(string id, string symbol) { if (_annotations.ContainsKey(symbol)) { List annotations = _annotations[symbol].Where(x => x.Id == id).ToList(); if (annotations.Count > 0) { foreach (CacheableAnnotation annotation in annotations) { _annotations[symbol].Remove(annotation); } } } } /// /// Removes annotation from cache by first looking it up by symbol. If it can't be found this does nothing. /// Returns the list of Ids that has been removed /// /// public List RemoveAllAnnotation(string symbol) { List removed = new List(); if (_annotations.ContainsKey(symbol)) { List annotations = _annotations[symbol].ToList(); foreach (CacheableAnnotation annotation in annotations) { removed.Add(annotation.Id); _annotations[symbol].Remove(annotation); } } return removed; } /// /// Data structure for storing all annotations. /// private Dictionary> _annotations = new Dictionary>(); /// /// Caches all current annotations to XML. /// /// XML string that can be used in Restore. public string Save() { try { XmlDocument doc = new XmlDocument(); doc.LoadXml(""); XmlNode annotationsNode = doc.Node("ANNOTATIONS"); foreach (string symbol in _annotations.Keys) { XmlNode symbolNode = annotationsNode.NewNode("SYMBOL"); symbolNode.SetProperty("SYMBOL", symbol); foreach (CacheableAnnotation annotation in _annotations[symbol]) { annotation.Save(symbolNode); } } return doc.OuterXml; } catch (Exception e) { string debugView = e.StackTrace; return ""; } } /// /// Restores annotations from XML. /// /// public void Restore(string xml) { try { _annotations.Clear(); XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); XmlNode annotationsNode = doc.Node(0); foreach (XmlNode symbolNode in annotationsNode.ChildNodes) { string symbol = symbolNode.Property("SYMBOL", ""); List annotations = new List(); foreach (XmlNode annotationNode in symbolNode.ChildNodes) { CacheableAnnotation annotation = new CacheableAnnotation(); annotation.Restore(annotationNode); annotations.Add(annotation); } _annotations.Add(symbol, annotations); } } catch { } } } /// /// Generic object to cache a single annotation. Some properties will be used for some annotation types while others will be used for all annotation types. /// public class CacheableAnnotation { public CacheableAnnotation() { } public ChartTimeframe ChartTimeframe { get; set; } public AnnotationType AnnotationType { get; set; } public double Height { get; set; } public double Width { get; set; } public double Y { get; set; } public Color Color { get; set; } public double StartTime { get; set; } public string Id { get; set; } public string Text { get; set; } public int LineWidth { get; set; } public override bool Equals(object obj) { CacheableAnnotation cacheableAnnotation = obj as CacheableAnnotation; if (null == cacheableAnnotation) return false; return cacheableAnnotation.Id == Id; } public override int GetHashCode() { return base.GetHashCode(); } public void Save(XmlNode parent) { XmlNode newNode = parent.NewNode("ANNOTATION"); newNode.SetProperty("TIMEFRAME", ChartTimeframe); newNode.SetProperty("TYPE", AnnotationType); newNode.SetProperty("HEIGHT", Height); newNode.SetProperty("WIDTH", Width); newNode.SetProperty("Y", Y); newNode.SetProperty("COLOR", Color); newNode.SetProperty("START_TIME", StartTime); newNode.SetProperty("ID", Id); newNode.SetProperty("TEXT", Text); newNode.SetProperty("LineWidth", LineWidth); } public void Restore(XmlNode description) { ChartTimeframe = description.PropertyEnum("TIMEFRAME", ChartTimeframe.Daily); AnnotationType = description.PropertyEnum("TYPE", TIProGUI.AnnotationType.Trendline); Height = description.Property("HEIGHT", 0.0); Width = description.Property("WIDTH", 0.0); Y = description.Property("Y", 0.0); Color = description.Property("COLOR", Color.Black); StartTime = description.Property("START_TIME", 0.0); Id = description.Property("ID", ""); Text = description.Property("TEXT", ""); LineWidth = description.Property("LineWidth", 2); } } public enum AnnotationType { HorizontalLine, Arrow, Trendline, Text }; }