Advertisement
Guest User

TreeViewFolderBrowser.cs

a guest
Feb 5th, 2014
537
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 32.45 KB | None | 0 0
  1. // Copyright © 2004 by Christoph Richner. All rights are reserved.
  2. // Modified by Zaq Williams
  3. // If you like this code then feel free to go ahead and use it.
  4. // The only thing I ask is that you don't remove or alter my copyright notice.
  5. //
  6. // Your use of this software is entirely at your own risk. I make no claims or
  7. // warrantees about the reliability or fitness of this code for any particular purpose.
  8. // If you make changes or additions to this code please mark your code as being yours.
  9. //
  10. // website http://raccoom.sytes.net, email microweb@bluewin.ch, msn chrisdarebell@msn.com
  11.  
  12. using System;
  13. using System.Drawing;
  14. using System.Collections;
  15. using System.Windows.Forms;
  16. using System.IO;
  17. using System.Drawing.Design;
  18. using System.ComponentModel;
  19. using System.Windows.Forms.ComponentModel;
  20. using System.Windows.Forms.Design;
  21. using System.ComponentModel.Design;
  22.  
  23. namespace Raccoom.Windows.Forms
  24. {
  25.     /// <summary>
  26.     /// TreeViewFolderBrowser works a bite like FolderBrowserDialog but was designed to let the user choose many directories by <c>Chechboxes</c>. 
  27.     /// <seealso cref="DriveTypes"/><seealso cref="CheckboxBehaviorMode"/><seealso cref="TreeNodePath"/>
  28.     /// </summary> 
  29.     /// <remarks>
  30.     /// Because this class delegates the drive, folder and ImageList specific task's to a <see cref="ITreeViewFolderBrowserDataProvider"/> instance, this class needs a wired <see cref="ITreeViewFolderBrowserDataProvider"/> instance before you can call any method wich fill's the tree view.
  31.     /// </remarks>
  32.     [Designer(typeof(TreeViewFolderBrowserDesigner))]
  33.     [System.Drawing.ToolboxBitmap(typeof(System.Windows.Forms.TreeView))]
  34.     [DefaultProperty("CheckboxBehaviorMode"), DefaultEvent("SelectedDirectoriesChanged")]
  35.     public class TreeViewFolderBrowser : TreeView
  36.     {
  37.         #region fields
  38.         /// <summary>
  39.         /// Fired if a directory was selected or deselected.
  40.         /// </summary>
  41.         public event SelectedDirectoriesChangedDelegate SelectedDirectoriesChanged;
  42.         /// <summary>
  43.         /// Fired if a data provider has changed
  44.         /// </summary>
  45.         public EventHandler DataSourceChanged;     
  46.         /// <summary>
  47.         /// Fired if a CheckboxBehaviorMode has changed
  48.         /// </summary>
  49.         public EventHandler CheckboxBehaviorModeChanged;
  50.         /// <summary>
  51.         /// Fired if a drive types has changed
  52.         /// </summary>
  53.         public EventHandler DriveTypesChanged;
  54.         /// <summary>holds the path list</summary>
  55.         protected System.Collections.Specialized.StringCollection folderList_;     
  56.         /// <summary>flag used to suppress CheckItem Event</summary>
  57.         private int _supressCheck;     
  58.         /// <summary>font used to mark nodes which contains checked sub nodes</summary>
  59.         protected Font boldFont_;
  60.         /// <summary>current working mode</summary>
  61.         private CheckboxBehaviorMode _checkboxBehavior;        
  62.         /// <summary>designer</summary>
  63.         private System.ComponentModel.IContainer components;       
  64.         /// <summary>designer</summary>
  65.         private Environment.SpecialFolder _specialFolderRootFolder;    
  66.         /// <summary>Specify which drive types are displayed.</summary>
  67.         private DriveTypes _driveTypes;
  68.         /// <summary>data provider which is responsible to manage this instance</summary>
  69.         private ITreeViewFolderBrowserDataProvider _dataProvider=null;
  70.         /// <summary>data provider helper instance</summary>
  71.         private TreeViewFolderBrowserHelper _helper = null;
  72.         #endregion
  73.        
  74.         #region constructors
  75.         /// <summary>
  76.         /// Required designer variable.
  77.         /// </summary>
  78.         public TreeViewFolderBrowser()
  79.         {
  80.             InitializeComponent(); 
  81.             // initalize a new helper instance for this tree view.
  82.             _helper = new TreeViewFolderBrowserHelper(this);
  83.             //
  84.             this.ContextMenu = new ContextMenu();
  85.             this.ContextMenu.Popup +=new EventHandler(OnContextMenu_Popup);
  86.             //
  87.             this._driveTypes = DriveTypes.NoRootDirectory | DriveTypes.RemovableDisk | DriveTypes.LocalDisk | DriveTypes.NetworkDrive | DriveTypes.CompactDisc | DriveTypes.RAMDisk;
  88.             this.RootFolder = Environment.SpecialFolder.MyComputer;
  89.             this.CheckboxBehaviorMode = CheckboxBehaviorMode.SingleChecked;
  90.             // init bold font
  91.             boldFont_ = new Font(this.Font, FontStyle.Bold);               
  92.         }
  93.         #endregion
  94.        
  95.         #region public interface
  96.         /// <summary>
  97.         /// Gets or sets <see cref="ITreeViewFolderBrowserDataProvider"/> which is responsible to fill this <c>TreeViewFolderBrowser</c> instance.
  98.         /// </summary>
  99.         [Browsable(true), Category("FolderBrowser"),Description("DataSource specifies the DataProvider which is responsible to fill this instance")]
  100.         [DefaultValue(Environment.SpecialFolder.MyComputer)]
  101.         [System.ComponentModel.TypeConverter(typeof(System.ComponentModel.ExpandableObjectConverter))]
  102.         public ITreeViewFolderBrowserDataProvider DataSource
  103.         {
  104.             get
  105.             {
  106.                 return _dataProvider;
  107.             }
  108.             set
  109.             {
  110.                 bool changed = !object.Equals(_dataProvider, value);
  111.                 _dataProvider = value;
  112.                 //
  113.                 if(_dataProvider!=null)
  114.                 {
  115.                     base.ImageList = _dataProvider.ImageList;                  
  116.                 }
  117.                 else
  118.                 {
  119.                     base.ImageList = null;
  120.                 }
  121.                 //
  122.                 if(changed) OnDataSourceChanged(EventArgs.Empty);
  123.             }
  124.         }          
  125.         /// <summary>
  126.         /// Gets or sets a value indicating whether check boxes are displayed next to the tree nodes in the tree view control.
  127.         /// </summary>
  128.         new public bool CheckBoxes
  129.         {
  130.             get
  131.             {
  132.                 return base.CheckBoxes;
  133.             }
  134. //          set
  135. //          {
  136. //              base.CheckBoxes = value;               
  137. //          }
  138.         }
  139.         /// <summary>
  140.         /// Gets or sets the root folder where the browsing starts from.
  141.         /// </summary>
  142.         [Browsable(true), Category("FolderBrowser"),Description("Only the specified folder and any subfolders that are beneath it will appear in the dialog box and be selectable.")]
  143.         [DefaultValue(Environment.SpecialFolder.MyComputer)]
  144.         public Environment.SpecialFolder RootFolder
  145.         {
  146.             get
  147.             {
  148.                 return _specialFolderRootFolder;
  149.             }
  150.             set
  151.             {
  152.                 _specialFolderRootFolder = value;              
  153.             }
  154.         }
  155.         /// <summary>
  156.         /// List contains the path for all checked items.
  157.         /// </summary>
  158.         [Browsable(false)]
  159.         public virtual System.Collections.Specialized.StringCollection SelectedDirectories
  160.         {
  161.             get
  162.             {
  163.                 if(folderList_==null)
  164.                 {
  165.                     folderList_= new System.Collections.Specialized.StringCollection();
  166.                 }              
  167.                 return folderList_;
  168.             }
  169.             set
  170.             {
  171.                 folderList_ = value;
  172.             }
  173.         }
  174.         /// <summary>
  175.         /// Specify how the tree view handles checkboxes and associated events.
  176.         /// </summary>
  177.         [Browsable(true), Category("FolderBrowser"),Description("Specify how the tree view handles checkboxes and associated events"), DefaultValue(CheckboxBehaviorMode.SingleChecked)]
  178.         public virtual CheckboxBehaviorMode CheckboxBehaviorMode
  179.         {
  180.             get
  181.             {
  182.                 return _checkboxBehavior;
  183.             }
  184.             set
  185.             {
  186.                 _checkboxBehavior = value;
  187.                 //
  188.                 OnCheckboxBehaviorModeChanged(EventArgs.Empty);
  189.             }
  190.         }      
  191.         /// <summary>
  192.         /// Specify which drive types are displayed.
  193.         /// </summary>
  194.         [Browsable(true), Category("FolderBrowser"),Description("Specify which drive types are displayed"),DefaultValue(DriveTypes.All)]
  195.         public virtual DriveTypes DriveTypes
  196.         {
  197.             get
  198.             {
  199.                 return _driveTypes;
  200.             }
  201.             set
  202.             {
  203.                 _driveTypes = value;
  204.                 //
  205.                 OnDriveTypesChanged(EventArgs.Empty);
  206.             }
  207.         }
  208.         /// <summary>
  209.         /// Clears the TreeView and popluates the root level.
  210.         /// </summary>
  211.         /// <param name="specialFolder">The <c> SpecialFolder</c> which should be selected after population. </param>
  212.         public virtual void Populate(Environment.SpecialFolder specialFolder)
  213.         {
  214.             Populate(Environment.GetFolderPath(specialFolder));
  215.         }
  216.         /// <summary>
  217.         /// Clears the TreeView and popluates the root level.
  218.         /// </summary>
  219.         public virtual void Populate()
  220.         {
  221.             Populate(null);
  222.         }
  223.         /// <summary>
  224.         /// Clears the TreeView and popluates the root level.
  225.         /// </summary>
  226.         /// <param name="selectedFolderPath">The path of the folder that should be selected after population.</param>
  227.         public virtual void Populate(string selectedFolderPath)
  228.         {          
  229.             // clear out the old values
  230.             this.BeginUpdate();
  231.             this.Nodes.Clear();
  232.             Cursor.Current = Cursors.WaitCursor;
  233.             try
  234.             {
  235.                 base.CheckBoxes = (this._checkboxBehavior != CheckboxBehaviorMode.None);
  236.                 _dataProvider.RequestRoot(_helper);
  237.             }
  238.             catch(Exception e)
  239.             {
  240.                 throw e;
  241.             }
  242.             finally
  243.             {
  244.                 this.EndUpdate();
  245.                 Cursor.Current = Cursors.Default;
  246.             }
  247.             // open selected folder
  248.             if((selectedFolderPath!=null) && (selectedFolderPath.Length > 0))
  249.             {
  250.                 this.ShowFolder(selectedFolderPath);
  251.             }
  252.         }
  253.         /// <summary>
  254.         /// Focus the specified folder and scroll it in to view.
  255.         /// </summary>
  256.         /// <param name="directoryPath">The path which should be focused</param>
  257.         public void ShowFolder(string directoryPath)
  258.         {
  259.             if ((directoryPath==null) || (directoryPath=="") || (directoryPath== string.Empty)) return;        
  260.             // start search at root node
  261.             TreeNodeCollection nodeCol = _dataProvider.RequestDriveCollection(_helper);
  262.             //
  263.             if(!System.IO.Directory.Exists(directoryPath) || nodeCol==null) return;
  264.             //
  265.             System.IO.DirectoryInfo dirInfo = new System.IO.DirectoryInfo(directoryPath);
  266.             // get path tokens
  267.             ArrayList dirs = new ArrayList();
  268.             dirs.Add(dirInfo.FullName);
  269.             //
  270.             while(dirInfo.Parent!=null)
  271.             {
  272.                 dirs.Add(dirInfo.Parent.FullName);
  273.                 //
  274.                 dirInfo = dirInfo.Parent;
  275.             }
  276.             // try to expand all path tokens
  277.             Cursor.Current = Cursors.WaitCursor;
  278.             this.BeginUpdate();        
  279.             // load on demand was not fired till now
  280.             if(nodeCol.Count==1 && ((TreeNodePath)nodeCol[0]).Path == null)
  281.             {
  282.                 nodeCol[0].Parent.Expand();
  283.             }
  284.             try
  285.             {
  286.                 //         
  287.                 for(int i= dirs.Count-1;i>=0;i--)
  288.                 {                
  289.                     foreach(TreeNodePath n in nodeCol)
  290.                     {
  291.                         if (n.Path.ToLower().CompareTo(dirs[i].ToString().ToLower())==0)
  292.                         {
  293.                             nodeCol = n.Nodes;
  294.                             if(i==0)
  295.                             {
  296.                                 n.EnsureVisible();
  297.                                 this.SelectedNode = n;
  298.                             }
  299.                             else
  300.                             {
  301.                                 n.Expand();
  302.                             }
  303.                             break;
  304.                         }
  305.                     }
  306.                 }
  307.             }
  308.             catch(Exception e)
  309.             {
  310.                 throw e;
  311.             }
  312.             finally
  313.             {
  314.                 this.EndUpdate();
  315.                 Cursor.Current = Cursors.Default;
  316.             }
  317.         }      
  318.         #endregion
  319.        
  320.         #region internal interface 
  321.         private void OnContextMenu_Popup(object sender, EventArgs e)
  322.         {
  323.             this.OnContextMenuPopup(e);
  324.         }
  325.         protected virtual void OnContextMenuPopup(EventArgs e)
  326.         {
  327.             if(_dataProvider==null) return;
  328.             //
  329.             ContextMenu.MenuItems.Clear();
  330.             //         
  331.             TreeNodePath node = _helper.TreeView.GetNodeAt(_helper.TreeView.PointToClient(Cursor.Position)) as TreeNodePath;
  332.             if(node==null) return;
  333.             //
  334.             _dataProvider.QueryContextMenuItems(_helper, node);
  335.         }
  336.  
  337.         /// <summary>
  338.         /// True to supress OnBeforeCheck Execution, otherwise false to allow it.
  339.         /// </summary>
  340.         /// <param name="supressEvent"></param>
  341.         protected internal virtual void SupressCheckEvent(bool supressEvent)
  342.         {
  343.             this._supressCheck += (supressEvent)? +1 : -1;
  344.         }
  345.         /// <summary>
  346.         /// Indicates if OnBeforeCheck is permitted to call code
  347.         /// </summary>
  348.         protected bool IsCheckEventSupressed
  349.         {
  350.             get
  351.             {
  352.                 return this._supressCheck != 0;
  353.             }
  354.         }
  355.         /// <summary>
  356.         /// Gets the root <c>TreeNodeCollection</c> depended on current RootFolder.
  357.         /// </summary>
  358.         /// <returns></returns>
  359.         protected virtual TreeNodeCollection GetRootCollection()
  360.         {
  361.             switch(RootFolder)
  362.             {
  363.                 case Environment.SpecialFolder.Desktop:
  364.                     return this.Nodes[0].Nodes[1].Nodes;                   
  365.                 default:
  366.                     return this.Nodes;
  367.             }          
  368.         }      
  369.         /// <summary>
  370.         /// Populates the Directory structure for a given path.
  371.         /// </summary>
  372.         /// <param name="parent"></param>
  373.         protected virtual void GetSubDirs( TreeNodePath parent, TreeViewCancelEventArgs e)
  374.         {
  375.             if(parent.Path==null) return;
  376.             // everything ok, here we go
  377.             this.BeginUpdate();
  378.             try
  379.             {
  380.                 parent.RemoveDummyNode();
  381.                 // if we have not scanned this folder before
  382.                 if ( parent.Nodes.Count == 0)
  383.                 {                  
  384.                     _dataProvider.RequestSubDirs(_helper, parent,e);
  385.                 }
  386.             }
  387.             catch( Exception ex )
  388.             {              
  389.                 throw ex;
  390.             }
  391.             finally
  392.             {
  393.                 this.EndUpdate();
  394.             }
  395.         }
  396.         /// <summary>
  397.         /// Toggle the check flag for tree nodes, works recursive
  398.         /// </summary>
  399.         /// <param name="parent"></param>
  400.         /// <param name="check"></param>
  401.         protected virtual void CheckNodesRec(TreeNode parent,TreeViewCancelEventArgs e, bool check)
  402.         {  
  403.             foreach(TreeNode n in parent.Nodes)
  404.             {
  405.                 n.Checked = check;
  406.                 //Populate the current node's subdirectory list
  407.                 try
  408.                 {
  409.                     TreeNodePath nPath = n as TreeNodePath;
  410.                    GetSubDirs(nPath, e);
  411.                 }
  412.                 catch { }
  413.                 //
  414.                 CheckNodesRec(n,e, check);
  415.             }
  416.         }
  417.         /// <summary>
  418.         /// Add or removes the nodes recursive to or from the folderList_.
  419.         /// </summary>
  420.         /// <param name="parent"></param>
  421.         /// <param name="add"></param>
  422.         protected virtual void ExchangeFoldersRec(TreeNodePath parent,TreeViewCancelEventArgs e, bool add)
  423.         {              
  424.             foreach(TreeNodePath n in parent.Nodes)
  425.             {              
  426.                 if (n.Path!=null)
  427.                 {
  428.                     ExchangePath( n.Path, add);
  429.                     MarkNode(parent);
  430.                 }
  431.                 //Populate the current node's subdirectory list
  432.                 try
  433.                 {
  434.                     GetSubDirs(n, e);
  435.                 }
  436.                 catch { }
  437.                 ExchangeFoldersRec(n,e,add);
  438.             }
  439.         }
  440.         /// <summary>
  441.         /// Add or removes path from the folderList_.
  442.         /// </summary>
  443.         /// <param name="path"></param>
  444.         /// <param name="add"></param>
  445.         protected virtual void ExchangePath(string path, bool add)
  446.         {
  447.            
  448.             if (add)
  449.             {
  450.                 if(!folderList_.Contains(path))
  451.                 {
  452.                     folderList_.Add(path);
  453.                     // notfiy add
  454.                     OnSelectedDirectoriesChanged(new SelectedDirectoriesChangedEventArgs(path, System.Windows.Forms.CheckState.Checked));
  455.                 }
  456.             }
  457.             else
  458.             {
  459.                 if (folderList_.Contains(path))
  460.                 {
  461.                     folderList_.Remove(path);
  462.                     // notfiy remove
  463.                     OnSelectedDirectoriesChanged(new SelectedDirectoriesChangedEventArgs(path, System.Windows.Forms.CheckState.Unchecked));
  464.                 }
  465.             }
  466.         }
  467.         /// <summary>
  468.         /// Set the text bold if there is a child node checked.
  469.         /// </summary>
  470.         /// <param name="node"></param>
  471.         protected internal virtual void MarkNode(TreeNodePath node)
  472.         {
  473.             if(this._checkboxBehavior == CheckboxBehaviorMode.None) return;
  474.             //
  475.             if(node==null) return;
  476.             // no path selected, no node could be marked
  477.             if (folderList_.Count == 0)
  478.             {
  479.                 try
  480.                 {
  481.                     if((node.NodeFont !=null) && (node.NodeFont.Bold))
  482.                     {
  483.                         node.NodeFont = this.Font;
  484.                     }
  485.                 }
  486.                 catch{}
  487.                 return;
  488.             }
  489.             // there are a few paths, so we have to check each against our node path
  490.             string path = node.Path;
  491.             //
  492.             bool isBold = false;
  493.             foreach(string s in folderList_)
  494.             {
  495.                 // if path is equal, return
  496.                 if (s.Equals(path)) continue;
  497.                 // if path is substring, mark node bold, otherwise normal font is used
  498.                 if (s.IndexOf(path) != -1)
  499.                 {
  500.                     isBold = true;
  501.                     break;
  502.                 }
  503.                 else
  504.                 {
  505.                     isBold = false;                
  506.                 }
  507.  
  508.             }
  509.             //
  510.             if (isBold)
  511.             {
  512.                 node.NodeFont = boldFont_;
  513.             }
  514.             else
  515.             {
  516.                 node.NodeFont = this.Font;
  517.             }
  518.         }
  519.         /// <summary>
  520.         /// Set the text bold for each parent node if there is a child node checked.
  521.         /// </summary>
  522.         /// <param name="parent"></param>
  523.         protected virtual void MarkNodesRec(TreeNodePath parent)
  524.         {
  525.             if(this._checkboxBehavior == CheckboxBehaviorMode.None) return;
  526.             //
  527.             if (parent == null) return;
  528.             //
  529.             MarkNode(parent);
  530.             if(parent.Parent !=null)
  531.             {
  532.                 MarkNodesRec(parent.Parent as TreeNodePath);
  533.             }
  534.         }
  535.         #endregion
  536.        
  537.         #region events 
  538.         /// <summary>
  539.         /// Raises the CheckboxBehaviorModeChanged event.
  540.         /// </summary>
  541.         /// <param name="e">An EventArgs that contains the event data.</param>
  542.         protected virtual void OnCheckboxBehaviorModeChanged(EventArgs e)
  543.         {
  544.             if(CheckboxBehaviorModeChanged!=null) CheckboxBehaviorModeChanged(this, e);
  545.         }
  546.         /// <summary>
  547.         /// Raises the DriveTypesChanged event.
  548.         /// </summary>
  549.         /// <param name="e">An EventArgs that contains the event data.</param>
  550.         protected virtual void OnDriveTypesChanged(EventArgs e)
  551.         {
  552.             if(DriveTypesChanged!=null) DriveTypesChanged(this, e);
  553.         }
  554.         /// <summary>
  555.         /// Raises the DataSourceChanged event.
  556.         /// </summary>
  557.         /// <param name="e">An EventArgs that contains the event data.</param>
  558.         protected virtual void OnDataSourceChanged(EventArgs e)
  559.         {
  560.             if(DataSourceChanged!=null) DataSourceChanged(this, e);
  561.         }
  562.         /// <summary>
  563.         /// Used for drives like floppy, cd - rom ect. where it can be that no valid medium is inserted.
  564.         /// in this case the click on the + will remove the +, after double click there's a new + to give the user
  565.         /// the chance to browse this device after inserting a valid medium.
  566.         /// </summary>     
  567.         protected override void OnDoubleClick(EventArgs e)
  568.         {
  569.             if (this.SelectedNode==null) return;
  570.             //
  571.             TreeNodePath node = this.SelectedNode as TreeNodePath;
  572.             if(node==null) return;
  573.             //
  574.             if ((node.Nodes.Count > 0) ||(node.Path.Length>3)) return;
  575.             //
  576.             node.AddDummyNode();
  577.             //
  578.             base.OnDoubleClick (e);
  579.         }
  580.         /// <summary>
  581.         /// Fired before check action occurs, manages the folderList_.
  582.         /// </summary>     
  583.         protected override void OnBeforeCheck(TreeViewCancelEventArgs e)
  584.         {
  585.  
  586.             //Populate the subdirectory structure for the node
  587.             TreeNodePath node = e.Node as TreeNodePath;
  588.             try
  589.             {
  590.                 GetSubDirs(node, e);
  591.             }
  592.             catch { }
  593.  
  594.             // check suppress flag
  595.             if (IsCheckEventSupressed)
  596.             {
  597.                 base.OnBeforeCheck(e);
  598.                 return;
  599.             }
  600.             // get current action      
  601.             bool check = !e.Node.Checked;
  602.             // set supress flag
  603.             SupressCheckEvent(true);           
  604.             // stop drawing tree content
  605.             this.BeginUpdate();
  606.             // set cursor
  607.             Cursor.Current = Cursors.WaitCursor;           
  608.             //
  609.             try
  610.             {
  611.                 // add or remove path
  612.                 ExchangePath(((TreeNodePath)e.Node).Path,check);               
  613.                 // handle recursive behaviour
  614.                 if(this.CheckboxBehaviorMode==CheckboxBehaviorMode.RecursiveChecked)
  615.                 {
  616.  
  617.                     //Add or remove childs from folderList_ depending on whether the note is being checked or unchecked
  618.                     bool addPaths = true;
  619.                     if (e.Node.Checked)
  620.                     {
  621.                         addPaths = false;                        
  622.                     }
  623.                     ExchangeFoldersRec(e.Node as TreeNodePath, e, addPaths);
  624.                    
  625.                     // check child nodes to reflect parent check state
  626.                     CheckNodesRec(e.Node, e, check);
  627.                 }
  628.                 // update marked nodes fonts
  629.                 MarkNodesRec(e.Node.Parent as TreeNodePath);               
  630.             }
  631.             catch(Exception ex)
  632.             {
  633.                 // ups, exception ?
  634.                 Console.WriteLine(ex.Message);
  635.             }
  636.             finally
  637.             {
  638.                 // reset supress flag
  639.                 SupressCheckEvent(false);
  640.                 // let the tree redraw his content
  641.                 this.EndUpdate();
  642.                 // reset the cursor
  643.                 Cursor.Current = Cursors.Default;              
  644.             }
  645.             //
  646.             base.OnBeforeCheck (e);
  647.         }
  648.         /// <summary>
  649.         /// Fired before node expands, used to fill next level in directory structure.
  650.         /// </summary>     
  651.         protected override void OnBeforeExpand(TreeViewCancelEventArgs e)
  652.         {
  653.             TreeNodePath node = e.Node as TreeNodePath;
  654.             //
  655.             Cursor.Current = Cursors.WaitCursor;
  656.             try
  657.             {
  658.                 GetSubDirs(node,e);            
  659.             }
  660.             catch(System.Exception ex)
  661.             {
  662.                 MessageBox.Show(ex.Message, System.Reflection.MethodBase.GetCurrentMethod().Name);
  663.                 e.Cancel = true;
  664.             }
  665.             finally
  666.             {
  667.                 Cursor.Current = Cursors.Default;
  668.             }          
  669.             //
  670.             base.OnBeforeExpand (e);
  671.         }
  672.         /// <summary>
  673.         /// Raises the SelectedDirectoriesChanged event.<seealso cref="SelectedDirectoriesChangedDelegate"/>
  674.         /// </summary>
  675.         protected virtual void OnSelectedDirectoriesChanged(SelectedDirectoriesChangedEventArgs e)
  676.         {
  677.             if(this.SelectedDirectoriesChanged!=null) SelectedDirectoriesChanged(this, e);
  678.         }
  679.         #endregion
  680.  
  681.         #region Windows Form Designer generated code
  682.         /// <summary>
  683.         /// Required method for Designer support - do not modify
  684.         /// the contents of this method with the code editor.
  685.         /// </summary>
  686.         private void InitializeComponent()
  687.         {              
  688.             //
  689.             // TreeViewFolderBrowser
  690.             //
  691.             this.HideSelection = false;
  692.  
  693.         }
  694.         #endregion
  695.     }
  696.     /// <summary>
  697.     /// <c>ITreeViewFolderBrowserDataProvider</c> is used by a <see cref="TreeViewFolderBrowser"/> instance and is responsible for
  698.     /// <list>
  699.     /// <item>retrieve the computer drives and directories</item>
  700.     /// <item>Imagelist which is used to assign images to the nodes created by this instance.</item>  
  701.     /// <item>ContextMenu</item>
  702.     /// </list>
  703.     /// <see cref="TreeViewFolderBrowser"/> calls the interface method's and provide a <see cref="TreeViewFolderBrowserHelper"/> instance which let you create node's and give you access to the underlying <see cref="TreeViewFolderBrowser"/> instance.
  704.     /// </summary>
  705.     public interface ITreeViewFolderBrowserDataProvider : IDisposable
  706.     {  
  707.         /// <summary>
  708.         /// Gets the ImageList that contains the Image objects used by the tree nodes.
  709.         /// </summary>
  710.         ImageList ImageList{get;}
  711.         /// <summary>
  712.         /// Fired before the context menu popup.
  713.         /// </summary>
  714.         /// <param name="helper">The helper instance which provides method's and properties related to create and get nodes.</param>
  715.         /// <param name="node">The node on which the context menu was requested.</param>
  716.         void QueryContextMenuItems(TreeViewFolderBrowserHelper helper, TreeNodePath node);
  717.         /// <summary>
  718.         /// Fill the root level.
  719.         /// </summary>
  720.         /// <param name="helper">The helper instance which provides method's and properties related to create and get nodes.</param>
  721.         void RequestRoot(TreeViewFolderBrowserHelper helper);
  722.         /// <summary>
  723.         /// Fill the Directory structure for a given path.
  724.         /// </summary>
  725.         /// <param name="helper">The helper instance which provides method's and properties related to create and get nodes.</param>
  726.         /// <param name="parent">The expanding node.</param>
  727.         void RequestSubDirs(TreeViewFolderBrowserHelper helper, TreeNodePath parent, TreeViewCancelEventArgs e);
  728.         /// <summary>
  729.         /// Gets the tree node collection which holds the drive node's. The requested collection is than used to search a specific node.
  730.         /// </summary>
  731.         TreeNodeCollection RequestDriveCollection(TreeViewFolderBrowserHelper helper);
  732.     }
  733.     /// <summary>
  734.     /// <c>TreeViewFolderBrowserHelper</c> is like a bridge between <see cref="ITreeViewFolderBrowserDataProvider"/> and <see cref="TreeViewFolderBrowser"/>
  735.     /// and provides access to the needed informations to fill the tree view.
  736.     /// </summary>
  737.     public class TreeViewFolderBrowserHelper
  738.     {
  739.         #region fields
  740.         /// <summary>the managed tree view instance</summary>
  741.         private TreeViewFolderBrowser _treeView;
  742.         #endregion
  743.  
  744.         #region constructors
  745.         /// <summary>
  746.         /// Initialize a new instance of TreeViewFolderBrowserHelper for the specified TreeViewFolderBrowser instance.
  747.         /// </summary>
  748.         /// <param name="treeView"></param>
  749.         internal TreeViewFolderBrowserHelper(TreeViewFolderBrowser treeView)
  750.         {
  751.             _treeView = treeView;
  752.         }
  753.         #endregion
  754.  
  755.         #region public interface
  756.         /// <summary>
  757.         /// Gets the underlying <see cref="TreeViewFolderBrowser"/> instance.
  758.         /// </summary>
  759.         public TreeViewFolderBrowser TreeView
  760.         {
  761.             get
  762.             {
  763.                 return _treeView;
  764.             }
  765.         }
  766.         /// <summary>
  767.         /// Creates a tree node and add it to the <c>TreeNodeCollection</c>.
  768.         /// </summary>
  769.         /// <param name="text">The text displayed in the label of the tree node.</param>
  770.         /// <param name="path">The path the node represents.</param>
  771.         /// <param name="addDummyNode">True to add + sign, otherwise no + sign appears.</param>
  772.         /// <param name="forceChecked">True to check node in each case, otherwise false to allow normal check against selected paths.</param>
  773.         /// <param name="isSpecialFolder">Specifies if this node is a special folder. Special folders do not request data from the attached data provider.</param>
  774.         /// <returns></returns>
  775.         public virtual TreeNodePath CreateTreeNode(string text, string path, bool addDummyNode,bool forceChecked, bool isSpecialFolder)
  776.         {          
  777.             TreeNodePath newNode = new TreeNodePath(text, isSpecialFolder);                            
  778.             // path
  779.             newNode.Path = path;
  780.             //                     
  781.             try
  782.             {
  783.                 _treeView.SupressCheckEvent(true);
  784.                 //
  785.                 if(forceChecked)
  786.                 {
  787.                     newNode.Checked = true;
  788.                 }
  789.                 else
  790.                 {
  791.                     newNode.Checked = _treeView.SelectedDirectories.Contains(path);
  792.                 }
  793.                 _treeView.MarkNode(newNode);
  794.             }
  795.             catch (System.Exception e)
  796.             {
  797.                 System.Diagnostics.Debug.WriteLine(e.Message,_treeView.Name);
  798.             }
  799.             finally
  800.             {
  801.                 _treeView.SupressCheckEvent(false);
  802.             }
  803.             //
  804.             if(addDummyNode)
  805.             {
  806.                 // add dummy node, otherwise there is no + sign
  807.                 newNode.AddDummyNode();
  808.             }
  809.             //
  810.             return newNode;
  811.         }
  812.         #endregion
  813.     }  
  814.     /// <summary>
  815.     /// A simple designer class for the <see cref="TreeViewFolderBrowser"/> control to remove
  816.     /// unwanted properties at design time.
  817.     /// </summary>
  818.     public class TreeViewFolderBrowserDesigner : System.Windows.Forms.Design.ControlDesigner
  819.     {
  820.         /// <summary>
  821.         /// Allows a designer to change or remove items from the set of properties that it exposes through a TypeDescriptor.
  822.         /// </summary>
  823.         /// <param name="properties">The properties for the class of the component.</param>
  824.         protected override void PreFilterProperties(System.Collections.IDictionary properties)
  825.         {
  826.             properties.Remove("CheckBoxes");           
  827.             properties.Remove("ImageList");
  828.             properties.Remove("SelectedImageIndex");
  829.             properties.Remove("ImageIndex");
  830.             properties.Remove("ContextMenu");
  831.         }
  832.     }
  833.     /// <summary>
  834.     /// Extends the <c>TreeNode</c> type with a path property. This node type is used by <see cref="TreeViewFolderBrowser"/>
  835.     /// </summary>
  836.     public class TreeNodePath : System.Windows.Forms.TreeNode
  837.     {
  838.         #region fields
  839.         /// <summary>Specifiy that this node instance represent a special folder.</summary>
  840.         private readonly bool _isSpecialFolder;
  841.         /// <summary>
  842.         /// File or directory path information
  843.         /// </summary>
  844.         private string _path;
  845.         #endregion fiels
  846.  
  847.         #region constructor
  848.         /// <summary>
  849.         /// Initializes a new instance of the TreeNodePath class.
  850.         /// </summary>
  851.         public TreeNodePath()
  852.         {
  853.         }
  854.         /// <summary>
  855.         /// Initializes a new instance of the TreeNodePath class.
  856.         /// </summary>
  857.         /// <param name="text">The label Text of the new tree node. </param>
  858.         public TreeNodePath(string text, bool isSpecialFolder) : base(text)
  859.         {
  860.             this._isSpecialFolder = isSpecialFolder;
  861.         }      
  862.         /// <summary>
  863.         /// Initializes a new instance of the TreeNodePath class.
  864.         /// </summary>
  865.         /// <param name="text">The label Text of the new tree node. </param>
  866.         /// <param name="imageIndex">The index value of Image to display when the tree node is unselected.</param>
  867.         /// <param name="selectedImageIndex">The index value of Image to display when the tree node is selected.</param>
  868.         public TreeNodePath(string text, bool isSpecialFolder, int imageIndex,  int selectedImageIndex) : base(text, imageIndex, selectedImageIndex)
  869.         {
  870.             _isSpecialFolder = isSpecialFolder;
  871.         }
  872.         #endregion
  873.  
  874.         #region public interface
  875.         /// <summary>
  876.         /// Adds a dummy node to the parent node
  877.         /// </summary>     
  878.         public virtual void AddDummyNode()
  879.         {
  880.             Nodes.Add(new TreeNodePath("@@Dummy@@",false));
  881.         }
  882.         /// <summary>
  883.         /// Removes the dummy node from the parent node.
  884.         /// </summary>     
  885.         public virtual void RemoveDummyNode()
  886.         {
  887.             if ((Nodes.Count == 1 ) & (Nodes[0].Text == "@@Dummy@@"))
  888.             {
  889.                 Nodes[0].Remove();
  890.             }
  891.         }
  892.         /// <summary>
  893.         /// Gets or sets this node as a special folder node.
  894.         /// </summary>
  895.         /// <remarks>
  896.         /// SpecialFolder's are folder's which are defined by <see cref="Environment.SpecialFolder"/> enum.
  897.         /// </remarks>
  898.         public bool IsSpecialFolder
  899.         {
  900.             get
  901.             {              
  902.                 return _isSpecialFolder;
  903.             }
  904.         }
  905.         /// <summary>
  906.         /// Gets or sets the file or directory path information
  907.         /// </summary>         
  908.         public string Path
  909.         {
  910.             get
  911.             {                  
  912.                 return _path;
  913.             }
  914.             set
  915.             {
  916.                 _path = value;
  917.             }
  918.         }
  919.         #endregion
  920.     }  
  921.     /// <summary>
  922.     /// Occurs when a directory checkstate has changed
  923.     /// </summary>
  924.     /// <remarks>
  925.     /// The SelectedDirectoriesChangedDelegate event passes an SelectedDirectoriesChangedEventArgs object to its event handler.
  926.     /// </remarks>
  927.     public delegate void SelectedDirectoriesChangedDelegate(object sender, SelectedDirectoriesChangedEventArgs e);
  928.     /// <summary>
  929.     /// Provides data for the SelectedDirectoriesChangedDelegate event of a TreeViewFolderBrowser control.
  930.     /// </summary>
  931.     public class SelectedDirectoriesChangedEventArgs
  932.     {
  933.         #region fields
  934.         /// <summary>File path</summary>
  935.         private readonly string _path;
  936.         /// <summary>Checkstate</summary>
  937.         private readonly System.Windows.Forms.CheckState _checkState;
  938.         #endregion
  939.  
  940.         #region constructors
  941.         /// <summary>Initalize a new instance of SelectedDirectoriesChangedEventArgs</summary>
  942.         public SelectedDirectoriesChangedEventArgs(string path,System.Windows.Forms.CheckState checkState)
  943.         {
  944.             _path = path;
  945.             _checkState = checkState;
  946.         }
  947.         #endregion
  948.  
  949.         /// <summary>Gets the path which was modified</summary>
  950.         public string Path
  951.         {
  952.             get{return _path;}
  953.         }
  954.         /// <summary>Gets the check state for the path</summary>
  955.         public System.Windows.Forms.CheckState CheckState
  956.         {
  957.             get{return _checkState;}
  958.         }
  959.     }
  960.     /// <summary>
  961.     /// Indicating whether check boxes are displayed next to the tree nodes in the tree view control and how the tree view handle related events.
  962.     /// </summary>
  963.     public enum CheckboxBehaviorMode
  964.     {
  965.         /// <summary>
  966.         /// No check boxes are displayed next to the tree nodes in the tree view control.
  967.         /// </summary>
  968.         None,
  969.         /// <summary>
  970.         /// Check boxes are displayed next to the tree nodes in the tree view control. The user can check directories.
  971.         /// </summary>
  972.         SingleChecked,
  973.         /// <summary>
  974.         /// Check boxes are displayed next to the tree nodes in the tree view control. The user can check directories, the subdirectories are checked recursive.
  975.         /// </summary>
  976.         RecursiveChecked
  977.     }
  978.     /// <summary>
  979.     /// Defines the DriveTypes used for Win32_LogicalDisk<seealso cref="TreeViewFolderBrowser"/>.This enumeration can be treated as a bit field, that is, a set of flags.
  980.     /// </summary>
  981.     [Flags]
  982.     [Editor(typeof(Raccoom.Windows.Forms.Design.FlagsEditor), typeof(UITypeEditor))]
  983.     public enum DriveTypes
  984.     {
  985.        
  986.         /// <summary>All drive types</summary>
  987.         All = NoRootDirectory | RemovableDisk | LocalDisk | NetworkDrive | CompactDisc | RAMDisk,
  988.         /// <summary>
  989.         /// NoRootDirectory
  990.         /// </summary>
  991.         NoRootDirectory = 0x0001,
  992.         /// <summary>
  993.         /// Drive has removable media. This includes all floppy drives and many other varieties of storage devices.
  994.         /// </summary>
  995.         RemovableDisk = 0x0002,
  996.         /// <summary>
  997.         /// Drive has fixed (nonremovable) media. This includes all hard drives, including hard drives that are removable.
  998.         /// </summary>
  999.         LocalDisk = 0x0004,
  1000.         /// <summary>
  1001.         /// Network drives. This includes drives shared anywhere on a network.
  1002.         /// </summary>
  1003.         NetworkDrive = 0x0008,
  1004.         /// <summary>
  1005.         /// Drive is a CD-ROM. No distinction is made between read-only and read/write CD-ROM drives.
  1006.         /// </summary>
  1007.         CompactDisc= 0x0020,
  1008.         /// <summary>
  1009.         /// Drive is a block of Random Access Memory (RAM) on the local computer that behaves like a disk drive.
  1010.         /// </summary>
  1011.         RAMDisk= 0x0040
  1012.     }
  1013.     /// <summary>
  1014.     /// Defines the DriveTypes used for Win32_LogicalDisk<seealso cref="TreeViewFolderBrowser"/>.This enumeration can a<b>not</b> be treated as a bit field
  1015.     /// </summary>
  1016.     public enum Win32_LogicalDiskDriveTypes
  1017.     {
  1018.         /// <summary>
  1019.         /// NoRootDirectory
  1020.         /// </summary>
  1021.         NoRootDirectory = 1,
  1022.         /// <summary>
  1023.         /// Drive has removable media. This includes all floppy drives and many other varieties of storage devices.
  1024.         /// </summary>
  1025.         RemovableDisk,
  1026.         /// <summary>
  1027.         /// Drive has fixed (nonremovable) media. This includes all hard drives, including hard drives that are removable.
  1028.         /// </summary>
  1029.         LocalDisk,
  1030.         /// <summary>
  1031.         /// Network drives. This includes drives shared anywhere on a network.
  1032.         /// </summary>
  1033.         NetworkDrive,
  1034.         /// <summary>
  1035.         /// Drive is a CD-ROM. No distinction is made between read-only and read/write CD-ROM drives.
  1036.         /// </summary>
  1037.         CompactDisc,
  1038.         /// <summary>
  1039.         /// Drive is a block of Random Access Memory (RAM) on the local computer that behaves like a disk drive.
  1040.         /// </summary>
  1041.         RAMDisk
  1042.     }
  1043. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement