807 lines
22 KiB
C#
807 lines
22 KiB
C#
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; }
|
|
|
|
public event EventHandler OnNodeChanged = null;
|
|
|
|
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 => hasChanged;
|
|
set
|
|
{
|
|
hasChanged = value;
|
|
|
|
OnNodeChanged?.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) => 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<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 (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()
|
|
{
|
|
ThreadControl.Clear(this);
|
|
|
|
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<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 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();
|
|
this.HasChanged = true;
|
|
}
|
|
|
|
break;
|
|
case Keys.Down:
|
|
if (e.Modifiers == Keys.Control)
|
|
{
|
|
this.SNode.MoveDown();
|
|
this.HasChanged = true;
|
|
}
|
|
|
|
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
|
|
{
|
|
ThreadControl.Add(this, 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 string decodePath(string value) => System.Web.HttpUtility.UrlDecode(value);
|
|
|
|
protected string encodePath(string value) => System.Web.HttpUtility.UrlEncode(value);
|
|
|
|
protected void traverseBookmarkList(List<BookmarkItemViewModel> 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<TreeNode> 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;
|
|
}
|
|
|
|
}
|
|
} |