1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2006 Alexander Olk
23 // Alexander Olk (alex.olk@googlemail.com)
29 using System
.ComponentModel
;
30 using System
.Resources
;
32 using System
.Collections
;
34 namespace System
.Windows
.Forms
{
35 [DefaultEvent ("HelpRequest")]
36 [DefaultProperty ("SelectedPath")]
37 [Designer ("System.Windows.Forms.Design.FolderBrowserDialogDesigner, " + Consts
.AssemblySystem_Design
, "System.ComponentModel.Design.IDesigner")]
38 public sealed class FolderBrowserDialog
: CommonDialog
40 #region Local Variables
41 private string description
= "";
42 private Environment
.SpecialFolder rootFolder
= Environment
.SpecialFolder
.Desktop
;
43 private string selectedPath
= "";
44 private bool showNewFolderButton
= true;
46 private Label descriptionLabel
;
47 private Button cancelButton
;
48 private Button okButton
;
49 private FolderBrowserTreeView folderBrowserTreeView
;
50 private Button newFolderButton
;
51 private ContextMenu folderBrowserTreeViewContextMenu
;
52 private MenuItem newFolderMenuItem
;
54 private string old_selectedPath
= "";
56 private readonly string folderbrowserdialog_string
= "FolderBrowserDialog";
57 private readonly string width_string
= "Width";
58 private readonly string height_string
= "Height";
59 private readonly string x_string
= "X";
60 private readonly string y_string
= "Y";
61 #endregion // Local Variables
63 #region Public Constructors
64 public FolderBrowserDialog ()
66 Size formConfigSize
= Size
.Empty
;
67 Point formConfigLocation
= Point
.Empty
;
69 object formWidth
= MWFConfig
.GetValue (folderbrowserdialog_string
, width_string
);
71 object formHeight
= MWFConfig
.GetValue (folderbrowserdialog_string
, height_string
);
73 if (formHeight
!= null && formWidth
!= null)
74 formConfigSize
= new Size ((int)formWidth
, (int)formHeight
);
76 object formLocationX
= MWFConfig
.GetValue (folderbrowserdialog_string
, x_string
);
77 object formLocationY
= MWFConfig
.GetValue (folderbrowserdialog_string
, y_string
);
79 if (formLocationX
!= null && formLocationY
!= null)
80 formConfigLocation
= new Point ((int)formLocationX
, (int)formLocationY
);
82 newFolderButton
= new Button ();
83 folderBrowserTreeView
= new FolderBrowserTreeView (this);
84 okButton
= new Button ();
85 cancelButton
= new Button ();
86 descriptionLabel
= new Label ();
87 folderBrowserTreeViewContextMenu
= new ContextMenu ();
89 form
.AcceptButton
= okButton
;
90 form
.CancelButton
= cancelButton
;
92 form
.SuspendLayout ();
93 form
.ClientSize
= new Size (322, 324);
94 form
.MinimumSize
= new Size (310, 254);
95 form
.Text
= "Search Folder";
96 form
.SizeGripStyle
= SizeGripStyle
.Show
;
98 newFolderMenuItem
= new MenuItem("New Folder", new EventHandler (OnClickNewFolderButton
));
99 folderBrowserTreeViewContextMenu
.MenuItems
.Add(newFolderMenuItem
);
102 descriptionLabel
.Anchor
= ((AnchorStyles
)(((AnchorStyles
.Top
| AnchorStyles
.Left
)
103 | AnchorStyles
.Right
)));
104 descriptionLabel
.Location
= new Point (15, 14);
105 descriptionLabel
.Size
= new Size (292, 40);
106 descriptionLabel
.TabIndex
= 0;
107 descriptionLabel
.Text
= "";
109 // folderBrowserTreeView
110 folderBrowserTreeView
.Anchor
= ((AnchorStyles
)((((AnchorStyles
.Top
| AnchorStyles
.Bottom
)
112 | AnchorStyles
.Right
)));
113 folderBrowserTreeView
.ImageIndex
= -1;
114 folderBrowserTreeView
.Location
= new Point (15, 60);
115 folderBrowserTreeView
.SelectedImageIndex
= -1;
116 folderBrowserTreeView
.Size
= new Size (292, 212);
117 folderBrowserTreeView
.TabIndex
= 1;
118 folderBrowserTreeView
.ShowLines
= false;
119 folderBrowserTreeView
.ShowPlusMinus
= true;
120 folderBrowserTreeView
.HotTracking
= true;
121 folderBrowserTreeView
.BorderStyle
= BorderStyle
.Fixed3D
;
122 folderBrowserTreeView
.ContextMenu
= folderBrowserTreeViewContextMenu
;
123 //folderBrowserTreeView.Indent = 2;
126 newFolderButton
.Anchor
= ((AnchorStyles
)((AnchorStyles
.Bottom
| AnchorStyles
.Left
)));
127 newFolderButton
.FlatStyle
= FlatStyle
.System
;
128 newFolderButton
.Location
= new Point (15, 285);
129 newFolderButton
.Size
= new Size (105, 23);
130 newFolderButton
.TabIndex
= 2;
131 newFolderButton
.Text
= "New Folder";
132 newFolderButton
.Enabled
= true;
135 okButton
.Anchor
= ((AnchorStyles
)((AnchorStyles
.Bottom
| AnchorStyles
.Right
)));
136 okButton
.FlatStyle
= FlatStyle
.System
;
137 okButton
.Location
= new Point (142, 285);
138 okButton
.Size
= new Size (80, 23);
139 okButton
.TabIndex
= 3;
140 okButton
.Text
= "OK";
143 cancelButton
.Anchor
= ((AnchorStyles
)((AnchorStyles
.Bottom
| AnchorStyles
.Right
)));
144 cancelButton
.DialogResult
= DialogResult
.Cancel
;
145 cancelButton
.FlatStyle
= FlatStyle
.System
;
146 cancelButton
.Location
= new Point (227, 285);
147 cancelButton
.Size
= new Size (80, 23);
148 cancelButton
.TabIndex
= 4;
149 cancelButton
.Text
= "Cancel";
151 form
.Controls
.Add (cancelButton
);
152 form
.Controls
.Add (okButton
);
153 form
.Controls
.Add (newFolderButton
);
154 form
.Controls
.Add (folderBrowserTreeView
);
155 form
.Controls
.Add (descriptionLabel
);
157 form
.ResumeLayout (false);
159 if (formConfigSize
!= Size
.Empty
) {
160 form
.Size
= formConfigSize
;
163 if (formConfigLocation
!= Point
.Empty
) {
164 form
.Location
= formConfigLocation
;
167 okButton
.Click
+= new EventHandler (OnClickOKButton
);
168 cancelButton
.Click
+= new EventHandler (OnClickCancelButton
);
169 newFolderButton
.Click
+= new EventHandler (OnClickNewFolderButton
);
171 RootFolder
= rootFolder
;
174 #endregion // Public Constructors
176 #region Public Instance Properties
180 public string Description
{
183 descriptionLabel
.Text
= description
;
192 [DefaultValue(Environment
.SpecialFolder
.Desktop
)]
194 public Environment
.SpecialFolder RootFolder
{
198 if (!Enum
.IsDefined(typeof(Environment
.SpecialFolder
), v
))
199 throw new InvalidEnumArgumentException ();
201 if (rootFolder
!= value)
204 folderBrowserTreeView
.RootFolder
= rootFolder
;
214 [Editor("System.Windows.Forms.Design.SelectedPathEditor, " + Consts
.AssemblySystem_Design
, typeof(System
.Drawing
.Design
.UITypeEditor
))]
216 public string SelectedPath
{
218 if (!Path
.IsPathRooted(value))
221 selectedPath
= value;
222 old_selectedPath
= value;
223 folderBrowserTreeView
.SelectedPath
= selectedPath
;
234 public bool ShowNewFolderButton
{
236 if (value != showNewFolderButton
) {
237 showNewFolderButton
= value;
238 if (showNewFolderButton
)
239 newFolderButton
.Show ();
241 newFolderButton
.Hide ();
246 return showNewFolderButton
;
249 #endregion // Public Instance Properties
251 #region Public Instance Methods
252 public override void Reset ()
255 RootFolder
= Environment
.SpecialFolder
.Desktop
;
257 ShowNewFolderButton
= true;
260 protected override bool RunDialog (IntPtr hwndOwner
)
266 #endregion // Public Instance Methods
268 #region Internal Methods
269 void OnClickOKButton (object sender
, EventArgs e
)
271 WriteConfigValues ();
273 form
.DialogResult
= DialogResult
.OK
;
276 void OnClickCancelButton (object sender
, EventArgs e
)
278 WriteConfigValues ();
280 selectedPath
= old_selectedPath
;
281 form
.DialogResult
= DialogResult
.Cancel
;
284 void OnClickNewFolderButton (object sender
, EventArgs e
)
286 folderBrowserTreeView
.CreateNewFolder ();
289 private void WriteConfigValues ()
291 MWFConfig
.SetValue (folderbrowserdialog_string
, width_string
, form
.Width
);
292 MWFConfig
.SetValue (folderbrowserdialog_string
, height_string
, form
.Height
);
293 MWFConfig
.SetValue (folderbrowserdialog_string
, x_string
, form
.Location
.X
);
294 MWFConfig
.SetValue (folderbrowserdialog_string
, y_string
, form
.Location
.Y
);
296 #endregion // Internal Methods
300 [EditorBrowsable(EditorBrowsableState
.Never
)]
301 public new event EventHandler HelpRequest
{
302 add { base.HelpRequest += value; }
303 remove { base.HelpRequest -= value; }
307 internal class FolderBrowserTreeView
: TreeView
309 private MWFVFS vfs
= new MWFVFS ();
310 new private FBTreeNode root_node
;
311 private FolderBrowserDialog parentDialog
;
312 private ImageList imageList
= new ImageList ();
313 private Environment
.SpecialFolder rootFolder
;
314 private bool dont_enable
= false;
316 private int platform
= (int) Environment
.OSVersion
.Platform
;
318 public FolderBrowserTreeView (FolderBrowserDialog parent_dialog
)
320 parentDialog
= parent_dialog
;
321 ImageList
= imageList
;
325 public Environment
.SpecialFolder RootFolder
{
329 string root_path
= "";
331 switch (rootFolder
) {
333 case Environment
.SpecialFolder
.Desktop
:
334 root_node
= new FBTreeNode ("Desktop");
335 root_node
.RealPath
= ThemeEngine
.Current
.Places (UIIcon
.PlacesDesktop
);
336 root_path
= MWFVFS
.DesktopPrefix
;
338 case Environment
.SpecialFolder
.MyComputer
:
339 root_node
= new FBTreeNode ("My Computer");
340 root_path
= MWFVFS
.MyComputerPrefix
;
342 case Environment
.SpecialFolder
.Personal
:
343 root_node
= new FBTreeNode ("Personal");
344 root_path
= MWFVFS
.PersonalPrefix
;
345 root_node
.RealPath
= ThemeEngine
.Current
.Places (UIIcon
.PlacesPersonal
);
349 root_node
.Tag
= root_path
;
350 root_node
.ImageIndex
= NodeImageIndex (root_path
);
352 FillNode (root_node
);
356 Nodes
.Add (root_node
);
360 public string SelectedPath
{
362 if (Check_if_path_is_child_of_RootFolder (value)) {
363 SetSelectedPath (Path
.GetFullPath (value));
368 private string parent_real_path
;
369 private bool dont_do_onbeforeexpand
= false;
371 public void CreateNewFolder ()
373 FBTreeNode fbnode
= SelectedNode
as FBTreeNode
;
375 if (fbnode
== null || fbnode
.Parent
== null)
378 if (fbnode
.RealPath
== null)
381 string tmp_filename
= "New Folder";
383 if (Directory
.Exists (Path
.Combine (fbnode
.RealPath
, tmp_filename
))) {
386 if ((platform
== 4) || (platform
== 128)) {
387 tmp_filename
= tmp_filename
+ "-" + i
;
389 tmp_filename
= tmp_filename
+ " (" + i
+ ")";
392 while (Directory
.Exists (Path
.Combine (fbnode
.RealPath
, tmp_filename
))) {
394 if ((platform
== 4) || (platform
== 128)) {
395 tmp_filename
= "New Folder" + "-" + i
;
397 tmp_filename
= "New Folder" + " (" + i
+ ")";
402 parent_real_path
= fbnode
.RealPath
;
404 FBTreeNode new_node
= new FBTreeNode (tmp_filename
);
405 new_node
.ImageIndex
= NodeImageIndex(tmp_filename
);
408 dont_do_onbeforeexpand
= true;
410 dont_do_onbeforeexpand
= false;
412 fbnode
.Nodes
.Add (new_node
);
415 if (!new_node
.IsEditing
)
416 new_node
.BeginEdit();
419 protected override void OnAfterLabelEdit (NodeLabelEditEventArgs e
)
421 if (e
.Label
!= null) {
422 if (e
.Label
.Length
> 0) {
423 FBTreeNode fbnode
= e
.Node
as FBTreeNode
;
425 fbnode
.RealPath
= Path
.Combine(parent_real_path
, e
.Label
);
427 if (vfs
.CreateFolder (fbnode
.RealPath
)) {
428 SelectedNode
= e
.Node
;
430 SelectedNode
= e
.Node
.Parent
;
431 e
.Node
.Parent
.Nodes
.Remove(e
.Node
);
434 e
.Node
.EndEdit (false);
444 private void SetSelectedPath (string path
)
448 FBTreeNode node
= FindPathInNodes (path
, Nodes
);
451 Stack stack
= new Stack ();
453 string path_cut
= path
.Substring (0, path
.LastIndexOf (Path
.AltDirectorySeparatorChar
));
455 while (node
== null && path_cut
.Length
> 0) {
456 node
= FindPathInNodes (path_cut
, Nodes
);
459 string path_cut_new
= path_cut
.Substring (0, path_cut
.LastIndexOf (Path
.AltDirectorySeparatorChar
));
460 string leftover
= path_cut
.Replace (path_cut_new
, "");
462 stack
.Push (leftover
);
464 path_cut
= path_cut_new
;
468 if (stack
.Count
> 0) {
472 // walk through the subdirs and fill the nodes
473 while (stack
.Count
> 0) {
474 string part_name
= stack
.Pop () as string;
476 foreach (TreeNode treeNode
in node
.Nodes
) {
477 FBTreeNode fbnode
= treeNode
as FBTreeNode
;
479 if (path_cut
+ part_name
== fbnode
.RealPath
) {
481 path_cut
+= part_name
;
490 // finally find the node for the complete path
491 foreach (TreeNode treeNode
in node
.Nodes
) {
492 FBTreeNode fbnode
= treeNode
as FBTreeNode
;
494 if (path
== fbnode
.RealPath
) {
504 node
.EnsureVisible ();
510 private FBTreeNode
FindPathInNodes (string path
, TreeNodeCollection nodes
)
512 foreach (TreeNode node
in nodes
) {
513 FBTreeNode fbnode
= node
as FBTreeNode
;
515 if (fbnode
!= null && fbnode
.RealPath
!= null) {
516 if (fbnode
.RealPath
== path
)
520 return FindPathInNodes (path
, node
.Nodes
);
526 private bool Check_if_path_is_child_of_RootFolder (string path
)
528 string root_path
= (string)root_node
.RealPath
;
530 if (root_path
!= null) {
532 if (!Directory
.Exists (path
))
535 switch (rootFolder
) {
536 case Environment
.SpecialFolder
.Desktop
:
537 case Environment
.SpecialFolder
.MyComputer
:
539 case Environment
.SpecialFolder
.Personal
:
540 if (!path
.StartsWith (root_path
))
553 private void FillNode (TreeNode node
)
558 vfs
.ChangeDirectory ((string)node
.Tag
);
559 ArrayList folders
= vfs
.GetFoldersOnly ();
561 foreach (FSEntry fsentry
in folders
) {
562 if (fsentry
.Name
.StartsWith ("."))
565 FBTreeNode child
= new FBTreeNode (fsentry
.Name
);
566 child
.Tag
= fsentry
.FullName
;
567 child
.RealPath
= fsentry
.RealName
== null ? fsentry
.FullName
: fsentry
.RealName
;
568 child
.ImageIndex
= NodeImageIndex (fsentry
.FullName
);
570 vfs
.ChangeDirectory (fsentry
.FullName
);
571 ArrayList sub_folders
= vfs
.GetFoldersOnly ();
573 foreach (FSEntry fsentry_sub
in sub_folders
) {
574 if (!fsentry_sub
.Name
.StartsWith (".")) {
575 child
.Nodes
.Add (new TreeNode (String
.Empty
));
580 node
.Nodes
.Add (child
);
586 private void SetupImageList ()
588 imageList
.ColorDepth
= ColorDepth
.Depth32Bit
;
589 imageList
.ImageSize
= new Size (16, 16);
590 imageList
.Images
.Add (ThemeEngine
.Current
.Images (UIIcon
.PlacesRecentDocuments
, 16));
591 imageList
.Images
.Add (ThemeEngine
.Current
.Images (UIIcon
.PlacesDesktop
, 16));
592 imageList
.Images
.Add (ThemeEngine
.Current
.Images (UIIcon
.PlacesPersonal
, 16));
593 imageList
.Images
.Add (ThemeEngine
.Current
.Images (UIIcon
.PlacesMyComputer
, 16));
594 imageList
.Images
.Add (ThemeEngine
.Current
.Images (UIIcon
.PlacesMyNetwork
, 16));
595 imageList
.Images
.Add (ThemeEngine
.Current
.Images (UIIcon
.NormalFolder
, 16));
596 imageList
.TransparentColor
= Color
.Transparent
;
599 private int NodeImageIndex (string path
)
603 if (path
== MWFVFS
.DesktopPrefix
)
606 if (path
== MWFVFS
.RecentlyUsedPrefix
)
609 if (path
== MWFVFS
.PersonalPrefix
)
612 if (path
== MWFVFS
.MyComputerPrefix
)
615 if (path
== MWFVFS
.MyNetworkPrefix
)
621 protected override void OnAfterSelect (TreeViewEventArgs e
)
626 FBTreeNode fbnode
= e
.Node
as FBTreeNode
;
628 if (fbnode
.RealPath
== null || fbnode
.RealPath
.IndexOf ("://") != -1) {
629 parentDialog
.okButton
.Enabled
= false;
630 parentDialog
.newFolderButton
.Enabled
= false;
631 parentDialog
.newFolderMenuItem
.Enabled
= false;
634 parentDialog
.okButton
.Enabled
= true;
635 parentDialog
.newFolderButton
.Enabled
= true;
636 parentDialog
.newFolderMenuItem
.Enabled
= true;
637 parentDialog
.selectedPath
= fbnode
.RealPath
;
641 base.OnAfterSelect (e
);
644 protected internal override void OnBeforeExpand (TreeViewCancelEventArgs e
)
646 if (!dont_do_onbeforeexpand
) {
647 if (e
.Node
== root_node
)
652 base.OnBeforeExpand (e
);
655 protected override void OnMouseUp (MouseEventArgs e
)
657 if (SelectedNode
== null) {
658 parentDialog
.okButton
.Enabled
= false;
659 parentDialog
.newFolderButton
.Enabled
= false;
660 parentDialog
.newFolderMenuItem
.Enabled
= false;
663 parentDialog
.okButton
.Enabled
= true;
664 parentDialog
.newFolderButton
.Enabled
= true;
665 parentDialog
.newFolderMenuItem
.Enabled
= true;
672 internal class FBTreeNode
: TreeNode
674 private string realPath
= null;
676 public FBTreeNode (string text
)
681 public string RealPath
{