Files
SourceCode/PROMS/VEPROMS.CSLA.Library/VEObjects/VETreeNode.cs
T

449 lines
18 KiB
C#

using System;
using System.Windows.Forms;
using System.Collections;
using System.Reflection;
namespace VEPROMS.CSLA.Library
{
public delegate void VETreeNodeEvent(object sender, VETreeNodeEventArgs args);
public class VETreeNodeEventArgs : EventArgs
{
public VETreeNodeEventArgs() { ; }
public VETreeNodeEventArgs(string info) => Info = info;
public VETreeNodeEventArgs(int value) => Value = value;
public VETreeNodeEventArgs(string info, int value)
{
Info = info;
Value = value;
}
public int Value { get; set; }
public string Info { get; set; }
}
public class VETreeNode : TreeNode
{
#region Events
private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public event VETreeNodeEvent LoadingChildrenSQL;
public event VETreeNodeEvent LoadingChildrenMax;
public event VETreeNodeEvent LoadingChildrenValue;
public event VETreeNodeEvent LoadingChildrenDone;
private void OnLoadingChildrenSQL(object sender, VETreeNodeEventArgs args) => LoadingChildrenSQL?.Invoke(sender, args);
private void OnLoadingChildrenMax(object sender, VETreeNodeEventArgs args) => LoadingChildrenMax?.Invoke(sender, args);
private void OnLoadingChildrenValue(object sender, VETreeNodeEventArgs args) => LoadingChildrenValue?.Invoke(sender, args);
private void OnLoadingChildrenDone(object sender, VETreeNodeEventArgs args) => LoadingChildrenDone?.Invoke(sender, args);
#endregion
#region Business Methods
protected IVEDrillDownReadOnly _VEObject;
public IVEDrillDownReadOnly VEObject
{
get { return _VEObject; }
set
{
_VEObject = value;
base.Text = _VEObject.ToString();
ResetNode("Dummy Set_VEObject");
}
}
// Only load the Children Once
protected bool _ChildrenLoaded = false;
public bool ChildrenLoaded
{
get { return _ChildrenLoaded; }
set { _ChildrenLoaded = value; }
}
protected bool _MovedToSeparateWindow = false; // C2015-022 tells us this tree node and childern are now in a child window (separate Window) - used on Parent window side for a folder context menu
public bool MovedToSeparateWindow
{
get { return _MovedToSeparateWindow; }
set { _MovedToSeparateWindow = value; }
}
protected bool _InChildWindow = false; // C2015-022 tells us this tree node is in the child window - used on child window side for folder context menu
public bool InChildWindow
{
get { return _InChildWindow; }
set { _InChildWindow = value; }
}
private void SetProperty(string name)
{
PropertyInfo propertyInfoObj = _VEObject.GetType().GetProperty(name);
if (propertyInfoObj == null) return;
PropertyInfo propertyInfoThis = GetType().GetProperty(name);
if (propertyInfoThis == null) return;
try
{
propertyInfoThis.SetValue(this, propertyInfoObj.GetValue(_VEObject, null), null);
}
catch (Exception ex)
{
Console.WriteLine("Error: {0}", ex.Message);
}
}
public void ResetNode(string dummy)
{
if (_VEObject!=null && _VEObject.HasChildren && _ChildrenLoaded == false && CheckForParts())
{
_ChildrenLoaded = false;// Reset the children loaded flag
Nodes.Add(dummy);// Add a Dummy Node so that the item will appear to be expanable.
}
else
{
_ChildrenLoaded = true;// Reset the children loaded flag
}
if (base.Text != _VEObject.ToString()) base.Text = _VEObject.ToString();
SetProperty("ForeColor");
SetProperty("BackColor");
SetProperty("ImageIndex");
SetProperty("IsVisible");
SetProperty("SelectedImageIndex");
// ToDo: Need to reset object as well
}
private bool CheckForParts()
{
if (_allParts) return true;
// only has 'children' if parts are steps or sections
if (_VEObject.GetType() == typeof(StepInfo) || _VEObject.GetType() == typeof(SectionInfo) || _VEObject.GetType() == typeof(ItemInfo))
{
IList ol = ((ItemInfo)_VEObject).GetChildren(_allParts);
if (ol == null || ol.Count == 0) return false;
}
return true;
}
public void RefreshNode()
{
ResetNode("Dummy RefreshNode");// Drop Children
LoadChildren();// Load Children
}
public static VETreeNode GetFolder(int folderID)
{
VETreeNode tn = new VETreeNode(FolderInfo.Get(folderID));
//tn.Nodes.Add("Dummy");
tn.ResetNode("Dummy GetFolder");
return tn;
}
public virtual void LoadChildren() => LoadChildren(true);
private bool _allParts = true;
private bool _excludeTablesFigsEqu = false; // used for inserting Step Text transitions (BNPP)
public virtual void LoadChildren(bool allParts, bool excldTablesFigEq = false)
{
_allParts = allParts;
// B2024-019 don't show Tables, Figures, or Equations in step tree when inserting Text Transitions
_excludeTablesFigsEqu = excldTablesFigEq;
if (!_ChildrenLoaded)
{
Nodes.Clear();
DateTime tStart = DateTime.Now;
OnLoadingChildrenSQL(this, new VETreeNodeEventArgs());
IList ol;
if (_VEObject is ItemInfo item) item.RefreshItemParts();
if (_VEObject.GetType() == typeof(StepInfo) || _VEObject.GetType() == typeof(SectionInfo) || _VEObject.GetType() == typeof(ItemInfo))
ol = ((ItemInfo)_VEObject).GetChildren(allParts);
else
ol = _VEObject.GetChildren();
if (ol != null)
{
OnLoadingChildrenMax(this, new VETreeNodeEventArgs(ol.Count));
if (TreeView != null) TreeView.BeginUpdate();
else _MyLog.WarnFormat("TreeView.BeginUpdate - Null");
ExpandChildren(ol);
if (TreeView != null) TreeView.EndUpdate();
else _MyLog.WarnFormat("TreeView.EndUpdate - Null");
}
_ChildrenLoaded = true;
OnLoadingChildrenDone(this, new VETreeNodeEventArgs(TimeSpan.FromTicks(DateTime.Now.Ticks - tStart.Ticks).TotalSeconds.ToString()));
}
}
private void ExpandChildren(IList ol)
{
int icnt = 0;
bool lastWasSection = false;
foreach (IVEDrillDownReadOnly o in ol)
{
OnLoadingChildrenValue(this, new VETreeNodeEventArgs(++icnt));
try
{
bool skipIt = false;
bool isStepPart = (o is PartInfo && (o as PartInfo).PartType == E_FromType.Step);
if (isStepPart)
{
// get parent section and see if it has the Editable flag set. Only skip
// if this flag is set to "N".
ItemInfo sectInfo = (ItemInfo)(o as PartInfo).ActiveParent;
bool hasMetaSubs = sectInfo != null && sectInfo.Sections != null && sectInfo.Sections.Count > 0;
bool editSteps = !hasMetaSubs || (sectInfo.MyConfig is SectionConfig && (sectInfo.MyConfig as SectionConfig).SubSection_Edit == "Y");
if (!editSteps) skipIt = true;
}
if (!skipIt)
{
VETreeNode tmp = new VETreeNode(o, _allParts);
// B2024-019 don't show Tables, Figures, or Equations in step tree when inserting Text Transitions
bool isTableFigEqu = tmp.Text.Equals("Table") ||
tmp.Text.Equals("Figure") ||
tmp.Text.Equals("Equation");
if (o.HasChildren)
{
if (o is PartInfo)
{
tmp.Nodes.Clear();
tmp.ExpandChildren(o.GetChildren());
tmp._ChildrenLoaded = true;
}
}
else
tmp._ChildrenLoaded = true;// Reset the children loaded flag
if (lastWasSection)
Nodes.Insert(0, tmp);
// B2024-019 don't show Tables, Figures, or Equations in step tree when inserting Text Transitions
else if (!_excludeTablesFigsEqu || !isTableFigEqu)
Nodes.Add(tmp);
// if last thing was section & this is step, do insert - i.e. so that steps go before sections.
lastWasSection = (o is PartInfo && (o as PartInfo).PartType == E_FromType.Section);
}
}
catch (Exception ex)
{
Console.WriteLine("{0}\r\n{1}", ex.Message, ex.InnerException);
}
}
}
private void TVAddChildren(IVEDrillDownReadOnly veobj, VETreeNode tn)
{
OnLoadingChildrenSQL(tn, new VETreeNodeEventArgs());
IList ol;
if (veobj.GetType() == typeof(StepInfo) || veobj.GetType() == typeof(SectionInfo) || veobj.GetType() == typeof(ItemInfo))
ol = ((ItemInfo)veobj).GetChildren(true);
else
ol = veobj.GetChildren();
if (ol != null)
{
OnLoadingChildrenMax(this, new VETreeNodeEventArgs(ol.Count));
TreeView.BeginUpdate();
int icnt = 0;
foreach (IVEDrillDownReadOnly o in ol)
{
OnLoadingChildrenValue(this, new VETreeNodeEventArgs(++icnt));
try
{
VETreeNode tmp = new VETreeNode(o);
PartInfo pi = o as PartInfo;
if (pi == null && o.HasChildren)
tmp.Nodes.Add("Dummy");// Add a Dummy Node so that the item will appear to be expanable.
else
tmp._ChildrenLoaded = true;// Reset the children loaded flag
tn.Nodes.Add(tmp);
if (pi != null && o.HasChildren)
TVAddChildren(o, tmp);
}
catch (Exception ex)
{
Console.WriteLine("{0}\r\n{1}", ex.Message, ex.InnerException);
}
}
TreeView.EndUpdate();
}
}
void myItemInfo_Deleted(object sender)
{
if (!(Parent is VETreeNode parnode)) return;
Remove();
// get rid of 'Steps', 'RNOs', i.e. grouping nodes, if there are no children.
if (parnode.VEObject is PartInfo && parnode.Nodes.Count == 0)
{
parnode.Remove();
// if only 'Steps' node is left, move steps 'up' a level.
if (parnode.Parent is VETreeNode grndparnode && grndparnode.Nodes.Count == 1)
{
VETreeNode sibnode = grndparnode.Nodes[0] as VETreeNode;
if (sibnode.VEObject is PartInfo pisib && (pisib.ToString() == "Steps"))
{
if (!sibnode.ChildrenLoaded) sibnode.LoadChildren();
while (sibnode.Nodes.Count > 0)
{
VETreeNode tmp = sibnode.Nodes[0] as VETreeNode;
tmp.Remove();
grndparnode.Nodes.Add(tmp);
}
sibnode.Remove();
}
}
}
}
#endregion
#region Factory Methods
// Constructors
public VETreeNode() : base("NoText") { ; }
public VETreeNode(IVEDrillDownReadOnly o, bool allParts)
: base(o.ToString())
{
_allParts = allParts;
_VEObject = o;// Save the BusinessObject
ResetNode("Dummy VETreeNode(IVEDrillDownReadOnly o)");
if (o is ItemInfo myItemInfo)
{
myItemInfo.Deleted -= new ItemInfoEvent(myItemInfo_Deleted);
myItemInfo.Deleted += new ItemInfoEvent(myItemInfo_Deleted);
myItemInfo.ChildrenDeleted -= new ItemInfoEvent(myItemInfo_ChildrenDeleted);
myItemInfo.ChildrenDeleted += new ItemInfoEvent(myItemInfo_ChildrenDeleted);
myItemInfo.MyContent.Changed -= new ContentInfoEvent(NodeText_Changed);
myItemInfo.MyContent.Changed += new ContentInfoEvent(NodeText_Changed);
myItemInfo.OrdinalChanged -= new ItemInfoEvent(NodeText_Changed);
myItemInfo.OrdinalChanged += new ItemInfoEvent(NodeText_Changed);
myItemInfo.NewSiblingAfter -= new ItemInfoInsertEvent(myItemInfo_NewSiblingAfter);
myItemInfo.NewSiblingAfter += new ItemInfoInsertEvent(myItemInfo_NewSiblingAfter);
myItemInfo.NewSiblingBefore -= new ItemInfoInsertEvent(myItemInfo_NewSiblingBefore);
myItemInfo.NewSiblingBefore += new ItemInfoInsertEvent(myItemInfo_NewSiblingBefore);
myItemInfo.NewChild -= new ItemInfoInsertEvent(myItemInfo_NewChild);
myItemInfo.NewChild += new ItemInfoInsertEvent(myItemInfo_NewChild);
}
}
void NodeText_Changed(object sender)
{
Text = _VEObject.ToString();
ItemInfo myItemInfo = _VEObject as ItemInfo;
if (myItemInfo != null && myItemInfo.MyDocVersion.DocVersionConfig.SelectedSlave > 0)
{
int k = myItemInfo.MyDocVersion.DocVersionConfig.SelectedSlave;
myItemInfo.MyDocVersion.DocVersionConfig.SelectedSlave = 0;
Text = myItemInfo.ToString();
myItemInfo.MyDocVersion.DocVersionConfig.SelectedSlave = k;
}
if (myItemInfo != null && myItemInfo.IsSection)
{
myItemInfo.RefreshConfig();
// check if metasection & has subsections. This could be a change in config
// item, i.e. Editable Data, that would add or remove any step nodes, i.e. requires a
// tree refresh.
if (myItemInfo.Sections != null && myItemInfo.Sections.Count > 0 && myItemInfo.ActiveFormat.PlantFormat.FormatData.SectData.UseMetaSections)
{
// see if change in children tree nodes.
Nodes.Clear();
_ChildrenLoaded = false;
LoadChildren(true);
}
}
}
public VETreeNode(IVEDrillDownReadOnly o)
: base(o.ToString())
{
_VEObject = o;// Save the BusinessObject
ResetNode("Dummy VETreeNode(IVEDrillDownReadOnly o)");
if (o is ItemInfo myItemInfo)
{
myItemInfo.Deleted -= new ItemInfoEvent(myItemInfo_Deleted);
myItemInfo.Deleted += new ItemInfoEvent(myItemInfo_Deleted);
myItemInfo.ChildrenDeleted -= new ItemInfoEvent(myItemInfo_ChildrenDeleted);
myItemInfo.ChildrenDeleted += new ItemInfoEvent(myItemInfo_ChildrenDeleted);
myItemInfo.MyContent.Changed -= new ContentInfoEvent(NodeText_Changed);
myItemInfo.MyContent.Changed += new ContentInfoEvent(NodeText_Changed);
myItemInfo.OrdinalChanged -= new ItemInfoEvent(NodeText_Changed);
myItemInfo.OrdinalChanged += new ItemInfoEvent(NodeText_Changed);
myItemInfo.NewSiblingAfter -= new ItemInfoInsertEvent(myItemInfo_NewSiblingAfter);
myItemInfo.NewSiblingAfter += new ItemInfoInsertEvent(myItemInfo_NewSiblingAfter);
myItemInfo.NewSiblingBefore -= new ItemInfoInsertEvent(myItemInfo_NewSiblingBefore);
myItemInfo.NewSiblingBefore += new ItemInfoInsertEvent(myItemInfo_NewSiblingBefore);
myItemInfo.NewChild -= new ItemInfoInsertEvent(myItemInfo_NewChild);
myItemInfo.NewChild += new ItemInfoInsertEvent(myItemInfo_NewChild);
}
}
void myItemInfo_ChildrenDeleted(object sender)
{
//Console.WriteLine("Fix Children");
ItemInfo myItemInfo = VEObject as ItemInfo;
//if (Nodes.Count > 1)
// Console.WriteLine("{0}, {1}",Nodes[0], Nodes[1]);
if (!myItemInfo.HasChildren && Nodes.Count>0 && !(Nodes[0] is VETreeNode))
Nodes.Clear();
}
void myItemInfo_NewChild(object sender, ItemInfoInsertEventArgs args)
{
if (args.ItemInserted.NextItem != null) // insert before
{
int nextItemID = args.ItemInserted.NextItem.ItemID;
VETreeNode nextNode = FindChildOrGrandChild(nextItemID);
nextNode?.myItemInfo_NewSiblingBefore(sender, args);
return;
}
if (args.ItemInserted.MyPrevious != null) // insert after
{
int prevItemID = args.ItemInserted.MyPrevious.ItemID;
VETreeNode prevNode = FindChildOrGrandChild(prevItemID);
prevNode.myItemInfo_NewSiblingAfter(sender, args);
return;
}
bool isExpanded = IsExpanded;
// Restore the tree as it currently is expanded.
Collapse();
Nodes.Clear();
_ChildrenLoaded = false;
ResetNode("Dummy myItemInfo_NewChild");
if (isExpanded && VEObject is ItemInfo item && item.MyContent.ContentPartCount > 1) // || args.ItemInserted.NextItem != null || args.ItemInserted.MyPrevious != null))
Expand();
else
Collapse();
}
private VETreeNode FindChildOrGrandChild(int itemID)
{
foreach (TreeNode childNode in Nodes)
{
if (childNode is VETreeNode child)
{
if (child.VEObject is ItemInfo item && item.ItemID == itemID)
return child;
}
}
foreach (TreeNode childNode in Nodes)
{
if (childNode is VETreeNode child && child.VEObject is PartInfo)
foreach (VETreeNode grandchild in child.Nodes)
{
if (grandchild.VEObject is ItemInfo item && item.ItemID == itemID)
return grandchild;
}
}
return null;
}
void myItemInfo_NewSiblingBefore(object sender, ItemInfoInsertEventArgs args)
{
if (Parent != null) // Only do this if the node has a parent - RHM 20100106
{
if (!(args.ItemInserted is ItemInfo ii))
Parent.Nodes.Insert(Index, (new VETreeNode(args.ItemInserted)));
else // B2020-142: Can't get properties of restored item (no treeview context menu would be correct after restore)
{
if (ii.IsProcedure) Parent.Nodes.Insert(Index, (new VETreeNode(ProcedureInfo.Get(ii.ItemID))));
if (ii.IsSection) Parent.Nodes.Insert(Index, (new VETreeNode(SectionInfo.Get(ii.ItemID))));
if (ii.IsStep) Parent.Nodes.Insert(Index, (new VETreeNode(StepInfo.Get(ii.ItemID))));
}
}
}
void myItemInfo_NewSiblingAfter(object sender, ItemInfoInsertEventArgs args)
{
if (Parent != null) // Only do this if the node has a parent - RHM 20100106
{
if (!(args.ItemInserted is ItemInfo ii))
Parent.Nodes.Insert(Index + 1, (new VETreeNode(args.ItemInserted)));
else // B2020-142: Can't get properties of restored item (no treeview context menu would be correct after restore)
{
if (ii.IsProcedure) Parent.Nodes.Insert(Index + 1, (new VETreeNode(ProcedureInfo.Get(ii.ItemID))));
if (ii.IsSection) Parent.Nodes.Insert(Index + 1, (new VETreeNode(SectionInfo.Get(ii.ItemID))));
if (ii.IsStep) Parent.Nodes.Insert(Index + 1, (new VETreeNode(StepInfo.Get(ii.ItemID))));
}
}
}
public VETreeNode(string s)
: base(s)
{
_VEObject = null;// Save the BusinessObject
}
#endregion
}
}