using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using TradeIdeas.TIProGUI; using TradeIdeas.TIProData; using TradeIdeas.MiscSupport; using System.Web; namespace TIProDevExtension { public partial class StockDataTester : Form { public StockDataTester() { InitializeComponent(); _labelAdapter = new StockDataAdapter(label1, LabelCallback, ""); /* DataNode stuff starts here. The bottom and top were somewhat similar but used different * approaches. The DataNode version is all about code reuse. If you want to copy this * sample, only copy one verion or the other. */ _normalForeground = dataNodeLabel.ForeColor; _normalBackground = dataNodeLabel.BackColor; _colorChooser.GradientInfo = _gradientInfo; _colorChooser.OnChange += UpdateDataNodeFactory; GuiDataNode.Init(); _simpleCombinedWidget = SimpleCombinedWidget().Create(); _simpleCombinedWidget.Dock = DockStyle.Fill; System.Diagnostics.Debug.Assert(_simpleCombinedWidget is IReplaceWithRuntime); combinedWidgettabPage.Controls.Add(_simpleCombinedWidget); UpdateDataNodeFactory(); } private RowData _lastRowDataReceived = new RowData(); private void LabelCallback(StockDataAdapter stockDataAdapter) { label1.Text = stockDataAdapter.RowData.ToString(); _lastRowDataReceived = stockDataAdapter.RowData; } StockDataAdapter _labelAdapter; private void updateFormulaButton_Click(object sender, EventArgs e) { if (null != _labelAdapter) { _labelAdapter.Cancel(); _labelAdapter = null; } string formula = formulaTextBox.Text; if (formula != "") _labelAdapter = new StockDataAdapter(label1, LabelCallback, formula); } private void updateSymbolButton_Click(object sender, EventArgs e) { if (null != _labelAdapter) _labelAdapter.Symbol = symbolTextBox.Text; } /* DataNode stuff starts here. The bottom and top were somewhat similar but used different * approaches. The DataNode version is all about code reuse. */ private Color _normalForeground; private Color _normalBackground; private void updateDataNodeFactoryButton_Click(object sender, EventArgs e) { UpdateDataNodeFactory(); } private void updateDataNodeSymbolButton_Click(object sender, EventArgs e) { UpdateDataNodeSymbol(); } private class MyFactories { public readonly DataNode.Factory Value; public readonly DataNode.Factory ForegroundColor; public readonly DataNode.Factory BackgroundColor; public MyFactories(DataNode.Factory value, DataNode.Factory foregroundColor, DataNode.Factory backgroundColor) { Value = value; ForegroundColor = foregroundColor; BackgroundColor = backgroundColor; } public MyFactories SetSymbol(String symbol) { return new MyFactories(Value.SetSymbol(symbol), ForegroundColor.SetSymbol(symbol), BackgroundColor.SetSymbol(symbol)); } public override string ToString() { StringBuilder result = new StringBuilder(); result.Append(" Value = ").Append(Value) .Append("\r\n Foreground = ").Append(ForegroundColor) .Append("\r\n Background = ").Append(BackgroundColor); return result.ToString(); } } private MyFactories _factoryTemplates; private GradientInfo _gradientInfo = new GradientInfo(); private Control _dataNodeLabel; private void UpdateDataNodeFactory() { _gradientInfo = _colorChooser.GradientInfo; // This makes a copy of the GradientInfo DataNode.Factory valueFactory = TopListStringDataNode.GetFactory(dataNodeFormulaTextBox.Text); if (integerTransformationRadioButton.Checked) valueFactory = TransformationDataNode.GetFactory(TransformationDataNode.StringToInt, valueFactory); else if (doubleTransformationRadioButton.Checked) valueFactory = TransformationDataNode.GetFactory(TransformationDataNode.StringToDouble, valueFactory); else if (dateTimeTransformationRadioButton.Checked) valueFactory = TransformationDataNode.GetFactory(TransformationDataNode.StringToTime, valueFactory); valueFactory = GuiDataNode.GetFactory(valueFactory); DataNode.Factory backgroundFactory; DataNode.Factory foregroundFactory; if (colorByValueCheckBox.Checked) { DataNode.Factory colorByFactory = TopListStringDataNode.GetFactory(dataNodeColorFormulaTextBox.Text); colorByFactory = TransformationDataNode.GetFactory(TransformationDataNode.StringToDouble, colorByFactory); backgroundFactory = GradientInfoDataNode.GetFactory(_gradientInfo, colorByFactory); foregroundFactory = TransformationDataNode.GetFactory(GradientInfoDataNode.AltColor, backgroundFactory); backgroundFactory = GuiDataNode.GetFactory(backgroundFactory); foregroundFactory = GuiDataNode.GetFactory(foregroundFactory); } else { backgroundFactory = ConstantDataNode.GetFactory(_normalBackground); foregroundFactory = ConstantDataNode.GetFactory(_normalForeground); } _factoryTemplates = new MyFactories(valueFactory, foregroundFactory, backgroundFactory); if (null != _dataNodeLabel) _dataNodeLabel.Dispose(); DataNodeLabel.Factory labelFactory = new DataNodeLabel.Factory(); labelFactory.Value = valueFactory; labelFactory.ForeColor = foregroundFactory; labelFactory.BackColor = backgroundFactory; labelFactory.FinalSetup = null; _dataNodeLabel = labelFactory.Create(); _dataNodeLabel.Parent = placeHolderLabel.Parent; _dataNodeLabel.Location = placeHolderLabel.Location; if (null != _simpleDataNodeControl) _simpleDataNodeControl.Dispose(); _simpleDataNodeControl = new SimpleDataNodeControl(new DataNodeTextViewer(valueFactory, foregroundFactory, backgroundFactory)); _simpleDataNodeControl.Parent = simpleDataNodeControlTabPage; _simpleDataNodeControl.Width = 70; _simpleDataNodeControl.Height = 30; UpdateDataNodeSymbol(); } private readonly List _links = new List(); private DataNode _valueDataNode; private DataNode _foregroundDataNode; private DataNode _backgroundDataNode; private SimpleDataNodeControl _simpleDataNodeControl; private void UpdateDataNodeSymbol() { // Note: I could have specified a symbol back when we specified the formula. I left that // blank, so now we have a PlaceHolder. Now we fill in the PlaceHolder with the symbol. // // In this simple example the symbol isn't any different from any of the other inputs. // If this was production code, instead of test/demo code, I probably would have filled in // the symbol at the same time as the rest of the details. // // This shows how we expect people to normally use DataNode objects. The structure // might be specified in an XML file. It might have been read from the server at run time // to make sure we have the latest, even if we have an old client. The symbol will change // all the time. The user might type a symbol, or select a row of a table and get the // symbol from there. Or we might have a lot of almost identical cells, each based on the // same factory templates, but each with a different symbol. MyFactories factoriesLive = _factoryTemplates.SetSymbol(dataNodeSymbolTextBox.Text); dataNodeFactoriesTextBox.Text = "Template:\r\n" + _factoryTemplates + "\r\nLive:\r\n" + factoriesLive; ClearDataNodeLinks(); _links.Add(factoriesLive.Value.Find(out _valueDataNode, ValueDataNodeCallback)); _links.Add(factoriesLive.ForegroundColor.Find(out _foregroundDataNode, ForegroundDataNodeCallback)); _links.Add(factoriesLive.BackgroundColor.Find(out _backgroundDataNode, BackgroundDataNodeCallback)); ValueDataNodeCallback(); ForegroundDataNodeCallback(); BackgroundDataNodeCallback(); _dataNodeLabel.TrySetSymbol(dataNodeSymbolTextBox.Text); _simpleCombinedWidget.TrySetSymbol(dataNodeSymbolTextBox.Text); _simpleDataNodeControl.SetSymbol(dataNodeSymbolTextBox.Text); } private void ClearDataNodeLinks() { foreach (DataNode.Link link in _links) link.Release(); _links.Clear(); // After releasing the links you shouldn't try to access the data nodes any more. They // might have cleaned up and trying to access them might throw an exception. _valueDataNode = null; _foregroundDataNode = null; _backgroundDataNode = null; } private void ForegroundDataNodeCallback() { object value = _foregroundDataNode.Value; if (!(value is Color)) dataNodeLabel.ForeColor = _normalForeground; else dataNodeLabel.ForeColor = (Color)value; } private void BackgroundDataNodeCallback() { object value = _backgroundDataNode.Value; if (!(value is Color)) dataNodeLabel.BackColor = _normalBackground; else dataNodeLabel.BackColor = (Color)value; } private void ValueDataNodeCallback() { object value = _valueDataNode.Value; string toDisplay; Type expectedType; // Display the data. This if statement could be replaced with another TransformationDataNode. // However, I think we're going to go a different direction. One paint method should take in // the input and fill our control. The same paint method should also work in a table cell. // The same input should be able to display a string, like "$12.34" or something graphic, like // our three logarithmic triangles. if (stringTransformationRadioButton.Checked) { expectedType = typeof(String); // Display things like a programmer might expect. if (null == value) toDisplay = "null"; else toDisplay = '"' + value.ToString() + '"'; } else if (integerTransformationRadioButton.Checked) { expectedType = typeof(Int64); if (value is Int64) // Include thousands seperators. toDisplay = String.Format("{0:n0}", value); else // This is the more common approach. Nulls are displayed as a blank field. // Use "is" or "as" to check for nulls. That will also check for items of // an unexpected type. Those will be treated just like a null. That's usually // what you want. null covers a lot of different types of errors. toDisplay =""; } else if (doubleTransformationRadioButton.Checked) { expectedType = typeof(Double); if (value is Double) // Include thousands and 2 digits after the decimal. toDisplay = String.Format("{0:n2}", value); else toDisplay = ""; } else // Date time { expectedType = typeof(DateTime); if (value is DateTime) toDisplay = ((DateTime)value).ToString(); else toDisplay = ""; } dataNodeLabel.Text = toDisplay; } private GradientColorChooser _colorChooser = new GradientColorChooser(); private void editColorGradientButton_Click(object sender, EventArgs e) { // We're demonstrating multiple things here. We're showing how to use the // GradientColorChooser with a DataNode. And we're showing how to use the // ConstantDataNode objects. And we're showing how you can quickly choose // between two different strategies. bool previouslyDoingColorByValue = colorByValueCheckBox.Checked; colorByValueCheckBox.Checked = true; using (TopListColorChooser dialog = new TopListColorChooser(ConnectionMaster.First)) { // The GradientColorChooser is overkill for this task, but it's the only // interface provided by the TopListColorChooser. The GradientColorChooser // gives instant feedback to the caller. You can see each time the user // makes a change. The idea is that the TopListColorChooser dialog box doesn't // contain a sample. Instead, we immediately update the window we're trying to // configure. dialog.GradientColorChooser = _colorChooser; dialog.ShowDialog(); if (dialog.DialogResult != System.Windows.Forms.DialogResult.OK) { // For the most part there's no reason to read anything from the dialog. // We got all the data in real time. The callbacks even handle the Cancel // button for us, so we don't have to treat this as a special case. // // However, this test/sample GUI is doing something else. You can // completely disable the colors in the result. If you try to configure // the colors, that will check the box saying that we want to use // the gradient colors. colorByValueCheckBox.Checked = previouslyDoingColorByValue; UpdateDataNodeFactory(); } } } private void dataNodeColorFormulaTextBox_TextChanged(object sender, EventArgs e) { if (colorByValueCheckBox.Checked) UpdateDataNodeFactory(); else // This will also call UpdateDataNodeFactory(). We always want to call that, // but only once. colorByValueCheckBox.Checked = true; } private Control _simpleCombinedWidget; private static DataNodeControlFactory SimpleCombinedWidget() { DataNode.Factory upForTheDay = TopListStringDataNode.GetFactory("[FCD]"); //upForTheDay = TransformationDataNode.GetFactory(TransformationDataNode.StringToDouble, upForTheDay); upForTheDay = upForTheDay.StringToDouble(); DataNodeLabel.Factory cell = new DataNodeLabel.Factory(); cell.Value = TopListStringDataNode.GetFactory("[Price]"); cell.Value = cell.Value.StringToDouble(); cell.BackColor = ConstantDataNode.GetFactory(Color.Black); cell.ForeColor = CompareToZeroDataNode.GetFactory(upForTheDay, Color.Green, Color.White, Color.Red); cell.FinalSetup = null; TwoOverOne layout = new TwoOverOne(); layout.TopLeft = cell; cell.Value = upForTheDay; layout.TopRight = cell; cell.Value = TopListStringDataNode.GetFactory("[D_Name]"); layout.Bottom = cell; return layout; } private void sendFakeDataButton_Click(object sender, EventArgs e) { StockDataManager.Find().DebugSend(fakeDataSymbolTextBox.Text, fakeDataToSendTextBox.Text); } private void copyFakeDataFromAboveButton_Click(object sender, EventArgs e) { StringBuilder result = new StringBuilder(); bool first = true; foreach (var kvp in _lastRowDataReceived.Data) { string key = kvp.Key as string; string value = kvp.Value as string; if ((null != key) && (null != value)) { if (first) first = false; else result.Append('&'); result.Append(HttpUtility.UrlEncode(key)).Append('=') .Append(HttpUtility.UrlEncode(value)); } } fakeDataToSendTextBox.Text = result.ToString(); } private void StockDataTester_FormClosed(object sender, FormClosedEventArgs e) { ClearDataNodeLinks(); // One advantage of using DataNodeLabel is that you don't have to do // any special cleanup, like this. The normal Dispose() call on the form is sufficient. } private void showAllDataNodeObjectsButton_Click(object sender, EventArgs e) { // This should really be in it's own window. This window always creates data nodes in its // constructor. It should delete those when it shuts down. So this display can never be // empty. Ideally I'd be able to watch what happens when I create the first window that // uses data nodes, and when I close the last one. allDataNodesTextBox.Text = DataNode.DebugDumpAll(); } } class TwoOverOne : DataNodeControlFactory { public override Control Create() { DataNodeTableLayoutPanel panel = new DataNodeTableLayoutPanel(); panel.ColumnCount = 2; panel.RowCount = 2; panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50)); panel.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 50)); panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50)); panel.RowStyles.Add(new RowStyle(SizeType.Percent, 50)); if (null != TopLeft) { Control child = TopLeft.Create(); panel.Controls.Add(child, 0, 0); child.Dock = DockStyle.Fill; } if (null != TopRight) { Control child = TopRight.Create(); panel.Controls.Add(child, 1, 0); child.Dock = DockStyle.Fill; } if (null != Bottom) { Control child = Bottom.Create(); panel.Controls.Add(child, 0, 1); panel.SetColumnSpan(child, 2); child.Dock = DockStyle.Fill; } return panel; } public DataNodeControlFactory TopLeft; public DataNodeControlFactory TopRight; public DataNodeControlFactory Bottom; public override int GetHashCode() { return MakeHashCode(TopLeft, TopRight, Bottom); } public override bool Equals(object obj) { if (base.Equals(obj)) return true; TwoOverOne other = (TwoOverOne)obj; return Equals(TopLeft, other.TopLeft) && Equals(TopRight, other.TopRight) && Equals(Bottom, other.Bottom); } } }