Implementing a schematic digitizing tool
DockableDigit.cs
// Copyright 2010 ESRI
// 
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
// 
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
// 
// See the use restrictions.
// 

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Xml;
using ESRI.ArcGIS.Schematic;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.esriSystem;

namespace DigitTool
{
  /// <summary>
  /// Designer class of the dockable window add-in. It contains user interfaces that
  /// make up the dockable window.
  /// </summary>
  public partial class DigitDockableWindow : UserControl
  {
    private DigitTool m_digitCommand;

    private XmlDocument m_dom = null;
    private bool m_loading = true;
    private bool m_clickPanel = false;
    private long m_curfrmWidth;

    private System.Windows.Forms.SplitterPanel m_Panel1;
    private System.Windows.Forms.SplitterPanel m_Panel2;

    private System.Windows.Forms.SplitterPanel m_curPanel;
    private System.Drawing.Color m_MandatoryColor = System.Drawing.Color.White;

    private ISchematicLayer m_schematicLayer;
    private ISchematicFeature m_schematicFeature1 = null;
    private ISchematicFeature m_schematicFeature2 = null;
    private bool m_createNode = true; //update when click on panel and on new
    private bool m_isClosed = false;
    private ESRI.ArcGIS.Framework.IApplication m_app;

    //For button OK to retrieve the coordinate of the digit feature
    private int m_x;
    private int m_y;

    private XmlElement m_curLink = null;
    private XmlElement m_curNode = null;
    private XmlNodeList m_relations = null;
    private ISchematicDataset m_schDataset = null;
    private ISchematicElementClassContainer m_schEltClassCont = null;
    private ISchematicElementClass m_schEltClass = null;
    private ISchematicInMemoryDiagram m_SchematicInMemoryDiagram = null;
    private bool m_autoClear = false;


    public DigitDockableWindow(object hook)
    {
      InitializeComponent();
      this.Hook = hook;
    }

    /// <summary>
    /// Host object of the dockable window
    /// </summary>
    private object Hook
    {
      get;
      set;
    }

    /// <summary>
    /// Implementation class of the dockable window add-in. It is responsible for 
    /// creating and disposing the user interface class of the dockable window.
    /// </summary>
    public class AddinImpl : ESRI.ArcGIS.Desktop.AddIns.DockableWindow
    {
      private DigitDockableWindow m_windowUI;

      public AddinImpl()
      {
      }

      protected override IntPtr OnCreateChild()
      {
        m_windowUI = new DigitDockableWindow(this.Hook);

        CurrentDigitTool.CurrentTool.digitDockableWindow = m_windowUI;

        if (CurrentDigitTool.CurrentTool.currentDigit != null)
        {
          m_windowUI.m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;
          m_windowUI.m_digitCommand.m_dockableDigit = m_windowUI;
        }
        else
        {
          // CurrentDigitTool.CurrentTool.CurrentDigit is null when we open ArcMap, but OnCreateChild
          // is called if the dockable window was shown during the last ArcMap session.
          ESRI.ArcGIS.Framework.IDockableWindowManager dockWinMgr = ArcMap.DockableWindowManager;
          UID u= new UID();
          u.Value = "DigitTool_DockableWindowCS";
          CurrentDigitTool.CurrentTool.currentDockableWindow = dockWinMgr.GetDockableWindow(u);
        }

        return m_windowUI.Handle;
      }

      protected override void Dispose(bool disposing)
      {
        if (m_windowUI != null)
          m_windowUI.Dispose(disposing);

        base.Dispose(disposing);
      }

    }

