This repository has been archived on 2022-09-30. You can view files and clone it, but cannot push or open issues or pull requests.
bookmark-manager/Windows/Forms/BookmarkTreeView.cs

718 lines
18 KiB
C#
Raw Normal View History

using bzit.bomg;
using bzit.bomg.Models;
using System;
2017-07-30 11:59:34 +00:00
using System.ComponentModel;
using System.Drawing;
using System.IO;
2017-07-30 11:59:34 +00:00
using System.Windows.Forms;
using Resources = bzit.bomg.Properties.Resources;
2017-07-30 11:59:34 +00:00
namespace RyzStudio.Windows.Forms
{
public class BookmarkTreeView : System.Windows.Forms.TreeView
2017-07-30 11:59:34 +00:00
{
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;
2017-07-30 11:59:34 +00:00
public delegate void NodeCountUpdated(ulong v);
public EventHandler OnChanged = null;
public NodeCountUpdated OnNodeCountUpdate = null;
protected const char pathSeparator = '|';
protected TreeNode draggingNode = null;
//protected bool allowBeginEdit = false;
2017-07-30 11:59:34 +00:00
protected ulong nodeCount = 0;
protected bool hasChanged = false;
public BookmarkTreeView() : base()
2017-07-30 11:59:34 +00:00
{
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;
2017-07-30 11:59:34 +00:00
this.ImageList.Images.Clear();
this.ImageList.Images.Add(Resources.transmit_blue);
this.ImageList.Images.Add(Resources.folder);
this.ImageList.Images.Add(Resources.folder_explore);
this.ImageList.Images.Add(Resources.page_white_world_bw);
}
[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new ImageList ImageList { get => base.ImageList; set => base.ImageList = value; }
2017-07-30 11:59:34 +00:00
[Browsable(false)]
public TreeNode[] NodeList
{
get
{
TreeNode[] rv = new TreeNode[0];
if (this.Nodes.Count <= 0)
{
return rv;
}
2017-07-30 11:59:34 +00:00
foreach (TreeNode tn in this.Nodes)
{
traverseNodeList(ref rv, tn);
}
return rv;
}
}
[Browsable(false)]
public ulong NodeCount
{
get
{
return nodeCount;
}
}
[Browsable(false)]
public ulong NodeCountCalc
{
get
{
ulong rv = 0;
if (this.Nodes.Count <= 0)
{
return rv;
}
2017-07-30 11:59:34 +00:00
foreach (TreeNode tn in this.Nodes)
{
traverseNodeCount(ref rv, tn);
}
2017-07-30 11:59:34 +00:00
return rv;
}
}
[Browsable(false)]
public bool HasChanged
{
get { return hasChanged; }
set
{
hasChanged = value;
OnChanged?.Invoke(null, null);
2017-07-30 11:59:34 +00:00
}
}
2017-07-30 11:59:34 +00:00
#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 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);
tn2.Nodes.Add(tn);
}
2017-07-30 11:59:34 +00:00
public void AddOrUpdateItem_OnSelectedNode(BookmarkItemViewModel viewModel)
2017-07-30 11:59:34 +00:00
{
switch (this.SNode.GetNodeType())
2017-07-30 11:59:34 +00:00
{
case NodeType.Root:
case NodeType.Folder:
addItem_OnSelectedNode(viewModel);
break;
case NodeType.Page:
updateItem_OnSelectedNode(viewModel);
break;
default:
break;
2017-07-30 11:59:34 +00:00
}
}
2017-07-30 11:59:34 +00:00
public NodeType GetNodeType(TreeNode node)
{
if (node.Tag == null)
{
if (node.Equals(this.Nodes[0]))
{
return NodeType.Root;
}
else
{
return NodeType.Folder;
}
}
else
2017-07-30 11:59:34 +00:00
{
if (node.Tag is BookmarkItemViewModel)
{
return NodeType.Page;
}
else
{
return NodeType.None;
}
2017-07-30 11:59:34 +00:00
}
}
//public void EditNode()
//{
// this.SNode.
// //this.HasChanged = true;
// //if (this.SelectedNode == null)
// //{
// // return;
// //}
// //if (!this.SelectedNode.IsEditing)
// //{
// // allowBeginEdit = true;
// // this.SelectedNode.BeginEdit();
// //}
//}
2017-07-30 11:59:34 +00:00
public string GetNodeFullPath(TreeNode node)
{
string rv = PathEncode(node.Text);
TreeNode tn = node;
while (true)
{
tn = tn.Parent;
if (tn == null)
{
break;
}
if (tn.Level == 0)
{
break;
}
2017-07-30 11:59:34 +00:00
rv = PathEncode(tn.Text) + pathSeparator.ToString() + rv;
}
2017-07-30 11:59:34 +00:00
return rv;
}
public bool FindTextNode(TreeNode node, string term)
{
if (node == null)
{
return false;
}
if (this.Nodes.Count <= 0)
{
return false;
}
2017-07-30 11:59:34 +00:00
bool rt = false;
bool inclusive = false;
TreeNode tn = node;
while (true)
{
if (tn == null)
{
break;
}
2017-07-30 11:59:34 +00:00
if (inclusive)
{
if (tn.Text.ToLower().Contains(term.ToLower()))
{
this.SelectedNode = tn;
this.SelectedNode.EnsureVisible();
rt = true;
break;
}
}
2017-07-30 11:59:34 +00:00
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;
}
}
}
2017-07-30 11:59:34 +00:00
return rt;
}
public void Clear()
{
nodeCount = 0;
NodeCountUpdate(nodeCount);
this.Nodes.Clear();
this.HasChanged = true;
}
#endregion
2017-07-30 11:59:34 +00:00
#region integrated behaviour
protected override void OnItemDrag(ItemDragEventArgs e)
{
base.OnItemDrag(e);
2017-07-30 11:59:34 +00:00
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))
2017-07-30 11:59:34 +00:00
{
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);
2017-07-30 11:59:34 +00:00
e.Effect = DragDropEffects.Move;
}
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
2017-07-30 11:59:34 +00:00
this.SelectedNode = this.GetNodeAt(e.Location);
}
protected override void OnDragOver(DragEventArgs e)
{
base.OnDragOver(e);
2017-07-30 11:59:34 +00:00
this.SelectedNode = this.GetNodeAt(this.PointToClient(new Point(e.X, e.Y)));
}
protected override void OnBeforeLabelEdit(NodeLabelEditEventArgs e)
{
//if (!allowBeginEdit)
//{
// e.CancelEdit = true;
// return;
//}
//this.HasChanged = true;
//base.OnBeforeLabelEdit(e);
//if (e.Node == null)
//{
// e.CancelEdit = true;
//}
//else
//{
// if (e.Node.Tag == null)
// {
// // do it
// }
// else
// {
// e.CancelEdit = true;
// }
//}
2017-07-30 11:59:34 +00:00
}
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;
2017-07-30 11:59:34 +00:00
}
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
TreeNode tn = this.SelectedNode;
if (tn == null)
{
return;
}
2017-07-30 11:59:34 +00:00
switch (e.KeyCode)
{
case Keys.Insert:
if (e.Modifiers == Keys.Shift)
{
this.SelectedNode = this.SNode.AddFolder();
2017-07-30 11:59:34 +00:00
}
else
{
//##AddBookmarkPage();
2017-07-30 11:59:34 +00:00
}
break;
case Keys.Delete:
if (!tn.IsEditing)
{
this.SNode.Delete();
2017-07-30 11:59:34 +00:00
}
break;
case Keys.F2:
this.SNode.Edit();
2017-07-30 11:59:34 +00:00
break;
case Keys.Up:
if (e.Modifiers == Keys.Control)
{
this.SNode.MoveUp();
2017-07-30 11:59:34 +00:00
}
break;
case Keys.Down:
if (e.Modifiers == Keys.Control)
{
this.SNode.MoveDown();
2017-07-30 11:59:34 +00:00
}
break;
default: break;
}
//base.OnPreviewKeyDown(e);
2017-07-30 11:59:34 +00:00
}
protected virtual void NodeCountUpdate(ulong v)
{
this.OnNodeCountUpdate?.Invoke(v);
}
#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
{
this.ImageList.Images.Add(model.SiteAddress, rs);
return this.ImageList.Images.IndexOfKey(model.SiteAddress);
}
}
Bitmap bmp = model.RetrieveFavicon();
if (bmp == null)
{
return (int)IconSet.Default;
}
this.ImageList.Images.Add(model.SiteAddress, bmp);
return this.ImageList.Images.IndexOfKey(model.SiteAddress);
}
protected TreeNode addFolderPath(string path)
{
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;
}
foreach (string item in folderList)
{
if (tn.Nodes.ContainsKey(item))
{
// do nothing
}
else
{
tn.Nodes.Add(item, item, (int)IconSet.Folder1, (int)IconSet.Folder2);
}
tn = tn.Nodes[item];
}
return tn;
}
protected void addItem_OnSelectedNode(BookmarkItemViewModel viewModel)
{
if (this.SelectedNode == null)
{
return;
}
int iconIndex = addIcon(viewModel);
TreeNode tn = new TreeNode(viewModel.SiteName, iconIndex, iconIndex);
tn.Tag = viewModel;
tn.ToolTipText = viewModel.ToString();
int n = this.SelectedNode.Nodes.Add(tn);
this.SelectedNode = this.SelectedNode.Nodes[n];
}
protected void updateItem_OnSelectedNode(BookmarkItemViewModel viewModel)
{
if (this.SelectedNode == null)
{
return;
}
int iconIndex = addIcon(viewModel);
this.SelectedNode.Text = viewModel.SiteName;
this.SelectedNode.ImageIndex = iconIndex;
this.SelectedNode.SelectedImageIndex = iconIndex;
this.SelectedNode.Tag = viewModel;
this.SelectedNode.ToolTipText = viewModel.ToString();
}
protected bool isNodeChild(TreeNode drag_node, TreeNode drop_node)
2017-07-30 11:59:34 +00:00
{
TreeNode tn = drop_node;
while (true)
{
if (tn.Parent == null)
{
break;
}
if (tn.Equals(drag_node))
{
return true;
}
tn = tn.Parent;
}
return false;
}
protected void traverseNodeList(ref TreeNode[] results, TreeNode node)
{
foreach (TreeNode tn in node.Nodes)
{
if (tn.Tag == null)
{
traverseNodeList(ref results, tn);
}
else
{
Array.Resize(ref results, (results.Length + 1));
results[(results.Length - 1)] = tn;
}
}
}
protected void traverseNodeCount(ref ulong results, TreeNode node)
{
foreach (TreeNode tn in node.Nodes)
{
if (tn.Tag == null)
{
traverseNodeCount(ref results, tn);
}
else
{
results++;
}
}
}
2017-07-30 11:59:34 +00:00
protected virtual void OnAddFolderNode(TreeNode node) { }
protected virtual void OnAddItemNode(TreeNode node) { }
////protected string PathEncode(string text) { return RyzStudio.String.EncodeTo64(text); }
//protected string PathDecode(string text) { return RyzStudio.String.DecodeFrom64(text); }
protected string PathEncode(string text) { return System.Web.HttpUtility.UrlEncode(text); }
2017-07-30 11:59:34 +00:00
protected string PathDecode(string text) { return System.Web.HttpUtility.UrlDecode(text); }
2017-07-30 11:59:34 +00:00
}
}