using bzit.bomg; using bzit.bomg.Data; using bzit.bomg.Models; using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.IO; using System.Text; using System.Windows.Forms; using Resources = bzit.bomg.Properties.Resources; namespace RyzStudio.Windows.Forms { public class BookmarkTreeView : System.Windows.Forms.TreeView { public enum IconSet { Root = 0, Folder1, Folder2, Default } public enum NodeType { None = 0, Root, Folder, Page } public BookmarkTreeViewSNode SNode { get; set; } protected IconDatabase iconDatabase = null; protected TreeNode draggingNode = null; protected bool hasChanged = false; public BookmarkTreeView() : base() { this.SNode = new BookmarkTreeViewSNode(this); if (this.ImageList == null) { this.ImageList = new ImageList(); } this.ImageList.ColorDepth = ColorDepth.Depth16Bit; this.ImageList.ImageSize = new Size(16, 16); this.ImageList.TransparentColor = Color.Transparent; this.ImageList.Images.Clear(); this.ImageList.Images.Add(Resources.hexagon); this.ImageList.Images.Add(Resources.folder); this.ImageList.Images.Add(Resources.folder_explore); this.ImageList.Images.Add(Resources.file_text); this.PathSeparator = "\n"; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool AllowBeginEdit { get; set; } = false; [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new ImageList ImageList { get => base.ImageList; set => base.ImageList = value; } [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool HasChanged { get { return hasChanged; } set { hasChanged = value; //OnChanged?.Invoke(null, null); } } #region public methods 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(TreeNode node) { //return this.AddFolder("New Folder " + (new Random()).Next(10001, 99999).ToString()); return this.AddFolder(node, "New Folder (" + DateTime.Now.ToString("yyyy-MM-dd-HHmmss") + ")"); } public TreeNode AddFolder(TreeNode node, string name) { if (node == null) { return null; } if (node.Tag != null) { return null; } return node.Nodes.Add(encodePath(name), name, (int)IconSet.Folder1, (int)IconSet.Folder2); } public void AddItem(List viewModelList) { this.Clear(); if (viewModelList == null) { return; } foreach (BookmarkItemViewModel item in viewModelList) { AddItem(item); } this.HasChanged = false; } public void AddItem(BookmarkItemViewModel viewModel) { int iconIndex = addIcon(viewModel); TreeNode tn = new TreeNode(viewModel.SiteName, iconIndex, iconIndex); tn.Tag = viewModel; tn.ToolTipText = viewModel.ToString(); TreeNode tn2 = addFolderPath(viewModel.TreeviewPath); if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { tn2.Nodes.Add(tn); })); } else { tn2.Nodes.Add(tn); } this.HasChanged = true; } public void AddItem(TreeNode treeNode, BookmarkItemViewModel viewModel) { if (treeNode == null) { return; } int iconIndex = addIcon(viewModel); TreeNode tn = new TreeNode(viewModel.SiteName, iconIndex, iconIndex); tn.Tag = viewModel; tn.ToolTipText = viewModel.ToString(); treeNode.Nodes.Add(tn); this.HasChanged = true; } public void AddOrUpdateItem(TreeNode treeNode, BookmarkItemViewModel viewModel) { switch (this.GetNodeType(treeNode)) { case NodeType.Root: case NodeType.Folder: AddItem(treeNode, viewModel); break; case NodeType.Page: UpdateItem(treeNode, viewModel); break; default: break; } } public void Clear() { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { this.Nodes.Clear(); })); } else { this.Nodes.Clear(); } this.HasChanged = true; } public void Clear(string name) { this.Nodes.Clear(); this.Nodes.Add("", name?.Trim(), (int)IconSet.Root, (int)IconSet.Root); this.HasChanged = true; } public void CloseIconDatabase() { iconDatabase.Close(); } public int CountBookmarkItem() { int itemCount = 0; if (this.Nodes.Count <= 0) { return itemCount; } foreach (TreeNode item in this.Nodes) { traverseBookmarkList(ref itemCount, item); } return itemCount; } public NodeType GetNodeType(TreeNode node) { if (node.Tag == null) { if (node.Equals(this.Nodes[0])) { return NodeType.Root; } else { return NodeType.Folder; } } else { if (node.Tag is BookmarkItemViewModel) { return NodeType.Page; } else { return NodeType.None; } } } public 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 BookmarkItemViewModel GetViewModel(TreeNode node) => (BookmarkItemViewModel)node.Tag; 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 List GetBookmarkNodeList() { 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 UpdateItem(TreeNode treeNode, BookmarkItemViewModel viewModel) { if (treeNode == null) { return; } int iconIndex = addIcon(viewModel); treeNode.Text = viewModel.SiteName; treeNode.ImageIndex = iconIndex; treeNode.SelectedImageIndex = iconIndex; treeNode.Tag = viewModel; treeNode.ToolTipText = viewModel.ToString(); this.HasChanged = true; } #endregion #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 en = this.GetNodeAt(this.PointToClient(new Point(e.X, e.Y))); if (en == null) { return; } if (isNodeChild(draggingNode, en)) { return; } TreeNode dn = draggingNode; if (en.Tag == null) { dn.Parent.Nodes.Remove(dn); en.Nodes.Insert(0, dn); } else { en.Parent.Nodes.Remove(dn); en.Parent.Nodes.Insert(en.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 OnPreviewKeyDown(PreviewKeyDownEventArgs e) { TreeNode tn = this.SelectedNode; if (tn == null) { return; } NodeType nodeType = this.SNode.GetNodeType(); switch (e.KeyCode) { case Keys.Insert: if (e.Modifiers == Keys.Shift) { if ((nodeType == NodeType.Root) || (nodeType == NodeType.Folder)) { this.SelectedNode = this.SNode.AddFolder(); } else if (nodeType == NodeType.Page) { this.SelectedNode = tn.Parent; this.SelectedNode = this.SNode.AddFolder(); } } break; case Keys.Delete: if (!tn.IsEditing) { this.SNode.Delete(); } break; case Keys.F2: if ((nodeType == NodeType.Root) || (nodeType == NodeType.Folder)) { this.AllowBeginEdit = true; this.SNode.Edit(); } break; case Keys.F3: switch (nodeType) { case NodeType.Root: case NodeType.Folder: try { Clipboard.SetText(tn.Text ?? string.Empty); } catch { } break; case NodeType.Page: BookmarkItemViewModel viewModel = this.SNode.GetViewModel(); if (viewModel != null) { try { Clipboard.SetText(viewModel.SiteAddress ?? string.Empty); } catch { } } break; default: break; } break; case Keys.Up: if (e.Modifiers == Keys.Control) { this.SNode.MoveUp(); } break; case Keys.Down: if (e.Modifiers == Keys.Control) { this.SNode.MoveDown(); } break; default: break; } base.OnPreviewKeyDown(e); } #endregion protected int addIcon(BookmarkItemViewModel viewModel) => addIcon(viewModel.ToModel()); protected int addIcon(BookmarkItemModel model) { if (this.ImageList.Images.ContainsKey(model.SiteAddress)) { return this.ImageList.Images.IndexOfKey(model.SiteAddress); } if (iconDatabase.HasIcon(model.SiteAddress)) { Image rs = iconDatabase.GetIcon(model.SiteAddress); if (rs == null) { return (int)IconSet.Default; } else { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { this.ImageList.Images.Add(model.SiteAddress, rs); })); } else { this.ImageList.Images.Add(model.SiteAddress, rs); } return this.ImageList.Images.IndexOfKey(model.SiteAddress); } } byte[] rawData; Bitmap bmp = model.RetrieveFavicon(out rawData); if (bmp == null) { return (int)IconSet.Default; } if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { this.ImageList.Images.Add(model.SiteAddress, bmp); })); } else { this.ImageList.Images.Add(model.SiteAddress, bmp); } iconDatabase.AddIcon(model.SiteAddress, rawData); return this.ImageList.Images.IndexOfKey(model.SiteAddress); } 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 { this.Nodes.Add(item, decodePath(item), (int)IconSet.Root, (int)IconSet.Root); })); } else { this.Nodes.Add(item, decodePath(item), (int)IconSet.Root, (int)IconSet.Root); } } tn = this.Nodes[item]; } else { if (!tn.Nodes.ContainsKey(item)) { if (this.InvokeRequired) { this.Invoke(new MethodInvoker(() => { tn.Nodes.Add(item, decodePath(item), (int)IconSet.Folder1, (int)IconSet.Folder2); })); } else { tn.Nodes.Add(item, decodePath(item), (int)IconSet.Folder1, (int)IconSet.Folder2); } } tn = tn.Nodes[item]; } } return tn; } protected string decodePath(string value) => System.Web.HttpUtility.UrlDecode(value); protected string encodePath(string value) => System.Web.HttpUtility.UrlEncode(value); protected void traverseBookmarkList(List rs, TreeNode node) { foreach (TreeNode tn in node.Nodes) { NodeType nodeType = this.GetNodeType(tn); if (nodeType == NodeType.Folder) { traverseBookmarkList(rs, tn); } else if (nodeType == NodeType.Page) { BookmarkItemViewModel nodeTag = this.GetViewModel(tn); nodeTag.TreeviewPath = this.GetNodePath(tn); if (nodeTag != null) { rs.Add(nodeTag); } } } } protected void traverseBookmarkList(List rs, TreeNode node) { foreach (TreeNode tn in node.Nodes) { NodeType nodeType = this.GetNodeType(tn); if (nodeType == NodeType.Folder) { traverseBookmarkList(rs, tn); } else if (nodeType == NodeType.Page) { BookmarkItemViewModel nodeTag = this.GetViewModel(tn); nodeTag.TreeviewPath = this.GetNodePath(tn); if (nodeTag != null) { rs.Add(tn); } } } } protected void traverseBookmarkList(ref int itemCount, TreeNode node) { foreach (TreeNode tn in node.Nodes) { NodeType nodeType = this.GetNodeType(tn); if (nodeType == NodeType.Folder) { traverseBookmarkList(ref itemCount, tn); } else if (nodeType == NodeType.Page) { itemCount++; } } } protected bool isNodeChild(TreeNode drag_node, TreeNode drop_node) { TreeNode tn = drop_node; while (true) { if (tn.Parent == null) { break; } if (tn.Equals(drag_node)) { return true; } tn = tn.Parent; } return false; } } }