2007-03-19 Chris Toshok <toshok@ximian.com>
[mono-project.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / FolderBrowserDialog.cs
blob7be9072e3e1d1dbdba1e517f03327026e398e097
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:
8 //
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
22 // Authors:
23 // Alexander Olk (alex.olk@googlemail.com)
27 using System;
28 using System.Drawing;
29 using System.ComponentModel;
30 using System.Resources;
31 using System.IO;
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);
101 // descriptionLabel
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)
111 | AnchorStyles.Left)
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;
125 // newFolderButton
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;
134 // okButton
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";
142 // cancelButton
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
177 [Browsable(true)]
178 [DefaultValue("")]
179 [Localizable(true)]
180 public string Description {
181 set {
182 description = value;
183 descriptionLabel.Text = description;
186 get {
187 return description;
191 [Browsable(true)]
192 [DefaultValue(Environment.SpecialFolder.Desktop)]
193 [Localizable(false)]
194 public Environment.SpecialFolder RootFolder {
195 set {
196 int v = (int)value;
198 if (!Enum.IsDefined(typeof(Environment.SpecialFolder), v))
199 throw new InvalidEnumArgumentException ();
201 if (rootFolder != value)
202 rootFolder = value;
204 folderBrowserTreeView.RootFolder = rootFolder;
207 get {
208 return rootFolder;
212 [Browsable(true)]
213 [DefaultValue("")]
214 [Editor("System.Windows.Forms.Design.SelectedPathEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
215 [Localizable(true)]
216 public string SelectedPath {
217 set {
218 if (!Path.IsPathRooted(value))
219 return;
221 selectedPath = value;
222 old_selectedPath = value;
223 folderBrowserTreeView.SelectedPath = selectedPath;
226 get {
227 return selectedPath;
231 [Browsable(true)]
232 [DefaultValue(true)]
233 [Localizable(false)]
234 public bool ShowNewFolderButton {
235 set {
236 if (value != showNewFolderButton) {
237 showNewFolderButton = value;
238 if (showNewFolderButton)
239 newFolderButton.Show ();
240 else
241 newFolderButton.Hide ();
245 get {
246 return showNewFolderButton;
249 #endregion // Public Instance Properties
251 #region Public Instance Methods
252 public override void Reset ()
254 Description = "";
255 RootFolder = Environment.SpecialFolder.Desktop;
256 selectedPath = "";
257 ShowNewFolderButton = true;
260 protected override bool RunDialog (IntPtr hwndOwner)
262 form.Refresh ();
264 return true;
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
298 #region Events
299 [Browsable(false)]
300 [EditorBrowsable(EditorBrowsableState.Never)]
301 public new event EventHandler HelpRequest {
302 add { base.HelpRequest += value; }
303 remove { base.HelpRequest -= value; }
305 #endregion
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;
322 SetupImageList ();
325 public Environment.SpecialFolder RootFolder {
326 set {
327 rootFolder = value;
329 string root_path = "";
331 switch (rootFolder) {
332 default:
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;
337 break;
338 case Environment.SpecialFolder.MyComputer:
339 root_node = new FBTreeNode ("My Computer");
340 root_path = MWFVFS.MyComputerPrefix;
341 break;
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);
346 break;
349 root_node.Tag = root_path;
350 root_node.ImageIndex = NodeImageIndex (root_path);
352 FillNode (root_node);
354 root_node.Expand ();
356 Nodes.Add (root_node);
360 public string SelectedPath {
361 set {
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)
376 return;
378 if (fbnode.RealPath == null)
379 return;
381 string tmp_filename = "New Folder";
383 if (Directory.Exists (Path.Combine (fbnode.RealPath, tmp_filename))) {
384 int i = 1;
386 if ((platform == 4) || (platform == 128)) {
387 tmp_filename = tmp_filename + "-" + i;
388 } else {
389 tmp_filename = tmp_filename + " (" + i + ")";
392 while (Directory.Exists (Path.Combine (fbnode.RealPath, tmp_filename))) {
393 i++;
394 if ((platform == 4) || (platform == 128)) {
395 tmp_filename = "New Folder" + "-" + i;
396 } else {
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);
407 FillNode (fbnode);
408 dont_do_onbeforeexpand = true;
409 fbnode.Expand ();
410 dont_do_onbeforeexpand = false;
412 fbnode.Nodes.Add (new_node);
414 LabelEdit = true;
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;
429 } else {
430 SelectedNode = e.Node.Parent;
431 e.Node.Parent.Nodes.Remove(e.Node);
434 e.Node.EndEdit (false);
435 } else {
436 e.CancelEdit = true;
437 e.Node.BeginEdit();
440 LabelEdit = false;
444 private void SetSelectedPath (string path)
446 BeginUpdate ();
448 FBTreeNode node = FindPathInNodes (path, Nodes);
450 if (node == null) {
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);
458 if (node == null) {
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) {
469 FillNode (node);
470 node.Expand ();
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) {
480 node = fbnode;
481 path_cut += part_name;
483 FillNode (node);
484 node.Expand ();
485 break;
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) {
495 node = fbnode;
496 break;
502 if (node != null) {
503 SelectedNode = node;
504 node.EnsureVisible ();
507 EndUpdate ();
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)
517 return fbnode;
520 return FindPathInNodes (path, node.Nodes);
523 return null;
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) {
531 try {
532 if (!Directory.Exists (path))
533 return false;
535 switch (rootFolder) {
536 case Environment.SpecialFolder.Desktop:
537 case Environment.SpecialFolder.MyComputer:
538 return true;
539 case Environment.SpecialFolder.Personal:
540 if (!path.StartsWith (root_path))
541 return false;
542 else
543 return true;
544 default:
545 return false;
547 } catch {}
550 return false;
553 private void FillNode (TreeNode node)
555 BeginUpdate ();
557 node.Nodes.Clear ();
558 vfs.ChangeDirectory ((string)node.Tag);
559 ArrayList folders = vfs.GetFoldersOnly ();
561 foreach (FSEntry fsentry in folders) {
562 if (fsentry.Name.StartsWith ("."))
563 continue;
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));
576 break;
580 node.Nodes.Add (child);
583 EndUpdate ();
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)
601 int index = 5;
603 if (path == MWFVFS.DesktopPrefix)
604 index = 1;
605 else
606 if (path == MWFVFS.RecentlyUsedPrefix)
607 index = 0;
608 else
609 if (path == MWFVFS.PersonalPrefix)
610 index = 2;
611 else
612 if (path == MWFVFS.MyComputerPrefix)
613 index = 3;
614 else
615 if (path == MWFVFS.MyNetworkPrefix)
616 index = 4;
618 return index;
621 protected override void OnAfterSelect (TreeViewEventArgs e)
623 if (e.Node == null)
624 return;
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;
632 dont_enable = true;
633 } else {
634 parentDialog.okButton.Enabled = true;
635 parentDialog.newFolderButton.Enabled = true;
636 parentDialog.newFolderMenuItem.Enabled = true;
637 parentDialog.selectedPath = fbnode.RealPath;
638 dont_enable = false;
641 base.OnAfterSelect (e);
644 protected internal override void OnBeforeExpand (TreeViewCancelEventArgs e)
646 if (!dont_do_onbeforeexpand) {
647 if (e.Node == root_node)
648 return;
649 FillNode (e.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;
661 } else
662 if (!dont_enable) {
663 parentDialog.okButton.Enabled = true;
664 parentDialog.newFolderButton.Enabled = true;
665 parentDialog.newFolderMenuItem.Enabled = true;
668 base.OnMouseUp (e);
672 internal class FBTreeNode : TreeNode
674 private string realPath = null;
676 public FBTreeNode (string text)
678 Text = text;
681 public string RealPath {
682 set {
683 realPath = value;
686 get {
687 return realPath;