bookmark-manager-r4/Windows/Forms/BookmarkTreeView.cs
2021-09-12 14:40:44 +01:00

1059 lines
29 KiB
C#

using bzit.bomg;
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 BookmarkItemViewModel GetNodeModel(TreeNode node)
{
if (node == null)
{
return null;
}
return (BookmarkItemViewModel)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 BookmarkItemViewModel)
{
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 IconDatabase iconDatabase = 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.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);
}
#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 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:
BookmarkItemViewModel 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 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 void AddItem(List<BookmarkItemViewModel> 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);
ThreadControl.Add(tn2, 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 (GetNodeType(treeNode))
// {
// case NodeType.Root:
// case NodeType.Folder:
// AddItem(treeNode, viewModel);
// break;
// case NodeType.Page:
// UpdateItem(treeNode, viewModel);
// break;
// default:
// break;
// }
//}
public void Clear()
{
ThreadControl.Clear(this);
this.HasChanged = false;
}
public void Clear(string name)
{
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 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 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 BookmarkItemViewModel GetNodeModel() => GetNodeModel(this.SelectedNode);
public List<BookmarkItemViewModel> GetBookmarkList()
{
List<BookmarkItemViewModel> rs = new List<BookmarkItemViewModel>();
if (this.Nodes.Count <= 0)
{
return rs;
}
foreach (TreeNode item in this.Nodes)
{
TraverseBookmarkList(rs, item);
}
return rs;
}
//public List<TreeNode> GetBookmarkNodeList()
//{
// List<TreeNode> rs = new List<TreeNode>();
// 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, 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;
//}
protected int addIcon(BookmarkItemViewModel viewModel)
{
return (int)IconSet.Default;
}
//protected int addIcon(BookmarkItemViewModel viewModel) => addIcon(viewModel.ToModel());
//protected int addIcon(BookmarkItemModel model)
//{
// return (int)IconSet.Default;
// 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
// // {
// // this.Add(this.ImageList, 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;
// }
// ThreadControl.Add(this, this.ImageList, 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<folderList.Length; i++)
{
string item = folderList[i];
if (i <= 0)
{
if (!this.Nodes.ContainsKey(item))
{
ThreadControl.Add(this, item, DecodePath(item), (int)IconSet.Root, (int)IconSet.Root);
}
tn = this.Nodes[item];
}
else
{
if (!tn.Nodes.ContainsKey(item))
{
ThreadControl.Add(tn, item, DecodePath(item), (int)IconSet.Folder1, (int)IconSet.Folder2);
}
tn = tn.Nodes[item];
}
}
return tn;
}
protected bool IsNodeChild(TreeNode dragNode, TreeNode dropNode)
{
TreeNode tn = dropNode;
while (true)
{
if (tn.Parent == null)
{
break;
}
if (tn.Equals(dragNode))
{
return true;
}
tn = tn.Parent;
}
return false;
}
protected void TraverseBookmarkList(List<BookmarkItemViewModel> 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)
{
BookmarkItemViewModel nodeTag = GetNodeModel(tn);
nodeTag.TreeviewPath = GetNodePath(tn);
if (nodeTag != null)
{
rs.Add(nodeTag);
}
}
}
}
protected void TraverseBookmarkList(List<TreeNode> 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)
{
BookmarkItemViewModel nodeTag = GetNodeModel(tn);
nodeTag.TreeviewPath = GetNodePath(tn);
if (nodeTag != null)
{
rs.Add(tn);
}
}
}
}
protected void TraverseBookmarkList(ref int itemCount, TreeNode node)
{
foreach (TreeNode tn in node.Nodes)
{
NodeType nodeType = GetNodeType(tn);
if (nodeType == NodeType.Folder)
{
TraverseBookmarkList(ref itemCount, tn);
}
else if (nodeType == NodeType.Page)
{
itemCount++;
}
}
}
}
}