811 lines
22 KiB
C#

/*********************************************************************************************
* Copyright 2004 - Volian Enterprises, Inc. All rights reserved.
* Volian Enterprises - Proprietary Information - DO NOT COPY OR DISTRIBUTE
* ------------------------------------------------------------------------------
* $Workfile: VEObject.cs $ $Revision: 9 $
* $Author: Jsj $ $Date: 8/30/06 10:04a $
*
* $History: VEObject.cs $
*
* ***************** Version 9 *****************
* User: Jsj Date: 8/30/06 Time: 10:04a
* Updated in $/LibSource/VEObject
* Added Multi Procedure Data Checker
*
* ***************** Version 8 *****************
* User: Kathy Date: 6/21/05 Time: 7:27a
* Updated in $/LibSource/VEObject
* edit for approve if from procset/procedures node
*
* ***************** Version 7 *****************
* User: Kathy Date: 5/11/05 Time: 9:29a
* Updated in $/LibSource/VEObject
* approve menu from procedures tree node
*
* ***************** Version 6 *****************
* User: Kathy Date: 4/21/05 Time: 10:24a
* Updated in $/LibSource/VEObject
* remove upgrade2005 define
*
* ***************** Version 5 *****************
* User: Kathy Date: 3/22/05 Time: 10:14a
* Updated in $/LibSource/VEObject
* approve: remove revise menu enable
*
* ***************** Version 4 *****************
* User: Kathy Date: 2/03/05 Time: 11:20a
* Updated in $/LibSource/VEObject
* Change 'DUMMY' node to 'TEMP' node (just in case user sees it)
*
* ***************** Version 3 *****************
* User: Kathy Date: 1/31/05 Time: 11:06a
* Updated in $/LibSource/VEObject
* Fix B2005-005 (connection & delete directory errors). also, fix icon
*
* ***************** Version 2 *****************
* User: Kathy Date: 10/25/04 Time: 10:24a
* Updated in $/LibSource/VEObject
* Fix B2004-049
*
* ***************** Version 1 *****************
* User: Kathy Date: 7/27/04 Time: 8:53a
* Created in $/LibSource/VEObject
*********************************************************************************************/
using System;
using System.Text;
using System.Collections;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using Utils;
using VENetwork;
using VEMessageNS;
namespace VEObject
{
/// <summary>
/// VEObject namespace provides classes for the Volian Enterprises Objects DataRoot, DataPath,
/// Plant, Procedure Set, Procedures, Library Documents and Archives.
///
/// This file has the base class, VEO_Base, which all other objects inherits from.
/// </summary>
public enum VEObjectTypesDefs
{
Generic = 0, ProcedureSet = 1, Procedure = 2, Archive = 3, LibraryDoc =4, System = 5, Plant = 6, DummySet = 7
};
public enum VEO_IconStates
{
Normal=0, LckByMe=1, LckByOther=2, LckPending=3, Empty=4
};
public enum ProcTypeOptions
{
// Standard=0, Background=1, Deviation=2, Slave=3
Standard=0, Slave=1, Background=2, Deviation=3
};
public class VEO_Base
{
public int [] iconStates;
public int icon;
public string _Title;
public string _Location;
public ArrayList Children;
public Object parentObj;
public UserRunTime usrRunTime;
public bool isOpen;
private bool Expanded;
public bool IsEmpty;
public int VEObjectType;
public bool isNew;
public bool AllowListViewSort;
public VELock Lock;
public VEConnection Connection;
public TreeNode treeNode;
public enum ProcColumnOptions
{
OneColumn=0, TwoColumn=1, ThreeColumn=2
};
public enum ArchiveTypeOptions
{
Full=0, Partial=1
};
// constructor
public VEO_Base()
{
Expanded = false;
isOpen = false;
AllowListViewSort = false;
Children = new ArrayList();
VEObjectType = (int)VEObjectTypesDefs.Generic;
}
~ VEO_Base()
{
if (Connection!=null) Connection.Exit();
}
public virtual void LoadLockInfo()
{
Lock = new VELock(_Location, usrRunTime==null?null:usrRunTime.myUserData, VENetwork.LockTypes.None);
}
public virtual bool mnuAllowDelete()
{
return true;
}
public virtual bool mnuAllowApprove()
{
return false;
}
public virtual bool mnuAllowApproveSel()
{
return false;
}
public virtual bool mnuAllowApproveAll()
{
return false;
}
public virtual bool mnuAllowProperties()
{
return true;
}
public virtual bool mnuAllowNew()
{
return true;
}
public virtual bool mnuAllowUpdRO()
{
return false;
}
public virtual bool mnuAllowClean()
{
return false;
}
public virtual bool mnuAllowDataCheck()
{
return false;
}
public virtual bool mnuAllowChgDef()
{
return false;
}
public virtual bool mnuAllowUpdateArch()
{
return false;
}
public virtual bool mnuAllowTestArchive()
{
return false;
}
public virtual bool mnuAllowExtractArch()
{
return false;
}
public virtual bool mnuAllowLckDB()
{
return false;
}
public virtual bool mnuAllowUnlckDB()
{
return false;
}
public virtual bool mnuAllowMonUsr()
{
if (usrRunTime.InMultiUserMode && !(Lock.LockType==VENetwork.LockTypes.None) &&
!(Lock.LockStatus==VENetwork.Status.LockedByOther)) return true;
return false;
}
public virtual bool canEdit()
{
return true;
}
// used to flag whether all siblings of a node should be collapsed before expanding the
// node. This is needed for multi-user support for the plant & procedure set levels so
// that a user does not have open connections all over the tree.
public virtual bool CollapseSibling()
{
return false;
}
public virtual bool amILockedByMe()
{
// if not a newtork serial number, treat it as anything is locked.
if (!usrRunTime.InMultiUserMode)return true;
VEO_Base obj = this;
while (obj!=null)
{
if (obj.Lock.LockStatus == VENetwork.Status.Locked) return true;
obj = (VEO_Base) obj.parentObj;
}
return false;
}
public virtual bool isProcSet()
{
return false;
}
public virtual bool isArchiveSet()
{
return false;
}
public virtual bool updateROValues()
{
return false;
}
public virtual void CleanTransitionsAndROsUsages(int clntype,string ProcName)
{
return;
}
public virtual void ApproveProcedures(int ApproveType, ArrayList prcs)
{
return;
}
public virtual void DataIntegrityCheck(string ProcName)
{
return;
}
// Add TreeNodes to the input TreeNode parent.
public virtual void AddToTree(TreeNode parentnd)
{
for(int i=0; i<Children.Count; i++)
{
VEO_Base veo = (VEO_Base) Children[i];
veo.treeNode = new TreeNode(veo.GetTreeNodeText(),veo.icon,veo.icon);
parentnd.Nodes.Add(veo.treeNode);
veo.treeNode.Tag = veo;
}
}
public virtual void Restore()
{
}
public virtual bool PropertiesDlg(Object parent)
{
Properties propdlg = new Properties(parent, this);
DialogResult dr = propdlg.ShowDialog();
if (dr == DialogResult.OK) return true;
// restore the data (user may have changed in properties dialog,
// but need to restore original.
this.Restore();
return false;
}
public virtual bool EditNode()
{
return true;
}
public virtual bool canDoDragDrop()
{
return false;
}
public void RefreshTreeNode(TreeNode nd)
{
VEO_Base veo = (VEO_Base) nd.Tag;
//refresh the connect & lock.
if (veo.Connection != null) veo.Connection.Enter(false);
// if the object doesn't have a lock type (i.e. isn't where the system,
// plant or procset lock would be set) read in data & add it to the tree.
if (veo.Lock.LockType == VENetwork.LockTypes.None && !(veo is VEO_DummySet))
{
if (veo.Children.Count>0) veo.Children.Clear();
if (nd.Nodes.Count>0) nd.Nodes.Clear();
veo.Read(false);
veo.AddToTree(nd);
}
// if the object can have a lock at this level, but it currently doesnot
// have a lock, if it has children add a temp node to the treeview. This
// is done so that if this becomes expanded, the lock is checked again.
else if (veo.Lock.LockStatus!=VENetwork.Status.LockedByOther)
{
veo.Read(true);
if (veo.Children.Count>0)
{
veo.Children.Clear();
TreeNode dmy = new TreeNode("TEMP");
nd.Nodes.Add(dmy);
}
}
// if multi-user serial number, may have to reset lock status icon.
if (usrRunTime.InMultiUserMode)
{
// if no lock & emtpy, show empty. Otherwise, show lock icon
if (IsEmpty && veo.Lock.LockStatus==VENetwork.Status.NoLock)
veo.icon = veo.iconStates[(int)VEO_IconStates.Empty];
else
veo.icon = veo.iconStates[(int)veo.Lock.LockStatus];
nd.ImageIndex = veo.icon;
nd.SelectedImageIndex = veo.icon;
}
}
// When the user collapses the treenode, also, do some object cleanup.
// This removes children, exits connections for all sub-tree children
// and also refreshes locks, updates icons based on lock changes and
// load in children at the current node level.
public void Collapse(TreeNode nd, TreeViewAction act, bool dorefresh,bool closeconn)
{
Expanded=false;
Children.Clear();
if (Connection != null && closeconn) Connection.Exit();
// if this is the actual node that was collapsed, then refresh at this level,
// i.e. refresh the lock, update the icon (in case of lock status change)
// and load children (may make into temp child if necessary)
if (act == TreeViewAction.Collapse||dorefresh) {
RefreshTreeNode(nd);
// need to exit again because refresh tree node opens the connection
// to determine locking status.
if (Connection != null && closeconn) Connection.Exit();
}
}
// Expand the TreeNode. This makes a new/reenters connection at the level, sets up
// icons for the level, enters it by loading its children (if it successfully
// entered it, i.e. it's not locked.
public virtual bool Expand(TreeNode mytreend)
{
if (Connection==null)
Connection = new VEConnection(Lock, usrRunTime);
// Enter the connection, i.e. refresh the lock & then see if can get into the
// data level.
bool canenter = Connection.Enter(false);
// update icons (in case of lock status change)
if (usrRunTime.InMultiUserMode)
{
// if no lock & emtpy, show empty. Otherwise, show lock icon
if (IsEmpty && Lock.LockStatus==VENetwork.Status.NoLock)
icon = iconStates[(int)VEO_IconStates.Empty];
else
icon = iconStates[(int)Lock.LockStatus];
mytreend.ImageIndex = icon;
mytreend.SelectedImageIndex = icon;
}
// if user cannot enter, it must be locked. Return a false.
if (canenter==false)
{
Collapse(mytreend,TreeViewAction.Unknown,true,false);
mytreend.Nodes.Clear();
mytreend.TreeView.Refresh();
return false;
}
if (Expanded) return true;
Expanded = true;
// load the children. First check for either no children (in case this was locked on
// load, and then subsequently unlocked before the selection or check for a 'TEMP'
// node. If it exists, remove it. Then if this has a lock type of none, load it's
// children. Otherwise, load a temp child under each child. The temp child is
// used because when the user actually expands this node, a recheck of the lock
// status is needed and a change may have occurred (another user may have added,
// deleted or modified children by the time this is entered).
TreeNode frstchld = mytreend.FirstNode;
if (frstchld==null || frstchld.Text == "TEMP")
{
mytreend.Nodes.Clear();
Read(false);
AddToTree(mytreend);
}
VEO_Base veo;
for (int i=0; i<mytreend.Nodes.Count; i++)
{
veo = (VEO_Base) mytreend.Nodes[i].Tag;
// if the object doesn't have a lock type (i.e. isn't where the system,
// plant or procset lock would be set) read in data & add it to the tree.
if (veo.Lock.LockType == VENetwork.LockTypes.None && !(veo is VEO_DummySet))
{
veo.Read(false);
veo.AddToTree(mytreend.Nodes[i]);
}
// if the object can have a lock at this level, but it currently does not
// have a lock, if it has children, add a temp node to the treeview. This
// is done so that if this becomes expanded, the lock is checked again.
else if (veo.Lock.LockStatus!=VENetwork.Status.LockedByOther)
{
veo.Read(true);
if (veo.Children.Count>0)
{
veo.Children.Clear();
TreeNode dmy = new TreeNode("TEMP");
mytreend.Nodes[i].Nodes.Add(dmy);
}
}
}
return true;
}
public virtual void LockedDlg()
{
}
// virtual read
public virtual bool Read(bool dummy)
{
return true;
}
// virtual write
public virtual bool Write()
{
return false;
}
public virtual bool Open()
{
return false;
}
public virtual bool Close()
{
return false;
}
// virtual cancel write (save)
public virtual void CancelWrite()
{
}
public virtual bool Delete()
{
return true;
}
// make a new plain vanilla object (this is really a virtual.
public virtual Object MakeNewChild()
{
return (new Object());
}
public virtual Object Copy()
{
return this; //default to returning self
}
public virtual Object AddNewChild()
{
VEO_Base newobj = (VEO_Base) this.MakeNewChild();
if (newobj==null) return null; // something happened, just return
newobj.parentObj = (VEO_Base) this;
newobj.isNew=true;
bool prpchg = newobj.PropertiesDlg(this);
if (prpchg == true)
{
// Copy is used so that a VEO-object is created that has editable
// (versus new) properties. When the object is 'new' many fields
// are editable that should not be editable when not new (this is
// mainly an issue with the property grid, since the ReadOnly
// setting can only be done at compile/build time - it CANNOT be
// done at run-time. So when a new object is created, if it's
// successful, it's copied to an object which is edit (not new)
// for the treeview & any further operations.
VEO_Base cpyobj = (VEO_Base) newobj.Copy();
Children.Add(cpyobj); // add the new one to the children
if(newobj!=cpyobj)Children.Remove(newobj);
cpyobj.Read(false); // read any child data
return cpyobj;
}
else
return null;
}
public virtual string GetTreeNodeText()
{
return _Title;
}
public virtual bool SaveChild(Object obj)
{
return false;
}
// virtual SaveNew
public virtual bool SaveNew(string pth)
{
return false;
}
public virtual void DoListView(ListView veoListView)
{
return;
}
public virtual void DoWizzard()
{
return;
}
// Comunication between this object & vfw
struct COPYDATASTRUCT
{
public IntPtr dwData;
public int cbData;
public IntPtr lpData;
}
const int WM_COPYDATA = 0x004A;
// sending side
[DllImport("user32.dll")]
static extern bool SendMessage(
IntPtr hWnd,
UInt32 Msg,
UInt32 wParam,
ref COPYDATASTRUCT lParam);
public struct RqstAttachMsg
{
public Int16 level;
public Int16 flag;
public Int32 longval;
}
public struct AnswerMsg
{
public Int16 done;
public Int16 intAnswer;
public Int32 longAnswer;
}
public struct PRecordMsg
{
public Int16 done;
public Int16 cnt;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=140)] public String buff;
}
[StructLayout(LayoutKind.Sequential)]
public struct PosUpdateStr
{
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=16)] public String sender;
[MarshalAs(UnmanagedType.ByValTStr,SizeConst=80)] public String directory;
public Int32 docnumindx;
public Int32 recID;
}
private VEO_Base GetObjectAtLevel(int level)
{
try
{
VEO_Base veo = this;
while (veo != null)
{
if (level == 2 && veo.VEObjectType == (int)VEObjectTypesDefs.ProcedureSet)
return veo;
else if (level == 1 && veo.VEObjectType == (int)VEObjectTypesDefs.Plant)
return veo;
else if (level == 0 && veo.VEObjectType == (int)VEObjectTypesDefs.System)
return veo;
veo = (VEO_Base)veo.parentObj;
}
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
}
return null;
}
private bool ReturnProcRecord(VEO_Base veo,Int16 size, IntPtr vfwhndl)
{
bool success=true;
COPYDATASTRUCT cds = new COPYDATASTRUCT();
PRecordMsg prmsg;
prmsg.done = 1;
byte [] bt = new byte[size+4];
prmsg.cnt = veo.Connection.GetProcRecBuff(size, ref bt);
if (prmsg.cnt != size)
{
MessageBox.Show("Could not read multi-user connection information");
return false;
}
prmsg.buff = Encoding.ASCII.GetString(bt,0,size);
IntPtr p = Marshal.AllocHGlobal(size+4);
Marshal.StructureToPtr(prmsg,p,true);
cds.dwData = (IntPtr)VEMessageNS.MessageOps.GETPROCESSREC;
// the following would be 'size+4', however marshalling requires space to be
// a multiple of 8
cds.cbData = 160;
cds.lpData = p;
try
{
SendMessage(vfwhndl,WM_COPYDATA,(UInt32)8, ref cds);
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
success=false;
}
Marshal.FreeHGlobal(p);
return success;
}
private bool Reply(Int16 done, Int16 intAnswer, Int32 longAnswer, IntPtr vfwhndl)
{
bool success=true;
COPYDATASTRUCT cds = new COPYDATASTRUCT();
AnswerMsg ans;
ans.done = done;
ans.intAnswer = intAnswer;
ans.longAnswer = longAnswer;
IntPtr p=Marshal.AllocHGlobal(8);
Marshal.StructureToPtr(ans,p,true);
cds.dwData = (IntPtr)VEMessageNS.MessageOps.GETANSWER;
cds.cbData = 8;
cds.lpData = p;
try
{
SendMessage(vfwhndl,WM_COPYDATA,(UInt32)8, ref cds);
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
success=false;
}
Marshal.FreeHGlobal(p);
return success;
}
public virtual void ProcessMessage(Message m, IntPtr vfwhndl)
{
VEO_Base veo = null;
bool success=false;
if (m.Msg==(int)VEMessageNS.MessageOps.POSQUERY)
{
// POSQUERY is only called to get initial procedure - make the main
// form invisible when this request is made. Wait until now so that
// the main form is visible until vfw window is just about to be
// made visible.
IntPtr handle =
System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
Form mainForm = (Form)Form.FromHandle(handle);
mainForm.Visible = false;
COPYDATASTRUCT cds = new COPYDATASTRUCT();
PosUpdateStr pu;
pu.sender = "NEWBROWSER";
VEO_Proc prc = null;
if (!(this is VEO_Proc))
{
// get to a proc, this is either a set or 'procedures' node
// from an approve selected.
VEO_ProcSet ps = null;
if (this is VEO_ProcSet)
ps = (VEO_ProcSet) this;
else if (this is VEO_DummySet)
ps = (VEO_ProcSet) this.parentObj;
else
{
MessageBox.Show("Error finding procedure for edit","VE-PROMS");
return;
}
prc=ps.AppSelForEdit;
}
else
prc = (VEO_Proc) this;
VEO_DummySet ds = (VEO_DummySet) prc.parentObj;
pu.directory = ds._Location;
pu.docnumindx = ds.Children.IndexOf(prc);
pu.recID = System.Convert.ToInt32(prc.recid,10);
IntPtr p=Marshal.AllocHGlobal(130);
Marshal.StructureToPtr(pu,p,true);
cds.dwData = (IntPtr)VEMessageNS.MessageOps.POSUPDATE;
cds.cbData = 130;
cds.lpData = p;
try
{
SendMessage(vfwhndl,WM_COPYDATA,(UInt32)8, ref cds);
}
catch (Exception e)
{
MessageBox.Show(e.Message.ToString());
}
Marshal.FreeHGlobal(p);
}
else if (m.Msg==WM_COPYDATA)
{
bool reply = true;
Int16 int1=0, int2=0;
int int3=0;
int lvl = 0;
COPYDATASTRUCT cds = (COPYDATASTRUCT) m.GetLParam(typeof(COPYDATASTRUCT));
int tmpmsg = (int)cds.dwData;
VEMessageNS.MessageOps msg = (VEMessageNS.MessageOps) tmpmsg;
RqstAttachMsg ramsg = (RqstAttachMsg)Marshal.PtrToStructure(cds.lpData,typeof(RqstAttachMsg));
// get level veobject associated with this request, i.e. system, plant, or procset
// and then connect at level
lvl = ramsg.level;
try
{
veo = GetObjectAtLevel(lvl);
switch (msg)
{
case VEMessageNS.MessageOps.RQSTATTACH:
success = veo.Connection.Enter(false);
int2 = (short)(success?1:0);
break;
case VEMessageNS.MessageOps.RQSTFILEOFFSET:
if (ramsg.flag==0)
int3 = (int)veo.Connection.FileOffset;
//else
// MessageBox.Show("Set file offset" + ramsg.longval.ToString());
break;
case VEMessageNS.MessageOps.RQSTFILEMODE:
int2 = (short) veo.Connection.GetVfwMode();
break;
case VEMessageNS.MessageOps.RQSTFILEOWNER:
int2 = 1;
break;
case VEMessageNS.MessageOps.RQSTFILESEEK:
int3 = (int)veo.Connection.Seek(ramsg.longval, ramsg.flag);
break;
case VEMessageNS.MessageOps.RQSTFILECLOSE: //used in lock/unlock
veo.Connection.Close();
break;
case VEMessageNS.MessageOps.RQSTFILEOPEN: //used in lock/unlock
int2 = (short) veo.Connection.Open(ramsg.flag);
break;
// RQSTFILEREAD - not used in vfw <-> browser communication
case VEMessageNS.MessageOps.RQSTFILEREAD:
MessageBox.Show("RqstFileRead");
break;
case VEMessageNS.MessageOps.RQSTFILEWRITE: //used in lock/unlock
MessageBox.Show("RqstFileWrite");
break;
case VEMessageNS.MessageOps.RQSTPROCESSRECORD:
reply=false;
success=ReturnProcRecord(veo,ramsg.flag,vfwhndl);
break;
case VEMessageNS.MessageOps.SETLOCKBYUSER: //do set lock yet.
if (ramsg.flag >= 0)
{
if (ramsg.flag==0)
veo.Lock.LockStatus=VENetwork.Status.NoLock;
else
veo.Lock.LockStatus=VENetwork.Status.Locked;
}
int2 = (Int16)((veo.Lock.LockStatus==VENetwork.Status.Locked)?1:0);
break;
}
if (reply) success = Reply(int1,int2,int3,vfwhndl);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
}
}