using BookmarkManager; using bzit.bomg.Models; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text; using System.Windows.Forms; using Resources = BookmarkManager.AppResource; namespace RyzStudio.Windows.Forms { public partial class BookmarkTreeView : TreeView { public static string DecodePath(string value) => System.Web.HttpUtility.UrlDecode(value); public static void DeleteNode(TreeNode node) { if (node == null) { return; } if (node.TreeView.Nodes.Count <= 0) { return; } if (node.Equals(node.TreeView.Nodes[0])) { return; } node.Remove(); } public static string EncodePath(string value) { return System.Web.HttpUtility.UrlEncode(value); } public static BookmarkItem GetNodeModel(TreeNode node) { if (node == null) { return null; } return (BookmarkItem)node.Tag; } public static string GetNodePath(TreeNode node) { string[] folderList = node.FullPath.Split('\n'); if (folderList.Length < 2) { return null; } //if (folderList.Length < 2) //{ // return "/"; //} StringBuilder sb = new StringBuilder(); for (int i = 0; i < (folderList.Length - 1); i++) { sb.Append("\\"); sb.Append(EncodePath(folderList[i] ?? string.Empty)); } sb.Append("\\"); return sb.ToString(); } public static NodeType GetNodeType(TreeNode node) { if (node.Tag == null) { if (node.Equals(node.TreeView.Nodes[0])) { return NodeType.Root; } else { return NodeType.Folder; } } else { if (node.Tag is BookmarkItem) { return NodeType.Page; } else { return NodeType.None; } } } public static void MoveDown(TreeNode node) { if (node == null) { return; } TreeNode tn = node; if (tn.Parent == null) { return; } TreeNode tn1 = tn.Parent; if (tn.Index >= (tn1.Nodes.Count - 1)) { return; } int n = tn.Index + 1; tn1.Nodes.Remove(tn); tn1.Nodes.Insert(n, tn); node.TreeView.SelectedNode = tn; } public static void MoveUp(TreeNode node) { if (node == null) { return; } TreeNode tn = node; if (tn.Parent == null) { return; } if (tn.Index <= 0) { return; } int n = tn.Index - 1; TreeNode tn1 = tn.Parent; tn1.Nodes.Remove(tn); tn1.Nodes.Insert(n, tn); node.TreeView.SelectedNode = tn; } public static void Sort(TreeNode node) { if (node == null) { return; } string[] tnv = new string[0]; TreeNode[] tna = new TreeNode[0]; foreach (TreeNode tn2 in node.Nodes) { Array.Resize(ref tna, (tna.Length + 1)); tna[(tna.Length - 1)] = tn2; Array.Resize(ref tnv, (tnv.Length + 1)); tnv[(tnv.Length - 1)] = tn2.Text; } Array.Sort(tnv, tna); node.Nodes.Clear(); foreach (TreeNode tn2 in tna) { node.Nodes.Add(tn2); } } public enum IconSet { Root = 0, Folder1, Folder2, Default } public enum NodeType { None = 0, Root, Folder, Page } protected const string DEFAULT_NEW_FOLDER_NAME = "New Folder"; protected const string PATH_SEPARATOR = "\n"; public event EventHandler OnNodeChanged = null; protected TreeNode draggingNode = null; protected bool hasChanged = false; public BookmarkTreeView() { if (this.ImageList == null) this.ImageList = new ImageList(); this.PathSeparator = PATH_SEPARATOR; this.AllowDrop = true; this.HideSelection = false; this.HotTracking = true; this.ImageIndex = 0; this.LabelEdit = true; this.PathSeparator = "\n"; this.SelectedImageIndex = 0; this.ShowNodeToolTips = true; this.ImageList.ColorDepth = ColorDepth.Depth32Bit; this.ImageList.ImageSize = new Size(16, 16); this.ImageList.TransparentColor = Color.Transparent; ResetImageList(); } #region integrated behaviour protected override void OnItemDrag(ItemDragEventArgs e) { base.OnItemDrag(e); draggingNode = (TreeNode)e.Item; DoDragDrop(e.Item, DragDropEffects.Move); } protected override void OnDragDrop(DragEventArgs e) { base.OnDragDrop(e); if (draggingNode.Level <= 0) { return; } TreeNode node = this.GetNodeAt(this.PointToClient(new Point(e.X, e.Y))); if (node == null) { return; } if (ThreadControl.IsChild(draggingNode, node)) { return; } TreeNode dn = draggingNode; if (node.Tag == null) { dn.Parent.Nodes.Remove(dn); node.Nodes.Insert(0, dn); } else { node.Parent.Nodes.Remove(dn); node.Parent.Nodes.Insert(node.Index + 1, dn); } this.HasChanged = true; } protected override void OnDragEnter(DragEventArgs e) { base.OnDragEnter(e); e.Effect = DragDropEffects.Move; } protected override void OnMouseDown(MouseEventArgs e) { base.OnMouseDown(e); this.SelectedNode = this.GetNodeAt(e.Location); } protected override void OnDragOver(DragEventArgs e) { base.OnDragOver(e); this.SelectedNode = this.GetNodeAt(this.PointToClient(new Point(e.X, e.Y))); } protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e) { if (!AllowBeginEdit) { AllowBeginEdit = false; e.CancelEdit = true; return; } this.HasChanged = true; base.OnBeforeLabelEdit(e); } protected override void OnAfterLabelEdit(NodeLabelEditEventArgs e) { base.OnAfterLabelEdit(e); //if (e.Node.Tag == null) //{ // if (e.Label == null) // { // e.CancelEdit = true; // } // else // { // if (e.Label.Trim().Length <= 0) // { // e.CancelEdit = true; // } // } //} //else //{ // e.CancelEdit = true; //} AllowBeginEdit = false; } protected override void OnNodeMouseClick(TreeNodeMouseClickEventArgs e) { if (e.Button == MouseButtons.Right) { switch (this.GetNodeType()) { case BookmarkTreeView.NodeType.Root: if (this.RootContextMenu != null) this.RootContextMenu.Show(e.Node.TreeView, e.X, e.Y); break; case BookmarkTreeView.NodeType.Folder: if (this.FolderContextMenu != null) this.FolderContextMenu.Show(e.Node.TreeView, e.X, e.Y); break; case BookmarkTreeView.NodeType.Page: if (this.PageContextMenu != null) this.PageContextMenu.Show(e.Node.TreeView, e.X, e.Y); break; default: break; } } base.OnNodeMouseClick(e); } protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e) { TreeNode tn = this.SelectedNode; if (tn == null) { return; } NodeType nodeType = this.GetNodeType(); switch (e.KeyCode) { case Keys.Insert: if (e.Modifiers == Keys.Shift) { if ((nodeType == NodeType.Root) || (nodeType == NodeType.Folder)) { this.SelectedNode = this.AddFolder(); } else if (nodeType == NodeType.Page) { this.SelectedNode = tn.Parent; this.SelectedNode = this.AddFolder(); } } break; case Keys.Delete: if (!tn.IsEditing) { this.DeleteNode(); } break; case Keys.F2: if ((nodeType == NodeType.Root) || (nodeType == NodeType.Folder)) { this.AllowBeginEdit = true; this.EditNode(); } break; case Keys.F3: switch (nodeType) { case NodeType.Root: case NodeType.Folder: try { Clipboard.SetText(tn.Text ?? string.Empty); } catch { } break; case NodeType.Page: BookmarkItem viewModel = this.GetNodeModel(); if (viewModel != null) { try { Clipboard.SetText(viewModel.SiteAddress ?? string.Empty); } catch { } } break; default: break; } break; case Keys.Up: if (e.Modifiers == Keys.Control) { this.MoveUp(); this.HasChanged = true; } break; case Keys.Down: if (e.Modifiers == Keys.Control) { this.MoveDown(); this.HasChanged = true; } break; case Keys.Apps: this.OnNodeMouseClick(new TreeNodeMouseClickEventArgs(tn, MouseButtons.Right, 1, tn.Bounds.X, tn.Bounds.Y)); break; default: break; } base.OnPreviewKeyDown(e); } #endregion #region encapsulation [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new ImageList ImageList { get => base.ImageList; set => base.ImageList = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new bool AllowDrop { get => base.AllowDrop; set => base.AllowDrop = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new bool HideSelection { get => base.HideSelection; set => base.HideSelection = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new bool HotTracking { get => base.HotTracking; set => base.HotTracking = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new int ImageIndex { get => base.ImageIndex; set => base.ImageIndex = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new bool LabelEdit { get => base.LabelEdit; set => base.LabelEdit = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new string PathSeparator { get => base.PathSeparator; set => base.PathSeparator = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new int SelectedImageIndex { get => base.SelectedImageIndex; set => base.SelectedImageIndex = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new bool ShowNodeToolTips { get => base.ShowNodeToolTips; set => base.ShowNodeToolTips = value; } #endregion [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool AllowBeginEdit { get; set; } = false; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool HasChanged { get => hasChanged; protected set { hasChanged = value; OnNodeChanged?.Invoke(null, null); } } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public IconDatabase IconDatabase { get; set; } = null; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ContextMenuStrip RootContextMenu { get; set; } = null; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ContextMenuStrip FolderContextMenu { get; set; } = null; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ContextMenuStrip PageContextMenu { get; set; } = null; public bool InitialiseIconDatabase(out string message, string filename) { message = string.Empty; //if (string.IsNullOrWhiteSpace(filename)) //{ // return false; //} //if (iconDatabase == null) //{ // iconDatabase = new IconDatabase(); //} //bool rv = false; //if (File.Exists(filename)) //{ // rv = iconDatabase.LoadFile(filename); // if (!rv) // { // rv = iconDatabase.Create(filename, true, null, true); // if (!rv) // { // message = iconDatabase.LastError; // return false; // } // } //} //else //{ // rv = iconDatabase.Create(filename, true, null, true); // if (!rv) // { // message = iconDatabase.LastError; // return false; // } //} return true; } public TreeNode AddFolder(string name = "") { return this.AddFolder(this.SelectedNode, name); } public TreeNode AddFolder(TreeNode node, string name = "") { if (node == null) { return null; } if (node.Tag != null) { return null; } if (string.IsNullOrWhiteSpace(name)) { name = DEFAULT_NEW_FOLDER_NAME; } return node.Nodes.Add(EncodePath(name), name, (int)IconSet.Folder1, (int)IconSet.Folder2); } public TreeNode AddItem(BookmarkItem item) { int iconIndex = FindIcon(item); TreeNode tn = new TreeNode(item.SiteName, iconIndex, iconIndex); tn.Tag = item; tn.ToolTipText = item.ToString(); TreeNode tn2 = AddFolderPath(item.TreeviewPath); ThreadControl.Add(tn2, tn); this.HasChanged = true; return tn; } public TreeNode AddItem(TreeNode treeNode, BookmarkItem item) { if (treeNode == null) return null; if (item == null) return null; int iconIndex = FindIcon(item); TreeNode tn = new TreeNode(item.SiteName, iconIndex, iconIndex); tn.Tag = item; tn.ToolTipText = item.ToString(); //treeNode.Nodes.Add(tn); ThreadControl.Add(treeNode, tn); this.HasChanged = true; return tn; } public void Clear() { ResetImageList(); ThreadControl.Clear(this); this.HasChanged = false; } public void Clear(string name) { ResetImageList(); var tt1 = this.ImageList; ThreadControl.Clear(this); ThreadControl.Add(this, this.Nodes, "", name?.Trim(), (int)IconSet.Root, (int)IconSet.Root); this.HasChanged = true; } public void CloseIconDatabase() { //iconDatabase.Close(); } public void DeleteNode() => DeleteNode(this.SelectedNode); public void EditNode() { this.EditNode(this.SelectedNode); } public void EditNode(TreeNode node) { if (node == null) { return; } if (node.IsEditing) { return; } switch (GetNodeType(node)) { case BookmarkTreeView.NodeType.Root: case BookmarkTreeView.NodeType.Folder: this.AllowBeginEdit = true; node.BeginEdit(); break; case BookmarkTreeView.NodeType.Page: this.AllowBeginEdit = true; node.BeginEdit(); break; default: break; } } public NodeType GetNodeType() => GetNodeType(this.SelectedNode); public string GetNodePath() => GetNodePath(this.SelectedNode); public BookmarkItem GetNodeModel() => GetNodeModel(this.SelectedNode); public List GetBookmarkList() { List rs = new List(); if (this.Nodes.Count <= 0) { return rs; } foreach (TreeNode item in this.Nodes) { TraverseBookmarkList(rs, item); } return rs; } public bool FindTextNode(TreeNode node, string term) { if (node == null) { return false; } if (this.Nodes.Count <= 0) { return false; } bool rt = false; bool inclusive = false; TreeNode tn = node; while (true) { if (tn == null) { break; } if (inclusive) { if (tn.Text.ToLower().Contains(term.ToLower())) { this.SelectedNode = tn; this.SelectedNode.EnsureVisible(); rt = true; break; } } if (tn.Nodes.Count > 0) { tn = tn.Nodes[0]; inclusive = true; } else { if (tn.NextNode != null) { tn = tn.NextNode; inclusive = true; } else { while (true) { tn = tn.Parent; if (tn == null) { break; } if (tn.NextNode != null) { tn = tn.NextNode; break; } } inclusive = true; } } } return rt; } public void MoveDown() => MoveDown(this.SelectedNode); public void MoveUp() => MoveUp(this.SelectedNode); public void SetNoChanges() { this.HasChanged = false; } public new void Sort() => Sort(this.SelectedNode); public void UpdateItem(TreeNode treeNode, BookmarkItem item) { if (treeNode == null) return; if (item == null) return; int iconIndex = FindIcon(item); treeNode.Text = item.SiteName; treeNode.ImageIndex = iconIndex; treeNode.SelectedImageIndex = iconIndex; treeNode.Tag = item; treeNode.ToolTipText = item.ToString(); this.HasChanged = true; } protected int FindIcon(BookmarkItem item) { if (this.IconDatabase == null) return (int)IconSet.Default; if (item == null) return (int)IconSet.Default; if (string.IsNullOrWhiteSpace(item.SiteAddress)) return (int)IconSet.Default; string iconID = item?.ToHash(); if (this.ImageList.Images.ContainsKey(iconID)) { return this.ImageList.Images.IndexOfKey(iconID); } Image image = this.IconDatabase.FindIcon(iconID); if (image == null) { return (int)IconSet.Default; } ThreadControl.Add(this, this.ImageList, iconID, image); return this.ImageList.Images.IndexOfKey(iconID); } protected TreeNode AddFolderPath(string path) { TreeNode tn = null; //TreeNode tn = this.Nodes[0]; //if (tn == null) //{ // return tn; //} if (string.IsNullOrWhiteSpace(path)) { return tn; } if (string.IsNullOrWhiteSpace(path.Trim('\\'))) { return tn; } string[] folderList = path.Trim('\\').Split('\\'); if (folderList.Length <= 0) { return tn; } for (int i=0; i rs, TreeNode node) { foreach (TreeNode tn in node.Nodes) { NodeType nodeType = GetNodeType(tn); if (nodeType == NodeType.Folder) { TraverseBookmarkList(rs, tn); } else if (nodeType == NodeType.Page) { BookmarkItem nodeTag = GetNodeModel(tn); nodeTag.TreeviewPath = GetNodePath(tn); if (nodeTag != null) { rs.Add(nodeTag); } } } } } }