C2024-036 Add Filtering ability to the main PROMS procedure tree. #608
55
PROMS/VEPROMS User Interface/frmVEPROMS.Designer.cs
generated
55
PROMS/VEPROMS User Interface/frmVEPROMS.Designer.cs
generated
@@ -71,9 +71,12 @@ namespace VEPROMS
|
||||
this.labelItem10 = new DevComponents.DotNetBar.LabelItem();
|
||||
this.bottomProgBar = new DevComponents.DotNetBar.ProgressBarItem();
|
||||
this.labelItem9 = new DevComponents.DotNetBar.LabelItem();
|
||||
this.lblPreEditView = new DevComponents.DotNetBar.LabelItem();
|
||||
this.lblEditView = new DevComponents.DotNetBar.LabelItem();
|
||||
this.labelItem11 = new DevComponents.DotNetBar.LabelItem();
|
||||
this.btnItemInfo = new DevComponents.DotNetBar.ButtonItem();
|
||||
this.btnFilter = new DevComponents.DotNetBar.ButtonItem();
|
||||
this.txtFilter = new DevComponents.DotNetBar.TextBoxItem();
|
||||
this.lblItemID = new DevComponents.DotNetBar.LabelItem();
|
||||
this.lblResolution = new DevComponents.DotNetBar.LabelItem();
|
||||
this.btnEditItem = new DevComponents.DotNetBar.ButtonItem();
|
||||
@@ -524,19 +527,22 @@ namespace VEPROMS
|
||||
this.bottomBar.Font = new System.Drawing.Font("Segoe UI", 9F);
|
||||
this.bottomBar.IsMaximized = false;
|
||||
this.bottomBar.Items.AddRange(new DevComponents.DotNetBar.BaseItem[] {
|
||||
this.labelItem10,
|
||||
this.btnFilter,
|
||||
this.txtFilter,
|
||||
this.labelItem10,
|
||||
this.bottomProgBar,
|
||||
this.labelItem9,
|
||||
this.lblEditView,
|
||||
this.labelItem11,
|
||||
this.btnItemInfo,
|
||||
this.lblItemID,
|
||||
this.lblResolution,
|
||||
this.btnEditItem,
|
||||
this.lblUser,
|
||||
this.lblLastChange,
|
||||
this.btnStepRTF,
|
||||
this.btnFixMSWord});
|
||||
this.lblPreEditView,
|
||||
this.lblEditView,
|
||||
this.labelItem11,
|
||||
this.btnItemInfo,
|
||||
this.lblItemID,
|
||||
this.lblResolution,
|
||||
this.btnEditItem,
|
||||
this.lblUser,
|
||||
this.lblLastChange,
|
||||
this.btnStepRTF,
|
||||
this.btnFixMSWord});
|
||||
this.bottomBar.Location = new System.Drawing.Point(5, 573);
|
||||
this.bottomBar.Name = "bottomBar";
|
||||
this.bottomBar.Size = new System.Drawing.Size(1185, 25);
|
||||
@@ -546,6 +552,21 @@ namespace VEPROMS
|
||||
this.bottomBar.TabStop = false;
|
||||
this.bottomBar.Text = "bar1";
|
||||
//
|
||||
// btnFilter
|
||||
//
|
||||
this.btnFilter.Name = "btnFilter";
|
||||
this.btnFilter.Text = "Tree View Search:";
|
||||
this.btnFilter.Click += SubmitFilter;
|
||||
//
|
||||
// txtFilter
|
||||
//
|
||||
this.txtFilter.TextBox.Font = new System.Drawing.Font("Microsoft Sans Serif", 10F);
|
||||
this.txtFilter.Name = "txtFilter";
|
||||
this.txtFilter.TextBoxWidth = 120;
|
||||
this.txtFilter.TextBox.TabIndex = 0;
|
||||
this.txtFilter.TextBox.KeyPress += new System.Windows.Forms.KeyPressEventHandler(this.FilterEnterKey);
|
||||
this.superTooltip1.SetSuperTooltip(this.txtFilter, new DevComponents.DotNetBar.SuperTooltipInfo("Filter", "", "This will filter the Procedure Tree in PROMS to Procedures containing entered words in the Procedure Number or Title. Press enter or the Tree View Search button to submit.", null, null, DevComponents.DotNetBar.eTooltipColor.Gray));
|
||||
//
|
||||
// txtSearch
|
||||
//
|
||||
this.txtSearch.Dock = System.Windows.Forms.DockStyle.Right;
|
||||
@@ -647,6 +668,11 @@ namespace VEPROMS
|
||||
this.lblEditView.ForeColor = System.Drawing.SystemColors.MenuText;
|
||||
this.lblEditView.Name = "lblEditView";
|
||||
this.lblEditView.Text = "Edit";
|
||||
// lblEditView
|
||||
//
|
||||
this.lblPreEditView.BorderSide = DevComponents.DotNetBar.eBorderSide.Left;
|
||||
this.lblPreEditView.BorderType = DevComponents.DotNetBar.eBorderType.Bump;
|
||||
this.lblPreEditView.Name = "lblPreEditView";
|
||||
//
|
||||
// labelItem11
|
||||
//
|
||||
@@ -1646,9 +1672,9 @@ namespace VEPROMS
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
#endregion
|
||||
#endregion
|
||||
|
||||
private DevComponents.DotNetBar.RibbonControl ribbonControl1;
|
||||
private DevComponents.DotNetBar.RibbonControl ribbonControl1;
|
||||
private DevComponents.DotNetBar.Office2007StartButton office2007StartButton1;
|
||||
private DevComponents.DotNetBar.ItemContainer itemContainer1;
|
||||
private DevComponents.DotNetBar.ItemContainer itemContainer2;
|
||||
@@ -1744,8 +1770,11 @@ namespace VEPROMS
|
||||
private DevComponents.DotNetBar.TabItem tabItemLibDocs;
|
||||
private Volian.Controls.Library.DisplayTags displayTags;
|
||||
private Volian.Controls.Library.DisplaySearch displaySearch1;
|
||||
private DevComponents.DotNetBar.LabelItem lblPreEditView;
|
||||
private DevComponents.DotNetBar.LabelItem lblEditView;
|
||||
private DevComponents.DotNetBar.ButtonItem btnItemInfo;
|
||||
private DevComponents.DotNetBar.ButtonItem btnFilter;
|
||||
private DevComponents.DotNetBar.TextBoxItem txtFilter;
|
||||
private DevComponents.DotNetBar.ButtonItem btnFixMSWord;
|
||||
private Volian.Controls.Library.DisplayBookMarks displayBookMarks;
|
||||
//private DevComponents.DotNetBar.LabelItem lblLocked;
|
||||
|
@@ -22,6 +22,9 @@ using Volian.Base.Library;
|
||||
using Volian.Print.Library;
|
||||
using JR.Utils.GUI.Forms;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
[assembly: log4net.Config.XmlConfigurator(Watch = true)]
|
||||
|
||||
@@ -2771,6 +2774,199 @@ namespace VEPROMS
|
||||
}
|
||||
}
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
// Recursively Expand the Tree
|
||||
// up to the procedure level
|
||||
// Since items are only loaded as they are expanded,
|
||||
// this is needed to search for matching text.
|
||||
private void LoadAllProcedures(VETreeNode tn)
|
||||
{
|
||||
if (tn == null || tn.VEObject.IsProcedure)
|
||||
return;
|
||||
|
||||
if (!tn.IsExpanded)
|
||||
{ tn.Expand(); }
|
||||
|
||||
foreach (var nde in tn.Nodes)
|
||||
LoadAllProcedures((VETreeNode)nde);
|
||||
}
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
// Return a list containing all
|
||||
// items in the Tree that match the entered text
|
||||
// + any item that is a parent of those.
|
||||
private List<IVEDrillDownReadOnly> GetMatchingTreeNodes(VETreeNode tn, string texttomatch)
|
||||
{
|
||||
List<IVEDrillDownReadOnly> matches = new List<IVEDrillDownReadOnly>();
|
||||
|
||||
//add any item that matches text
|
||||
//and all parents back up to the top most item
|
||||
if (tn.Text.ToLower().Contains(texttomatch.ToLower()))
|
||||
{
|
||||
matches.Add(tn.VEObject);
|
||||
VETreeNode parent_tn = (VETreeNode) tn.Parent;
|
||||
while (parent_tn != null)
|
||||
{
|
||||
if (!matches.Contains(parent_tn.VEObject))
|
||||
{ matches.Add(parent_tn.VEObject); }
|
||||
parent_tn = (VETreeNode)parent_tn.Parent;
|
||||
}
|
||||
}
|
||||
|
||||
if (!tn.VEObject.IsProcedure)
|
||||
{
|
||||
//if not at a procedure level,
|
||||
//loop through sub items
|
||||
//to check those for matches
|
||||
foreach (VETreeNode nde in tn.Nodes.OfType<VETreeNode>())
|
||||
{
|
||||
if (nde.Text != "Dummy VETreeNode(IVEDrillDownReadOnly o)")
|
||||
{
|
||||
List<IVEDrillDownReadOnly> tmpmatches = GetMatchingTreeNodes(nde, texttomatch);
|
||||
matches.AddRange(from mtch in tmpmatches
|
||||
where !matches.Contains(mtch)
|
||||
select mtch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
// Recursively loop through the Child Nodes
|
||||
// in the TreeView
|
||||
// remove anything not in the list
|
||||
private bool FilterTreeNodes(VETreeNode tn, List<IVEDrillDownReadOnly> filterlist)
|
||||
{
|
||||
if (tn == null)
|
||||
return false;
|
||||
|
||||
if (!filterlist.Contains(tn.VEObject) && (tn != (VETreeNode) tv.Nodes[0])) //Note:Always keep the top node
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (!tn.VEObject.IsProcedure)
|
||||
{
|
||||
//if not a procedure
|
||||
//mark the sub-items that need removal
|
||||
List<TreeNode> lst = (from VETreeNode nde in tn.Nodes.OfType<VETreeNode>()
|
||||
where FilterTreeNodes(nde, filterlist)
|
||||
select (TreeNode) nde).ToList();
|
||||
|
||||
//remove all items in the removal list
|
||||
//need to do this separately as can't modify the collection while looping through it above
|
||||
while (lst.Count > 0)
|
||||
{
|
||||
tn.Nodes.Remove(lst[0]);
|
||||
lst.Remove(lst[0]);
|
||||
}
|
||||
|
||||
//found a folder that matched that has no matching procedures
|
||||
//if this is case, allow folder to be expanded
|
||||
if (tn.Nodes.Count == 0 && filterlist.Contains(tn.VEObject))
|
||||
{
|
||||
tn.ChildrenLoaded = false;
|
||||
tn.RefreshNode();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
//Collection to block for task to complete
|
||||
private BlockingCollection<string> blockingQueueFilter = new BlockingCollection<string>();
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
// When Text Changes, Perform the filtering
|
||||
// Note that uses a blocking collection
|
||||
// in case multiple events fire at the same time
|
||||
// this is to prevent incorrect behavior when
|
||||
//doing something like hitting backspace a bunch
|
||||
private void SubmitFilter(object sender, EventArgs e)
|
||||
{
|
||||
//Consumer
|
||||
Task.Run(() =>
|
||||
{
|
||||
//Blocks until a new filter is available
|
||||
while (!blockingQueueFilter.IsCompleted)
|
||||
{
|
||||
string fltrtxt = blockingQueueFilter.Take();
|
||||
ProcessFilter(fltrtxt);
|
||||
}
|
||||
});
|
||||
|
||||
//Producer
|
||||
Task.Run(() => { blockingQueueFilter.Add(txtFilter?.Text); });
|
||||
|
||||
}
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
// When Enter Key is pressed in the TextBox
|
||||
private void FilterEnterKey(object sender, KeyPressEventArgs e)
|
||||
{
|
||||
if (e.KeyChar == '\r') // enter key pressed
|
||||
{
|
||||
e.Handled = true;
|
||||
SubmitFilter(sender, e);
|
||||
}
|
||||
}
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
// When Text Changes, Perform the filtering
|
||||
// Note that uses Invoke to
|
||||
// avoid multi-threaded problems
|
||||
//with the blocking collection
|
||||
private void ProcessFilter(string fltrtxt)
|
||||
{
|
||||
//Step 1: reload the base tree
|
||||
VETreeNode tbase = (VETreeNode)tv.Nodes[0];
|
||||
tbase.ChildrenLoaded = false;
|
||||
this.Invoke((Action) (() => { tbase.RefreshNode(); }));
|
||||
|
||||
if (!string.IsNullOrEmpty(fltrtxt))
|
||||
{
|
||||
//Step 2: Expand all TreeNodes
|
||||
this.Invoke((Action)(() => { LoadAllProcedures(tbase); }));
|
||||
|
||||
//Step 3: get items that match filter to those containing the title or number
|
||||
List<IVEDrillDownReadOnly> filterlist = GetMatchingTreeNodes(tbase, fltrtxt);
|
||||
|
||||
//Step 4: filter to those containing the title or number
|
||||
this.Invoke((Action)(() => {FilterTreeNodes(tbase, filterlist);}));
|
||||
|
||||
//Step 5: refresh the view
|
||||
this.Invoke((Action)(() => {tv.Update();}));
|
||||
|
||||
//Step 6: select 1st procedure in tree view
|
||||
this.Invoke((Action)(() => {SelectFirstProcedure(filterlist);}));
|
||||
}
|
||||
|
||||
//Step 7: set progress bar as done
|
||||
this.Invoke((Action)(() => {ProgBarText = "Filtering Complete";}));
|
||||
|
||||
}
|
||||
|
||||
//C2024-036 IntelliSense
|
||||
//Gives Focus to last child in first section of treeview
|
||||
//then given focus to treeview
|
||||
//so that can click enter and open 1st found item/procedure
|
||||
void SelectFirstProcedure(List<IVEDrillDownReadOnly> filterlist)
|
||||
{
|
||||
TreeNode tn = tv.Nodes[0];
|
||||
while (tn.Nodes.Count > 0 && filterlist.Contains(((VETreeNode) tn).VEObject))
|
||||
{
|
||||
tn = tn.Nodes[0];
|
||||
}
|
||||
|
||||
tv.SelectedNode = tn;
|
||||
tv.Enabled = true;
|
||||
tv.SelectedNode.Collapse();
|
||||
tv.Focus();
|
||||
}
|
||||
|
||||
void btnPrevious_Click(object sender, EventArgs e)
|
||||
{
|
||||
CurrentID = FindPreviousLine();
|
||||
|
Reference in New Issue
Block a user