using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using TradeIdeas.TIProData.Configuration;
using TradeIdeas.TIProData.Interfaces;
namespace TradeIdeas.TIProGUI
{
///
/// 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;
public bool isDefaultStrategy = false;
/*Dictionary for mapping a node name to its assignmed
integral image index. We will need this when using the
orange arrow to select strategies. Must be mutually exclusive*/
private Dictionary _dict = new Dictionary();
private int _nodeNameTally = 0;
private string _nodeName;
//Start location of Config window when first brought up...
private static int _configLocation_X = 50;
private static int _configLocation_Y = 50;
//Start size of Config window when *first* brought up (default size)
private static int _configWindowHeight = -1;
private static int _configWindowWidth = -1;
private bool _raceConfigMode = false;
// Font support.
private const float DEFAULT_FONT_SIZE = 8.25F;
private FontManager _fontManager;
///
/// 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();
StartPosition = FormStartPosition.CenterParent;
MinimizeBox = false;
if (!IsHandleCreated)
CreateHandle();
// Font support.
_fontManager = new FontManager(this, DEFAULT_FONT_SIZE);
_fontManager.selectTheFont();
// Take this code out since it messes with font support.
//if ((_configWindowHeight == -1 && _configWindowWidth == -1))
//{
// _configWindowWidth = Width;
// _configWindowHeight = Height;
//}
_configurationWindowManager = new ConfigurationWindowManager();
_configurationWindowManager.LoadFromServer(settings.ConnectionMaster, settings.ConfigurationType,
OnLoaded, settings.InitialConfig);
UpdateButtons();
_customFilters["MinPrice"] = minPriceTextBox;
_customFilters["MaxPrice"] = maxPriceTextBox;
_customFilters["MinVol"] = minAverageVolumeTextBox;
_customFilters["MinTV"] = minVolumeTodayTextBox;
Icon = GuiEnvironment.Icon;
}
///
/// Set Race Config Mode to true when called from RTSR.
/// In this mode, the "Select Base" tab is hidden.
///
public bool RaceConfigMode
{
get { return _raceConfigMode; }
set {
_raceConfigMode = value;
if (_raceConfigMode)
{
Text = "Configure Your Race";
}
}
}
///
/// 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;
if (_raceConfigMode)
{
// Remove the "Select Base" tab and make selected tab "Customize".
tabControl1.SelectedTab = customizeTabPage;
tabControl1.TabPages.Remove(selectBaseTabPage);
}
else
tabControl1.SelectedTab = selectBaseTabPage;
tabControl1.TabPages.Remove(loadingTabPage);
foreach (var kvp in _customFilters)
kvp.Value.Text = GetFilterValue(kvp.Key);
AddStrategyNodes();
baseTreeView.CollapseAll();
}
///
/// 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()
{
advancedButton.Enabled = tabControl1.SelectedTab != loadingTabPage;
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)
{
StrategyNode node = e.Node.Tag as StrategyNode;
TreeNode newNode = e.Node as TreeNode;
//if (node.IsFolder() && newNode.IsSelected)
if (node.IsFolder())
{
if (baseTreeView.SelectedNode.IsExpanded)
{
baseTreeView.SelectedNode.Collapse();
}
else
{
baseTreeView.SelectedNode.Expand();
}
return;
}
UpdateFromTree();
}
///
/// Updates the Strategy from the treeview node.
///
/// Node to get the Strategy from. If null, use Selected Node.
private void UpdateFromTree(StrategyNode node = null)
{
if (node == null)
node = baseTreeView.SelectedNode.Tag as StrategyNode;
//StrategyNode node = baseTreeView.SelectedNode.Tag as StrategyNode;
bool topIsCurrent = (null != _configurationWindowManager.CurrentSettings) && (_configurationWindowManager.CurrentSettings == node.PrepairedStrategy);
if (null == node)
{
strategyDescriptionLabel.Text = "";
return;
}
if (null != node.PrepairedStrategy)
{ // TODO strategyDescriptionLabel should be able to scroll, like in the traditional dialog box.
Strategy = node.PrepairedStrategy;
if (isDefaultStrategy && topIsCurrent)
{
strategyDescriptionLabel.Text = "These are your default settings." + Environment.NewLine + Environment.NewLine + "Strategy Name: " + Environment.NewLine + Strategy.WindowName;
}
else if (topIsCurrent)
{
strategyDescriptionLabel.Text = node.Description + Environment.NewLine + Environment.NewLine + "Strategy Name: " + Environment.NewLine + Strategy.WindowName;
}
else
{
strategyDescriptionLabel.Text = node.Description;
}
Strategy = node.PrepairedStrategy;
strategyNameTextBox.Text = Strategy.WindowName;
}
UpdateTreeSelectionImage();
}
private void UpdateTreeSelectionImage()
{
TreeNode selected = baseTreeView.SelectedNode as TreeNode;
if (null == selected)
return;
StrategyNode selectedStrategy = baseTreeView.SelectedNode.Tag as StrategyNode;
// Orage arrow icon do not apply to folders.
if (!selectedStrategy.IsFolder())
{
selected.SelectedImageIndex = 1; //orange arrow icon
selected.ImageIndex = 1; //orange arrow icon
_nodeName = selected.Name;
TreeNodeCollection nodes = baseTreeView.Nodes;
loadSetRecursive(nodes);
}
}
private void loadSetRecursive(TreeNodeCollection nodes)
{
/*This method is affiliated with the orange arrow
placement - and traverses the whole tree... makes sure
that no other nodes other than the selected node
have an orange arrow icon*/
foreach (TreeNode n in nodes)
{
if (n.Name != _nodeName)
{
foreach (var pair in _dict)
{
if (pair.Key == n.Name)
{
n.SelectedImageIndex = n.ImageIndex = pair.Value;
}
}
}
loadSetRecursive(n.Nodes);
}
}
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);
// If Race Config Mode, set the Strategy to the "Current Settings" node since the "Select Base" tab will be hidden/removed.
if (_raceConfigMode && node.Name == "Current Settings")
UpdateFromTree(node);
}
}
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 && isDefaultStrategy)
{
newNode.Text = "Default Settings";
}
switch (top.Icon)
{
case "+":
newNode.ImageIndex = 4;
newNode.Name = _nodeNameTally.ToString();
_dict.Add(newNode.Name, newNode.ImageIndex);
break;
case "-":
newNode.ImageIndex = 5;
newNode.Name = _nodeNameTally.ToString();
_dict.Add(newNode.Name, newNode.ImageIndex);
break;
case "*":
newNode.ImageIndex = 2;
newNode.Name = _nodeNameTally.ToString();
_dict.Add(newNode.Name, newNode.ImageIndex);
break;
case "folder":;
newNode.ImageIndex = 3;
newNode.Name = _nodeNameTally.ToString();
_dict.Add(newNode.Name, newNode.ImageIndex);
break;
case ":)":
newNode.ImageIndex = 6;
newNode.Name = _nodeNameTally.ToString();
_dict.Add(newNode.Name, newNode.ImageIndex);
break;
default:
newNode.ImageIndex = 0;
newNode.Name = _nodeNameTally.ToString();
_dict.Add(newNode.Name, newNode.ImageIndex);
break;
}
newNode.SelectedImageIndex = newNode.ImageIndex;
newNode.Tag = top;
into.Add(newNode);
_nodeNameTally++;
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_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
if (e.Node.Bounds.Contains(e.Location))
{
StrategyNode node = e.Node.Tag as StrategyNode;
TreeNode newNode = e.Node as TreeNode;
if (node.IsFolder() && newNode.IsSelected)
{
if (baseTreeView.SelectedNode.IsExpanded)
{
baseTreeView.SelectedNode.Collapse();
}
else
{
baseTreeView.SelectedNode.Expand();
}
return;
}
}
}
private void baseTreeView_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
{
//Select and advanced strategies to the next tab. Ignore folders.
if (e.Node.Bounds.Contains(e.Location))
{
StrategyNode node = e.Node.Tag as StrategyNode;
if (node.IsFolder())
{
return;
}
// Update new selection
UpdateFromTree();
// Advance to next tab
tabControl1.SelectedIndex = tabControl1.SelectedIndex + 1;
}
}
private void SmallConfigWindow_VisibleChanged(object sender, EventArgs e)
{
//Here we retain the location whin this window is created again
if (!this.Visible)
{
_configLocation_X = Location.X;
_configLocation_Y = Location.Y;
_configWindowHeight = Height;
_configWindowWidth = Width;
}
else
{
if (GuiEnvironment.ConfigWindowRemembersLocation)
Location = new Point(_configLocation_X, _configLocation_Y);
// Take this code out since it messes with font support.
//Width = _configWindowWidth;
//Height = _configWindowHeight;
}
}
}
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.isDefaultStrategy = this.IsDefaultStrategy;
smallConfigWindow.RaceConfigMode = this.RaceConfigMode;
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;
}
}
}
}