using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Xml; using TradeIdeas.XML; namespace TradeIdeas.TIProGUI.CBT { [ToolboxItem(false)] public partial class ConfigDemoUpVsDown : UserControl, IChild { static public void SaveAll() { foreach (XmlNode example in ConfigDemoUserControl.ConfigDemoXml.Node("CONFIG_DEMO_UP_VS_DOWN").Enum()) { bool percentFlip = example.Property("RULE", "-") == "%"; if (percentFlip) // This class used to handle these. But now these should be handled by the // ConfigDemoPercentUpDown class. The config file might have two copies of this // rule for a while, so older versions of the code can still use this class to // handle these cases. continue; // This is not obvious at first. The the delegate referenced "example" directly, all // of the delegates would point to the last value in the example variable. By creating // this "savedCopy" variable, I am ensuring that each delegate points to the current // value in the example variable. XmlNode savedCopy = example; foreach (XmlNode node in example) { //some nodes have more than one filter code..loop thru these... if (node.SafeName() == "FILTER") { string filterCode = node.Property("CODE"); ConfigDemoUserControl.Add(filterCode, delegate(IContainer container) { return new ConfigDemoUpVsDown(container, savedCopy); }); } } } } private readonly TradeIdeas.TIProGUI.CBT.IContainer _container; private readonly bool _percentFlip; private readonly bool _percentLimit; public ConfigDemoUpVsDown(TradeIdeas.TIProGUI.CBT.IContainer container, XmlNode config) { _container = container; InitializeComponent(); container.MinTextBox.TextChanged += new EventHandler(MinTextBox_TextChanged); container.MaxTextBox.TextChanged += new EventHandler(MaxTextBox_TextChanged); string description = config.PropertyForCulture("UP", "***"); minUpLabel.Text = "Min " + description; maxUpLabel.Text = "Max " + description; description = config.PropertyForCulture("DOWN", "***"); minDownLabel.Text = "Min " + description; maxDownLabel.Text = "Max " + description; _percentFlip = config.Property("RULE", "-") == "%"; System.Diagnostics.Debug.Assert(!_percentFlip); // obsolete flipButton.Enabled = !config.Property("DISABLE_FLIP", false); _percentLimit = config.Property("PERCENT_LIMIT", false); } string IChild.Name { get { return "Up vs. Down"; } } Control IChild.Body { get { return this; } } bool IChild.CanShowExample { get { return true; } } void IChild.OnShow() { } static string Copy(string original) { double asDouble; if (double.TryParse(original, out asDouble)) return asDouble.ToString(); else return ""; } string Negate(string original) { double asDouble; if (double.TryParse(original, out asDouble)) if (_percentFlip) return (100 - asDouble).ToString(); else return (-asDouble).ToString(); else return ""; } void MinTextBox_TextChanged(object sender, EventArgs e) { StartEditing(sender); SafeStore(minUpTextBox, Copy(_container.MinTextBox.Text)); DoneEditing(sender); } void MaxTextBox_TextChanged(object sender, EventArgs e) { StartEditing(sender); SafeStore(maxUpTextBox, Copy(_container.MaxTextBox.Text)); DoneEditing(sender); } private void minUpTextBox_TextChanged(object sender, EventArgs e) { StartEditing(sender); SafeStore(_container.MinTextBox, Copy(minUpTextBox.Text)); SafeStore(maxDownTextBox, Negate(minUpTextBox.Text)); DoneEditing(sender); CheckLimits(); } private void maxUpTextBox_TextChanged(object sender, EventArgs e) { StartEditing(sender); SafeStore(_container.MaxTextBox, Copy(maxUpTextBox.Text)); SafeStore(minDownTextBox, Negate(maxUpTextBox.Text)); DoneEditing(sender); CheckLimits(); } private void SetColor(TextBox textBox, bool ok) { textBox.BackColor = ok ? SystemColors.Window : ConfigDemoUserControl.ERROR_BACKGROUND; } private void CheckLimits() { if (!_percentLimit) return; double? min = _container.MinValue; double? max = _container.MaxValue; bool minOk = (!min.HasValue) || (min.Value <= 100 && min.Value >= 0); bool maxOk = (!max.HasValue) || (max.Value <= 100 && max.Value >= 0); SetColor(minUpTextBox, minOk); SetColor(maxDownTextBox, minOk); SetColor(maxUpTextBox, maxOk); SetColor(minDownTextBox, maxOk); warningLabel.Visible = !(minOk && maxOk); } private void minDownTextBox_TextChanged(object sender, EventArgs e) { StartEditing(sender); SafeStore(maxUpTextBox, Negate(minDownTextBox.Text)); DoneEditing(sender); } private void maxDownTextBox_TextChanged(object sender, EventArgs e) { StartEditing(sender); SafeStore(minUpTextBox, Negate(maxDownTextBox.Text)); DoneEditing(sender); } /// /// Prevent cycles. Each field knows what fields it should change. But any /// attempt to change a busy field will be ignored. /// private readonly HashSet _busy = new HashSet(); private void StartEditing(object item) { _busy.Add(item); } private void DoneEditing(object item) { _busy.Remove(item); } private void SafeStore(TextBox destination, string value) { if (!_busy.Contains(destination)) destination.Text = value; } /// /// If we were looking for something down 3 to 7 dollars, /// now we are looking for something up 3 to 7 dollars. /// /// /// private void flipButton_Click(object sender, EventArgs e) { string oldMinDown = minDownTextBox.Text; string oldMaxDown = maxDownTextBox.Text; minUpTextBox.Text = Copy(oldMinDown); maxUpTextBox.Text = Copy(oldMaxDown); } } }