using System;
using System.Collections.Generic;
using System.Windows.Forms;
using TradeIdeas.TIProData.Configuration;
using TradeIdeas.TIProData.Interfaces;
using TradeIdeas.TIProGUI;
namespace TIProDevExtension
{
///
/// This in a very simple version of the config window. The idea is that a user would start from a
/// strategy that we built. We can select a base strategy, and he can do some simple things to
/// customize it. This includes an "Advanced" button, that allows him to switch to the full version
/// if he wants.
///
/// This is typically called by SmallConfigWindowWrapper. SmallConfigWindowWrapper has some of the
/// logic to make this work. In particular, the advanced button. (Perhaps SmallConfigWindow should
/// be private? I don't know if that's even possible for a form.)
///
public partial class SmallConfigWindow : Form
{
private Dictionary _customFilters = new Dictionary();
///
/// This is an output. We store the strategy here when we are done. This is also used internally
/// as a workspace while we are building the strategy.
///
public PrepairedStrategy Strategy { get; private set; }
private ConfigurationWindowManager _configurationWindowManager;
///
/// Standard constructor. This automatically and immediately requests data.
///
///
/// This describes the window that we want.
/// This is only used as an input. The caller should read/pull the values of
/// and from this object.
///
public SmallConfigWindow(ConfigWindowWrapper settings)
{
InitializeComponent();
if (!IsHandleCreated)
CreateHandle();
_configurationWindowManager = new ConfigurationWindowManager();
_configurationWindowManager.LoadFromServer(settings.ConnectionMaster, settings.ConfigurationType,
OnLoaded, settings.InitialConfig);
UpdateButtons();
_customFilters["MinPrice"] = minPriceTextBox;
_customFilters["MaxPrice"] = maxPriceTextBox;
_customFilters["MinVol"] = minAverageVolumeTextBox;
}
///
/// Looks up a filter to find the corresponding value.
/// We always look this up in the user's initial settings.
///
/// A filter code like MaxPrice or MinVol.
///
/// The value, or "" if the value was not found.
/// Various types of errors are all treated as not found and return "".
///
private string GetFilterValue(string code)
{ // TODO convert between the user's preferred number format and the server's preferred number format.
PrepairedStrategy settings = _configurationWindowManager.CurrentSettings;
if (null == settings)
return "";
Filter filter;
bool max;
_configurationWindowManager.FindFilter(code, out filter, out max);
if (null == filter)
return "";
Dictionary values;
if (max)
values = settings.MaxFilters;
else
values = settings.MinFilters;
string value;
values.TryGetValue(filter, out value);
return value??"";
}
///
/// Store the given filter settings.
/// This always goes into the Strategy named in the Strategy property.
///
/// A filter code like MaxPrice or MinVol.
/// The value to store. Typically a number or the empty string.
private void SetFilterValue(string code, string value)
{ // TODO convert between the user's preferred number format and the server's preferred number format.
Filter filter;
bool max;
_configurationWindowManager.FindFilter(code, out filter, out max);
if (null == filter)
return;
Dictionary values;
if (max)
values = Strategy.MaxFilters;
else
values = Strategy.MinFilters;
if (value == "")
values.Remove(filter);
else
values[filter] = value;
}
///
/// Called from the network thread.
///
///
private void OnLoaded(ConfigurationWindowManager configurationWindowManager)
{
this.BeginInvokeIfRequired(delegate
{
OnLoaded();
});
}
///
/// Called from the GUI thread.
/// Configuration data is now valid.
///
private void OnLoaded()
{
loaded = true;
tabControl1.SelectedTab = selectBaseTabPage;
tabControl1.TabPages.Remove(loadingTabPage);
foreach (var kvp in _customFilters)
kvp.Value.Text = GetFilterValue(kvp.Key);
AddStrategyNodes();
}
///
/// Configuration data is valid.
/// We have received it from the server.
///
private bool loaded;
private void tabControl1_Selecting(object sender, TabControlCancelEventArgs e)
{
if (loaded)
{
if (e.TabPage == loadingTabPage)
e.Cancel = true;
}
else
{
if (e.TabPage != loadingTabPage)
e.Cancel = true;
}
}
private void nextButton_Click(object sender, EventArgs e)
{
if (tabControl1.SelectedTab == nameTabPage)
{
UpdateResult();
DialogResult = System.Windows.Forms.DialogResult.OK;
}
else
tabControl1.SelectedIndex = tabControl1.SelectedIndex + 1;
}
private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateButtons();
if (tabControl1.SelectedTab == selectBaseTabPage)
// Do this so the selected item will be drawn in the selection color.
baseTreeView.Focus();
}
private void UpdateButtons()
{
nextButton.Enabled = tabControl1.SelectedTab != loadingTabPage;
if (tabControl1.SelectedTab == nameTabPage)
nextButton.Text = "Done";
else
nextButton.Text = "Next";
}
private void cancelButton_Click(object sender, EventArgs e)
{
Strategy = null;
_configurationWindowManager.Abandon();
}
private void advancedButton_Click(object sender, EventArgs e)
{
UpdateResult();
}
private void UpdateResult()
{
if (null == Strategy)
{ // We hope this doesn't happen. But the server could send us an empty set of strategies.
if (_configurationWindowManager.ConfigurationType == ConfigurationType.Alerts)
Strategy = new AlertStrategy();
else
Strategy = new TopListStrategy();
}
Strategy.WindowName = strategyNameTextBox.Text;
foreach (var kvp in _customFilters)
SetFilterValue(kvp.Key, kvp.Value.Text);
}
private void baseTreeView_AfterSelect(object sender, TreeViewEventArgs e)
{
UpdateFromTree();
}
private void baseTreeView_DoubleClick(object sender, EventArgs e)
{
tabControl1.SelectedIndex = tabControl1.SelectedIndex + 1;
}
private void UpdateFromTree()
{
StrategyNode node = baseTreeView.SelectedNode.Tag as StrategyNode;
if (null == node)
{
strategyDescriptionLabel.Text = "";
return;
}
if (null != node.PrepairedStrategy)
{ // TODO strategyDescriptionLabel should be able to scroll, like in the traditional dialog box.
strategyDescriptionLabel.Text = node.Description;
Strategy = node.PrepairedStrategy;
strategyNameTextBox.Text = Strategy.WindowName;
}
}
private void AddStrategyNodes()
{
baseTreeView.Nodes.Clear();
strategyDescriptionLabel.Text = "";
StrategyNode top = _configurationWindowManager.StrategyTree;
if (top == null)
{
return;
}
if (top.IsFolder())
{
foreach (StrategyNode node in top.Children)
{
AddStrategyNodes(node, baseTreeView.Nodes);
}
}
else
{
// We should never get here. The way our library parses the message from the
// server, there has to be a folder on top.
//AddStrategyNodes(top, null);
System.Diagnostics.Debug.Assert(false);
}
}
private void AddStrategyNodes(StrategyNode top, TreeNodeCollection into)
{
TreeNode newNode = new TreeNode(top.Name);
bool topIsCurrent = (null != _configurationWindowManager.CurrentSettings)
&& (_configurationWindowManager.CurrentSettings == top.PrepairedStrategy);
if (top.UserMustModify && !topIsCurrent)
// This is a "start from scratch" type strategy.
return;
if (topIsCurrent)
newNode.ImageIndex = 1;
else
switch (top.Icon)
{
case "+":
newNode.ImageIndex = 4;
break;
case "-":
newNode.ImageIndex = 5;
break;
case "*":
newNode.ImageIndex = 2;
break;
case "folder":
newNode.ImageIndex = 3;
break;
case ":)":
newNode.ImageIndex = 6;
break;
default:
newNode.ImageIndex = 0;
break;
}
newNode.SelectedImageIndex = newNode.ImageIndex;
newNode.Tag = top;
into.Add(newNode);
if (top.IsFolder())
{
foreach (StrategyNode node in top.Children)
{
AddStrategyNodes(node, newNode.Nodes);
}
}
else if (topIsCurrent || (null == baseTreeView.SelectedNode))
baseTreeView.SelectedNode = newNode;
}
private void baseTreeView_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{ // Don't let someone select a folder.
StrategyNode node = e.Node.Tag as StrategyNode;
if ((null == node) || (null == node.PrepairedStrategy))
e.Cancel = true;
}
}
public class SmallConfigWindowWrapper : ConfigWindowWrapper
{
public SmallConfigWindowWrapper(ConfigurationType configurationType, IConnectionMaster connectionMaster) :
base(configurationType, connectionMaster)
{
}
public static new ConfigWindowWrapper Factory(ConfigurationType configurationType,
IConnectionMaster connectionMaster)
{
return new SmallConfigWindowWrapper(configurationType, connectionMaster);
}
///
/// This examines the request and decides if the SmallConfigWindow can handle it.
///
///
/// True means to show the advanced window.
/// False means to display the small window.
///
private bool NeedAdvanced()
{
return OnlyShowColumns || (null != SortBy) || (null != InitialFilter) || IsSingleStock;
}
public override void ShowIt()
{
if (NeedAdvanced())
{
TraditionalConfigWindowWrapper advanced = new TraditionalConfigWindowWrapper(this);
advanced.ShowIt();
Strategy = advanced.Strategy;
}
else
using (SmallConfigWindow smallConfigWindow = new SmallConfigWindow(this))
{
smallConfigWindow.ShowDialog();
if (smallConfigWindow.DialogResult == System.Windows.Forms.DialogResult.OK)
Strategy = smallConfigWindow.Strategy;
else if (smallConfigWindow.DialogResult == DialogResult.Retry)
{
TraditionalConfigWindowWrapper advanced = new TraditionalConfigWindowWrapper(this);
if (null != smallConfigWindow.Strategy)
// Read the user's settings. Strategy will be null if the user didn't finish
// loading the config info from the server. In that case we keep the original
// inputs, which were copied by the constructor.
advanced.InitialConfig = smallConfigWindow.Strategy.MakeConfigString();
advanced.ShowIt();
Strategy = advanced.Strategy;
}
else
Strategy = null;
}
}
}
}