* TreeView.cs: Don't draw the selected node when we lose
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / FolderBrowserDialog.cs
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.
11 //
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.
19 //
20 // Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
21 //
22 // Authors:
23 //      Alexander Olk (xenomorph2@onlinehome.de)
24 //
25 //
26
27 // NOT COMPLETE
28 // TODO:
29 // - create new folder if NewFolderButton is pressed
30 // - better handling of Environment.SpecialFolders
31 // - fix: if SelectedPath != "" and it is beyond RootFolder then show it (currently TreeNode.EnsureVisible() is missing...)
32
33 using System;
34 using System.Drawing;
35 using System.ComponentModel;
36 using System.Resources;
37 using System.IO;
38 using System.Collections;
39
40 namespace System.Windows.Forms
41 {
42         [DefaultEvent("HelpRequest")]
43         [DefaultProperty("SelectedPath")]
44         [Designer("System.Windows.Forms.Design.FolderBrowserDialogDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
45         public sealed class FolderBrowserDialog : CommonDialog
46         {
47                 #region Local Variables
48                 private string description = "";
49                 private Environment.SpecialFolder rootFolder = Environment.SpecialFolder.Desktop;
50                 private string selectedPath = "";
51                 private bool showNewFolderButton = true;
52
53                 #endregion      // Local Variables
54                 
55                 #region Public Constructors
56                 public FolderBrowserDialog( )
57                 {
58                         form = new FolderBrowserDialogForm( this );
59                         form.Size =  new Size( 322, 288 );
60                         form.MinimumSize = new Size( 322, 288 );
61                         form.Text = "Search Folder";
62                 }
63                 #endregion      // Public Constructors
64                 
65                 #region Public Instance Properties
66                 [Browsable(true)]
67                 [DefaultValue("")]
68                 [Localizable(true)]
69                 public string Description
70                 {
71                         set
72                         {
73                                 description = value;
74                         }
75                         
76                         get
77                         {
78                                 return description;
79                         }
80                 }
81                 
82                 [Browsable(true)]
83                 [DefaultValue(Environment.SpecialFolder.Desktop)]
84                 [Localizable(false)]
85                 public Environment.SpecialFolder RootFolder
86                 {
87                         set
88                         {
89                                 rootFolder = value;
90                         }
91                         
92                         get
93                         {
94                                 return rootFolder;
95                         }
96                 }
97                 
98                 [Browsable(true)]
99                 [DefaultValue("")]
100                 [Editor("System.Windows.Forms.Design.SelectedPathEditor, " + Consts.AssemblySystem_Design, typeof(System.Drawing.Design.UITypeEditor))]
101                 [Localizable(true)]
102                 public string SelectedPath
103                 {
104                         set
105                         {
106                                 selectedPath = value;
107                         }
108                         
109                         get
110                         {
111                                 return selectedPath;
112                         }
113                 }
114
115                 [Browsable(true)]
116                 [DefaultValue(true)]
117                 [Localizable(false)]
118                 public bool ShowNewFolderButton
119                 {
120                         set
121                         {
122                                 showNewFolderButton = value;
123                         }
124                         
125                         get
126                         {
127                                 return showNewFolderButton;
128                         }
129                 }
130                 #endregion      // Public Instance Properties
131                 
132                 #region Public Instance Methods
133                 public override void Reset( )
134                 {
135                         description = "";
136                         rootFolder = Environment.SpecialFolder.Desktop;
137                         selectedPath = "";
138                         showNewFolderButton = true;
139                 }
140                 
141                 protected override bool RunDialog( IntPtr hwndOwner )
142                 {
143                         FolderBrowserDialogPanel fb = new FolderBrowserDialogPanel (this);
144                         form.Controls.Add (fb);
145                         return true;
146                 }
147                 #endregion      // Public Instance Methods
148
149                 #region Internal Methods
150                 internal class FolderBrowserDialogForm : DialogForm
151                 {
152                         internal FolderBrowserDialogForm( CommonDialog owner )
153                         : base( owner )
154                         {}
155                         
156                         protected override CreateParams CreateParams
157                         {
158                                 get
159                                 {
160                                         CreateParams    cp;
161                                         
162                                         ControlBox = true;
163                                         MinimizeBox = false;
164                                         MaximizeBox = false;
165                                         
166                                         cp = base.CreateParams;
167                                         cp.Style = (int)( WindowStyles.WS_POPUP | WindowStyles.WS_CAPTION | WindowStyles.WS_SYSMENU | WindowStyles.WS_CLIPCHILDREN | WindowStyles.WS_CLIPSIBLINGS );
168                                         cp.Style |= (int)WindowStyles.WS_OVERLAPPEDWINDOW;
169                                         
170                                         return cp;
171                                 }
172                         }
173                 }
174                 
175                 internal class FolderBrowserDialogPanel : Panel
176                 {
177                         private Label descriptionLabel;
178                         private Button cancelButton;
179                         private Button okButton;
180                         private TreeView folderBrowserTreeView;
181                         private Button newFolderButton;
182                         
183                         private FolderBrowserDialog folderBrowserDialog;
184                         private string selectedPath;
185                         
186                         private ImageList imageList;
187                         private TreeNode selectedPathNode = null;
188                         private TreeNode root_node;
189
190                         public FolderBrowserDialogPanel (FolderBrowserDialog folderBrowserDialog)
191                         {
192                                 this.folderBrowserDialog = folderBrowserDialog;
193                                 
194                                 newFolderButton = new Button( );
195                                 folderBrowserTreeView = new TreeView( );
196                                 okButton = new Button( );
197                                 cancelButton = new Button( );
198                                 descriptionLabel = new Label( );
199                                 
200                                 imageList = new ImageList( );
201                                 
202                                 folderBrowserDialog.form.AcceptButton = okButton;
203                                 folderBrowserDialog.form.CancelButton = cancelButton;
204                                 
205                                 SuspendLayout( );
206                                 
207                                 // descriptionLabel
208                                 descriptionLabel.Anchor = ( (AnchorStyles)( ( ( AnchorStyles.Top | AnchorStyles.Left )
209                                 | AnchorStyles.Right ) ) );
210                                 descriptionLabel.Location = new Point( 17, 14 );
211                                 descriptionLabel.Size = new Size( 290, 40 );
212                                 descriptionLabel.TabIndex = 0;
213                                 descriptionLabel.Text = folderBrowserDialog.Description;
214                                 
215                                 // folderBrowserTreeView
216                                 folderBrowserTreeView.Anchor = ( (AnchorStyles)( ( ( ( AnchorStyles.Top | AnchorStyles.Bottom )
217                                 | AnchorStyles.Left )
218                                 | AnchorStyles.Right ) ) );
219                                 folderBrowserTreeView.ImageIndex = -1;
220                                 folderBrowserTreeView.Location = new Point( 20, 61 );
221                                 folderBrowserTreeView.SelectedImageIndex = -1;
222                                 folderBrowserTreeView.Size = new Size( 278, 153 );
223                                 folderBrowserTreeView.TabIndex = 1;
224                                 folderBrowserTreeView.ImageList = imageList;
225                                 folderBrowserTreeView.ShowLines = false;
226                                 folderBrowserTreeView.ShowPlusMinus = true;
227                                 folderBrowserTreeView.HotTracking = true;
228                                 //folderBrowserTreeView.Indent = 2;
229                                 
230                                 // newFolderButton
231                                 newFolderButton.Anchor = ( (AnchorStyles)( ( AnchorStyles.Bottom | AnchorStyles.Left ) ) );
232                                 newFolderButton.FlatStyle = FlatStyle.System;
233                                 newFolderButton.Location = new Point( 14, 230 );
234                                 newFolderButton.Size = new Size( 125, 23 );
235                                 newFolderButton.TabIndex = 2;
236                                 newFolderButton.Text = "New Folder";
237                                 newFolderButton.Enabled = folderBrowserDialog.ShowNewFolderButton;
238                                 
239                                 // okButton
240                                 okButton.Anchor = ( (AnchorStyles)( ( AnchorStyles.Bottom | AnchorStyles.Right ) ) );
241                                 okButton.FlatStyle = FlatStyle.System;
242                                 okButton.Location = new Point( 142, 230 );
243                                 okButton.Size = new Size( 80, 23 );
244                                 okButton.TabIndex = 3;
245                                 okButton.Text = "OK";
246                                 
247                                 // cancelButton
248                                 cancelButton.Anchor = ( (AnchorStyles)( ( AnchorStyles.Bottom | AnchorStyles.Right ) ) );
249                                 cancelButton.DialogResult = DialogResult.Cancel;
250                                 cancelButton.FlatStyle = FlatStyle.System;
251                                 cancelButton.Location = new Point( 226, 230 );
252                                 cancelButton.Size = new Size( 80, 23 );
253                                 cancelButton.TabIndex = 4;
254                                 cancelButton.Text = "Cancel";
255                                 
256                                 // FolderBrowserDialog
257                                 ClientSize = new Size( 322, 288 );
258                                 Dock = DockStyle.Fill;
259
260                                 Controls.Add( cancelButton );
261                                 Controls.Add( okButton );
262                                 Controls.Add( newFolderButton );
263                                 Controls.Add( folderBrowserTreeView );
264                                 Controls.Add( descriptionLabel );
265                                 ResumeLayout( false );
266                                 
267                                 SetupImageList( );
268                                 
269                                 okButton.Click += new EventHandler( OnClickOKButton );
270                                 cancelButton.Click += new EventHandler( OnClickCancelButton );
271
272                                 string root_path = Environment.GetFolderPath (folderBrowserDialog.RootFolder);
273                                 root_node = new TreeNode (Path.GetFileName (root_path));
274                                 root_node.Tag = root_path;
275                                 root_node.ImageIndex = NodeImageIndex (root_path);
276
277                                 // If we add the sub nodes before the root is added to the
278                                 // tree no refreshing will be done whil adding
279                                 if (folderBrowserDialog.RootFolder == Environment.SpecialFolder.Desktop) {
280
281
282                                         // Add something similar to 'My Computer'
283                                         TreeNode mycomp = new TreeNode ("My Computer");
284                                         if (Path.DirectorySeparatorChar == '/')
285                                                 mycomp.Tag = "/";
286                                         else
287                                                 mycomp.Tag = Environment.GetFolderPath (Environment.SpecialFolder.MyComputer);
288                                         mycomp.ImageIndex = NodeImageIndex ((string) mycomp.Tag);
289
290                                         // A home directory
291                                         string home_path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
292                                         TreeNode home = new TreeNode (Path.GetFileName (home_path));
293                                         home.Tag = home_path;
294                                         home.ImageIndex = NodeImageIndex (home_path);
295                                         
296                                         // This is so we get the expand box
297                                         mycomp.Nodes.Add (new TreeNode (String.Empty));
298                                         home.Nodes.Add (new TreeNode (String.Empty)); 
299
300                                         root_node.Nodes.Add (mycomp);
301                                         root_node.Nodes.Add (home);
302                                         root_node.Expand ();
303                                 } else {
304                                         FillNode (root_node);
305                                 }
306
307                                 folderBrowserTreeView.Nodes.Add (root_node);
308
309                                 folderBrowserTreeView.BeforeExpand += new TreeViewCancelEventHandler (OnBeforeExpand);
310                                 folderBrowserTreeView.AfterSelect += new TreeViewEventHandler( OnAfterSelectFolderBrowserTreeView );
311                         }
312                         
313                         public string SelectedPath
314                         {
315                                 set
316                                 {
317                                         selectedPath = value;
318                                 }
319                                 
320                                 get
321                                 {
322                                         return selectedPath;
323                                 }
324                         }
325                         
326                         void OnClickOKButton( object sender, EventArgs e )
327                         {
328                                 folderBrowserDialog.SelectedPath = selectedPath;
329                                 
330                                 folderBrowserDialog.form.Controls.Remove( this );
331                                 folderBrowserDialog.form.DialogResult = DialogResult.OK;
332                         }
333                         
334                         void OnClickCancelButton( object sender, EventArgs e )
335                         {
336                                 folderBrowserDialog.form.Controls.Remove( this );
337                                 folderBrowserDialog.form.DialogResult = DialogResult.Cancel;
338                         }
339                         
340                         void OnAfterSelectFolderBrowserTreeView( object sender, TreeViewEventArgs e )
341                         {
342                                 if (e.Node == null)
343                                         return;
344                                 selectedPath = (string) e.Node.Tag;
345                         }
346
347                         private void OnBeforeExpand (object sender, TreeViewCancelEventArgs e)
348                         {
349                                 if (e.Node == root_node)
350                                         return;
351                                 FillNode (e.Node);
352                         }
353
354                         private void OnAfterCollapse (object sender, TreeViewCancelEventArgs e)
355                         {
356                                 if (e.Node == root_node)
357                                         return;
358                                 e.Node.Nodes.Clear ();
359                         }
360
361                         private void FillNode (TreeNode node)
362                         {
363                                 Cursor old = folderBrowserTreeView.Cursor;
364                                 folderBrowserTreeView.Cursor = Cursors.WaitCursor;
365
366                                 folderBrowserTreeView.BeginUpdate ();
367
368                                 node.Nodes.Clear ();
369                                 string path = node.Tag as string;
370                                 string [] dirs = Directory.GetDirectories (path);
371
372                                 foreach (string s in dirs) {
373                                         string name = Path.GetFileName (s);
374                                         // filter out . directories
375                                         if (name.StartsWith ("."))
376                                                 continue;
377                                         TreeNode child = new TreeNode (name);
378                                         child.Tag = s;
379                                         child.ImageIndex = NodeImageIndex (s);
380
381                                         try {
382                                                 // so we get the plus
383                                                 string [] subdirs = Directory.GetDirectories (s);
384                                                 foreach (string subdir in subdirs) {
385                                                         // filter out . directories (le sigh)
386                                                         string subdirname = Path.GetFileName (subdir);
387                                                         if (!subdirname.StartsWith (".")) {
388                                                                 child.Nodes.Add (new TreeNode (String.Empty));
389                                                                 break;
390                                                         }
391                                                 }
392                                         } catch {
393                                                 // Probably don't have access
394                                         }
395
396                                         node.Nodes.Add (child);
397                                 }
398
399                                 folderBrowserTreeView.EndUpdate ();
400                                 folderBrowserTreeView.Cursor = old;
401                         }
402
403                         private int NodeImageIndex( string path )
404                         {
405                                 int index = 5;
406                                 
407                                 if ( path == Environment.GetFolderPath( Environment.SpecialFolder.Desktop ) )
408                                         index = 1;
409                                 else
410                                 if ( path == Environment.GetFolderPath( Environment.SpecialFolder.Personal ) )
411                                         index = 2;
412                                 
413                                 return index;
414                         }
415                         
416                         private void SetupImageList( )
417                         {
418                                 imageList.ColorDepth = ColorDepth.Depth32Bit;
419                                 imageList.ImageSize = new Size( 16, 16 );
420                                 imageList.Images.Add( (Image)Locale.GetResource( "last_open" ) );
421                                 imageList.Images.Add( (Image)Locale.GetResource( "desktop" ) );
422                                 imageList.Images.Add( (Image)Locale.GetResource( "folder_with_paper" ) );
423                                 imageList.Images.Add( (Image)Locale.GetResource( "monitor-computer" ) );
424                                 imageList.Images.Add( (Image)Locale.GetResource( "monitor-planet" ) );
425                                 imageList.Images.Add( (Image)Locale.GetResource( "folder" ) );
426                                 imageList.Images.Add( (Image)Locale.GetResource( "paper" ) );
427                                 imageList.TransparentColor = Color.Transparent;
428                         }
429                 }
430                 #endregion      // Internal Methods
431
432                 #region Events
433                 [Browsable(false)]
434                 [EditorBrowsable(EditorBrowsableState.Never)]
435                 public event EventHandler HelpRequest;
436                 #endregion
437         }
438 }