using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Text.RegularExpressions; using System.Windows.Forms; using System.Runtime.InteropServices; // For DragHelper using System.Reflection; using Csla; using Csla.Validation; using VEPROMS.CSLA.Library; namespace Volian.Controls.Library { #region DelegatesAndEventArgs public delegate void vlnTreeViewEvent(object sender, vlnTreeEventArgs args); public delegate void vlnTreeViewItemInfoEvent(object sender, vlnTreeItemInfoEventArgs args); public delegate bool vlnTreeViewBoolEvent(object sender, vlnTreeEventArgs args); public delegate bool vlnTreeViewItemInfoDeleteEvent(object sender, vlnTreeItemInfoEventArgs args); public delegate bool vlnTreeViewItemInfoInsertEvent(object sender, vlnTreeItemInfoInsertEventArgs args); public delegate bool vlnTreeViewItemInfoPasteEvent(object sender, vlnTreeItemInfoPasteEventArgs args); public delegate TreeNode vlnTreeViewTreeNodeEvent(object sender, vlnTreeEventArgs args); public delegate DialogResult vlnTreeViewPropertyEvent(object sender, vlnTreePropertyEventArgs args); public delegate void vlnTreeViewSectionInfoEvent(object sender, vlnTreeSectionInfoEventArgs args); public delegate void WordSectionDeletedEvent(object sender, WordSectionEventArgs args); public partial class vlnTreeSectionInfoEventArgs { private SectionInfo _MySectionInfo; public SectionInfo MySectionInfo { get { return _MySectionInfo; } set { _MySectionInfo = value; } } public vlnTreeSectionInfoEventArgs(SectionInfo mySectionInfo) { _MySectionInfo = mySectionInfo; } } public partial class vlnTreeEventArgs { #region Business Methods private TreeNode _Node; public TreeNode Node { get { return _Node; } set { _Node = value; } } private TreeNode _Destination=null; public TreeNode Destination { get { return _Destination; } set { _Destination = value; } } private int _Index; public int Index { get { return _Index; } set { _Index = value; } } #endregion #region Factory Methods private vlnTreeEventArgs() { ;} public vlnTreeEventArgs(TreeNode node) { _Node = node; } public vlnTreeEventArgs(TreeNode node, TreeNode destination, int index) { _Node = node; _Destination = destination; _Index = index; } #endregion } public partial class vlnTreeItemInfoEventArgs { #region Business Methods private ItemInfo _MyItemInfo; public ItemInfo MyItemInfo { get { return _MyItemInfo; } set { _MyItemInfo = value; } } #endregion #region Factory Methods private vlnTreeItemInfoEventArgs() { ;} public vlnTreeItemInfoEventArgs(ItemInfo myItemInfo) { _MyItemInfo = myItemInfo; } #endregion } public enum E_InsertType {Before, After, Child}; public partial class vlnTreeItemInfoInsertEventArgs { #region Business Methods private ItemInfo _MyItemInfo; public ItemInfo MyItemInfo { get { return _MyItemInfo; } set { _MyItemInfo = value; } } private E_InsertType _InsertType; public E_InsertType InsertType { get { return _InsertType; } set { _InsertType = value; } } private int _Type; public int Type { get { return _Type; } set { _Type = value; } } private E_FromType _FromType; public E_FromType FromType { get { return _FromType; } set { _FromType = value; } } private string _StepText; public string StepText { get { return _StepText; } set { _StepText = value; } } #endregion #region Factory Methods private vlnTreeItemInfoInsertEventArgs() { ;} public vlnTreeItemInfoInsertEventArgs(ItemInfo myItemInfo, E_InsertType insertType, string stepText) { _MyItemInfo = myItemInfo; _InsertType = insertType; _StepText = stepText; } public vlnTreeItemInfoInsertEventArgs(ItemInfo myItemInfo, E_InsertType insertType, string stepText, int type, E_FromType fromType) { _MyItemInfo = myItemInfo; _InsertType = insertType; _StepText = stepText; _Type = type; _FromType = fromType; } #endregion } #region PasteEventArgs public partial class vlnTreeItemInfoPasteEventArgs { #region Business Methods private ItemInfo _MyItemInfo; public ItemInfo MyItemInfo { get { return _MyItemInfo; } set { _MyItemInfo = value; } } private int _CopyStartID; public int CopyStartID { get { return _CopyStartID; } set { _CopyStartID = value; } } private ItemInfo.EAddpingPart _PasteType; public ItemInfo.EAddpingPart PasteType { get { return _PasteType; } set { _PasteType = value; } } private int? _Type; public int? Type { get { return _Type; } set { _Type = value; } } #endregion #region Factory Methods private vlnTreeItemInfoPasteEventArgs() { ;} public vlnTreeItemInfoPasteEventArgs(ItemInfo myItemInfo, int copyStartId, ItemInfo.EAddpingPart pasteType, int? type) { _MyItemInfo = myItemInfo; _CopyStartID = copyStartId; _PasteType = pasteType; _Type = type; } #endregion } #endregion public partial class vlnTreePropertyEventArgs : EventArgs { private string _Title; public string Title { get { return _Title; } set { _Title = value; } } private object _ConfigObject; public object ConfigObject { get { return _ConfigObject; } set { _ConfigObject = value; } } private FolderConfig _FolderConfig; public FolderConfig FolderConfig { get { return _FolderConfig; } set { _ConfigObject = _FolderConfig = value; } } private DocVersionConfig _DocVersionConfig; public DocVersionConfig DocVersionConfig { get { return _DocVersionConfig; } set { _ConfigObject = _DocVersionConfig = value; } } private ProcedureConfig _ProcedureConfig; public ProcedureConfig ProcedureConfig { get { return _ProcedureConfig; } set { _ConfigObject = _ProcedureConfig = value; } } private SectionConfig _SectionConfig; public SectionConfig SectionConfig { get { return _SectionConfig; } set { _ConfigObject = _SectionConfig = value; } } private vlnTreePropertyEventArgs() { ;} public vlnTreePropertyEventArgs(string title, FolderConfig folderConfig) { _Title = title; FolderConfig = folderConfig; } public vlnTreePropertyEventArgs(string title, DocVersionConfig docVersionConfig) { _Title = title; DocVersionConfig = docVersionConfig; } public vlnTreePropertyEventArgs(string title, ProcedureConfig procedureConfig) { _Title = title; ProcedureConfig = procedureConfig; } public vlnTreePropertyEventArgs(string title, SectionConfig sectionConfig) { _Title = title; DocStyleListConverter.MySection = sectionConfig.MySection; SectionConfig = sectionConfig; } } #endregion public partial class vlnTreeView : TreeView { #region Local Vars private static readonly log4net.ILog _MyLog = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType); FolderInfo _LastFolderInfo = null; ProcedureInfo _LastProcedureInfo = null; DocVersionInfo _LastDocVersionInfo = null; SectionInfo _LastSectionInfo = null; VETreeNode _LastTreeNode = null; StepInfo _LastStepInfo = null; ItemInfo _LastItemInfo = null; #endregion #region Events public event vlnTreeViewItemInfoDeleteEvent DeleteItemInfo; private bool OnDeleteItemInfo(object sender, vlnTreeItemInfoEventArgs args) { if (DeleteItemInfo != null) return DeleteItemInfo(sender, args); return false; } public event vlnTreeViewItemInfoInsertEvent InsertItemInfo; private bool OnInsertItemInfo(object sender, vlnTreeItemInfoInsertEventArgs args) { if (InsertItemInfo != null) return InsertItemInfo(sender, args); return false; } public event vlnTreeViewItemInfoPasteEvent PasteItemInfo; private bool OnPasteItemInfo(object sender, vlnTreeItemInfoPasteEventArgs args) { if (PasteItemInfo != null) return PasteItemInfo(sender, args); return false; } public event vlnTreeViewEvent NodeMove; private void OnNodeMove(object sender, vlnTreeEventArgs args) { if (NodeMove != null) NodeMove(sender, args); } public event vlnTreeViewEvent NodeCopy; private void OnNodeCopy(object sender, vlnTreeEventArgs args) { if (NodeCopy != null) NodeCopy(sender, args); } public event vlnTreeViewPropertyEvent NodeOpenProperty; private DialogResult OnNodeOpenProperty(object sender, vlnTreePropertyEventArgs args) { if (NodeOpenProperty != null) return NodeOpenProperty(sender, args); return DialogResult.Cancel; } public event vlnTreeViewEvent NodeSelect; private void OnNodeSelect(object sender, vlnTreeEventArgs args) { if (NodeSelect != null) NodeSelect(sender, args); } public event vlnTreeViewEvent NodeNew; private void OnNodeNew(object sender, vlnTreeEventArgs args) { if (NodeNew != null) NodeNew(sender, args); } public event vlnTreeViewEvent NodeSelectionChange; private void OnNodeSelectionChange(object sender, vlnTreeEventArgs args) { if (NodeSelectionChange != null) NodeSelectionChange(sender, args); } public event vlnTreeViewSectionInfoEvent SectionShouldClose; private void OnSectionShouldClose(object sender, vlnTreeSectionInfoEventArgs args) { if (SectionShouldClose != null) SectionShouldClose(sender, args); } public event WordSectionDeletedEvent WordSectionDeleted; internal void OnWordSectionDeleted(object sender, WordSectionEventArgs args) { WordSectionDeleted(sender, args); } public event vlnTreeViewItemInfoEvent OpenItem; private void OnOpenItem(object sender, vlnTreeItemInfoEventArgs args) { if (OpenItem != null) OpenItem(sender, args); } #endregion #region Constructors public vlnTreeView() { InitializeComponent(); this.AllowDrop = true; DragHelper.InitCommonControls(); this.ItemDrag += new ItemDragEventHandler(tv_ItemDrag); this.DragDrop += new DragEventHandler(tv_DragDrop); this.DragEnter += new DragEventHandler(tv_DragEnter); this.DragLeave += new EventHandler(tv_DragLeave); this.DragOver += new DragEventHandler(tv_DragOver); this.MouseDown += new MouseEventHandler(tv_MouseDown); this.KeyPress += new KeyPressEventHandler(tv_KeyPress); base.AfterSelect += new TreeViewEventHandler(tv_AfterSelect); } #endregion #region MenuSupport private void tv_AfterSelect(object sender, TreeViewEventArgs e) { if(!_AdjustingTree) OnNodeSelectionChange(sender, new vlnTreeEventArgs(e.Node)); } // use to determine which menu items have been selected for those tree nodes // that allow more than one type of operation associated with their selection. public enum MenuSelections : int { Folder = 1, FolderBefore = 2, FolderAfter = 3, DocVersion = 4, Procedure = 5, ProcedureBefore = 6, ProcedureAfter = 7, Section = 8, SectionBefore = 9, SectionAfter = 10, Step = 11, StepBefore = 12, StepAfter = 13, StepReplace = 14 } void tv_MouseDown(object sender, MouseEventArgs e) { if (e.Button == MouseButtons.Right) { VETreeNode tn = this.GetNodeAt(new Point(e.X, e.Y)) as VETreeNode; if (tn != null) { this.SelectedNode = tn as TreeNode; Application.DoEvents(); // Display Menu ToolStripMenuItem mi = new ToolStripMenuItem(); ContextMenu cm = new ContextMenu(); #region Menu_New if (tn.VEObject as FolderInfo != null) { // For Folders, if no children, can add either docversion or folder. If children are // folders then can only add another folder, and if children are docversions can only // add docversion. FolderInfo fi = tn.VEObject as FolderInfo; if (fi.MyParent != null) // don't allow insert before/after if at top node { cm.MenuItems.Add("Insert Folder Before", new EventHandler(mi_Click)); cm.MenuItems.Add("Insert Folder After", new EventHandler(mi_Click)); } if (fi.FolderDocVersionCount == 0) cm.MenuItems.Add("New Folder", new EventHandler(mi_Click)); if (fi.ChildFolderCount == 0) cm.MenuItems.Add("Create Working Draft", new EventHandler(mi_Click)); } else if (tn.VEObject as DocVersionInfo != null) // DocVersions can only contain procs cm.MenuItems.Add("New Procedure", new EventHandler(mi_Click)); else if (tn.VEObject as ProcedureInfo != null) // Procs can only contain sections { cm.MenuItems.Add("Insert Procedure Before", new EventHandler(mi_Click)); cm.MenuItems.Add("Insert Procedure After", new EventHandler(mi_Click)); cm.MenuItems.Add("New Section", new EventHandler(mi_Click)); } else if (tn.VEObject as SectionInfo != null) { // A step Section can contain other steps or can contain subsections (either step section // or word doc section). Also note that there can be a mix. // A word doc section can contain another subsection (either step section or word doc section), // but cannot contain steps. SectionInfo si = tn.VEObject as SectionInfo; // Do not need step versus Word doc options, user enters this in property page during // insert process. cm.MenuItems.Add("Insert Section Before", new EventHandler(mi_Click)); cm.MenuItems.Add("Insert Section After", new EventHandler(mi_Click)); cm.MenuItems.Add("New Subsection", new EventHandler(mi_Click)); if (si.IsStepSection) cm.MenuItems.Add("New Step", new EventHandler(mi_Click)); } else if (tn.VEObject as StepInfo != null) { // check the format for allowable inserts, and also, ItemInfo i = tn.VEObject as ItemInfo; if (AddToInsertMenu(i,0)) cm.MenuItems.Add("Insert Step Before", new EventHandler(mi_Click)); if (AddToInsertMenu(i,1)) cm.MenuItems.Add("Insert Step After", new EventHandler(mi_Click)); } #endregion #region Menu_Open if (!tn.IsExpanded && tn.VEObject as SectionInfo != null) { SectionInfo si = tn.VEObject as SectionInfo; if (si.IsStepSection) cm.MenuItems.Add("Open", new EventHandler(mi_Click)); } else if (!tn.IsExpanded && tn.VEObject as StepInfo != null) { StepInfo stpi = tn.VEObject as StepInfo; if (stpi.HasChildren) cm.MenuItems.Add("Open", new EventHandler(mi_Click)); } else if (!tn.IsExpanded) cm.MenuItems.Add("Open", new EventHandler(mi_Click)); #endregion #region Menu_CutCopy // For initial release, copy is not available for folders or docversions if (tn.VEObject as ItemInfo != null) { cm.MenuItems.Add("Copy", new EventHandler(mi_Click)); } #endregion Menu_Paste(tn, cm); #region Menu_Delete // Add delete to the menu unless at the very 'top' node or on a grouping (partinfo) // node (RNOs, Steps, Cautions, Notes) PartInfo pi = tn.VEObject as PartInfo; if (pi == null && tn.Parent!=null) cm.MenuItems.Add("Delete", new EventHandler(mi_Click)); #endregion #region Menu_Properties // Add Properties to the menu unless at the very 'top' node or on a grouping (partinfo) // node (RNOs, Steps, Cautions, Notes) or at the step level. PartInfo pia = tn.VEObject as PartInfo; ItemInfo ii = tn.VEObject as ItemInfo; if (pia == null && tn.VEObject as StepInfo == null) cm.MenuItems.Add("Properties...", new EventHandler(mi_Click)); #endregion cm.Show(this, new Point(e.X, e.Y)); } } } private bool AddToInsertMenu(ItemInfo ii, int ba) // 0 = before, 1 = after { // set up insert buttons based on format bool retB = true; E_AccStep? actable = 0; StepData sd = ii.FormatStepData; actable = sd.StepEditData.AcTable; if (actable == null) actable = 0; return (ba == 0) ? !ii.IsRNOPart && (actable & E_AccStep.AddingPrev) > 0 : !ii.IsRNOPart && (actable & E_AccStep.AddingNext) > 0; } private void Menu_Paste(VETreeNode tn, ContextMenu cm) { #region MenuPaste // Find what's in paste buffer & determine whether the paste can occur for the selected node. object tmpClip = Clipboard.GetData("PromsClipboard"); if (tmpClip != null) { PromsClipboard tstClip = (PromsClipboard)tmpClip; ItemInfo iiClipboard = ItemInfo.Get(tstClip.itemId); // if the item doesn't exist anymore, don't allow the paste, by not adding // paste menu items to context menu. if (iiClipboard == null) { Clipboard.Clear(); return; } // can it be pasted at current node. if (tn.VEObject as DocVersionInfo != null) // paste item must be a proc { if (iiClipboard.IsProcedure) cm.MenuItems.Add("Paste Procedure", new EventHandler(mi_Click)); } else { ItemInfo iiPasteHere = tn.VEObject as ItemInfo; if (iiPasteHere != null) { if (iiPasteHere.IsProcedure && iiClipboard.IsProcedure) // procedure can be pasted before/replace/after { cm.MenuItems.Add("Paste Procedure Before", new EventHandler(mi_Click)); cm.MenuItems.Add("Replace Existing Procedure", new EventHandler(mi_Click)); cm.MenuItems.Add("Paste Procedure After", new EventHandler(mi_Click)); } else if (iiPasteHere.IsProcedure && iiClipboard.IsSection) // procedure must have sections only cm.MenuItems.Add("Paste Section", new EventHandler(mi_Click)); else if (iiPasteHere.IsSection && iiClipboard.IsSection) { cm.MenuItems.Add("Paste Section Before", new EventHandler(mi_Click)); cm.MenuItems.Add("Replace Existing Section", new EventHandler(mi_Click)); cm.MenuItems.Add("Paste Section After", new EventHandler(mi_Click)); } else if (iiPasteHere.IsStepSection && iiClipboard.IsStep) cm.MenuItems.Add("Paste Step", new EventHandler(mi_Click)); else if (iiPasteHere.IsStep && iiClipboard.IsStep) { if (AddToInsertMenu(iiPasteHere, 0)) cm.MenuItems.Add("Paste Step Before", new EventHandler(mi_Click)); cm.MenuItems.Add("Replace Existing Step", new EventHandler(mi_Click)); if (AddToInsertMenu(iiPasteHere, 1)) cm.MenuItems.Add("Paste Step After", new EventHandler(mi_Click)); } } } } #endregion } void mi_Click(object sender, EventArgs e) { MenuItem mi = (MenuItem)sender; switch (mi.Text) { case "Open": OpenNode(); break; case "Insert Folder Before": tv_NodeNew(MenuSelections.FolderBefore); break; case "Insert Folder After": tv_NodeNew(MenuSelections.FolderAfter); break; case "New Folder": SelectedNode.Expand(); tv_NodeNew(MenuSelections.Folder); break; case "Create Working Draft": SelectedNode.Expand(); tv_NodeNew(MenuSelections.DocVersion); break; case "New Procedure": SelectedNode.Expand(); tv_NodeNew(MenuSelections.Procedure); break; case "Insert Procedure Before": tv_NodeNew(MenuSelections.ProcedureBefore); break; case "Insert Procedure After": tv_NodeNew(MenuSelections.ProcedureAfter); break; case "New Section": case "New Subsection": SelectedNode.Expand(); tv_NodeNew(MenuSelections.Section); break; case "Insert Section Before": tv_NodeNew(MenuSelections.SectionBefore); break; case "Insert Section After": tv_NodeNew(MenuSelections.SectionAfter); break; case "Insert Step Before": tv_NodeNew(MenuSelections.StepBefore); break; case "Insert Step After": tv_NodeNew(MenuSelections.StepAfter); break; case "New Step": SelectedNode.Expand(); tv_NodeNew(MenuSelections.Step); break; case "Copy"://Copy the selected node tv_NodeCopy(); break; // lots of paste options: case "Paste Procedure": case "Paste Procedure Before": case "Replace Existing Procedure": case "Paste Procedure After": case "Paste Section": case "Paste Section Before": case "Replace Existing Section": case "Paste Section After": case "Paste Step": case "Paste Step Before": case "Replace Existing Step": case "Paste Step After": tv_NodePaste(mi.Text); break; case "Delete": if (tv_NodeDelete()) { TreeNode myParent = SelectedNode.Parent; SelectedNode.Remove(); SelectedNode = myParent; OnNodeSelect(this, new vlnTreeEventArgs(SelectedNode)); } break; case "Properties..."://Show the properties for the selected node SetLastValues((VETreeNode)SelectedNode); SetupNodeProperties(); break; default: MessageBox.Show(string.Format("Unrecognized Menu Item '{0}'", mi.Text)); break; } } [Serializable] public struct PromsClipboard { public int cType; public int itemId; } public enum PromsClipboardType : int { Copy = 1, Cut = 2 } private void tv_NodePaste(string p) { object oClip = Clipboard.GetData("PromsClipboard"); if (oClip == null) return; PromsClipboard iClip = (PromsClipboard) oClip; ItemInfo iiClipboard = ItemInfo.Get(iClip.itemId); VETreeNode tn = SelectedNode as VETreeNode; DocVersionInfo dvi = tn.VEObject as DocVersionInfo; if (dvi != null) { return; } ItemInfo iiPaste = tn.VEObject as ItemInfo; if (iiPaste == null) return; if (p.IndexOf("Before") > -1) PasteBeforeOrAfter(MenuSelections.StepBefore, tn, iiClipboard.ItemID); else if (p.IndexOf("After") > -1) PasteBeforeOrAfter(MenuSelections.StepAfter, tn, iiClipboard.ItemID); else if (p.IndexOf("Replace") > -1) PasteReplace(tn, iiClipboard.ItemID); } private void PasteBeforeOrAfter(MenuSelections newtype, VETreeNode tn, int copyStartID) { // If paste-from step is open in the editor, use the OnPasteItemInfo to paste the step and add stepitems // to the step editor panel. ItemInfo ii = tn.VEObject as ItemInfo; ItemInfo.EAddpingPart pasteOpt = newtype == MenuSelections.StepBefore ? ItemInfo.EAddpingPart.Before : ItemInfo.EAddpingPart.After; // If parent step is open in step editor, the 'OnPasteItemInfo' event will cause // the item to be pasted in the step editor and the tree. if (!OnPasteItemInfo(this, new vlnTreeItemInfoPasteEventArgs(ii, copyStartID, pasteOpt, ii.MyContent.Type))) { // The parent step was not open in the step editor, just paste step (in data) and add treenode. ItemInfo newItemInfo = null; if (newtype == MenuSelections.StepBefore) newItemInfo = ii.PasteSiblingBefore(copyStartID); else newItemInfo = ii.PasteSiblingAfter(copyStartID); } SelectedNode = (VETreeNode)((newtype == MenuSelections.StepAfter) ? tn.NextNode : tn.PrevNode); } private void PasteReplace(VETreeNode tn, int copyStartID) { VETreeNode prevtn = (VETreeNode) tn.PrevNode; VETreeNode partn = (VETreeNode) tn.Parent; ItemInfo ii = tn.VEObject as ItemInfo; if (!OnPasteItemInfo(this, new vlnTreeItemInfoPasteEventArgs(ii, copyStartID, ItemInfo.EAddpingPart.Replace, ii.MyContent.Type))) { //return; ItemInfo replItemInfo = Item.PasteReplace(ii, copyStartID); } SelectedNode = (VETreeNode)((prevtn != null) ? prevtn.NextNode : partn.FirstNode); } private void tv_NodeCopy() { if (SelectedNode==null)return; VETreeNode tn = SelectedNode as VETreeNode; ItemInfo ii = tn.VEObject as ItemInfo; if (ii != null) { Clipboard.Clear(); PromsClipboard iClip; iClip.itemId = ii.ItemID; iClip.cType = (int)PromsClipboardType.Copy; DataObject myDO = new DataObject(); myDO.SetText(ii.DisplayNumber==null||ii.DisplayNumber==""?" ":ii.DisplayNumber); myDO.SetData("PromsClipboard", iClip); Clipboard.SetDataObject(myDO); //Clipboard.SetData("PromsClipboard", iClip); //Clipboard.SetData(DataFormats.Text, ii.DisplayNumber); } } #endregion #region PropertyPagesInterface private void SetupNodeProperties() { VETreeNode tn = SelectedNode as VETreeNode; if (tn==null)return; if ((tn.VEObject as FolderInfo) != null) OpenProperties(tn.VEObject as FolderInfo); else if ((tn.VEObject as DocVersionInfo) != null) OpenProperties(tn.VEObject as DocVersionInfo); else if ((tn.VEObject as ProcedureInfo) != null) OpenProperties(tn.VEObject as ProcedureInfo); else if ((tn.VEObject as SectionInfo) != null) OpenProperties(tn.VEObject as SectionInfo); else if ((tn.VEObject as StepInfo) != null) MessageBox.Show("Open up info tab or whatever is associated with step"); tn.RefreshNode(); } private void OpenProperties(FolderInfo folderInfo) { using (Folder folder = folderInfo.Get()) { OnNodeOpenProperty(this, new vlnTreePropertyEventArgs(string.Format("{0} Properties", folder.FolderConfig.Name), folder.FolderConfig)); } } private void OpenProperties(DocVersionInfo dvInfo) { using (DocVersion dv = dvInfo.Get()) { OnNodeOpenProperty(this, new vlnTreePropertyEventArgs(string.Format("{0} Properties", dv.DocVersionConfig.Name), dv.DocVersionConfig)); } } private void OpenProperties(ProcedureInfo procInfo) { using (Procedure proc = procInfo.Get()) { OnNodeOpenProperty(this, new vlnTreePropertyEventArgs(string.Format("{0} {1} Properties", proc.ProcedureConfig.Number, proc.ProcedureConfig.Title), proc.ProcedureConfig)); } } private void OpenProperties(SectionInfo sectInfo) { OnSectionShouldClose(this, new vlnTreeSectionInfoEventArgs(sectInfo)); using (Section sect = sectInfo.Get()) { string title = null; if (sectInfo.SectionConfig.Number.Length > 0) title = string.Format("{0} {1} Properties", sectInfo.SectionConfig.Number, sectInfo.SectionConfig.Title); else title = string.Format("{0} Properties", sectInfo.SectionConfig.Title); OnNodeOpenProperty(this, new vlnTreePropertyEventArgs(title, sect.SectionConfig)); } } private void OpenProperties(StepInfo stpinfo) { using (Step stp = stpinfo.Get()) { } } #endregion #region OpenNode private void tv_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar == '\r') { OpenNode(); e.Handled = true; } } public void OpenNode() { VETreeNode tn = SelectedNode as VETreeNode; if (tn != null) { if (tn.VEObject.GetType() == typeof(FolderInfo) || tn.VEObject.GetType() == typeof(DocVersionInfo) || tn.VEObject.GetType() == typeof(PartInfo)) { if (tn.Nodes.Count > 0) { tn.Expand(); SelectedNode = tn.Nodes[0]; Focus(); } } else OnNodeSelect(this, new vlnTreeEventArgs(SelectedNode)); } } #endregion #region InsertAllLevels public void tv_NodeNew(MenuSelections newtype) { VETreeNode tn = null; if (SelectedNode == null) return; SetLastValues((VETreeNode)SelectedNode); #region InsertFolderOrDocVersion if (_LastFolderInfo != null) { using (Folder parentfolder = _LastFolderInfo.Get()) { if (newtype == MenuSelections.DocVersion) { int dvid = -1; // flag to allow user to cancel from dialog & then we remove it. using (DocVersion docversion = DocVersion.MakeDocVersion(parentfolder, "Working Draft", "Title", null, null, null)) { ShowBrokenRules(docversion.BrokenRulesCollection); SetLastValues(DocVersionInfo.Get(docversion.VersionID)); if (OnNodeOpenProperty(this, new vlnTreePropertyEventArgs("Working Draft", docversion.DocVersionConfig)) == DialogResult.OK) { docversion.Save().Dispose(); tn = new VETreeNode(_LastDocVersionInfo); SelectedNode.Nodes.Add(tn); // add tree node to end of list. } else dvid = docversion.VersionID; } if (dvid != -1) DocVersion.Delete(dvid); } else if (newtype == MenuSelections.Folder) { int f1 = -1; // flag to allow user to cancel from dialog & then we remove it. string uniquename = _LastFolderInfo.UniqueChildName("New Folder"); using (Folder folder = Folder.MakeFolder(parentfolder, parentfolder.MyConnection, uniquename, string.Empty, "Short Name", null, string.Empty, DateTime.Now, "Test")) { ShowBrokenRules(folder.BrokenRulesCollection); SetLastValues(FolderInfo.Get(folder.FolderID)); if (OnNodeOpenProperty(this, new vlnTreePropertyEventArgs(uniquename, folder.FolderConfig)) == DialogResult.OK) { folder.Save().Dispose(); tn = new VETreeNode((IVEDrillDownReadOnly)_LastFolderInfo); SelectedNode.Nodes.Add(tn); // add new tree node to end of childlist. } else f1 = folder.FolderID; } if (f1 != -1) Folder.Delete(f1); } else if (newtype == MenuSelections.FolderAfter||newtype == MenuSelections.FolderBefore) { int f2 = -1; string uniquename = _LastFolderInfo.MyParent.UniqueChildName("New Folder"); int myindex = SelectedNode.Index + ((newtype == MenuSelections.FolderAfter) ? 1 : 0); FolderInfo parfolderinfo = FolderInfo.Get(parentfolder.FolderID); double? myorder = parfolderinfo.NewManualOrder(myindex); using (Folder folder = Folder.MakeFolder(parentfolder.MyParent, parentfolder.MyConnection, uniquename, string.Empty, "Short Name", null, myorder, string.Empty, DateTime.Now, "Test")) { ShowBrokenRules(folder.BrokenRulesCollection); SetLastValues(FolderInfo.Get(folder.FolderID)); if (OnNodeOpenProperty(this, new vlnTreePropertyEventArgs(uniquename, folder.FolderConfig)) == DialogResult.OK) { folder.Save().Dispose(); tn = new VETreeNode((IVEDrillDownReadOnly)_LastFolderInfo); if (newtype == MenuSelections.FolderBefore) SelectedNode.Parent.Nodes.Insert(SelectedNode.Index, tn); if (newtype == MenuSelections.FolderAfter) SelectedNode.Parent.Nodes.Insert(SelectedNode.Index + 1, tn); } else f2 = folder.FolderID; } if (f2 != -1) Folder.Delete(f2); } } } #endregion #region InsertProcedure else if (newtype == MenuSelections.Procedure) { int p1 = -1; using (Procedure procedure = Procedure.MakeProcedure(_LastDocVersionInfo, _LastDocVersionInfo.Procedures.Count!=0?_LastDocVersionInfo.Procedures[_LastDocVersionInfo.Procedures.Count-1]:null, null, "New Procedure", 0)) { ShowBrokenRules(procedure.BrokenRulesCollection); SetLastValues(ProcedureInfo.Get(procedure.ItemID)); if (OnNodeOpenProperty(this, new vlnTreePropertyEventArgs("New Procedure", procedure.ProcedureConfig)) == DialogResult.OK) { procedure.Save().Dispose(); tn = new VETreeNode(_LastProcedureInfo); SelectedNode.Nodes.Add(tn); // add tree node to end of list. } else p1 = procedure.ItemID; } if (p1 != -1) Item.Delete(p1); } else if (newtype == MenuSelections.ProcedureAfter || newtype == MenuSelections.ProcedureBefore) { int p2 = -1; int tvindex = SelectedNode.Index; // if inserting before, the parent is set in case previous is null, i.e. beginning of the list. using (Procedure procedure = Procedure.MakeProcedure((newtype == MenuSelections.ProcedureAfter) ? null : _LastProcedureInfo.ActiveParent, (newtype == MenuSelections.ProcedureAfter) ? _LastProcedureInfo : _LastProcedureInfo.MyPrevious, null, "New Procedure", 0)) { ShowBrokenRules(procedure.BrokenRulesCollection); SetLastValues(ProcedureInfo.Get(procedure.ItemID)); if (OnNodeOpenProperty(this, new vlnTreePropertyEventArgs("New Procedure", procedure.ProcedureConfig)) == DialogResult.OK) { procedure.Save().Dispose(); tn = new VETreeNode(_LastProcedureInfo); TreeNode par = SelectedNode.Parent; par.Nodes.Insert(tvindex + ((newtype == MenuSelections.ProcedureBefore) ? 0 : 1), tn); } else p2 = procedure.ItemID; } if (p2 != -1) Item.Delete(p2); } #endregion #region InsertSection else if (newtype == MenuSelections.Section) // Insert subsection at end of parents section list { int s1 = -1; if (!(_LastProcedureInfo == null) || !(_LastSectionInfo == null)) { using (Section section = Section.MakeSection(_LastItemInfo, _LastItemInfo.LastChild(E_FromType.Section), null, "New Section", 10000)) { ShowBrokenRules(section.BrokenRulesCollection); SetLastValues(SectionInfo.Get(section.ItemID)); if (OnNodeOpenProperty(this, new vlnTreePropertyEventArgs("New Section", section.SectionConfig)) == DialogResult.OK) { tn = new VETreeNode(_LastSectionInfo); SelectedNode.Nodes.Add(tn); // add tree node to end of list. } else s1 = section.ItemID; } if (s1 != -1) Item.Delete(s1); } } else if (newtype == MenuSelections.SectionAfter || newtype == MenuSelections.SectionBefore) { int tvindex = SelectedNode.Index; // if inserting before, the parent is set in case previous is null, i.e. beginning of the list. int s2 = -1; using (Section section = Section.MakeSection((newtype == MenuSelections.SectionAfter) ? null : _LastSectionInfo.MyParent, (newtype == MenuSelections.SectionAfter) ? _LastSectionInfo : _LastSectionInfo.MyPrevious, null, "New Section", 10000)) { ShowBrokenRules(section.BrokenRulesCollection); SetLastValues(SectionInfo.Get(section.ItemID)); if (OnNodeOpenProperty(this, new vlnTreePropertyEventArgs("New Section", section.SectionConfig)) == DialogResult.OK) { tn = new VETreeNode(_LastSectionInfo); TreeNode par = SelectedNode.Parent; par.Nodes.Insert(tvindex + ((newtype == MenuSelections.SectionBefore) ? 0 : 1), tn); } else s2 = section.ItemID; } if (s2 != -1) Item.Delete(s2); } #endregion #region InsertStep else if (newtype == MenuSelections.Step) // insert step from section - no substeps from tree. { tn = InsertChildStep((VETreeNode)SelectedNode); } else if (newtype == MenuSelections.StepAfter || newtype == MenuSelections.StepBefore && _LastStepInfo != null) { tn = InsertBeforeOrAfter(newtype, (VETreeNode)SelectedNode); } #endregion if (tn != null) { SelectedNode = tn; OnNodeNew(this, new vlnTreeEventArgs(SelectedNode)); Refresh(); } } private VETreeNode InsertChildStep(VETreeNode tn) { // If parent step is open in editor, use the OnInsertItemInfo to insert step & add stepitems to step editor panel ItemInfo ii = tn.VEObject as ItemInfo; if (OnInsertItemInfo(this, new vlnTreeItemInfoInsertEventArgs(ii, E_InsertType.Child, "New Step", 20002, E_FromType.Step))) { return null; // should we try to get to the child? } // The parent step was not open in the step editor, just create new step and add treenode. using (Step step = Step.MakeStep(_LastItemInfo, _LastItemInfo.LastChild(E_FromType.Step), null, "New Step", 20002, E_FromType.Step)) { ShowBrokenRules(step.BrokenRulesCollection); SetLastValues(StepInfo.Get(step.ItemID)); tn = new VETreeNode(_LastStepInfo); SelectedNode.Nodes.Add(tn); // add tree node to end of list. } return tn; } private VETreeNode InsertBeforeOrAfter(MenuSelections newtype, VETreeNode tn) { // If parent step is open in editor, use the OnInsertItemInfo to insert step & add stepitems to step editor panel ItemInfo ii = tn.VEObject as ItemInfo; if (OnInsertItemInfo(this, new vlnTreeItemInfoInsertEventArgs(ii,(newtype == MenuSelections.StepAfter) ? E_InsertType.After:E_InsertType.Before, "New Step"))) { return (VETreeNode)((newtype == MenuSelections.StepAfter) ? tn.NextNode : tn.PrevNode); } // The parent step was not open in the step editor, just create new step and add treenode. int tvindex = SelectedNode.Index; // if inserting before, the parent is set in case previous is null, i.e. beginning of the list. ItemInfo parent = (newtype == MenuSelections.StepAfter) ? null : _LastStepInfo.MyParent; using (Step step = Step.MakeStep(parent, (newtype == MenuSelections.StepAfter) ? _LastStepInfo : _LastStepInfo.MyPrevious, null, "New Step", (int)_LastStepInfo.MyContent.Type, (E_FromType)_LastStepInfo.FirstSibling.ItemParts[0].FromType)) { ShowBrokenRules(step.BrokenRulesCollection); SetLastValues(StepInfo.Get(step.ItemID)); tn = new VETreeNode(_LastStepInfo); TreeNode par = SelectedNode.Parent; par.Nodes.Insert(tvindex + ((newtype == MenuSelections.StepBefore) ? 0 : 1), tn); } return tn; } private void ShowBrokenRules(BrokenRulesCollection brs) { if (brs != null) { foreach (BrokenRule br in brs) { Console.WriteLine("broken rule {0}", br.Description); } } } #endregion #region DeleteAllLevels private bool tv_NodeDelete() { SetLastValues((VETreeNode)SelectedNode); DialogResult result = MessageBox.Show("Are you sure you want to delete " + SelectedNode.Text, "Verify Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result == DialogResult.Yes) { if (_LastFolderInfo != null) { Folder.Delete(_LastFolderInfo.FolderID); _LastFolderInfo = null; return true; } else if (_LastDocVersionInfo != null) { DocVersion.Delete(_LastDocVersionInfo.VersionID); _LastDocVersionInfo = null; return true; } else if (_LastProcedureInfo != null) { // always return false because an event gets fired to delete tree nodes. if (!DeleteItemInfoAndChildren(_LastProcedureInfo)) return false; _LastProcedureInfo = null; return false; } else if (_LastSectionInfo != null) { OnSectionShouldClose(this, new vlnTreeSectionInfoEventArgs(_LastSectionInfo)); // always return false because an event gets fired to delete tree nodes. if (!DeleteItemInfoAndChildren(_LastSectionInfo)) { return false; } WordSectionEventArgs args = new WordSectionEventArgs(_LastSectionInfo); OnWordSectionDeleted(this, args); _LastSectionInfo = null; return false; } else if (_LastStepInfo != null) { // always return false because an event gets fired to delete tree nodes. if (!DeleteItemInfoAndChildren(_LastStepInfo)) return false; _LastStepInfo = null; return false; } } return false; } private bool DeleteItemInfoAndChildren(ItemInfo ii) { try { // send an event to frmVeproms that sends an event to the stepeditor to // do delete using stepitem - this manages windowing from the step editor. // If the procedure is open & you're deleting procedure, you want to close open // window - this is done in DisplayTabControl-DeleteStepTabItem. if (!OnDeleteItemInfo(this, new vlnTreeItemInfoEventArgs(ii))) Item.DeleteItemAndChildren(ii); return true; } catch (System.Data.SqlClient.SqlException ex) { HandleSqlExceptionOnDelete(ex, ii); return false; } } private void HandleSqlExceptionOnDelete(System.Data.SqlClient.SqlException ex, ItemInfo ii) { if (ex.Message.Contains("has External Transitions and has no next step")) { using (TransitionInfoList exTrans = TransitionInfoList.GetExternalTransitions(ii.ItemID)) { DialogResult ans = MessageBox.Show("Transitions exist to this step and cannot be adjusted automatically." + "\r\n\r\nDo you want to be placed on the " + (exTrans.Count > 1 ? "first " : "") + "substep with the problem Transition?" + "\r\n\r\nSubsteps with Problem Transitions" + exTrans.Summarize(), "Cannot Delete This Step", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (ans == DialogResult.Yes) { OnOpenItem(this, new vlnTreeItemInfoEventArgs(exTrans[0].MyContent.ContentItems[0])); } } } else if (ex.Message.Contains("has External Transitions to it's children")) { using (TransitionInfoList exTrans = TransitionInfoList.GetExternalTransitionsToChildren(ii.ItemID)) { DialogResult ans = MessageBox.Show("Transitions exist to substeps of this step and cannot be adjusted automatically." + "\r\n\r\nDo you want to be placed on the " + (exTrans.Count > 1 ? "first " : "") + "substep with the problem Transition?" + "\r\n\r\nSubsteps with Problem Transitions:" + exTrans.Summarize(), "Cannot Delete This Step", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (ans == DialogResult.Yes) { OnOpenItem(this, new vlnTreeItemInfoEventArgs(exTrans[0].MyContent.ContentItems[0])); } } } else MessageBox.Show(ex.Message, "SQL Exception", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); } #endregion #region SetLastValuesAndSaveIfChangedStuff private void SetLastValues(VETreeNode node) { _LastTreeNode = node; SetLastValues(node.VEObject); } private void SetLastValues(IVEDrillDownReadOnly veobject) { _LastFolderInfo = veobject as FolderInfo; _LastDocVersionInfo = veobject as DocVersionInfo; _LastProcedureInfo = veobject as ProcedureInfo; _LastSectionInfo = veobject as SectionInfo; _LastStepInfo = veobject as StepInfo; _LastItemInfo = veobject as ItemInfo; } #endregion #region Cursor private bool SetupDragCursor(ImageList il, TreeNode tn) { // Reset image list used for drag image il.Images.Clear(); int howBig = tn.Bounds.Size.Width + this.Indent; if (howBig > 256) howBig = 256; il.ImageSize = new Size(howBig, tn.Bounds.Height); // Create new bitmap // This bitmap will contain the tree node image to be dragged Bitmap bmp = new Bitmap(tn.Bounds.Width + this.Indent, tn.Bounds.Height); // Get graphics from bitmap Graphics gfx = Graphics.FromImage(bmp); // Draw node icon into the bitmap if (this.ImageList != null) gfx.DrawImage(this.ImageList.Images[0], 0, 0); // Draw node label into bitmap gfx.DrawString(tn.Text, this.Font, new SolidBrush(this.ForeColor), // new SolidBrush(Color.Blue), (float)this.Indent, 1.0f); // Add bitmap to imagelist _dragImageList.Images.Add(bmp); // Get mouse position in client coordinates Point p = this.PointToClient(Control.MousePosition); // Compute delta between mouse position and node bounds int dx = p.X + this.Indent - tn.Bounds.Left; int dy = p.Y - tn.Bounds.Top; // Begin dragging image return DragHelper.ImageList_BeginDrag(_dragImageList.Handle, 0, dx, dy); } private void tv_ItemDrag(object sender, System.Windows.Forms.ItemDragEventArgs e) { // Get drag node and select it try { TreeNode dragNode = (TreeNode)e.Item; Type t = dragNode.GetType(); //if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("Item Drag {0} - {1}", t.FullName, t.BaseType.FullName); Type t2 = Type.GetType(t.FullName); //if(t2 != null) // if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("Item Drag {0} - {1}", t2.FullName, t2.BaseType.FullName); this.SelectedNode = dragNode; ItemInfo iidrag = ((VETreeNode)dragNode).VEObject as ItemInfo; FolderInfo fdrag = ((VETreeNode)dragNode).VEObject as FolderInfo; DocVersionInfo ddrag = ((VETreeNode)dragNode).VEObject as DocVersionInfo; if ((iidrag == null && fdrag == null && ddrag == null) || (iidrag != null && iidrag.IsStep)) { MessageBox.Show(iidrag==null?"Cannot drag/drop a grouping node.":"Cannot drag/drop a Step"); return; } if (SetupDragCursor(_dragImageList, dragNode)) { this.DoDragDrop(dragNode, DragDropEffects.Move | DragDropEffects.Copy);// Begin dragging DragHelper.ImageList_EndDrag();// End dragging image } } catch (Exception ex) { if(_MyLog.IsErrorEnabled)_MyLog.Error("tv_ItemDrag", ex); } } #endregion #region DragDrop ImageList _dragImageList = new ImageList(); public enum DropPosition : int { Child = 0, Before = 1, After = 2 } private class DropLocation { #region Business Methods private TreeNode _dropNode; public TreeNode DropNode { get { return _dropNode; } set { _dropNode = value; } } private int _index; public int Index { get { return _index; } set { _index = value; } } private DropPosition _position; public DropPosition Position { get { return _position; } set { _position = value; } } DateTime _lastScroll; public DateTime LastScroll { get { return _lastScroll; } } private string _location = string.Empty; #endregion #region Constructors public DropLocation(TreeView tv, System.Windows.Forms.DragEventArgs e, DateTime lastScroll) { _lastScroll = lastScroll; _dropNode = tv.GetNodeAt(tv.PointToClient(new Point(e.X, e.Y))); if (_dropNode == null) return; int OffsetY = tv.PointToClient(Cursor.Position).Y - _dropNode.Bounds.Top; if (OffsetY < _dropNode.Bounds.Height / 3) // First Third - Before { _index = _dropNode.Index; _dropNode = _dropNode.Parent; _position = DropPosition.Before; _location = string.Format("Before1 {0}[{1}] y={2}", _dropNode.Text, _index, OffsetY); } else if ((OffsetY / 2) < _dropNode.Bounds.Height / 3) // Second Third - Child { _location = string.Format("Child {0} y={1}", _dropNode.Text, OffsetY); _position = DropPosition.Child; _index = 0; //if (_dropNode.Parent == null) //{ // if(_MyLog.IsInfoEnabled)_MyLog.Info("Root Node"); //} } else // Last Third - After Now I need to check the X value { if (_dropNode.NextVisibleNode != null && _dropNode.Nodes.Count > 0 && _dropNode.IsExpanded)// Has Children & Expanded - Insert first child { // _dropNode = _dropNode.Nodes[0]; _index = 0; _position = DropPosition.Before; _location = string.Format("Before2 {0}[{1}] y={2}", _dropNode.Text, _index, OffsetY); } else // No Children or Children Collapsed - Insert Next at various levels depending upon horizontal location. { Point pt = tv.PointToClient(new Point(e.X, e.Y)); TreeNode nextParent = _dropNode.NextNode; if (nextParent != null) nextParent = nextParent.Parent; do { _index = _dropNode.Index; _dropNode = _dropNode.Parent; } while (pt.X < _dropNode.Bounds.X && _dropNode != nextParent); _location = string.Format("After {0}[{1}] y={2}", _dropNode.Text, _index, OffsetY); _position = DropPosition.After; } } LimitMoves(e); } public void LimitMoves(DragEventArgs e) { if ((e.KeyState & 8) == 0) { //TreeNode dragNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode"); //TreeNode dragNode = (TreeNode)e.Data.GetData("TreeTest.FolderTreeNode"); TreeNode dragNode = vlnTreeView.GetTreeNodeFromData(e.Data); switch (_position) { case DropPosition.Before: if (dragNode == _dropNode.Nodes[_index] || dragNode == _dropNode.Nodes[_index].PrevNode) { // if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("Before {0} {1} {2} {3} {4}", dragNode.Text ,_position.ToString() , _dropNode.Nodes[_index].Text // ,_dropNode.Nodes[_index].PrevNode,_dropNode.Nodes[_index].NextNode); _dropNode = null; } break; case DropPosition.Child: if (dragNode.Parent == _dropNode) { // if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("Child {0} {1} {2} {3} {4} {5}", dragNode.Text ,_position.ToString() , _dropNode.Nodes[_index].Text // ,_dropNode.Nodes[_index].PrevNode,_dropNode.Nodes[_index].NextNode,DateTime.Now); _dropNode = null; } break; case DropPosition.After: if (dragNode == _dropNode.Nodes[_index] || dragNode == _dropNode.Nodes[_index].NextNode) { // if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("After {0} {1} {2} {3} {4}", dragNode.Text ,_position.ToString() , _dropNode.Nodes[_index].Text // ,_dropNode.Nodes[_index].PrevNode,_dropNode.Nodes[_index].NextNode); _dropNode = null; } break; } } } #endregion public override string ToString() { return string.Format("{0}[{1}].{2}", _dropNode.Text, _index, _position.ToString()); } #region Drawing private void TreeNodeTriangle(Graphics g) { Rectangle r = _dropNode.Bounds; int RightPos = r.Right + 6; Point[] RightTriangle = new Point[]{ new Point(RightPos, r.Y ), new Point(RightPos - (r.Height / 2), r.Y + (r.Height / 2)), new Point(RightPos, r.Y + r.Height), new Point(RightPos - (r.Height / 3), r.Y + (r.Height / 2)) }; g.FillPolygon(System.Drawing.Brushes.Black, RightTriangle); } private void InsertPointer(TreeNode tn, Graphics g) { TreeView tv = _dropNode.TreeView; Rectangle r2 = _dropNode.Nodes[_index].Bounds; Rectangle r3 = tn.Bounds; int y = (_position == DropPosition.Before ? r2.Y : r3.Bottom); int x = r2.Left; if (y == 0) { return; } //if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("Line at {0} Node {1}[{2}] {3}", _location, _dropNode.Text, _index, _position.ToString()); Color lc = (_position == DropPosition.After ? Color.Red : Color.Blue); Brush lb = (_position == DropPosition.After ? Brushes.Red : Brushes.Blue); Point[] RightTriangle; if (_position == DropPosition.After) { RightTriangle = new Point[]{ new Point(x, y ), new Point(x+4, y+4), new Point(x+8, y)}; } else { RightTriangle = new Point[]{ new Point(x, y), new Point(x+4, y-4), new Point(x+8, y)}; } g.DrawLine(new System.Drawing.Pen(lc, 2), new Point(r2.Left, y), new Point(tv.Width - 8, y)); g.FillPolygon(lb, RightTriangle); } public void ShowLocation(System.Windows.Forms.DragEventArgs e, bool ScrollOnly) { //if (e.Effect == DragDropEffects.None) return; if (_dropNode != null) { // if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("ShowLocation1 {0} {1}", e.Effect.ToString(), DateTime.Now.Millisecond); DragHelper.ImageList_DragShowNolock(false); TreeView tv = _dropNode.TreeView; TreeNode tmp = tv.GetNodeAt(tv.PointToClient(new Point(e.X, e.Y))); // if (!ScrollOnly) // { if (ScrollTreeView(tmp) || !ScrollOnly) { //if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("ShowLocation2 {0} {1}", e.Effect.ToString(), DateTime.Now.Millisecond); tv.Refresh(); if (e.Effect != DragDropEffects.None) { //tv.SelectedNode = dropNode; Graphics g = tv.CreateGraphics(); TreeNodeTriangle(g); if (_position != DropPosition.Child)InsertPointer(tmp, g); } } // } // else ScrollTreeView(tmp); DragHelper.ImageList_DragShowNolock(true); } } #endregion public void ShowLocation() { //if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("{0}[{1}] {2}", _dropNode.Text, _index, _position.ToString()); } #region AutoScroll private bool ScrollTreeView(TreeNode tn) { bool retval = false; TimeSpan ts = new TimeSpan(DateTime.Now.Ticks - _lastScroll.Ticks); if (ts.Milliseconds > 100)// This controls the scroll speed { int top = tn.Bounds.Top; _lastScroll = DateTime.Now; if (tn.TreeView.ClientSize.Height < tn.Bounds.Bottom) tn.EnsureVisible();// Make sure that the current node is visible if (tn.NextVisibleNode != null && tn.TreeView.ClientSize.Height < tn.NextVisibleNode.Bounds.Bottom) tn.NextVisibleNode.EnsureVisible();// Make sure that the next node is visible else if (tn.PrevVisibleNode != null && tn.PrevVisibleNode.PrevVisibleNode != null && tn.PrevVisibleNode.PrevVisibleNode.IsVisible == false) tn.PrevVisibleNode.PrevVisibleNode.EnsureVisible();// Make sure that the previous node is visible } else if (tn.PrevVisibleNode != null && tn.PrevVisibleNode.IsVisible == false) tn.PrevVisibleNode.EnsureVisible();// Make sure that the previous node is visible retval = (top != tn.Bounds.Top); // if (retval) if(_MyLog.IsInfoEnabled)_MyLog.Info("Scroll"); } return retval; } #endregion public bool Equals(DropLocation dl) { return (dl != null && _lastScroll.Equals(dl.LastScroll) && _dropNode.Equals(dl.DropNode) && _position.Equals(dl.Position)); } } private DropLocation _LastDropLocation = null; private void tv_DragOver(object sender, System.Windows.Forms.DragEventArgs e) { try { TreeNode dragNode = GetTreeNodeFromData(e.Data); // Compute drag position and move image Point formP = this.FindForm().PointToClient(new Point(e.X, e.Y)); DragHelper.ImageList_DragMove(formP.X - this.Left, formP.Y - this.Top); DropLocation dl = new DropLocation(this, e, _LastDropLocation == null ? DateTime.Now : _LastDropLocation.LastScroll); string s = string.Empty; if (dl.DropNode == null) { e.Effect = DragDropEffects.None; } else { DragDropEffects ee = e.Effect; if ((e.KeyState & 8) == 8) ee = DragDropEffects.Copy; // Copy it else ee = DragDropEffects.Move; // Move it if (IsChild(dragNode, dl.DropNode)) // Don't copy or move to a child node ee = DragDropEffects.None; else if (IsDocVersion((VETreeNode)dragNode)) // Don't move docversions ee = DragDropEffects.None; else if (IsFolder((VETreeNode)dragNode)) // Folder move is only valid if moving to folder with NO docversions { FolderInfo fdropi = ((VETreeNode)dl.DropNode).VEObject as FolderInfo; if (fdropi == null || fdropi.FolderDocVersionCount > 0) ee = DragDropEffects.None; } else if (IsSection((VETreeNode)dragNode)) { // A section can be moved within a procedure or to a section within the same procedure... // For HLP, just move within the same procedure // TODO: allow for section move within subsections. ProcedureInfo pdropi = ((VETreeNode)dl.DropNode).VEObject as ProcedureInfo; if (pdropi == null || (dragNode.Parent != dl.DropNode)) ee = DragDropEffects.None; } else if (!IsFolder((VETreeNode)dragNode) && (dragNode.Parent != dl.DropNode)) ee = DragDropEffects.None; if (e.Effect != ee) e.Effect = ee; dl.ShowLocation(e, dl.Equals(_LastDropLocation)); _LastDropLocation = dl; } } catch (Exception ex) { if(_MyLog.IsErrorEnabled)_MyLog.Error("tv_DragOver", ex); } } private bool IsSection(VETreeNode vETreeNode) { SectionInfo sectInfo = vETreeNode.VEObject as SectionInfo; if (sectInfo != null) return true; return false; } private bool IsProcedure(VETreeNode vETreeNode) { ProcedureInfo procInfo = vETreeNode.VEObject as ProcedureInfo; if (procInfo != null) return true; return false; } private bool IsDocVersion(VETreeNode dragNode) { DocVersionInfo dvInfo = dragNode.VEObject as DocVersionInfo; if (dvInfo != null) return true; return false; } private static TreeNode GetTreeNodeFromData(IDataObject datobj) { foreach (string s in datobj.GetFormats()) { try { return (TreeNode)datobj.GetData(s); } catch (Exception ex) { if(_MyLog.IsErrorEnabled)_MyLog.Error("GetTreeNodeFromData", ex); } } return null; } private bool IsFolder(VETreeNode veTreeNode) { return (veTreeNode.VEObject.GetType() == typeof(FolderInfo)); } private void tv_DragDrop(object sender, System.Windows.Forms.DragEventArgs e) { try { TreeNode dragNode = GetTreeNodeFromData(e.Data); DragHelper.ImageList_DragLeave(this.Handle); int index = _LastDropLocation.Index + (_LastDropLocation.Position == DropPosition.After ? 1 : 0); int myIndex = index; if (dragNode.Parent == _LastDropLocation.DropNode && dragNode.Index <= _LastDropLocation.Index) index--; if (e.Effect == DragDropEffects.Move)// If Move Remove drag node from parent dragNode.Remove(); else dragNode = Clone(dragNode); _LastDropLocation.DropNode.Nodes.Insert(index, dragNode); this.SelectedNode = dragNode; FolderInfo fdragi = ((VETreeNode)dragNode).VEObject as FolderInfo; FolderInfo fdropi = ((VETreeNode)_LastDropLocation.DropNode).VEObject as FolderInfo; if (fdragi != null && fdropi != null && fdropi.FolderDocVersionCount==0) { using (Folder fdrag = fdragi.Get()) { using (Folder fdrop = fdropi.Get()) { fdrag.ManualOrder = fdropi.NewManualOrder(myIndex); fdrag.MyParent = fdrop; fdrag.Save(); } } return; } // No drag/drop supported for document versions. // Allow drag/drop of procedures within a Document Version (must have same parent). Note that drop location // may either be a document version or a procedure depending on where the user wants to position the procedure. ProcedureInfo pdragi = ((VETreeNode)dragNode).VEObject as ProcedureInfo; ProcedureInfo pdropi = null; if (pdragi != null) // moving a procedure { pdropi = ((VETreeNode)_LastDropLocation.DropNode).VEObject as ProcedureInfo; if (pdropi != null && pdragi.ActiveParent == pdropi.ActiveParent) { pdragi.MoveProcedure(pdragi.ActiveParent, myIndex); return; } DocVersionInfo dvdropi = ((VETreeNode)_LastDropLocation.DropNode).VEObject as DocVersionInfo; DocVersionInfo dvdragpar = pdragi.ActiveParent as DocVersionInfo; if (dvdropi != null && dvdragpar.VersionID == dvdropi.VersionID) { pdragi.MoveProcedure(dvdropi, myIndex); return; } } // Allow drag/drop of sections within the same procedure or same section (if subsection) (must have same parent) SectionInfo sdragi = ((VETreeNode)dragNode).VEObject as SectionInfo; SectionInfo sdropi = null; if (sdragi != null) // moving a section { sdropi = ((VETreeNode)_LastDropLocation.DropNode).VEObject as SectionInfo; if (sdropi != null && sdragi.ActiveParent == sdropi.ActiveParent) { sdragi.MoveSection(sdragi, myIndex); return; } pdropi = ((VETreeNode)_LastDropLocation.DropNode).VEObject as ProcedureInfo; if (pdropi != null && sdragi.MyParent.ItemID == pdropi.ItemID) { sdragi.MoveSection(pdropi, myIndex); return; } } // Allow drag/drop of steps within the same parent only StepInfo stdragi = ((VETreeNode)dragNode).VEObject as StepInfo; StepInfo stdropi = null; if (stdragi != null) // moving a step { stdropi = ((VETreeNode)_LastDropLocation.DropNode).VEObject as StepInfo; if (stdropi != null && stdragi.ActiveParent == stdropi.ActiveParent) { stdragi.MoveStep(stdragi.ActiveParent, myIndex); return; } sdropi = ((VETreeNode)_LastDropLocation.DropNode).VEObject as SectionInfo; if (sdropi != null && stdragi.MyParent.ItemID == sdropi.ItemID) { stdragi.MoveStep(stdragi.ActiveParent, myIndex); return; } // the following handles items under the app nodes of 'steps', 'notes', 'cautions', etc. if (sdropi == null && dragNode.Parent == _LastDropLocation.DropNode) { stdragi.MoveStep(stdragi.ActiveParent, myIndex); return; } } } catch (Exception ex) { if(_MyLog.IsErrorEnabled)_MyLog.Error("tv_DragDrop", ex); } } // private void DumpMembers(object o) // { // Type t = o.GetType(); // //if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("\r\n\r\nMembers for type {0}", t.ToString()); // MemberInfo[] mis = t.GetMembers(); // int i = 0; // foreach (MemberInfo mi in mis) // { // i++; // try // { // //if(mi.MemberType != MemberTypes.Method) // //if(_MyLog.IsInfoEnabled)_MyLog.InfoFormat("{0} {1} {2}", i, mi.Name, mi.MemberType); //// if (fi.Name == "TreeView") //// fi.SetValue(o, null); // } // catch (Exception ex) // { // if(_MyLog.IsErrorEnabled)_MyLog.Error("DumpMembers", ex); // } // } // } private TreeNode Clone(TreeNode tn) { TreeNode tmp = (TreeNode)tn.Clone(); ExpandMatch(tmp,tn); return tmp; } private void tv_DragDropOld(object sender, System.Windows.Forms.DragEventArgs e) { TreeNode dragNode = (TreeNode)e.Data.GetData("System.Windows.Forms.TreeNode");// Get the drag node DragHelper.ImageList_DragLeave(this.Handle); TreeNode cloneNode = (TreeNode)dragNode.Clone();// copy the source node ExpandMatch(cloneNode, dragNode); _LastDropLocation.DropNode.Nodes.Insert(_LastDropLocation.Index + (_LastDropLocation.Position == DropPosition.After ? 1 : 0), cloneNode); if (e.Effect == DragDropEffects.Move)// If Move Remove drag node from parent dragNode.Remove(); this.SelectedNode = cloneNode; } private void tv_DragEnter(object sender, System.Windows.Forms.DragEventArgs e) { DragHelper.ImageList_DragEnter(this.Handle, e.X - this.Left, e.Y - this.Top); } private void tv_DragLeave(object sender, System.EventArgs e) { DragHelper.ImageList_DragLeave(this.Handle); this.Refresh(); } private void ExpandMatch(TreeNode tn1, TreeNode tn2) { if (tn2.IsExpanded) tn1.Expand(); foreach (TreeNode tc in tn2.Nodes) ExpandMatch(tn1.Nodes[tc.Index], tc); } private bool IsChild(TreeNode parent, TreeNode child) { if (parent.Equals(child)) return true;// Check against self foreach (TreeNode tc in parent.Nodes) if (IsChild(tc, child)) return true;//Check all children return false;// Must not be a child at this level } #endregion private bool _AdjustingTree = false; public void AdjustTree(ItemInfo selectedItem) { // start at the top parent and walk down the nodes to find child VETreeNode node = FindNodeAndExpand(selectedItem); if (node != null) { _AdjustingTree = true; this.SelectedNode = node; _AdjustingTree = false; } } public VETreeNode FindNodeAndExpand(IVEDrillDownReadOnly selectedItem) { if (selectedItem.ActiveParent == null) { return (VETreeNode)this.Nodes[0]; // Return the top node } VETreeNode parent = FindNodeAndExpand(selectedItem.ActiveParent); if (parent == null) return null; if (!parent.IsExpanded) parent.Expand(); foreach (TreeNode childNode in parent.Nodes) { VETreeNode child = childNode as VETreeNode; if (child != null && CompareVEObject(child.VEObject, selectedItem)) return child; } foreach (TreeNode childNode in parent.Nodes) { VETreeNode child = childNode as VETreeNode; if (child.VEObject is PartInfo) foreach (VETreeNode grandchild in child.Nodes) if (CompareVEObject(grandchild.VEObject, selectedItem)) return grandchild; } return null; } public bool CompareVEObject(IVEDrillDownReadOnly obj1, IVEDrillDownReadOnly obj2) { ItemInfo myItem = obj1 as ItemInfo; if (myItem != null) if (myItem.ItemID == ((ItemInfo)obj2).ItemID) return true; DocVersionInfo myDV = obj1 as DocVersionInfo; if (myDV != null) if (myDV.VersionID == ((DocVersionInfo)obj2).VersionID) return true; FolderInfo myFolder = obj1 as FolderInfo; if (myFolder != null) if (myFolder.FolderID == ((FolderInfo)obj2).FolderID) return true; return false; } } #region DragHelper public class DragHelper { [DllImport("comctl32.dll")] public static extern bool InitCommonControls(); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] public static extern bool ImageList_BeginDrag(IntPtr himlTrack, int iTrack, int dxHotspot, int dyHotspot); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] public static extern bool ImageList_DragMove(int x, int y); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] public static extern void ImageList_EndDrag(); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] public static extern bool ImageList_DragEnter(IntPtr hwndLock, int x, int y); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] public static extern bool ImageList_DragLeave(IntPtr hwndLock); [DllImport("comctl32.dll", CharSet = CharSet.Auto)] public static extern bool ImageList_DragShowNolock(bool fShow); static DragHelper() { InitCommonControls(); } } #endregion }