    public void Init(ISchematicLayer schematicLayer)
    {
      try
      {
        if (schematicLayer == null)
          return;

        m_schematicLayer = schematicLayer;
        XmlNode col = null;
        String myString = "";

        m_schDataset = schematicLayer.SchematicDiagram.SchematicDiagramClass.SchematicDataset;

        m_schEltClassCont = (ISchematicElementClassContainer)m_schDataset;
        m_SchematicInMemoryDiagram = schematicLayer.SchematicInMemoryDiagram;

        m_dom = new XmlDocument();

        ISchematicDiagram schematicDiagram;
        schematicDiagram = m_SchematicInMemoryDiagram.SchematicDiagram;

        // get the path of the xml file that contains the definitions of the digitize dockable window
        String path;

        ISchematicDiagramClass schematicDiagramClass = schematicDiagram.SchematicDiagramClass;
        ISchematicAttributeContainer schematicAttributeContainer = (ISchematicAttributeContainer)schematicDiagramClass;

        ISchematicAttribute schematicAttribute = schematicAttributeContainer.GetSchematicAttribute("DigitizePropertiesLocation", true);

        if (schematicAttribute == null)
        {
          System.Windows.Forms.MessageBox.Show("Need an attribute named DigitizePropertiesLocation in the corresponding DiagramTemplate attributes");
          return;
        }

        path = (string)schematicAttribute.GetValue((ISchematicObject)schematicDiagram);

        if (IsRelative(path)) //Concat the workspace's path with this path
        {
          //current workspace path
          ISchematicDataset myDataset = schematicDiagramClass.SchematicDataset;
          if (myDataset != null)
          {
            ISchematicWorkspace mySchematicWorkspace = myDataset.SchematicWorkspace;
            if (mySchematicWorkspace != null)
            {
              ESRI.ArcGIS.Geodatabase.IWorkspace myWorkspace = mySchematicWorkspace.Workspace;
              if (myWorkspace != null)
              {
                string workspacePath = myWorkspace.PathName;
                //add "..\" to path to step back one level...
                string stepBack = "..\\";
                path = stepBack + path;

                path = System.IO.Path.Combine(workspacePath, path);
              }
            }
          }
        }
        //else keep the original hard path

        XmlReader reader = XmlReader.Create(path);

        m_dom.Load(reader);

        //Load Nodes
        XmlNodeList nodes = m_dom.SelectNodes("descendant::NodeFeature");

        //Clear combo box after each call
        cboNodeType.Items.Clear();
        foreach (XmlElement node in nodes)
        {
          cboNodeType.Items.Add(node.GetAttribute("FeatureClassName").ToString());
        }


        //Load Links
        XmlNodeList links = m_dom.SelectNodes("descendant::LinkFeature");

        //Clear combo box after each call
        cboLinkType.Items.Clear();
        foreach (XmlElement link in links)
        {
          cboLinkType.Items.Add(link.GetAttribute("FeatureClassName").ToString());
        }

        col = m_dom.SelectSingleNode("descendant::MandatoryColor");
        if (col != null)
        {
          myString = "System.Drawing.";
          myString = col.InnerText.ToString();
          m_MandatoryColor = System.Drawing.Color.FromName(myString);
        }

        col = m_dom.SelectSingleNode("descendant::FormName");
        if (col != null)
        {
          myString = col.InnerText.ToString();
          Text = myString;
        }


        XmlNodeList rels = m_dom.SelectNodes("descendant::Relation");
        if (rels.Count > 0)
          m_relations = rels;

        col = m_dom.SelectSingleNode("descendant::AutoClearAfterCreate");
        if ((col != null) && col.InnerText.ToString() == "True")
          m_autoClear = true;

      }
      catch (System.Exception e)
      {
        System.Windows.Forms.MessageBox.Show(e.Message);
      }

      m_Panel1 = Splitter.Panel1;
      m_Panel2 = Splitter.Panel2;
      m_curPanel = Splitter.Panel1;
      lblMode.Text = "Create Node";
      m_loading = false;
      m_clickPanel = false;
      m_schEltClass = null;

    }

