summaryrefslogtreecommitdiff
path: root/Form1.cs
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2016-06-01 19:42:52 -0700
committerScott Gasch <[email protected]>2016-06-01 19:42:52 -0700
commit373eb7051410d0d7a1bcdbc93e9cc34f2951333d (patch)
tree1202df799efb4a87221199e8d6ace6a230d2e50d /Form1.cs
Initial checkin of typhoon UI project.HEADmaster
Diffstat (limited to 'Form1.cs')
-rw-r--r--Form1.cs542
1 files changed, 542 insertions, 0 deletions
diff --git a/Form1.cs b/Form1.cs
new file mode 100644
index 0000000..766ac22
--- /dev/null
+++ b/Form1.cs
@@ -0,0 +1,542 @@
+/**
+ * Copyright (c) Lynn J. Gasch
+ * 7/17/04
+ * Redmond, Washington
+ *
+ * typhoonUI displays the contents of an xml file in a tree control.
+ * It was developed to support chess programming, but can really be
+ * used for any xml file you wish.
+ *
+ * Xml nodes that do not have children should be written within
+ * a single tag, as &lt; tag anAttrib="value" /> so that they can
+ * be displayed on a single line (node) of the tree.
+ *
+ * Tags starting with "FEN" can be used to lauch chess board
+ * viewers with the board value (they must use the single-line
+ * formatting as described above to trigger this functionality).
+ *
+ * This app is pretty special purpose and I'm sure there are plenty
+ * of ways to break it with various inputs. I coded it up in a few
+ * hours and it meets our needs.
+ */
+
+using System;
+using System.Drawing;
+using System.Collections;
+using System.ComponentModel;
+using System.Windows.Forms;
+using System.Data;
+using System.Xml;
+using System.IO;
+using System.Diagnostics;
+using System.Text;
+
+namespace typhoonUI
+{
+ // TODO: write tag for eval; Write evals dumps to file
+ // and retrieve the text into a separate text block
+ // on selection of the node
+ // TODO: command line file launch
+ // TODO: speed up loading
+
+ /// <summary>
+ /// Summary description for Form1.
+ /// </summary>
+ public class Form1 : System.Windows.Forms.Form
+ {
+ #region Private Fields
+
+ /// <summary>
+ /// inserted between tag names and their values for display
+ /// in the tree. For tags that have no children other than their
+ /// values, list them in the xml as
+ /// &lt; tag attrib="something to display" /> and they will only
+ /// take up one tree node and be listed as
+ /// tag something to display.
+ /// </summary>
+ private const string VALUE_SEPARATOR = " ";
+
+ /// <summary>
+ /// Use this tag name to identify the board configuration node
+ /// in your xml. This will provide menu item and double-clicking
+ /// to launch the position in a viewer that you can specify.
+ /// </summary>
+ private const string TAG_BOARD = "FEN";
+
+ /// <summary>
+ /// name of a tag for which the first attrib should be added to its parent
+ /// node text. If it's the only child, the node itself will be skipped
+ /// </summary>
+ private const string TAG_SCORE = "score";
+
+ /// <summary>
+ /// Attributes named tip will be set as tool tip text for the node
+ /// </summary>
+ private const string ATTRIB_TIP = "tip";
+
+ /// <summary>
+ /// an attrib name to denote request for boldfacing the text.
+ /// In order for the text to be displayed, it must be the frst attrib.
+ /// </summary>
+ private const string ATTRIB_BOLD = "bold";
+
+ /// <summary>
+ /// Name of a (reusable) file that is written with the board
+ /// position and used as a command arg to the board viewer app.
+ /// </summary>
+ private const string POSITION_FILE_NAME = "boardConfigFile.txt";
+
+ /// <summary>
+ /// Windows designer generated code
+ /// </summary>
+ private System.Windows.Forms.MainMenu mainMenu1;
+ private System.Windows.Forms.MenuItem menuItem1;
+ private System.Windows.Forms.MenuItem menuItem2;
+ private System.Windows.Forms.TreeView _treeView1;
+
+ /// <summary>
+ /// appears when right-clicking on a "board" node. See
+ /// BOARD_TAG_NAME
+ /// </summary>
+ private System.Windows.Forms.ContextMenu _contextMenu;
+
+ /// <summary>
+ /// Path to the viewer app, to be collected from the user.
+ /// TODO: allow the user to enter it into the Path environment
+ /// variable and just attempt to run it; only request path
+ /// if fail to run.
+ /// </summary>
+ private string _boardViewerAppPath = null;
+
+ /// <summary>
+ /// the view app process, so we can kill it if another board
+ /// is to be viewed
+ /// </summary>
+ private Process _process = null;
+
+ /// <summary>
+ /// local dir for writing the board position file for input
+ /// into the viewer app.
+ /// </summary>
+ private string _applicationDir;
+
+ /// <summary>
+ /// Required designer variable.
+ /// </summary>
+ private System.ComponentModel.Container components = null;
+
+ /// <summary>
+ /// for displaying long or multi-line text
+ /// </summary>
+ private ToolTip _tip;
+
+ private string _tipText;
+
+ #endregion
+
+ #region Construction / Destruction
+
+ /// <summary>
+ /// The main thing
+ /// </summary>
+ public Form1(string startFile)
+ {
+ //
+ // Required for Windows Form Designer support
+ //
+ InitializeComponent();
+
+ // create the context menu that will be used for board nodes
+ _contextMenu = new ContextMenu();
+ MenuItem item = new MenuItem("View board");
+ item.Click += new EventHandler(OnViewBoardMenuClicked);
+ _contextMenu.MenuItems.Add(item);
+
+ _applicationDir = Path.GetDirectoryName(
+ Application.ExecutablePath);
+
+ _tip = new ToolTip();
+ _tipText = string.Empty;
+ _tip.SetToolTip(_treeView1, _tipText);
+
+ if ((startFile != null) && (startFile.Length > 0))
+ Display(startFile);
+ }
+
+ /// <summary>
+ /// Clean up any resources being used.
+ /// </summary>
+ protected override void Dispose( bool disposing )
+ {
+ if( disposing )
+ {
+ KillProcess();
+ if (components != null)
+ {
+ components.Dispose();
+ }
+ }
+ base.Dispose( disposing );
+ }
+
+
+ #endregion
+
+ #region Windows Form Designer generated code
+ /// <summary>
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ /// </summary>
+ private void InitializeComponent()
+ {
+ this.mainMenu1 = new System.Windows.Forms.MainMenu();
+ this.menuItem1 = new System.Windows.Forms.MenuItem();
+ this.menuItem2 = new System.Windows.Forms.MenuItem();
+ this._treeView1 = new System.Windows.Forms.TreeView();
+ this.SuspendLayout();
+ //
+ // mainMenu1
+ //
+ this.mainMenu1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+ this.menuItem1});
+ //
+ // menuItem1
+ //
+ this.menuItem1.Index = 0;
+ this.menuItem1.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] {
+ this.menuItem2});
+ this.menuItem1.Text = "File";
+ //
+ // menuItem2
+ //
+ this.menuItem2.Index = 0;
+ this.menuItem2.Text = "Open";
+ this.menuItem2.Click += new System.EventHandler(this.OnOpenMenuClick);
+ //
+ // _treeView1
+ //
+ this._treeView1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right);
+ this._treeView1.HideSelection = false;
+ this._treeView1.ImageIndex = -1;
+ this._treeView1.Name = "_treeView1";
+ this._treeView1.SelectedImageIndex = -1;
+ this._treeView1.Size = new System.Drawing.Size(680, 600);
+ this._treeView1.TabIndex = 0;
+ this._treeView1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.OnTreeViewMouseDown);
+ this._treeView1.DoubleClick += new System.EventHandler(this.OnTreeViewDoubleClick);
+ this._treeView1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.OnTreeViewMouseMove);
+ //
+ // Form1
+ //
+ this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
+ this.ClientSize = new System.Drawing.Size(680, 598);
+ this.Controls.AddRange(new System.Windows.Forms.Control[] {
+ this._treeView1});
+ this.Menu = this.mainMenu1;
+ this.Name = "Form1";
+ this.Text = "Scott\'s Move Tree";
+ this.ResumeLayout(false);
+
+ }
+ #endregion
+
+ /// <summary>
+ /// The main entry point for the application.
+ /// </summary>
+ [STAThread]
+ static void Main(string[] args)
+ {
+ string filename = string.Empty;
+ if (args.Length > 0)
+ filename = args[0];
+
+ Application.Run(new Form1(filename));
+ }
+
+ /// <summary>
+ /// Use Xml support to load and parse the indicated xml doc.
+ /// Populate tree control with it.
+ /// </summary>
+ /// <param name="filename">path to the xml file to load</param>
+ private void Display(string filename)
+ {
+ _treeView1.BeginUpdate();
+ try
+ {
+ XmlDocument doc = new XmlDocument();
+ doc.Load(filename);
+ _treeView1.Nodes.Clear();
+ TreeNode root = new TreeNode(doc.DocumentElement.Name);
+ _treeView1.Nodes.Add(root);
+ // recursively add all
+ StringBuilder builder = new StringBuilder();
+ foreach(XmlNode node in doc.DocumentElement.ChildNodes)
+ {
+ AddNode(node, ref root, ref builder);
+ }
+ }
+ catch(Exception e)
+ {
+ MessageBox.Show(this, e.Message + "\r\n" +
+ e.StackTrace, "Error",
+ MessageBoxButtons.OK, MessageBoxIcon.Error);
+ }
+ _treeView1.EndUpdate();
+ }
+
+ /// <summary>
+ /// Recursively add nodes to the tree.
+ /// </summary>
+ /// <param name="element">the current info to add; corresponds
+ /// to the parent node so that we are adding its children.</param>
+ /// <param name="parent">parent node in the tree</param>
+ /// <param name="builder">on;y create one instance of string builder
+ /// and use it for text manipulation</param>
+ /// <remarks>Nodes that don't have any nested nodes (other than their
+ /// own "value") should be written in the form
+ /// &lt; tagName attrib="Attrib value" />
+ /// In this case, the tag name and the first attrib value are
+ /// shown in one line (in one node) in the tree. NOTE: any
+ /// additional tags are ignored. (the attrib value is not required).
+ /// </remarks>
+ private void AddNode(XmlNode element, ref TreeNode parent,
+ ref StringBuilder builder)
+ {
+ builder.Length = 0;
+ string text = element.Name;
+
+ // special cases:
+ // - score: append parent text with score instead of adding
+ // it as a node.
+ // - any with attribs - append first attrib val to node text
+ // - bold - (must be first attrib) - boldface the node
+ // - tip - (any attrib) - set as the tag of the node for tooltip
+
+ if (text.Equals(TAG_SCORE))
+ {
+ builder.Append(parent.Text);
+ builder.Append(VALUE_SEPARATOR);
+ builder.Append(TAG_SCORE);
+ builder.Append(" ");
+ builder.Append(element.Attributes[0].Value);
+ parent.Text = builder.ToString();
+ // done
+ }
+ else
+ {
+ builder.Append(text);
+ XmlAttributeCollection coll = element.Attributes;
+ int numAttribs = coll.Count;
+ XmlAttribute attrib = null;
+ if (numAttribs > 0)
+ {
+ attrib = coll[0];
+ // append the tag name with the first attrib value
+ builder.Append(VALUE_SEPARATOR);
+ builder.Append(attrib.Value);
+ }
+ TreeNode node = new TreeNode(builder.ToString());
+
+ if ((attrib != null) && attrib.Name.Equals(ATTRIB_BOLD))
+ node.ForeColor = Color.Red;
+ if (numAttribs > 1)
+ {
+ attrib = coll[1];
+ if (attrib.Name.Equals(ATTRIB_TIP))
+ {
+ node.Tag = attrib.Value;
+ }
+ }
+
+ parent.Nodes.Add(node);
+
+ foreach (XmlElement child in element.ChildNodes)
+ {
+ AddNode(child, ref node, ref builder);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets and saves the path to the viewer app from the user.
+ /// </summary>
+ private DialogResult SetViewerAppPath()
+ {
+ DialogResult result = DialogResult.OK;
+ if (_boardViewerAppPath == null)
+ {
+ result = MessageBox.Show(this,
+ "Please set path to Winboard or XBoard viewer app",
+ "Input requested", MessageBoxButtons.OKCancel,
+ MessageBoxIcon.Question);
+ if ( result == DialogResult.OK)
+ {
+ OpenFileDialog browse = new OpenFileDialog();
+ browse.Filter = "Executable files (*.exe)|*.exe";
+ browse.Multiselect = false;
+ result = browse.ShowDialog(this);
+ if (result == DialogResult.OK)
+ {
+ _boardViewerAppPath = browse.FileName;
+ }
+ }
+ }
+ return result;
+ }
+
+ /// <summary>
+ /// Closes the viewer app
+ /// </summary>
+ private void KillProcess()
+ {
+ if (_process != null)
+ {
+ if (!_process.HasExited)
+ {
+ if (!_process.CloseMainWindow())
+ _process.Kill();
+ }
+ _process = null;
+ }
+ }
+
+ /// <summary>
+ /// Writes board position to file and calls the viewer app with it.
+ /// </summary>
+ /// <param name="text">text of the board node, starting with the
+ /// "board" tag and separator</param>
+ private void ViewBoard(string text)
+ {
+ string boardCode = text.Substring(TAG_BOARD.Length
+ + VALUE_SEPARATOR.Length);
+ StreamWriter f = new StreamWriter(new FileStream(
+ Path.Combine(_applicationDir, POSITION_FILE_NAME),
+ FileMode.Create, FileAccess.Write));
+ f.WriteLine(boardCode);
+ f.Close();
+
+ if (SetViewerAppPath() == DialogResult.OK)
+ {
+
+ try
+ {
+ KillProcess();
+ ProcessStartInfo pInfo =
+ new ProcessStartInfo(_boardViewerAppPath);
+ pInfo.Arguments =
+ "/mode editposition /ncp /top /coords /size small /lpf " +
+ Path.Combine(_applicationDir, POSITION_FILE_NAME);
+
+ _process = new Process();
+ _process.StartInfo = pInfo;
+ _process.Start();
+ }
+ catch(Exception)
+ {
+ MessageBox.Show(this, "Unable to run viewer app", "Error",
+ MessageBoxButtons.OK, MessageBoxIcon.Error);
+ _boardViewerAppPath = null;
+ _process = null;
+ }
+ }
+ }
+
+
+ #region Event Handlers
+
+ /// <summary>
+ /// Handler for File | Open menu. Get the xml file to load.
+ /// </summary>
+ /// <param name="sender">ignored</param>
+ /// <param name="e">ignored</param>
+ private void OnOpenMenuClick(object sender, System.EventArgs e)
+ {
+ OpenFileDialog dialog = new OpenFileDialog();
+ dialog.Multiselect = false;
+ dialog.Filter = "XML files (*.xml)|*.xml|All files (*.*)|*.*";
+ if (dialog.ShowDialog(this) == DialogResult.OK)
+ {
+ Display(dialog.FileName);
+ }
+ }
+
+ /// <summary>
+ /// Handles mouse down. if right-click on "board" node,
+ /// displays board context menu.
+ /// </summary>
+ /// <param name="sender">ignored</param>
+ /// <param name="e">select the tree node at the click
+ /// coords</param>
+ private void OnTreeViewMouseDown(object sender, MouseEventArgs e)
+ {
+ // this doesn't automatically happen
+ _treeView1.SelectedNode = _treeView1.GetNodeAt(e.X, e.Y);
+ if (e.Button.Equals(MouseButtons.Right))
+ {
+ string text = _treeView1.SelectedNode.Text;
+ if (text.StartsWith(TAG_BOARD))
+ {
+ _treeView1.ContextMenu = _contextMenu;
+ }
+ }
+ }
+
+ /// <summary>
+ /// when view board menu item chosen, writes the selected board
+ /// position to a file and calls the viewer app.
+ /// </summary>
+ /// <param name="sender">ignored</param>
+ /// <param name="e">ignored</param>
+ private void OnViewBoardMenuClicked(object sender, EventArgs e)
+ {
+ string text = _treeView1.SelectedNode.Text;
+ if (text.StartsWith(TAG_BOARD))
+ {
+ ViewBoard(text);
+ }
+ _treeView1.ContextMenu = null;
+ }
+
+ /// <summary>
+ /// If double-click a "board" node, calls the viewer
+ /// for the position
+ /// </summary>
+ /// <param name="sender"></param>
+ /// <param name="e"></param>
+ private void OnTreeViewDoubleClick(object sender, System.EventArgs e)
+ {
+ string text = _treeView1.SelectedNode.Text;
+ if (text.StartsWith(TAG_BOARD))
+ {
+ ViewBoard(text);
+ }
+ }
+
+ /// <summary>
+ /// set tooltip if over a node with a displayable tag
+ /// </summary>
+ /// <param name="sender">ignored</param>
+ /// <param name="e">holds mouse position</param>
+ private void OnTreeViewMouseMove(object sender, MouseEventArgs e)
+ {
+ TreeNode node = _treeView1.GetNodeAt(e.X, e.Y);
+ string tag = string.Empty;
+ if ((node != null) && (node.Tag != null))
+ {
+ tag = (string)node.Tag;
+ }
+ if (!tag.Equals(_tipText))
+ {
+ _tipText = tag;
+ _tip.SetToolTip(_treeView1, _tipText);
+ }
+ }
+
+
+ #endregion
+
+
+ }
+}