フィロさんの「お気に入り」C#コードを改造

フィロさんのタブブラウザの「お気に入り」のC#コード
http://note.phyllo.net/?eid=540651

これを、少し改造してみました。
・右クリックしてからのお気に入り削除後、TreeNodeが折りたたまれるのを回避。
・新規フォルダ作成
・お気に入り登録(ブックマーク)
・TreeNoeクリック時、OnUrlOpenイベントを発行。(Webブラウザ側に通知)

久々に再帰関数を書いてみたらヘボくなった。。。(;´Д`A ```

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Drawing;
using System.Text.RegularExpressions;
using Microsoft.VisualBasic;
using ABCS.Forms;

namespace ABCS.Classes
{
    //==クラス定義==
    //IEお気に入りツリークラス
    class MyBookmarkTree:TreeView
    {
        //==デリゲート定義==
        private delegate bool SetNodesDelegate(string vDirPath);

        //URLオープンデリゲート&イベント
        public delegate void OnURLOpenDelegate(string url);

        public event OnURLOpenDelegate OnUrlOpen = null;

        //ファイル・フォルダ変更してTreeを再構築後、Treeの最後に選択していたのノードを
        //選択するためのキーとなる最新のTag
        private string lastTag = "";
        //ファイルウォッチイベントはスレッドが違うため、Invkeを使うが、
        //そのInvokeで呼び出すメソッドとデリゲート
        public delegate void selectTargetNodeDelegate();
        public void selectTargetNode()
        {
            TreeNode t = this.SelectNodeByTag(this.lastTag);

            if (t != null)
            {
                this.SelectedNode = t;
                t.Expand();
            }
        }

        //---------------------------------------------
        //==Private変数定義==
        //タブブラウザ
        //private MyTabBrowser prTabBrowser;
        //IEお気に入りフォルダパス
        private string prBookmarkDirPath;
        //右クリックメニュー
        private ContextMenuStrip prMenu;
        //ファイル変更監視
        FileSystemWatcher prFileStytemWatcher;
        //----------------------------------------------
        //コンストラクタ
        public MyBookmarkTree(/*MyTabBrowser rTabBrowser*/)
        {
            try
            {
                //this.frmmain_ = frmmain;
                //prTabBrowser = rTabBrowser;
                //----------------------------------
                //IEお気に入りフォルダパスを取得
                prBookmarkDirPath = Environment.GetFolderPath(Environment.SpecialFolder.Favorites);
                //----------------------------------
                //IEお気に入りをツリーに設置
                if (!SetNodes(prBookmarkDirPath))
                {
                    //エラー
                }
                //----------------------------------
                //==右クリックメニュー==
                prMenu = new ContextMenuStrip();
                ToolStripItem wItem;
                //メニュー項目「開く」を作成
                wItem = prMenu.Items.Add("開く");
                wItem.Click += new EventHandler(MenuOpen_Click);
                //メニュー項目「お気に入りから削除」を作成
                wItem = prMenu.Items.Add("お気に入りから削除");
                wItem.Click += new EventHandler(MenuDelete_Click);
                //メニュー項目「新規フォルダ」を作成
                wItem = prMenu.Items.Add("新規フォルダ作成");
                wItem.Click += new EventHandler(MenuNewDir_Click);
                //----------------------------------
                //==フォルダの変更監視==
                prFileStytemWatcher = new FileSystemWatcher(prBookmarkDirPath);
                //監視対象のフォルダ
                prFileStytemWatcher.Path = prBookmarkDirPath;
                //サブフォルダまで監視
                prFileStytemWatcher.IncludeSubdirectories = true;
                //全てを監視
                prFileStytemWatcher.Filter = "";
                //ディレクトリ名、ファイル名、最終更新時間、サイズの変更を監視
                prFileStytemWatcher.NotifyFilter = NotifyFilters.DirectoryName |
                                                    NotifyFilters.FileName |
                                                    NotifyFilters.LastWrite |
                                                    NotifyFilters.Size;
                //監視を開始
                prFileStytemWatcher.EnableRaisingEvents = true;
                //----------------------------------
                //==イベント設定==
                //ノードクリックイベント
                this.NodeMouseClick += new TreeNodeMouseClickEventHandler(BookmarkTree_NodeMouseClick);
                //------------------
                //フォルダ内の作成イベント
                prFileStytemWatcher.Created += new FileSystemEventHandler(FileStytemWatcher_Created);
                //フォルダ内の変更イベント
                prFileStytemWatcher.Changed += new FileSystemEventHandler(FileStytemWatcher_Changed);
                //フォルダ内の削除イベント
                prFileStytemWatcher.Deleted += new FileSystemEventHandler(FileStytemWatcher_Deleted);
                //フォルダ内のリネームイベント
                prFileStytemWatcher.Renamed += new RenamedEventHandler(FileStytemWatcher_Renamed);
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }
        }
        //----------------------------------------------
        //==Privateメソッド定義==
        //ツリーにノードを設置
        private bool SetNodes(string vDirPath)
        {
            bool wRet = true;
            try
            {
                //ツリーのノードをクリアする
                this.Nodes.Clear();
                //------------------------------------
                //ルートノード作成
                TreeNode wRootNode = new TreeNode("ルート");
                //フォルダの階層
                int wNodeLv = 0;
                //----------------------------------
                //IEお気に入りをルートノードに配置
                wNodeLv = SetChildNodes(wRootNode, vDirPath, wNodeLv);
                //ルートノードの子ノードをツリーに配置
                foreach(TreeNode wNode in wRootNode.Nodes)
                {
                    //ツリーにノードを配置
                    this.Nodes.Add(wNode);
                }

                this.SelectNode(wRootNode);
            }
            catch(Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wRet = false;
            }
            return wRet;
        }
        //親ノードに子ノードを追加する
        private int SetChildNodes(TreeNode rNode, string vDirPath, int vNodeLv)
        {
            try
            {
                TreeNode wNode;
                //上位フォルダ内にフォルダノードを作成
                foreach (string wDirPath in Directory.GetDirectories(vDirPath))
                {
                    //親ノードにフォルダノードを追加する
                    wNode = rNode.Nodes.Add(getFileName(wDirPath));
                    //再起処理でフォルダノードの下位ノードを設置する
                    vNodeLv = SetChildNodes(wNode, wDirPath, vNodeLv);
                    //ノードにフォルダパスを格納
                    wNode.Tag = (string)wDirPath;
                }
                //親フォルダ内のファイルノードを作成
                foreach (string wFilePath in Directory.GetFiles(vDirPath, "*.url"))
                {
                    //上位ノードにファイルノードを追加する
                    wNode = rNode.Nodes.Add(getFileName(wFilePath));
                    //ノードにURLファイルパスを格納
                    wNode.Tag = (string)wFilePath;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                vNodeLv = -1;
            }
            return vNodeLv;
        }
        //新規ノードを作成
        private TreeNode newTreeNode(string vPath)
        {
            TreeNode wTreeNode;
            try
            {
                //フォルダ名またはファイル名を取得
                string wName = getFileName(vPath);
                //取得した名称でノードを作成
                wTreeNode = new TreeNode(wName);
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wTreeNode = null;
            }
            //作成したノードを返す
            return wTreeNode;
        }
        //パスからフォルダ名・ファイル名を取得
        private string getFileName(string vFilePath)
        {
            string wName;
            string[] wFileNameArray;
            try
            {
                char y = '\\';
                //パスを\で区切り配列に格納
                wFileNameArray = vFilePath.Split(y);
                //最下位のフォルダ名またはファイル名を取得
                wName = wFileNameArray[wFileNameArray.Length - 1];
                //ファイル名の.url拡張子をなくす
                wName = wName.Replace(".url", "");
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                //エラーの場合は空白
                wName = "";
            }
            return wName;
        }
        //ノードに設定されたURLファイルの内容でWebページを開く
        private bool OpenPage(string vPath)
        {
            bool wRet = true;
            try
            {
                string wLine;
                string wUrl;
                //ファイルがある場合
                if (File.Exists(vPath))
                {
                    //ファイルを開く
                    StreamReader reader = new StreamReader(vPath, Encoding.Default);
                    //1行ずつ読み込む
                    while (!reader.EndOfStream)
                    {
                        wLine = reader.ReadLine();
                        //「URL=」を含む行を取得
                        if (wLine.IndexOf("URL=") == 0)
                        {
                            //「URL=」を除き、URLを取得する
                            wUrl = wLine.Replace("URL=", "");
                            //タブブラウザにタブを追加
                            //prTabBrowser.AddNewTabPage();
                            //指定URLでWebページを開く
                            //prTabBrowser.ActiveTabPage.WebBrowser.Navigate(wUrl);
                            //Webページを開いたらループ終了
                            this.OnUrlOpen(wUrl);
                            break;
                        }
                    }
                    //ファイルを閉じる
                    reader.Close();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wRet = false;
            }
            return wRet;
        }
        //引数Tagに一致するTreeNodeを検索する
        private TreeNode SelectNodeByTag(string tag)
        {
            foreach (TreeNode t in this.Nodes)
            {
                if (t.Tag.ToString() == tag)
                {
                    return t;
                }
                TreeNode r = childNodeByTag(t, tag);
                if (r != null)
                {
                    return r;
                }
            }
            return null;
        }
        //SelectNodeByTagから呼び出され、再帰検索する
        private TreeNode childNodeByTag(TreeNode pNode, string tag)
        {
            foreach (TreeNode t in pNode.Nodes)
            {
                if (t.Tag.ToString() == tag)
                {
                    return t;
                }
                TreeNode r = childNodeByTag(t, tag);
                if (r != null)
                {
                    return r;
                }
            }
            return null;
        }
        //ノードが選択された場合の処理
        private bool SelectNode(TreeNode vNode)
        {
            bool wRet = true;
            try
            {
                //ノードからお気に入りのパスを取得
                string wPath = (string)vNode.Tag;
                //-----------------------------------
                //ファイルの場合
                if (File.Exists(wPath))
                {
                    
                    //WEBページを開く
                    if (!OpenPage(wPath))
                    {
                        //エラー
                    }
                }
                //フォルダの場合
                else if (Directory.Exists(wPath))
                {
                    //ノードが展開している場合
                    if (vNode.IsExpanded)
                    {
                        //ノードの展開を閉じる
                        vNode.Collapse();
                    }
                    //ノードが見展開の場合
                    else
                    {
                        //ノードを展開する
                        vNode.Expand();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wRet = false;
            }
            return wRet;
        }
        //フルパスからベースフォルダ名を取得する
        private string getBaseDir(string strgFullPath)
        {
            if (File.Exists(strgFullPath))
            {
                Regex reg = new Regex("[\\\\][^\\\\]*$");
                return reg.Replace(strgFullPath, "");
            }
            else
            {
                return strgFullPath;
            }
        }
        //ノードに設定されたパスを削除する
        private bool FileDelete(string vPath)
        {
            bool wRet = true;
            try
            {
                string wMsg = "お気に入りから[   " + getFileName(vPath) + "   ]を削除して宜しいですか?";
                if (MessageBox.Show(wMsg, "確認メッセージ", MessageBoxButtons.OKCancel) == DialogResult.OK)
                {
                    if (File.Exists(vPath))
                    {
                        File.Delete(vPath);
                    }
                    else if (Directory.Exists(vPath))
                    {
                        //フォルダ内にフォルダまたはファイルが存在しない場合は削除
                        if (Directory.GetFiles(vPath).Length == 0 && Directory.GetDirectories(vPath).Length == 0)
                        {
                            Directory.Delete(vPath);
                        }
                        else
                        {
                            MessageBox.Show("フォルダ内が空でない場合は、削除できません。");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wRet = false;
            }
            return wRet;
        }
        //新規ノードを追加する
        private bool CreateNode(TreeNode vNode)
        {
            bool wRet = true;
            try
            {
                //ノードからお気に入りのパスを取得
                string wPath = (string)vNode.Tag;
                //-----------------------------------
                //ファイルの場合
                if (File.Exists(wPath))
                {
                    string basedir = this.getBaseDir(wPath);

                    InputForm ipt = new InputForm("フォルダ名を入力してください。","");
                    ipt.ShowDialog();
                    string dirname = ipt.returnString;

                    if (dirname == "")
                    {
                        return true;
                    }


                    //string dirname = Interaction.InputBox("フォルダ名を入力してください。", "", "", -1, -1);

                    string fullpath = basedir + "\\" + dirname;

                    Directory.CreateDirectory(fullpath);

                    this.lastTag = fullpath;

                }
                //フォルダの場合
                else if (Directory.Exists(wPath))
                {
                    string basedir = this.getBaseDir(wPath);

                    InputForm ipt = new InputForm("フォルダ名を入力してください。", "");
                    ipt.ShowDialog();
                    string dirname = ipt.returnString;

                    if (dirname == "")
                    {
                        return true;
                    }
                    //string dirname = Interaction.InputBox("フォルダ名を入力してください。", "", "", -1, -1);

                    string fullpath = basedir + "\\" + dirname;

                    Directory.CreateDirectory(fullpath);

                    this.lastTag = fullpath;

                    //ノードを展開する
                    vNode.Expand();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wRet = false;
            }
            return wRet;
        }
        //urlをお気に入りにする
        public bool RegistURL(string url, string title)
        {
            TreeNode vNode = this.SelectedNode;
            bool wRet = true;
            try
            {
                //ノードからお気に入りのパスを取得
                string wPath = (string)vNode.Tag;

                string fullpath = "";

                //-----------------------------------
                //ファイルの場合
                if (File.Exists(wPath))
                {
                   fullpath = this.getBaseDir(wPath);
                }
                //フォルダの場合
                else if (Directory.Exists(wPath))
                {
                    fullpath = wPath;
                }

                System.IO.StreamWriter sw = null;
                try
                {
                    //FileStream fm = File.Create(fullpath + "\\" + title + ".url");
                    sw = new System.IO.StreamWriter(
                        fullpath + "\\" + title + ".url",
                        false,
                        System.Text.Encoding.UTF8);
                    sw.Write("URL=" + url);
                }
                catch (Exception excp)
                {
                    MessageBox.Show("エラーのため、お気に入りに登録できませんでした。");
                }
                finally
                {
                    if (sw != null)
                    {
                        sw.Close();
                    }
                }

                this.lastTag = fullpath;
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wRet = false;
            }
            return wRet;
        }
        //----------------------------------------------
        //==イベント定義==
        //ノードクリックイベント
        private void BookmarkTree_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            try
            {   //左クリックの場合
                if (e.Button == MouseButtons.Left)
                {
                    TreeNode wNode = (TreeNode)e.Node;
                    //-----------------------------------
                    //ノードの選択処理
                    if (!SelectNode(wNode))
                    {
                        //エラー
                    }
                }
                //右クリックの場合
                else if (e.Button == MouseButtons.Right)
                {
                    //マウス位置にあるノードを取得
                    TreeNode wNode = this.GetNodeAt(e.X, e.Y);
                    //取得したノードを選択状態にする
                    this.SelectedNode = wNode;
                    //-----------------------------------
                    //右クリックメニューを表示
                    prMenu.Show(this, new Point(e.X, e.Y));
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }
        }

        //-----------------------
        //メニュー項目「開く」クリックイベント
        private void MenuOpen_Click(object sender, EventArgs e)
        {
            try
            {
                //選択状態のノードを取得
                TreeNode wNode = this.SelectedNode;
                //-----------------------------------
                //ノードの選択処理
                if (!SelectNode(wNode))
                {
                    //エラー
                }
            }

            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }
        }
        //メニュー項目「削除」クリックイベント
        private void MenuDelete_Click(object sender, EventArgs e)
        {
            try
            {
                //選択状態のノードを取得
                TreeNode wNode = this.SelectedNode;

                //ツリー再表示ため、Tagを保持
                this.lastTag = wNode.Parent.Tag.ToString();

                if (!FileDelete*1
                {
                    //エラー
                }

                //TreeNode選択
                this.selectTargetNode();

            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }
        }
        //-----------------------
       
        //メニュー項目「新規フォルダ」クリックイベント
        private void MenuNewDir_Click(object sender, EventArgs e)
        {
            try
            {
                //選択状態のノードを取得
                TreeNode wNode = this.SelectedNode;

                //ツリー再表示ため、Tagを保持
                this.lastTag = wNode.Tag.ToString();

                //ノードの選択処理
                if (!CreateNode(wNode))
                {
                    //エラー
                }

                //TreeNode選択
                this.selectTargetNode();

            }

            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }
        }
        //-----------------------
        //フォルダ内の作成イベント
        private void FileStytemWatcher_Created(object sender, FileSystemEventArgs e)
        {
            try
            {
                if (!this.InvokeRequired)
                {
                    //IEお気に入りをツリーに再設置
                    if (!SetNodes(prBookmarkDirPath))
                    {
                        //エラー
                    }
                    //TreeNode選択
                    this.selectTargetNode();

                }
                else
                {
                    //IEお気に入りをツリーに再設置(監視クラスはスレッドが違う為、Invokeでツリーにスレッドを戻す)
                    this.Invoke(new SetNodesDelegate(SetNodes), prBookmarkDirPath);

                    //TreeNode選択
                    this.Invoke(new selectTargetNodeDelegate(this.selectTargetNode));
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }
        }
        //フォルダ内の変更イベント
        private void FileStytemWatcher_Changed(object sender, FileSystemEventArgs e)
        {
            try
            {
                TreeNode t = this.SelectNodeByTag(this.lastTag);

                if (!this.InvokeRequired)
                {
                    //IEお気に入りをツリーに再設置
                    if (!SetNodes(prBookmarkDirPath))
                    {
                        //エラー
                    }

                    //TreeNode選択
                    this.selectTargetNode();
                }
                else
                {
                    //IEお気に入りをツリーに再設置(監視クラスはスレッドが違う為、Invokeでツリーにスレッドを戻す)
                    this.Invoke(new SetNodesDelegate(SetNodes), prBookmarkDirPath);

                    //TreeNode選択
                    this.Invoke(new selectTargetNodeDelegate(this.selectTargetNode));
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }
        }
        //フォルダ内の削除イベント
        private void FileStytemWatcher_Deleted(object sender, FileSystemEventArgs e)
        {
            try
            {
                if (!this.InvokeRequired)
                {
                    //IEお気に入りをツリーに再設置
                    if (!SetNodes(prBookmarkDirPath))
                    {
                        //エラー
                    }

                    //TreeNode選択
                    this.selectTargetNode();

                }
                else
                {
                    //IEお気に入りをツリーに再設置(監視クラスはスレッドが違う為、Invokeでツリーにスレッドを戻す)
                    this.Invoke(new SetNodesDelegate(SetNodes), prBookmarkDirPath);

                    //TreeNode選択
                    this.Invoke(new selectTargetNodeDelegate(this.selectTargetNode));

                }


            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }

        }


        //フォルダ内のリネームイベント
        void FileStytemWatcher_Renamed(object sender, RenamedEventArgs e)
        {
            try
            {
                if (!this.InvokeRequired)
                {
                    //IEお気に入りをツリーに再設置
                    if (!SetNodes(prBookmarkDirPath))
                    {
                        //エラー
                    }

                    this.selectTargetNode();
                }
                else
                {
                    //IEお気に入りをツリーに再設置(監視クラスはスレッドが違う為、Invokeでツリーにスレッドを戻す)
                    this.Invoke(new SetNodesDelegate(SetNodes), prBookmarkDirPath);

                    this.Invoke(new selectTargetNodeDelegate(this.selectTargetNode));
                }

            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
            }

        }

        //お気に入りフォルダ内のファイル名(お気に入り名)とURLから
        //keywordにマッチしたファイル名とURLを返す
        //(再帰処理用)
        private List findChildNode(string keyword, TreeNode childNode, out List urls)
        {
            urls = new List();
            List bookmarks = new List();
            foreach (TreeNode node in childNode.Nodes)
            {
                //ノードからお気に入りのパスを取得
                string wPath = (string)node.Tag;
                //-----------------------------------
                //ファイルの場合
                if (File.Exists(wPath))
                {
                    string url = OpenFile(wPath);
                    if *2 >= 0)
                        || (getFileName(wPath).ToLower().IndexOf(keyword.ToLower()) >= 0))
                    {
                        urls.Add(url);
                        bookmarks.Add(getFileName(wPath));
                    }
                }

                //サブノード検索
                List sub_urls = null;
                List sub_bookmarks = findChildNode(keyword, node, out sub_urls);

                urls.AddRange(sub_urls);
                bookmarks.AddRange(sub_bookmarks);
            }
            return bookmarks;
        }

        //お気に入りフォルダ内のファイル名(お気に入り名)とURLから
        //keywordにマッチしたファイル名とURLを返す
        public List getBookmarks(string keyword,  out List urls)
        {
            urls = new List();
            List bookmarks = new List();
            foreach (TreeNode node in this.Nodes)
            {
                //サブノード検索
                List sub_urls = null;
                List sub_bookmarks = findChildNode(keyword, node, out sub_urls);

                urls.AddRange(sub_urls);
                bookmarks.AddRange(sub_bookmarks);                
            }

            return bookmarks;

        }
        //ノードに設定されたURLファイル内のUrlをString型で返す
        private string OpenFile(string vPath)
        {
            string wRet = "";
            try
            {
                string wLine;
                string wUrl;
                //ファイルがある場合
                if (File.Exists(vPath))
                {
                    //ファイルを開く
                    StreamReader reader = new StreamReader(vPath, Encoding.Default);
                    //1行ずつ読み込む
                    while (!reader.EndOfStream)
                    {
                        wLine = reader.ReadLine();
                        //「URL=」を含む行を取得
                        if (wLine.IndexOf("URL=") == 0)
                        {
                            //「URL=」を除き、URLを取得する
                            wUrl = wLine.Replace("URL=", "");
                            //タブブラウザにタブを追加
                            //prTabBrowser.AddNewTabPage();
                            //指定URLでWebページを開く
                            //prTabBrowser.ActiveTabPage.WebBrowser.Navigate(wUrl);
                            //Webページを開いたらループ終了
                            return wUrl;
                            break;
                        }
                    }
                    //ファイルを閉じる
                    reader.Close();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("例外エラー:" + ex.Message);
                wRet = "";
            }
            return wRet;
        }
    }
}

*1:string)wNode.Tag

*2:url.ToLower().IndexOf(keyword.ToLower(