    public bool ValidateFields()
    {
      bool blnValidated = true;
      System.Windows.Forms.MaskedTextBox mctrl = null;
      string errors = "";

      //check all mandatory fields
      System.Windows.Forms.Control ctrl2;

      foreach (System.Windows.Forms.Control ctrl in m_curPanel.Controls)
      {
        ctrl2 = ctrl;
        if (ctrl2.GetType() == typeof(System.Windows.Forms.Label))
        {
        }
        //ignore labels
        else
        {
          if ((string)ctrl2.Tag == "Mandatory")
          {
            if (ctrl2.GetType() == typeof(System.Windows.Forms.MaskedTextBox))
            {
              mctrl = (System.Windows.Forms.MaskedTextBox)ctrl2;
              if (mctrl.MaskCompleted == false)
              {
                blnValidated = false;
                if (errors.Length > 0)
                  errors = "Incomplete mandatory field";
                else
                  errors = errors + "\n" + "Incomplete mandatory field";
              }
            }
            else
            {
              if (ctrl2.Text.Length <= 0)
              {
                blnValidated = false;
                if (errors.Length <= 0)
                  errors = "Incomplete mandatory field";
                else
                  errors = errors + "\n" + "Incomplete mandatory field";
              }
            }
          }


          //check masked edit controls
          if (ctrl2.GetType() == typeof(System.Windows.Forms.MaskedTextBox))
          {
            mctrl = (System.Windows.Forms.MaskedTextBox)ctrl2;
            //if they typed something, but didn't complete it, then error
            //if they typed nothing and it is not mandatory, then it is OK
            if ((mctrl.Text.Length > 0) && mctrl.Modified && (!mctrl.MaskCompleted))
            {
              blnValidated = false;
              if (errors.Length > 0)
                errors = "Invalid entry in a masked text field";
              else
                errors = errors + "\n" + "Invalid entry in a masked text field";
            }
          }

          //check link connections
          if (m_curPanel == Splitter.Panel2)
          {
            //make sure that the relation is correct if it exists
            XmlNodeList fields = m_curLink.SelectNodes("descendant::Field");
            foreach (XmlElement field in fields)
            {
              //find the field with a type of "Relation"
              if (field.GetAttribute("Type") == "Relation")
              {
                ESRI.ArcGIS.Geodatabase.IDataset pDataset1;
                ESRI.ArcGIS.Geodatabase.IDataset pDataset2;

                string FeatureClass1Name;
                string FeatureClass2Name;

                pDataset1 = (ESRI.ArcGIS.Geodatabase.IDataset)m_schematicFeature1.SchematicElementClass;
                pDataset2 = (ESRI.ArcGIS.Geodatabase.IDataset)m_schematicFeature2.SchematicElementClass;

                FeatureClass1Name = pDataset1.Name;
                FeatureClass2Name = pDataset2.Name;

                foreach (XmlElement rel in m_relations)
                {
                  //loop through the xml relations to match based on the from node and to node types

                  if ((rel.GetAttribute("FromType") == FeatureClass1Name) && (rel.GetAttribute("ToType") == FeatureClass2Name))
                  {
                    //find the control with the pick list for relationships
                    Control[] ctrls = m_curPanel.Controls.Find(field.GetAttribute("DBColumnName"), true);
                    if (ctrls.Length > 0)
                      ctrl2 = ctrls[0];

                    XmlNodeList vals = rel.SelectNodes("descendant::Value");
                    string myString = rel.GetAttribute("FromType") + "-" + rel.GetAttribute("ToType");
                    //validate that the current control string is correct
                    //if there are values, use them
                    bool blnfound = false;
                    if (vals.Count > 0)
                    {
                      foreach (XmlElement val in vals)
                      {
                        if (myString + "-" + val.InnerText.ToString() == ctrl2.Text)
                        {
                          blnfound = true;
                          break;
                        }
                        else
                          blnfound = false;
                      }
                      if (!blnfound)
                      {
                        blnValidated = false;
                        if (errors.Length > 0)
                          errors = "Invalid link connection";
                        else
                          errors = errors + "\n" + "Invalid link connection";
                      }
                    }
                    else
                    {
                      if (ctrl2.Text != myString)
                      {
                        blnValidated = false;
                        if (errors.Length > 0)
                          errors = "Invalid link connection";
                        else
                          errors = errors + "\n" + "Invalid link connection";
                      }
                    }

                    if (!blnfound) //fix connection list
                    {
                      XmlNodeList vlist = m_dom.SelectNodes("descendant::Relation");
                      XmlNodeList rellist = null;
                      System.Windows.Forms.ComboBox cboconn = (System.Windows.Forms.ComboBox)ctrl2;
                      cboconn.Items.Clear();
                      foreach (XmlElement v in vlist)
                      {
                        if ((v.GetAttribute("LinkType").ToString() == m_curLink.GetAttribute("FeatureClassName").ToString())
                          //make sure the node types are ok
                          && ((v.GetAttribute("FromType").ToString() == FeatureClass1Name && (v.GetAttribute("ToType").ToString() == FeatureClass2Name))))
                        {
                          rellist = v.SelectNodes("descendant::Value");
                          if (rellist.Count > 0)
                          {
                            foreach (XmlElement r in rellist)
                            {
                              myString = v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString() + "-" + r.InnerText.ToString();
                              cboconn.Items.Add(myString);
                            }
                          }
                          else //assume they are not using subtypes
                            cboconn.Items.Add(v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString());
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }

      if (errors.Length > 0)
      {

        if (m_curPanel == Splitter.Panel1)
        {
          btnOKPanel1.Visible = true;
          ErrorProvider1.SetError(btnOKPanel1, errors);
        }
        else
        {
          btnOKPanel2.Visible = true;
          ErrorProvider1.SetError(btnOKPanel2, errors);
        }
      }
      return blnValidated;

    }

    public void SelectionChanged()
    {

      try
      {
        System.Windows.Forms.Control ctrl = null;
        System.Windows.Forms.Control ctrl2 = null;
        Control[] ctrls = null;
        System.Collections.ArrayList ctrlstoremove = new System.Collections.ArrayList();
        string labelName = "";
        string featureClass = "";
        System.Windows.Forms.ComboBox cbo = null;
        System.Windows.Forms.Label lblMain = null;

        if (m_digitCommand == null)
          return;

        //clear any current elements
        if (m_schematicFeature1 != null)
        {
          m_schematicFeature1 = null;
          m_digitCommand.SchematicFeature1(m_schematicFeature1);
        }

        if (m_schematicFeature2 != null)
        {
          m_schematicFeature2 = null;
          m_digitCommand.SchematicFeature2(m_schematicFeature2);
        }

        if (m_curPanel == Splitter.Panel1)
        {
          labelName = "lblNodeLabel";
          featureClass = "descendant::NodeFeature";
          cbo = cboNodeType;
          lblMain = lblNodeLabel;
        }
        else
        {
          labelName = "lblLinkLabel";
          featureClass = "descendant::LinkFeature";
          cbo = cboLinkType;
          lblMain = lblLinkLabel;
        }

        foreach (System.Windows.Forms.Control ctrlfor in m_curPanel.Controls)
        {
          if (ctrlfor.Name.StartsWith("lbl") && (ctrlfor.Name.ToString() != labelName))
          {
            ctrls = m_curPanel.Controls.Find(ctrlfor.Name.Substring(3), true);
            ctrl2 = ctrls[0];
            ctrlstoremove.Add(ctrlfor);
            ctrlstoremove.Add(ctrl2);
          }
        }

        if (ctrlstoremove.Count > 0)
        {
          foreach (System.Windows.Forms.Control ctrol in ctrlstoremove)
          {
            m_curPanel.Controls.Remove(ctrol);
          }
        }

        XmlNodeList elems = null;
        m_curfrmWidth = m_curPanel.Width;
        elems = m_dom.SelectNodes(featureClass);

        bool blnFound = false;
        XmlElement elem = null;
        foreach (XmlElement elem0 in elems)
        {
          if (elem0.GetAttribute("FeatureClassName").ToString() == cbo.Text.ToString())
          {
            elem = elem0;
            blnFound = true;
            break;
          }
        }

        if (blnFound == false)
        {
          m_schEltClass = null;
          return;
        }

        if (m_curPanel == Splitter.Panel1)
          m_curNode = elem;
        else
          m_curLink = elem;

        //set grid
        elems = elem.SelectNodes("descendant::Field");
        int x = Splitter.Location.X;
        int y = lblMain.Location.Y + lblMain.Height + 5;

        System.Drawing.Point p = new System.Drawing.Point();

        foreach (XmlElement f in elems)
        {
          System.Windows.Forms.Label lbl = new System.Windows.Forms.Label();
          lbl.Name = "lbl" + f.GetAttribute("DBColumnName").ToString();
          lbl.Text = f.GetAttribute("DisplayName").ToString();
          lbl.AutoSize = true;
          m_curPanel.Controls.Add(lbl);
          p.X = 3;
          p.Y = y;
          lbl.Location = p;
          y = y + lbl.Height + 10;

          switch (f.GetAttribute("Type").ToString())
          {
            case "Text":
              System.Windows.Forms.TextBox tx = new System.Windows.Forms.TextBox();
              ctrl = tx;
              tx.Name = f.GetAttribute("DBColumnName").ToString();
              if (f.GetAttribute("Length").Length > 0)
                tx.MaxLength = System.Convert.ToInt32(f.GetAttribute("Length"));

              if (f.GetAttribute("Default").Length > 0)
                tx.Text = f.GetAttribute("Default");

              m_curPanel.Controls.Add(tx);
              break;

            case "Combo":

              System.Windows.Forms.ComboBox cb = new System.Windows.Forms.ComboBox();
              string defaulttext = "";
              ctrl = cb;
              cb.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
              cb.Name = f.GetAttribute("DBColumnName").ToString();
              XmlNodeList vlist = f.SelectNodes("descendant::Value");

              foreach (XmlElement v in vlist)
              {
                cb.Items.Add(v.InnerText.ToString());
                if (v.GetAttribute("Default").Length > 0)
                  defaulttext = v.InnerText;
              }

              if (defaulttext.Length > 0)
                cb.Text = defaulttext;

              m_curPanel.Controls.Add(cb);
              break;

            case "MaskText":
              System.Windows.Forms.MaskedTextBox MaskControl = new System.Windows.Forms.MaskedTextBox();
              ctrl = MaskControl;
              string mask = "";
              MaskControl.Name = f.GetAttribute("DBColumnName").ToString();
              if (f.GetAttribute("Mask").Length > 0)
                mask = f.GetAttribute("Mask");
              else
                mask = "";

              MaskControl.Mask = mask;

              if (f.GetAttribute("Default").Length > 0)
                MaskControl.Text = f.GetAttribute("Default");

              MaskControl.Modified = false;
              m_curPanel.Controls.Add(MaskControl);
              MaskControl.TextChanged += new System.EventHandler(MaskedTextBox);

              break;

            case "Number":
              System.Windows.Forms.MaskedTextBox MaskControl2 = new System.Windows.Forms.MaskedTextBox();
              ctrl = MaskControl2;
              string mask2 = "";
              MaskControl2.Name = f.GetAttribute("DBColumnName").ToString();
              int i = 1;
              if (f.GetAttribute("Length").Length > 0)
              {
                for (i = 1; i <= System.Convert.ToInt32(f.GetAttribute("Length")); i++)
                  mask = mask2 + "9";
              }
              else
              {
                if (f.GetAttribute("Mask").Length > 0)
                  mask2 = f.GetAttribute("Mask");
                else
                  mask2 = "";
              }

              MaskControl2.Mask = mask2;
              if (f.GetAttribute("Default").Length > 0)
                MaskControl2.Text = f.GetAttribute("Default");

              MaskControl2.Modified = false;
              m_curPanel.Controls.Add(MaskControl2);
              MaskControl2.TextChanged += new System.EventHandler(MaskedTextBox);
              break;

            case "Date":
              System.Windows.Forms.DateTimePicker dt = new System.Windows.Forms.DateTimePicker();
              ctrl = dt;
              dt.Name = f.GetAttribute("DBColumnName").ToString();
              dt.Value = DateTime.Now;
              dt.Format = System.Windows.Forms.DateTimePickerFormat.Short;
              m_curPanel.Controls.Add(dt);
              break;

            case "Relation":
              System.Windows.Forms.ComboBox cb2 = new System.Windows.Forms.ComboBox();
              ctrl = cb2;
              cb2.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
              cb2.Name = f.GetAttribute("DBColumnName").ToString();
              XmlNodeList vlist2 = m_dom.SelectNodes("descendant::Relation");
              XmlNodeList rellist = null;
              string str = null;
              foreach (XmlElement v in vlist2)
              {
                if (v.GetAttribute("LinkType").ToString() == elem.GetAttribute("FeatureClassName").ToString())
                {
                  rellist = v.SelectNodes("descendant::Value");
                  if (rellist.Count > 0)
                    foreach (XmlElement r in rellist)
                    {
                      str = v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString() + "-" + r.InnerText.ToString();
                      cb2.Items.Add(str);
                    }
                  else //assume they are not using subtypes
                    cb2.Items.Add(v.GetAttribute("FromType").ToString() + "-" + v.GetAttribute("ToType").ToString());
                }
              }
              //relations are always mandatory
              ctrl.BackColor = m_MandatoryColor;
              ctrl.Tag = "Mandatory";
              m_curPanel.Controls.Add(cb2);
              break;
          }

          if (f.GetAttribute("Mandatory").ToString() == "True")
          {
            ctrl.BackColor = m_MandatoryColor;
            ctrl.Tag = "Mandatory";
          }
        }
        ResizeForm();

        // set m_schEltClass
        XmlElement curElement = null;

        if (m_curPanel == Splitter.Panel1)
          curElement = m_curNode;
        else
          curElement = m_curLink;

        if (m_schEltClass == null)
          m_schEltClass = m_schEltClassCont.GetSchematicElementClass(curElement.GetAttribute("FeatureClassName"));
        else
          if (m_schEltClass.Name != curElement.GetAttribute("FeatureClassName"))
            m_schEltClass = m_schEltClassCont.GetSchematicElementClass(curElement.GetAttribute("FeatureClassName"));
      }

      catch (System.Exception e)
      {
        System.Windows.Forms.MessageBox.Show(e.Message);
      }
    }

    public bool CheckValidFeature(bool blnFromNode)
    {
      if (m_curLink == null)
        return false;

      XmlNodeList fields = m_curLink.SelectNodes("descendant::Field");

      foreach (XmlElement field in fields)
      {
        if (field.GetAttribute("Type") == "Relation")
        {
          foreach (XmlElement rel in m_relations)
          {
            if (blnFromNode)
            {
              if (m_schematicFeature1 == null)
                return false;

              if (rel.GetAttribute("FromType") == m_schematicFeature1.SchematicElementClass.Name)
                return true;
            }
            else
            {
              if (m_schematicFeature2 == null)
                return false;

              if (rel.GetAttribute("ToType") == m_schematicFeature2.SchematicElementClass.Name)
                return true;
            }
          }
          return false;
        }
      }
      return true;
    }

    public void FillValue(ref ISchematicFeature schFeature)
    {
      try
      {
        if (m_schEltClass == null)
          throw new Exception("Error getting Feature Class");

        int fldIndex;

        foreach (System.Windows.Forms.Control ctrl in m_curPanel.Controls)
        {
          if (!((ctrl.GetType() == typeof(System.Windows.Forms.Label)) || (ctrl.Name == "cboNodeType")))
          {
            if ((ctrl.GetType() == typeof(System.Windows.Forms.TextBox)) || (ctrl.GetType() == typeof(System.Windows.Forms.ComboBox)))
            {
              if (ctrl.Text.Length > 0)
              {
                //insert in DB
                fldIndex = schFeature.Fields.FindField(ctrl.Name);
                if (fldIndex > -1)
                {
                  schFeature.set_Value(fldIndex, ctrl.Text);
                  schFeature.Store();
                }
              }
            }
            else if (ctrl.GetType() == typeof(System.Windows.Forms.DateTimePicker))
            {
              fldIndex = schFeature.Fields.FindField(ctrl.Name);
              if (fldIndex > -1)
              {
                schFeature.set_Value(fldIndex, ctrl.Text);
                schFeature.Store();
              }
            }
            else if (ctrl.GetType() == typeof(System.Windows.Forms.MaskedTextBox))
            {
              System.Windows.Forms.MaskedTextBox mctrl = (System.Windows.Forms.MaskedTextBox)ctrl;
              if ((mctrl.Text.Length > 0) && (mctrl.Modified) && (mctrl.MaskCompleted))
              {

                fldIndex = schFeature.Fields.FindField(ctrl.Name);
                if (fldIndex > -1)
                {
                  schFeature.set_Value(fldIndex, ctrl.Text);
                  schFeature.Store();
                }
              }
            }
          }
        }

        return;
      }

      catch (System.Exception e)
      {
        System.Windows.Forms.MessageBox.Show(e.Message);
      }
    }

    private void ResizeForm()
    {
      try
      {
        System.Windows.Forms.Control ctr2;
        Control[] ctrls = null;
        System.Drawing.Point p = new System.Drawing.Point();
        //handle panel 1
        foreach (System.Windows.Forms.Control ctr in Splitter.Panel1.Controls)
        {
          if ((ctr.Name.StartsWith("lbl")) && (ctr.Name.ToString() != "lblNodeLabel"))
          {
            ctrls = Splitter.Panel1.Controls.Find(ctr.Name.Substring(3), true);
            if (ctrls.GetLength(0) > 0)
            {
              ctr2 = ctrls[0];

              p.Y = ctr.Location.Y;
              p.X = ctr.Width + 3;
              ctr2.Location = p;
              ctr2.Width = Splitter.Panel1.Width - ctr.Width - 5;
            }
          }
        }

        Splitter.Panel1.Refresh();
        //handle panel 2
        foreach (System.Windows.Forms.Control ctr in Splitter.Panel2.Controls)
        {
          if ((ctr.Name.StartsWith("lbl")) && (ctr.Name.ToString() != "lblLinkLabel"))
          {
            ctrls = Splitter.Panel2.Controls.Find(ctr.Name.Substring(3), true);
            if (ctrls.GetLength(0) > 0)
            {
              ctr2 = ctrls[0];
              p.Y = ctr.Location.Y;
              p.X = ctr.Width + 3;
              ctr2.Location = p;
              ctr2.Width = Splitter.Panel2.Width - ctr.Width - 5;
            }
          }
        }

        Splitter.Panel2.Refresh();
      }
      catch (System.Exception e)
      {
        System.Windows.Forms.MessageBox.Show(e.Message);
      }
    }

    private void cboType_SelectedIndexChanged(Object sender, System.EventArgs e)
    {
      SelectionChanged();
    }

    public void cboLinkType_SelectedIndexChanged(Object sender, System.EventArgs e)
    {
      SelectionChanged();
    }

    private void MaskedTextBox(Object sender, System.EventArgs e)
    {
      System.Windows.Forms.MaskedTextBox mctrl = (System.Windows.Forms.MaskedTextBox)sender;
      mctrl.Modified = true;
    }

    /// <summary>
    /// m_createNode is true when the active panel is the one that digitize nodes.
    /// </summary>
    /// <returns></returns>
    public bool CreateNode()
    {
      return m_createNode;
    }

    public bool AutoClear()
    {
      return m_autoClear;
    }

    public bool IsClosed()
    {
      return m_isClosed;
    }

    public ISchematicElementClass FeatureClass()
    {
      return m_schEltClass;
    }

    public void x(int x)
    {
      m_x = x;
      return;
    }

    public void y(int y)
    {
      m_y = y;
      return;
    }

    public void SchematicFeature1(ISchematicFeature schematicFeature)
    {
      m_schematicFeature1 = schematicFeature;
      return;
    }

    public void SchematicFeature2(ISchematicFeature schematicFeature)
    {
      m_schematicFeature2 = schematicFeature;
      return;
    }

    public void FrmApplication(ESRI.ArcGIS.Framework.IApplication app)
    {
      m_app = app;
      return;
    }

    private void Splitter_Panel2_Click(object sender, EventArgs e)
    {
      if (m_digitCommand == null)
        m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;

      if (m_digitCommand == null)
        return;
      
      m_createNode = false;

      if (m_curPanel != Splitter.Panel2)
      {

        m_curPanel = Splitter.Panel2;
        foreach (System.Windows.Forms.Control ctrl in Splitter.Panel1.Controls)
          ctrl.Enabled = false;

        foreach (System.Windows.Forms.Control ctrl in Splitter.Panel2.Controls)
          ctrl.Enabled = true;

        lblMode.Text = "Create Link";

        if (m_schematicFeature1 != null)
        {
          m_schematicFeature1 = null;
          m_digitCommand.SchematicFeature1(m_schematicFeature1);
        }

        if (m_schematicFeature2 != null)
        {
          m_schematicFeature2 = null;
          m_digitCommand.SchematicFeature2(m_schematicFeature2);
        }

        if (m_curPanel == Splitter.Panel1)
        {
          btnOKPanel1.Visible = false;
          ErrorProvider1.SetError(btnOKPanel1, "");
        }
        else
        {
          btnOKPanel2.Visible = false;
          ErrorProvider1.SetError(btnOKPanel2, "");
        }

        System.EventArgs e2 = new System.EventArgs();
        cboLinkType_SelectedIndexChanged(sender, e2);

      }

    }

    private void Splitter_Panel1_Click(object sender, EventArgs e)
    {
      if (m_digitCommand == null)
        m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;

      if (m_digitCommand != null)
        m_digitCommand.EndFeedBack();

      m_createNode = true;

      if (m_curPanel != Splitter.Panel1 || m_clickPanel == false)
      {
        m_clickPanel = true;
        m_curPanel = Splitter.Panel1;

        foreach (System.Windows.Forms.Control ctrl in Splitter.Panel2.Controls)
          ctrl.Enabled = false;

        foreach (System.Windows.Forms.Control ctrl in Splitter.Panel1.Controls)
          ctrl.Enabled = true;

        lblMode.Text = "Create Node";

        if (m_curPanel == Splitter.Panel1)
        {
          btnOKPanel1.Visible = false;
          ErrorProvider1.SetError(btnOKPanel1, "");
        }
        else
        {
          btnOKPanel2.Visible = false;
          ErrorProvider1.SetError(btnOKPanel2, "");
        }
        System.EventArgs e2 = new System.EventArgs();
        cboType_SelectedIndexChanged(sender, e2);
      }
    }

    private void btnOKPanel1_Click(object sender, EventArgs e)
    {
      //try to create the node at the original point
      if (m_digitCommand != null)
        m_digitCommand.MyMouseUp(m_x, m_y);

      ErrorProvider1.SetError(btnOKPanel1, "");
      btnOKPanel1.Visible = false;
    }

    private void btnOKPanel2_Click(object sender, EventArgs e)
    {
      //try to create the link with the original points
      if (m_digitCommand != null)
        m_digitCommand.MyMouseUp(m_x, m_y);

      ErrorProvider1.SetError(btnOKPanel1, "");
      btnOKPanel1.Visible = false;
    }

    private void WindowVisibleChange(object sender, EventArgs e)
    {

      if (m_digitCommand == null)
        m_digitCommand = CurrentDigitTool.CurrentTool.currentDigit;

      if (m_digitCommand == null)
        return;

      if ((this.Visible) && CurrentDigitTool.CurrentTool.currentDockableWindow.IsVisible())
      {      
        if (!(m_digitCommand.FromDeactivate()))
        {
          ESRI.ArcGIS.Framework.IApplication app = (ESRI.ArcGIS.Framework.IApplication) this.Hook;
          app.CurrentTool = null;
        }
      }
      m_digitCommand.EndFeedBack();
      m_digitCommand.FromDeactivate(false);
    }
    
    private void DigitWindow_Resize(object sender, EventArgs e)
    {
      if (!m_loading)
        ResizeForm();
    }
     

    //IsRelative return true when the path start with "."
    private bool IsRelative(string path)
    {
      bool startwith = path.StartsWith(".");
      return startwith;
    }

  }
}